From 7dbc9129db980a7cef03211ff08bdffb8b5f7514 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Mon, 11 Nov 2024 13:01:59 +0100 Subject: [PATCH] hw: detach UTCB from core PD in thread destruction Ref genodelabs/genode#5380 --- repos/base-hw/src/core/platform_thread.cc | 155 ++++++++++++++-------- repos/base-hw/src/core/platform_thread.h | 19 ++- 2 files changed, 116 insertions(+), 58 deletions(-) diff --git a/repos/base-hw/src/core/platform_thread.cc b/repos/base-hw/src/core/platform_thread.cc index 7ae23acd04..fb8f8d1b50 100644 --- a/repos/base-hw/src/core/platform_thread.cc +++ b/repos/base-hw/src/core/platform_thread.cc @@ -30,6 +30,79 @@ using namespace Core; +Ram_dataspace_capability Platform_thread::Utcb::_allocate_utcb(bool core_thread) +{ + Ram_dataspace_capability ds; + + if (core_thread) + return ds; + + try { + ds = core_env().pd_session()->alloc(sizeof(Native_utcb), CACHED); + } catch (...) { + error("failed to allocate UTCB"); + throw Out_of_ram(); + } + + return ds; +} + + +addr_t Platform_thread::Utcb::_core_local_address(addr_t utcb_addr, + bool core_thread) +{ + if (core_thread) + return utcb_addr; + + addr_t ret = 0; + + Region_map::Attr attr { }; + attr.writeable = true; + core_env().rm_session()->attach(_ds, attr).with_result( + [&] (Region_map::Range range) { + ret = range.start; }, + [&] (Region_map::Attach_error) { + error("failed to attach UTCB of new thread within core"); }); + + return ret; +} + + +Platform_thread::Utcb::Utcb(addr_t pd_addr, bool core_thread) +: + _ds(_allocate_utcb(core_thread)), + _core_addr(_core_local_address(pd_addr, core_thread)) +{ + /* + * All non-core threads use the typical dataspace/rm_session + * mechanisms to allocate and attach its UTCB. + * But for the very first core threads, we need to use plain + * physical and virtual memory allocators to create/attach its + * UTCBs. Therefore, we've to allocate and map those here. + */ + if (core_thread) { + platform().ram_alloc().try_alloc(sizeof(Native_utcb)).with_result( + + [&] (void *utcb_phys) { + map_local((addr_t)utcb_phys, _core_addr, + sizeof(Native_utcb) / get_page_size()); + }, + [&] (Range_allocator::Alloc_error) { + error("failed to allocate UTCB for core/kernel thread!"); + throw Out_of_ram(); + } + ); + } +} + + +Platform_thread::Utcb::~Utcb() +{ + /* detach UTCB from core/kernel */ + core_env().rm_session()->detach((addr_t)_core_addr); +} + + void Platform_thread::_init() { } @@ -37,21 +110,6 @@ Weak_ptr& Platform_thread::address_space() { return _address_space; } -Platform_thread::~Platform_thread() -{ - /* detach UTCB of main threads */ - if (_main_thread) { - Locked_ptr locked_ptr(_address_space); - if (locked_ptr.valid()) - locked_ptr->flush((addr_t)_utcb_pd_addr, sizeof(Native_utcb), - Address_space::Core_local_addr{0}); - } - - /* free UTCB */ - core_env().pd_session()->free(_utcb); -} - - void Platform_thread::quota(size_t const quota) { _quota = (unsigned)quota; @@ -64,26 +122,10 @@ Platform_thread::Platform_thread(Label const &label, Native_utcb &utcb) _label(label), _pd(_kernel_main_get_core_platform_pd()), _pager(nullptr), - _utcb_core_addr(&utcb), - _utcb_pd_addr(&utcb), + _utcb((addr_t)&utcb, true), _main_thread(false), _location(Affinity::Location()), - _kobj(_kobj.CALLED_FROM_CORE, _label.string()) -{ - /* create UTCB for a core thread */ - platform().ram_alloc().try_alloc(sizeof(Native_utcb)).with_result( - - [&] (void *utcb_phys) { - map_local((addr_t)utcb_phys, (addr_t)_utcb_core_addr, - sizeof(Native_utcb) / get_page_size()); - }, - [&] (Range_allocator::Alloc_error) { - error("failed to allocate UTCB"); - /* XXX distinguish error conditions */ - throw Out_of_ram(); - } - ); -} + _kobj(_kobj.CALLED_FROM_CORE, _label.string()) { } Platform_thread::Platform_thread(Platform_pd &pd, @@ -96,33 +138,39 @@ Platform_thread::Platform_thread(Platform_pd &pd, _label(label), _pd(pd), _pager(nullptr), - _utcb_pd_addr((Native_utcb *)utcb), + _utcb(utcb, false), _priority(_scale_priority(virt_prio)), _quota((unsigned)quota), _main_thread(!pd.has_any_thread), _location(location), _kobj(_kobj.CALLED_FROM_CORE, _priority, _quota, _label.string()) { - try { - _utcb = core_env().pd_session()->alloc(sizeof(Native_utcb), CACHED); - } catch (...) { - error("failed to allocate UTCB"); - throw Out_of_ram(); - } - - Region_map::Attr attr { }; - attr.writeable = true; - core_env().rm_session()->attach(_utcb, attr).with_result( - [&] (Region_map::Range range) { - _utcb_core_addr = (Native_utcb *)range.start; }, - [&] (Region_map::Attach_error) { - error("failed to attach UTCB of new thread within core"); }); - _address_space = pd.weak_ptr(); pd.has_any_thread = true; } +Platform_thread::~Platform_thread() +{ + /* core/kernel threads have no dataspace, but plain memory as UTCB */ + if (!_utcb._ds.valid()) { + error("UTCB of core/kernel thread gets destructed!"); + return; + } + + /* detach UTCB of main threads */ + if (_main_thread) { + Locked_ptr locked_ptr(_address_space); + if (locked_ptr.valid()) + locked_ptr->flush(user_utcb_main_thread(), sizeof(Native_utcb), + Address_space::Core_local_addr{0}); + } + + /* free UTCB */ + core_env().pd_session()->free(_utcb._ds); +} + + void Platform_thread::affinity(Affinity::Location const &) { /* yet no migration support, don't claim wrong location, e.g. for tracing */ @@ -147,16 +195,15 @@ void Platform_thread::start(void * const ip, void * const sp) error("invalid RM client"); return -1; }; - _utcb_pd_addr = (Native_utcb *)user_utcb_main_thread(); Hw::Address_space * as = static_cast(&*locked_ptr); - if (!as->insert_translation((addr_t)_utcb_pd_addr, dsc->phys_addr(), + if (!as->insert_translation(user_utcb_main_thread(), dsc->phys_addr(), sizeof(Native_utcb), Hw::PAGE_FLAGS_UTCB)) { error("failed to attach UTCB"); return -1; } return 0; }; - if (core_env().entrypoint().apply(_utcb, lambda)) + if (core_env().entrypoint().apply(_utcb._ds, lambda)) return; } @@ -174,9 +221,9 @@ void Platform_thread::start(void * const ip, void * const sp) utcb.cap_add(Capability_space::capid(_kobj.cap())); if (_main_thread) { utcb.cap_add(Capability_space::capid(_pd.parent())); - utcb.cap_add(Capability_space::capid(_utcb)); + utcb.cap_add(Capability_space::capid(_utcb._ds)); } - Kernel::start_thread(*_kobj, cpu, _pd.kernel_pd(), *_utcb_core_addr); + Kernel::start_thread(*_kobj, cpu, _pd.kernel_pd(), *(Native_utcb*)_utcb._core_addr); } diff --git a/repos/base-hw/src/core/platform_thread.h b/repos/base-hw/src/core/platform_thread.h index 4c386eb1ef..c02973303a 100644 --- a/repos/base-hw/src/core/platform_thread.h +++ b/repos/base-hw/src/core/platform_thread.h @@ -55,13 +55,24 @@ class Core::Platform_thread : Noncopyable using Label = String<32>; + struct Utcb + { + Ram_dataspace_capability _ds { }; /* UTCB ds of non-core threads */ + + addr_t const _core_addr; /* UTCB address within core/kernel */ + + Ram_dataspace_capability _allocate_utcb(bool core_thread); + addr_t _core_local_address(addr_t utcb_addr, bool core_thread); + + Utcb(addr_t pd_addr, bool core_thread); + ~Utcb(); + }; + Label const _label; Platform_pd &_pd; Weak_ptr _address_space { }; Pager_object * _pager; - Native_utcb * _utcb_core_addr { }; /* UTCB addr in core */ - Native_utcb * _utcb_pd_addr; /* UTCB addr in pd */ - Ram_dataspace_capability _utcb { }; /* UTCB dataspace */ + Utcb _utcb; unsigned _priority {0}; unsigned _quota {0}; @@ -241,7 +252,7 @@ class Core::Platform_thread : Noncopyable Platform_pd &pd() const { return _pd; } - Ram_dataspace_capability utcb() const { return _utcb; } + Ram_dataspace_capability utcb() const { return _utcb._ds; } }; #endif /* _CORE__PLATFORM_THREAD_H_ */