nova: remove echo thread in core

and replace by remote delegate syscall

Fixes #2895
This commit is contained in:
Alexander Boettcher 2018-06-29 14:04:32 +02:00 committed by Christian Helmuth
parent 117b932176
commit bac7ba6639
11 changed files with 56 additions and 205 deletions

View File

@ -14,7 +14,6 @@ SRC_CC += stack_area.cc \
dataspace_component.cc \ dataspace_component.cc \
default_log.cc \ default_log.cc \
dump_alloc.cc \ dump_alloc.cc \
echo.cc \
io_mem_session_component.cc \ io_mem_session_component.cc \
io_mem_session_support.cc \ io_mem_session_support.cc \
io_port_session_component.cc \ io_port_session_component.cc \

View File

@ -78,7 +78,8 @@ Core_region_map::attach(Dataspace_capability ds_cap, size_t,
Nova::Utcb * const utcb = reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb()); Nova::Utcb * const utcb = reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb());
const Nova::Rights rights(true, writeable && ds->writable(), executable); const Nova::Rights rights(true, writeable && ds->writable(), executable);
if (map_local(utcb, ds->phys_addr(), reinterpret_cast<addr_t>(virt_ptr), if (map_local(platform_specific()->core_pd_sel(), utcb,
ds->phys_addr(), reinterpret_cast<addr_t>(virt_ptr),
page_rounded_size >> get_page_size_log2(), rights, true)) { page_rounded_size >> get_page_size_log2(), rights, true)) {
platform()->region_alloc()->free(virt_ptr, page_rounded_size); platform()->region_alloc()->free(virt_ptr, page_rounded_size);
throw Out_of_ram(); throw Out_of_ram();

View File

@ -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 <platform.h>
/* local includes */
#include <echo.h>
#include <nova_util.h>
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<Hip *>(__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<mword_t>(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<unsigned *>(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<unsigned *>(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; }

View File

@ -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 <nova/syscalls.h>
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_ */

View File

@ -37,7 +37,8 @@ namespace Genode {
inline bool map_local(addr_t from_phys, addr_t to_virt, size_t num_pages, 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) 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, from_phys, to_virt, num_pages,
Nova::Rights(read, write, exec), true) == 0); Nova::Rights(read, write, exec), true) == 0);
} }

View File

@ -23,7 +23,6 @@
#include <nova/syscalls.h> #include <nova/syscalls.h>
/* local includes */ /* local includes */
#include <echo.h>
#include <util.h> #include <util.h>
/** /**
@ -55,31 +54,22 @@ inline Genode::addr_t boot_cpu()
* target * target
* \param kern_pd Whether to map the items from the kernel or from core * \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 * \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, static int map_local(Genode::addr_t const pd, Nova::Utcb * const utcb,
bool kern_pd = false, bool dma_mem = false, Nova::Crd const src_crd, Nova::Crd const dst_crd,
bool write_combined = false) bool const kern_pd = false, bool const dma_mem = false,
bool const write_combined = false)
{ {
/* open receive window at current EC */ /* asynchronously map capabilities */
utcb->crd_rcv = dst_crd; utcb->set_msg_word(0);
/* tell echo thread what to map */ /* ignore return value as one item always fits into the utcb */
utcb->msg()[0] = src_crd.value(); bool const ok = utcb->append_item(src_crd, 0, kern_pd, false, false,
utcb->msg()[1] = 0; dma_mem, write_combined);
utcb->msg()[2] = kern_pd; (void)ok;
utcb->msg()[3] = dma_mem;
utcb->msg()[4] = write_combined;
utcb->set_msg_word(5);
/* establish the mapping via a portal traversal during reply phase */ Nova::uint8_t res = Nova::delegate(pd, pd, dst_crd);
Nova::uint8_t res = Nova::call(echo()->pt_sel()); if (res != Nova::NOVA_OK) {
if (res != Nova::NOVA_OK || utcb->msg_words() != 1 || !utcb->msg()[0] ||
utcb->msg_items() != 1) {
typedef Genode::Hex Hex; typedef Genode::Hex Hex;
error("map_local failed ", 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) { static inline int unmap_local(Nova::Crd crd, bool self = true) {
return Nova::revoke(crd, self); } return Nova::revoke(crd, self); }
inline int map_local_phys_to_virt(Nova::Utcb *utcb, Nova::Crd src, inline int map_local_phys_to_virt(Nova::Utcb * const utcb, Nova::Crd const src,
Nova::Crd dst) { Nova::Crd const dst, Genode::addr_t const pd)
return map_local(utcb, src, dst, true); } {
return map_local(pd, utcb, src, dst, true);
}
inline int map_local_one_to_one(Nova::Utcb *utcb, Nova::Crd crd) { inline int map_local_one_to_one(Nova::Utcb * const utcb, Nova::Crd const crd,
return map_local(utcb, crd, crd, true); } 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 to_start local virtual destination address
* \param num_pages number of pages to map * \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::addr_t from_start, Genode::addr_t to_start,
Genode::size_t num_pages, Genode::size_t num_pages,
Nova::Rights const &permission, Nova::Rights const &permission,
@ -169,7 +164,7 @@ inline int map_local(Nova::Utcb *utcb,
if ((to_end - to_curr) < (1UL << order)) if ((to_end - to_curr) < (1UL << order))
order = log2(to_end - to_curr); 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((from_curr >> 12), order - get_page_size_log2(), permission),
Mem_crd((to_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); kern_pd, dma_mem, write_combined);

View File

@ -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)); Nova::Mem_crd virt_crd(virt_addr >> 12, 0, Rights(true, false, false));
Utcb * utcb = reinterpret_cast<Utcb *>(Thread::myself()->utcb()); Utcb * utcb = reinterpret_cast<Utcb *>(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); platform()->region_alloc()->free(virt, 4096);
return false; return false;
} }
@ -142,7 +142,8 @@ void Irq_object::start(unsigned irq, Genode::addr_t const device_phys)
Obj_crd dst(irq_sel(), 0); Obj_crd dst(irq_sel(), 0);
enum { MAP_FROM_KERNEL_TO_CORE = true }; 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); src, dst, MAP_FROM_KERNEL_TO_CORE);
if (ret) { if (ret) {
error("getting IRQ from kernel failed - ", irq); error("getting IRQ from kernel failed - ", irq);

View File

@ -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<addr_t>(core_local_ptr); addr_t const core_local_addr = reinterpret_cast<addr_t>(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); Nova::Rights(true, true, false), true);
return res ? 0 : core_local_addr; 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) 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 { enum {
GLOBAL = false, GLOBAL = false,
EXC_BASE = 0 EXC_BASE = 0
@ -307,12 +308,13 @@ Platform::Platform() :
/* locally map the whole I/O port range */ /* locally map the whole I/O port range */
enum { ORDER_64K = 16 }; 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 */ /* map BDA region, console reads IO ports at BDA_VIRT_ADDR + 0x400 */
enum { BDA_PHY = 0x0U, BDA_VIRT = 0x1U, BDA_VIRT_ADDR = 0x1000U }; enum { BDA_PHY = 0x0U, BDA_VIRT = 0x1U, BDA_VIRT_ADDR = 0x1000U };
map_local_phys_to_virt(__main_thread_utcb, map_local_phys_to_virt(__main_thread_utcb,
Mem_crd(BDA_PHY, 0, Rights(true, false, false)), 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 * we do this that early, because Core_mem_allocator uses
* the main_thread_utcb very early to establish mappings * 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))) { (addr_t)main_thread_utcb(), 1, Rights(true, true, false))) {
error("could not remap utcb of main thread"); error("could not remap utcb of main thread");
nova_die(); nova_die();
@ -359,7 +361,7 @@ Platform::Platform() :
error("unaligned sc_idle_base value ", Hex(sc_idle_base)); error("unaligned sc_idle_base value ", Hex(sc_idle_base));
nova_die(); 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)) Obj_crd(sc_idle_base, log2cpu), true))
nova_die(); nova_die();
@ -388,7 +390,7 @@ Platform::Platform() :
#endif #endif
/* set up page fault handler for core - for debugging */ /* 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 (verbose_boot_info) {
if (hip->has_feature_vmx()) if (hip->has_feature_vmx())
@ -458,10 +460,6 @@ Platform::Platform() :
region_alloc()->remove_range(CORE_PAGER_UTCB_ADDR - get_page_size(), region_alloc()->remove_range(CORE_PAGER_UTCB_ADDR - get_page_size(),
get_page_size() * 3); 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 */ /* 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(), region_alloc()->remove_range((addr_t)__main_thread_utcb - get_page_size(),
get_page_size() * 4); get_page_size() * 4);
@ -469,7 +467,7 @@ Platform::Platform() :
/* sanity checks */ /* sanity checks */
addr_t check [] = { addr_t check [] = {
reinterpret_cast<addr_t>(__main_thread_utcb), CORE_PAGER_UTCB_ADDR, reinterpret_cast<addr_t>(__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++) { for (unsigned i = 0; i < sizeof(check) / sizeof(check[0]); i++) {
@ -826,7 +824,7 @@ Platform::Platform() :
"cross"); "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, struct Core_trace_source : public Trace::Source::Info_accessor,
private Trace::Control, private Trace::Control,
private Trace::Source private Trace::Source
@ -867,7 +865,7 @@ Platform::Platform() :
new (core_mem_alloc()) new (core_mem_alloc())
Core_trace_source(Trace::sources(), Core_trace_source(Trace::sources(),
Affinity::Location(0, 0, _cpus.width(), 1), Affinity::Location(0, 0, _cpus.width(), 1),
ec_echo_sel, "echo"); ec_core_exc_sel, "core_fault");
new (core_mem_alloc()) new (core_mem_alloc())
Core_trace_source(Trace::sources(), 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, bool Mapped_mem_allocator::_map_local(addr_t virt_addr, addr_t phys_addr,
unsigned size) 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(), virt_addr, size / get_page_size(),
Rights(true, true, false), true); Rights(true, true, false), true);
return true; return true;

View File

@ -91,9 +91,10 @@ int Platform_thread::start(void *ip, void *sp)
Utcb * const utcb = reinterpret_cast<Utcb *>(Thread::myself()->utcb()); Utcb * const utcb = reinterpret_cast<Utcb *>(Thread::myself()->utcb());
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(_location.xpos()); 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(); 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))) { Obj_crd(pt_oom, 0), Obj_crd(_sel_pt_oom(), 0))) {
error("setup of out-of-memory notification portal - failed"); error("setup of out-of-memory notification portal - failed");
return -8; return -8;
@ -162,7 +163,7 @@ int Platform_thread::start(void *ip, void *sp)
/* remap exception portals for first thread */ /* remap exception portals for first thread */
for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) { 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(remap_src[i], 0),
Obj_crd(_sel_exc_base + remap_dst[i], 0))) Obj_crd(_sel_exc_base + remap_dst[i], 0)))
return -6; return -6;

View File

@ -87,7 +87,8 @@ void Ram_dataspace_factory::_export_ram_ds(Dataspace_component *ds) {
Nova::Utcb * const utcb = reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb()); Nova::Utcb * const utcb = reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb());
const Nova::Rights rights_rw(true, true, false); const Nova::Rights rights_rw(true, true, false);
if (map_local(utcb, ds->phys_addr(), reinterpret_cast<addr_t>(virt_ptr), if (map_local(platform_specific()->core_pd_sel(), utcb, ds->phys_addr(),
reinterpret_cast<addr_t>(virt_ptr),
page_rounded_size >> get_page_size_log2(), rights_rw, true)) { page_rounded_size >> get_page_size_log2(), rights_rw, true)) {
platform()->region_alloc()->free(virt_ptr, page_rounded_size); platform()->region_alloc()->free(virt_ptr, page_rounded_size);
throw Core_virtual_memory_exhausted(); throw Core_virtual_memory_exhausted();

View File

@ -114,7 +114,8 @@ void Thread::start()
utcb_obj->crd_rcv = Obj_crd(); utcb_obj->crd_rcv = Obj_crd();
utcb_obj->crd_xlt = Obj_crd(); utcb_obj->crd_xlt = Obj_crd();
if (map_local(reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb()), if (map_local(platform_specific()->core_pd_sel(),
reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb()),
Obj_crd(PT_SEL_PAGE_FAULT, 0), Obj_crd(PT_SEL_PAGE_FAULT, 0),
Obj_crd(native_thread().exc_pt_sel + PT_SEL_PAGE_FAULT, 0))) { Obj_crd(native_thread().exc_pt_sel + PT_SEL_PAGE_FAULT, 0))) {
error("could not create page fault portal"); error("could not create page fault portal");