mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 22:47:50 +00:00
nova: remove echo thread in core
and replace by remote delegate syscall Fixes #2895
This commit is contained in:
parent
117b932176
commit
bac7ba6639
@ -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 \
|
||||
|
@ -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();
|
||||
|
@ -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; }
|
@ -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_ */
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user