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 \
default_log.cc \
dump_alloc.cc \
echo.cc \
io_mem_session_component.cc \
io_mem_session_support.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());
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)) {
platform()->region_alloc()->free(virt_ptr, page_rounded_size);
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,
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);
}

View File

@ -23,7 +23,6 @@
#include <nova/syscalls.h>
/* local includes */
#include <echo.h>
#include <util.h>
/**
@ -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);

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));
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);
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);

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);
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<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++) {
@ -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;

View File

@ -91,9 +91,10 @@ int Platform_thread::start(void *ip, void *sp)
Utcb * const utcb = reinterpret_cast<Utcb *>(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;

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());
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)) {
platform()->region_alloc()->free(virt_ptr, page_rounded_size);
throw Core_virtual_memory_exhausted();

View File

@ -114,7 +114,8 @@ void Thread::start()
utcb_obj->crd_rcv = 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(native_thread().exc_pt_sel + PT_SEL_PAGE_FAULT, 0))) {
error("could not create page fault portal");