From bac7ba663964b6308d951a58c12ee8f1fb602993 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Fri, 29 Jun 2018 14:04:32 +0200 Subject: [PATCH] nova: remove echo thread in core and replace by remote delegate syscall Fixes #2895 --- repos/base-nova/lib/mk/core-nova.inc | 1 - repos/base-nova/src/core/core_region_map.cc | 3 +- repos/base-nova/src/core/echo.cc | 94 ------------------- repos/base-nova/src/core/include/echo.h | 58 ------------ repos/base-nova/src/core/include/map_local.h | 3 +- repos/base-nova/src/core/include/nova_util.h | 53 +++++------ .../src/core/irq_session_component.cc | 5 +- repos/base-nova/src/core/platform.cc | 33 ++++--- repos/base-nova/src/core/platform_thread.cc | 5 +- .../src/core/ram_dataspace_support.cc | 3 +- repos/base-nova/src/core/thread_start.cc | 3 +- 11 files changed, 56 insertions(+), 205 deletions(-) delete mode 100644 repos/base-nova/src/core/echo.cc delete mode 100644 repos/base-nova/src/core/include/echo.h diff --git a/repos/base-nova/lib/mk/core-nova.inc b/repos/base-nova/lib/mk/core-nova.inc index 5cabf50180..cdd9229580 100644 --- a/repos/base-nova/lib/mk/core-nova.inc +++ b/repos/base-nova/lib/mk/core-nova.inc @@ -14,7 +14,6 @@ SRC_CC += stack_area.cc \ dataspace_component.cc \ default_log.cc \ dump_alloc.cc \ - echo.cc \ io_mem_session_component.cc \ io_mem_session_support.cc \ io_port_session_component.cc \ diff --git a/repos/base-nova/src/core/core_region_map.cc b/repos/base-nova/src/core/core_region_map.cc index b7615e7bf2..b63bdb99be 100644 --- a/repos/base-nova/src/core/core_region_map.cc +++ b/repos/base-nova/src/core/core_region_map.cc @@ -78,7 +78,8 @@ Core_region_map::attach(Dataspace_capability ds_cap, size_t, Nova::Utcb * const utcb = reinterpret_cast(Thread::myself()->utcb()); const Nova::Rights rights(true, writeable && ds->writable(), executable); - if (map_local(utcb, ds->phys_addr(), reinterpret_cast(virt_ptr), + if (map_local(platform_specific()->core_pd_sel(), utcb, + ds->phys_addr(), reinterpret_cast(virt_ptr), page_rounded_size >> get_page_size_log2(), rights, true)) { platform()->region_alloc()->free(virt_ptr, page_rounded_size); throw Out_of_ram(); diff --git a/repos/base-nova/src/core/echo.cc b/repos/base-nova/src/core/echo.cc deleted file mode 100644 index 77de2c2bb9..0000000000 --- a/repos/base-nova/src/core/echo.cc +++ /dev/null @@ -1,94 +0,0 @@ -/* - * \brief Echo implementation - * \author Norman Feske - * \author Alexander Boettcher - * \date 2010-01-19 - */ - -/* - * Copyright (C) 2010-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* core-local includes */ -#include - -/* local includes */ -#include -#include - -enum { - ECHO_STACK_SIZE = 512, - ECHO_GLOBAL = false, - ECHO_EXC_BASE = 0, - ECHO_LOG2_COUNT = 1 /* selector for EC and out-of-memory portal */ -}; - - -inline void *echo_stack_top() -{ - static char echo_stack[ECHO_STACK_SIZE]; - return &echo_stack[ECHO_STACK_SIZE - sizeof(long)]; -} - - -/** - * IDC handler for the echo portal, executed by the echo EC - */ -static void echo_reply() -{ - /* collect map information from calling thread, sent as 3 words */ - Nova::Crd snd_rcv(echo()->utcb()->msg()[0]); - Nova::mword_t offset = echo()->utcb()->msg()[1]; - bool kern_pd = echo()->utcb()->msg()[2]; - bool dma_mem = echo()->utcb()->msg()[3]; - bool write_combined = echo()->utcb()->msg()[4]; - - /* reset message transfer descriptor */ - echo()->utcb()->set_msg_word(0); - /* append capability-range as message-transfer item */ - bool res = echo()->utcb()->append_item(snd_rcv, offset, kern_pd, false, - false, dma_mem, write_combined); - - /* set return code, 0 means failure */ - echo()->utcb()->msg()[0] = res; - echo()->utcb()->items += 1; - - /* during reply the mapping will be established */ - Nova::reply(echo_stack_top()); -} - - -Echo::Echo(Genode::addr_t utcb_addr) -: - _ec_sel(Genode::cap_map()->insert(ECHO_LOG2_COUNT)), - _pt_sel(Genode::cap_map()->insert()), - _utcb((Nova::Utcb *)utcb_addr) -{ - using namespace Nova; - - extern Genode::addr_t __initial_sp; - Hip const * const hip = reinterpret_cast(__initial_sp); - - /* create echo EC */ - Genode::addr_t const core_pd_sel = hip->sel_exc; - uint8_t res = create_ec(_ec_sel, core_pd_sel, boot_cpu(), utcb_addr, - reinterpret_cast(echo_stack_top()), - ECHO_EXC_BASE, ECHO_GLOBAL); - - /* make error condition visible by raising an unhandled page fault */ - if (res != Nova::NOVA_OK) { *reinterpret_cast(0) = 0xdead; } - - /* set up echo portal to ourself */ - res = create_pt(_pt_sel, core_pd_sel, _ec_sel, Mtd(0), (mword_t)echo_reply); - if (res != Nova::NOVA_OK) { *reinterpret_cast(0) = 0xdead; } - revoke(Obj_crd(_pt_sel, 0, Obj_crd::RIGHT_PT_CTRL)); - - /* echo thread doesn't receive anything, it transfers items during reply */ - utcb()->crd_rcv = utcb()->crd_xlt = 0; -} - - -Echo *echo() { static Echo inst(Echo::ECHO_UTCB_ADDR); return &inst; } diff --git a/repos/base-nova/src/core/include/echo.h b/repos/base-nova/src/core/include/echo.h deleted file mode 100644 index 8cbb17e5ae..0000000000 --- a/repos/base-nova/src/core/include/echo.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * \brief Echo interface - * \author Norman Feske - * \date 2010-01-19 - */ - -/* - * Copyright (C) 2010-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__INCLUDE__ECHO_H_ -#define _CORE__INCLUDE__ECHO_H_ - -/* NOVA includes */ -#include - -class Echo -{ - private: - - int _ec_sel; /* execution context */ - int _pt_sel; /* portal */ - Nova::Utcb *_utcb; - - public: - - enum { - ECHO_UTCB_ADDR = 0xbff00000, - }; - - /** - * Constructor - * - * \param utcb_addr designated UTCB location for echo EC - */ - Echo(Genode::addr_t utcb_addr); - - /** - * UTCB of echo execution context - */ - Nova::Utcb *utcb() { return _utcb; } - - /** - * Capability selector for portal to echo - */ - int pt_sel() { return _pt_sel; } -}; - - -/** - * Get single 'Echo' instance - */ -Echo *echo(); - -#endif /* _CORE__INCLUDE__ECHO_H_ */ diff --git a/repos/base-nova/src/core/include/map_local.h b/repos/base-nova/src/core/include/map_local.h index dc34771c09..b05bb22b0e 100644 --- a/repos/base-nova/src/core/include/map_local.h +++ b/repos/base-nova/src/core/include/map_local.h @@ -37,7 +37,8 @@ namespace Genode { inline bool map_local(addr_t from_phys, addr_t to_virt, size_t num_pages, bool read = true, bool write = true, bool exec = true) { - return (::map_local((Nova::Utcb *)Thread::myself()->utcb(), + return (::map_local(platform_specific()->core_pd_sel(), + (Nova::Utcb *)Thread::myself()->utcb(), from_phys, to_virt, num_pages, Nova::Rights(read, write, exec), true) == 0); } diff --git a/repos/base-nova/src/core/include/nova_util.h b/repos/base-nova/src/core/include/nova_util.h index 48017c0bd7..d8a03e3c54 100644 --- a/repos/base-nova/src/core/include/nova_util.h +++ b/repos/base-nova/src/core/include/nova_util.h @@ -23,7 +23,6 @@ #include /* local includes */ -#include #include /** @@ -55,31 +54,22 @@ inline Genode::addr_t boot_cpu() * target * \param kern_pd Whether to map the items from the kernel or from core * \param dma_mem Whether the memory is usable for DMA or not - * - * This functions sends a message from the calling EC to the echo EC. - * The calling EC opens a receive window and the echo EC creates a transfer - * item of the message and replies. The kernel will map during the reply - * from the echo EC to the calling EC. */ -static int map_local(Nova::Utcb *utcb, Nova::Crd src_crd, Nova::Crd dst_crd, - bool kern_pd = false, bool dma_mem = false, - bool write_combined = false) +static int map_local(Genode::addr_t const pd, Nova::Utcb * const utcb, + Nova::Crd const src_crd, Nova::Crd const dst_crd, + bool const kern_pd = false, bool const dma_mem = false, + bool const write_combined = false) { - /* open receive window at current EC */ - utcb->crd_rcv = dst_crd; + /* asynchronously map capabilities */ + utcb->set_msg_word(0); - /* tell echo thread what to map */ - utcb->msg()[0] = src_crd.value(); - utcb->msg()[1] = 0; - utcb->msg()[2] = kern_pd; - utcb->msg()[3] = dma_mem; - utcb->msg()[4] = write_combined; - utcb->set_msg_word(5); + /* ignore return value as one item always fits into the utcb */ + bool const ok = utcb->append_item(src_crd, 0, kern_pd, false, false, + dma_mem, write_combined); + (void)ok; - /* establish the mapping via a portal traversal during reply phase */ - Nova::uint8_t res = Nova::call(echo()->pt_sel()); - if (res != Nova::NOVA_OK || utcb->msg_words() != 1 || !utcb->msg()[0] || - utcb->msg_items() != 1) { + Nova::uint8_t res = Nova::delegate(pd, pd, dst_crd); + if (res != Nova::NOVA_OK) { typedef Genode::Hex Hex; error("map_local failed ", @@ -103,12 +93,17 @@ static int map_local(Nova::Utcb *utcb, Nova::Crd src_crd, Nova::Crd dst_crd, static inline int unmap_local(Nova::Crd crd, bool self = true) { return Nova::revoke(crd, self); } -inline int map_local_phys_to_virt(Nova::Utcb *utcb, Nova::Crd src, - Nova::Crd dst) { - return map_local(utcb, src, dst, true); } +inline int map_local_phys_to_virt(Nova::Utcb * const utcb, Nova::Crd const src, + Nova::Crd const dst, Genode::addr_t const pd) +{ + return map_local(pd, utcb, src, dst, true); +} -inline int map_local_one_to_one(Nova::Utcb *utcb, Nova::Crd crd) { - return map_local(utcb, crd, crd, true); } +inline int map_local_one_to_one(Nova::Utcb * const utcb, Nova::Crd const crd, + Genode::addr_t const pd) +{ + return map_local(pd, utcb, crd, crd, true); +} /** @@ -133,7 +128,7 @@ lsb_bit(unsigned long const &value, unsigned char const shift = 0) * \param to_start local virtual destination address * \param num_pages number of pages to map */ -inline int map_local(Nova::Utcb *utcb, +inline int map_local(Genode::addr_t const pd, Nova::Utcb *utcb, Genode::addr_t from_start, Genode::addr_t to_start, Genode::size_t num_pages, Nova::Rights const &permission, @@ -169,7 +164,7 @@ inline int map_local(Nova::Utcb *utcb, if ((to_end - to_curr) < (1UL << order)) order = log2(to_end - to_curr); - int const res = map_local(utcb, + int const res = map_local(pd, utcb, Mem_crd((from_curr >> 12), order - get_page_size_log2(), permission), Mem_crd((to_curr >> 12), order - get_page_size_log2(), permission), kern_pd, dma_mem, write_combined); diff --git a/repos/base-nova/src/core/irq_session_component.cc b/repos/base-nova/src/core/irq_session_component.cc index 4f78c7611a..ce29d55e36 100644 --- a/repos/base-nova/src/core/irq_session_component.cc +++ b/repos/base-nova/src/core/irq_session_component.cc @@ -84,7 +84,7 @@ static bool msi(Genode::addr_t irq_sel, Genode::addr_t phys_mem, Nova::Mem_crd virt_crd(virt_addr >> 12, 0, Rights(true, false, false)); Utcb * utcb = reinterpret_cast(Thread::myself()->utcb()); - if (map_local_phys_to_virt(utcb, phys_crd, virt_crd)) { + if (map_local_phys_to_virt(utcb, phys_crd, virt_crd, platform_specific()->core_pd_sel())) { platform()->region_alloc()->free(virt, 4096); return false; } @@ -142,7 +142,8 @@ void Irq_object::start(unsigned irq, Genode::addr_t const device_phys) Obj_crd dst(irq_sel(), 0); enum { MAP_FROM_KERNEL_TO_CORE = true }; - int ret = map_local((Nova::Utcb *)Thread::myself()->utcb(), + int ret = map_local(platform_specific()->core_pd_sel(), + (Nova::Utcb *)Thread::myself()->utcb(), src, dst, MAP_FROM_KERNEL_TO_CORE); if (ret) { error("getting IRQ from kernel failed - ", irq); diff --git a/repos/base-nova/src/core/platform.cc b/repos/base-nova/src/core/platform.cc index f7fedb068a..1eed812805 100644 --- a/repos/base-nova/src/core/platform.cc +++ b/repos/base-nova/src/core/platform.cc @@ -86,7 +86,8 @@ addr_t Platform::_map_pages(addr_t const phys_addr, addr_t const pages, addr_t const core_local_addr = reinterpret_cast(core_local_ptr); - int res = map_local(__main_thread_utcb, phys_addr, core_local_addr, pages, + int res = map_local(_core_pd_sel, __main_thread_utcb, phys_addr, + core_local_addr, pages, Nova::Rights(true, true, false), true); return res ? 0 : core_local_addr; @@ -219,7 +220,7 @@ static void startup_handler() static addr_t init_core_page_fault_handler(addr_t const core_pd_sel) { - /* create echo EC */ + /* create fault handler EC for core main thread */ enum { GLOBAL = false, EXC_BASE = 0 @@ -307,12 +308,13 @@ Platform::Platform() : /* locally map the whole I/O port range */ enum { ORDER_64K = 16 }; - map_local_one_to_one(__main_thread_utcb, Io_crd(0, ORDER_64K)); + map_local_one_to_one(__main_thread_utcb, Io_crd(0, ORDER_64K), _core_pd_sel); /* map BDA region, console reads IO ports at BDA_VIRT_ADDR + 0x400 */ enum { BDA_PHY = 0x0U, BDA_VIRT = 0x1U, BDA_VIRT_ADDR = 0x1000U }; map_local_phys_to_virt(__main_thread_utcb, Mem_crd(BDA_PHY, 0, Rights(true, false, false)), - Mem_crd(BDA_VIRT, 0, Rights(true, false, false))); + Mem_crd(BDA_VIRT, 0, Rights(true, false, false)), + _core_pd_sel); /* @@ -324,7 +326,7 @@ Platform::Platform() : * we do this that early, because Core_mem_allocator uses * the main_thread_utcb very early to establish mappings */ - if (map_local(__main_thread_utcb, (addr_t)__main_thread_utcb, + if (map_local(_core_pd_sel, __main_thread_utcb, (addr_t)__main_thread_utcb, (addr_t)main_thread_utcb(), 1, Rights(true, true, false))) { error("could not remap utcb of main thread"); nova_die(); @@ -359,7 +361,7 @@ Platform::Platform() : error("unaligned sc_idle_base value ", Hex(sc_idle_base)); nova_die(); } - if (map_local(__main_thread_utcb, Obj_crd(0, log2cpu), + if (map_local(_core_pd_sel, __main_thread_utcb, Obj_crd(0, log2cpu), Obj_crd(sc_idle_base, log2cpu), true)) nova_die(); @@ -388,7 +390,7 @@ Platform::Platform() : #endif /* set up page fault handler for core - for debugging */ - addr_t const ec_echo_sel = init_core_page_fault_handler(core_pd_sel()); + addr_t const ec_core_exc_sel = init_core_page_fault_handler(core_pd_sel()); if (verbose_boot_info) { if (hip->has_feature_vmx()) @@ -458,10 +460,6 @@ Platform::Platform() : region_alloc()->remove_range(CORE_PAGER_UTCB_ADDR - get_page_size(), get_page_size() * 3); - /* exclude utcb of echo thread + empty guard pages before and after */ - region_alloc()->remove_range(Echo::ECHO_UTCB_ADDR - get_page_size(), - get_page_size() * 3); - /* exclude utcb of main thread and hip + empty guard pages before and after */ region_alloc()->remove_range((addr_t)__main_thread_utcb - get_page_size(), get_page_size() * 4); @@ -469,7 +467,7 @@ Platform::Platform() : /* sanity checks */ addr_t check [] = { reinterpret_cast(__main_thread_utcb), CORE_PAGER_UTCB_ADDR, - Echo::ECHO_UTCB_ADDR, BDA_VIRT_ADDR + BDA_VIRT_ADDR }; for (unsigned i = 0; i < sizeof(check) / sizeof(check[0]); i++) { @@ -826,7 +824,7 @@ Platform::Platform() : "cross"); } - /* add echo thread and EC root thread to trace sources */ + /* add exception handler EC for core and EC root thread to trace sources */ struct Core_trace_source : public Trace::Source::Info_accessor, private Trace::Control, private Trace::Source @@ -867,7 +865,7 @@ Platform::Platform() : new (core_mem_alloc()) Core_trace_source(Trace::sources(), Affinity::Location(0, 0, _cpus.width(), 1), - ec_echo_sel, "echo"); + ec_core_exc_sel, "core_fault"); new (core_mem_alloc()) Core_trace_source(Trace::sources(), @@ -899,7 +897,12 @@ unsigned Platform::kernel_cpu_id(unsigned genode_cpu_id) bool Mapped_mem_allocator::_map_local(addr_t virt_addr, addr_t phys_addr, unsigned size) { - map_local((Utcb *)Thread::myself()->utcb(), phys_addr, + /* platform_specific()->core_pd_sel() deadlocks if called from platform constructor */ + Hip const * const hip = (Hip const * const)__initial_sp; + Genode::addr_t const core_pd_sel = hip->sel_exc; + + map_local(core_pd_sel, + (Utcb *)Thread::myself()->utcb(), phys_addr, virt_addr, size / get_page_size(), Rights(true, true, false), true); return true; diff --git a/repos/base-nova/src/core/platform_thread.cc b/repos/base-nova/src/core/platform_thread.cc index 1813f426c9..f745f4024e 100644 --- a/repos/base-nova/src/core/platform_thread.cc +++ b/repos/base-nova/src/core/platform_thread.cc @@ -91,9 +91,10 @@ int Platform_thread::start(void *ip, void *sp) Utcb * const utcb = reinterpret_cast(Thread::myself()->utcb()); unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(_location.xpos()); + addr_t const source_pd = platform_specific()->core_pd_sel(); addr_t const pt_oom = _pager->get_oom_portal(); - if (!pt_oom || map_local(utcb, + if (!pt_oom || map_local(source_pd, utcb, Obj_crd(pt_oom, 0), Obj_crd(_sel_pt_oom(), 0))) { error("setup of out-of-memory notification portal - failed"); return -8; @@ -162,7 +163,7 @@ int Platform_thread::start(void *ip, void *sp) /* remap exception portals for first thread */ for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) { - if (map_local(utcb, + if (map_local(source_pd, utcb, Obj_crd(remap_src[i], 0), Obj_crd(_sel_exc_base + remap_dst[i], 0))) return -6; diff --git a/repos/base-nova/src/core/ram_dataspace_support.cc b/repos/base-nova/src/core/ram_dataspace_support.cc index dcf70fde62..0c5043b3d6 100644 --- a/repos/base-nova/src/core/ram_dataspace_support.cc +++ b/repos/base-nova/src/core/ram_dataspace_support.cc @@ -87,7 +87,8 @@ void Ram_dataspace_factory::_export_ram_ds(Dataspace_component *ds) { Nova::Utcb * const utcb = reinterpret_cast(Thread::myself()->utcb()); const Nova::Rights rights_rw(true, true, false); - if (map_local(utcb, ds->phys_addr(), reinterpret_cast(virt_ptr), + if (map_local(platform_specific()->core_pd_sel(), utcb, ds->phys_addr(), + reinterpret_cast(virt_ptr), page_rounded_size >> get_page_size_log2(), rights_rw, true)) { platform()->region_alloc()->free(virt_ptr, page_rounded_size); throw Core_virtual_memory_exhausted(); diff --git a/repos/base-nova/src/core/thread_start.cc b/repos/base-nova/src/core/thread_start.cc index 0957218c5b..f65e654396 100644 --- a/repos/base-nova/src/core/thread_start.cc +++ b/repos/base-nova/src/core/thread_start.cc @@ -114,7 +114,8 @@ void Thread::start() utcb_obj->crd_rcv = Obj_crd(); utcb_obj->crd_xlt = Obj_crd(); - if (map_local(reinterpret_cast(Thread::myself()->utcb()), + if (map_local(platform_specific()->core_pd_sel(), + reinterpret_cast(Thread::myself()->utcb()), Obj_crd(PT_SEL_PAGE_FAULT, 0), Obj_crd(native_thread().exc_pt_sel + PT_SEL_PAGE_FAULT, 0))) { error("could not create page fault portal");