Imported Genode release 11.11

This commit is contained in:
Genode Labs
2011-12-22 16:19:25 +01:00
committed by Christian Helmuth
parent 6bcc9aef0e
commit da4e1feaa5
2462 changed files with 320115 additions and 3 deletions

47
base-nova/Makefile Normal file
View File

@@ -0,0 +1,47 @@
#
# \brief Download, and unpack the NOVA hypervisor.
# \author Stefan Kalkowski
# \date 2011-07-20
#
VERBOSE ?= @
ECHO = @echo
DOWNLOAD_DIR = download
CONTRIB_DIR = contrib
NOVA_ARCHIVE = nova-hypervisor-0.4.tar.bz2
NOVA_URI = http://os.inf.tu-dresden.de/~us15/nova/$(NOVA_ARCHIVE)
#
# Print help information by default
#
help:
$(ECHO)
$(ECHO) "Prepare the NOVA base repository"
$(ECHO)
$(ECHO) "--- available commands ---"
$(ECHO) "prepare - download and extract the NOVA source code"
$(ECHO) "clean - clean everything except downloaded archives"
$(ECHO) "cleanall - clean everything including downloaded archives"
$(ECHO)
$(DOWNLOAD_DIR)/$(NOVA_ARCHIVE):
$(ECHO) "downloading source code to '$(DOWNLOAD_DIR)/'"
$(VERBOSE)mkdir -p $(DOWNLOAD_DIR)
$(VERBOSE)wget -c $(NOVA_URI) -O $@
$(CONTRIB_DIR): clean
$(CONTRIB_DIR): $(DOWNLOAD_DIR)/$(NOVA_ARCHIVE)
$(ECHO) "unpacking source code to '$(CONTRIB_DIR)/'"
$(VERBOSE)tar xjf $<
$(VERBOSE)mv hypervisor $@
$(VERBOSE)patch -d $@ -p1 < patches/utcb.patch
$(VERBOSE)touch $@
prepare: $(CONTRIB_DIR)
clean:
$(VERBOSE)rm -rf $(CONTRIB_DIR)
cleanall: clean
$(VERBOSE)rm -rf $(DOWNLOAD_DIR)

10
base-nova/README Normal file
View File

@@ -0,0 +1,10 @@
This repository contains the port of Genode to the NOVA microhypervisor.
For more information on this base platform, please refer to the official
website.
:[http://hypervisor.org]: Official website for the NOVA microhypervisor.
For information on using Genode on NOVA, please revisit the documentation at
'base-nova/doc/nova.txt':

254
base-nova/doc/nova.txt Normal file
View File

@@ -0,0 +1,254 @@
==========================================
How to use Genode with the NOVA hypervisor
==========================================
Norman Feske
When we started the development of Genode in 2006 at the OS Group of the TU
Dresden, it was originally designated to be the user land of a next-generation
and to-be-developed new kernel called NOVA. Because the kernel was not ready at
that time, we had to rely on intermediate solutions as kernel platform such as
L4/Fiasco and Linux during development. These circumstances led us to the
extremely portable design that Genode has today and motivated us to make Genode
available on the whole family of L4 microkernels. In December 2009, the day we
waited for a long time had come. The first version of NOVA was publicly
released:
:Official website of the NOVA hypervisor:
[http://hypervisor.org]
Besides the novel and modern kernel interface, NOVA has a list of features that
sets it apart from most other microkernels, in particular support for
virtualization hardware, multi-processor support, and capability-based
security.
Why bringing Genode to NOVA?
############################
NOVA is an acronym for NOVA OS Virtualization Architecture. It stands for a
radically new approach of combining full x86 virtualization with microkernel
design principles. Because NOVA is a microkernelized hypervisor, the term
microhypervisor was coined. In its current form, it successfully addresses
three main challenges. First, how to consolidate a microkernel system-call API
with a hypercall API in such a way that the API remains orthogonal? The answer
to this question lies in NOVA's unique IPC interface. Second, how to implement
a virtual machine monitor outside the hypervisor without spoiling
performance? The Vancouver virtual machine monitor that runs on top NOVA proves
that a decomposition at this system level is not only feasible but can yield
high performance. Third, being a modern microkernel, NOVA set out to pursue a
capability-based security model, which is a challenge on its own.
Up to now, the NOVA developers were most concerned about optimizing and
evaluating NOVA for the execution of virtual machines, not so much about
running a fine-grained decomposed multi-server operating system. This is where
Genode comes into play. With our port of Genode to NOVA, we contribute the
workload to evaluate NOVA's kernel API against this use case. We are happy to
report that the results so far are overly positive.
At this point, we want to thank the main developers of NOVA Udo Steinberg and
Bernhard Kauer for making their exceptional work and documentation publicly
available, and for being so responsive to our questions. We also greatly
enjoyed the technical discussions we had and look forward to the future
evolution of NOVA.
How to explore Genode on NOVA?
##############################
To download the NOVA kernel and integrate it with Genode, issue the following
command from within the 'base-nova' directory:
! make prepare
For creating a preconfigured build directory prepared for compiling Genode for
NOVA, use the 'create_builddir' tool:
! <genode-dir>/tool/create_builddir nova_x86 BUILD_DIR=<build-dir>
This tool will create a fresh build directory at the location specified
as 'BUILD_DIR'. Provided that you have installed the
[http://genode.org/download/tool-chain - Genode tool chain], you can now build
the NOVA kernel via
! make kernel
For test driving Genode on NOVA directly from the build directory, you can use
Genode's run mechanism. For example, the following command builds and executes
Genode's graphical demo scenario on Qemu:
! make run/demo
Challenges
##########
From all currently supported base platforms of Genode, the port to NOVA was
the most venturesome effort. It is the first platform with kernel support for
capabilities and local names. That means no process except the kernel has
global knowledge. This raises a number of questions that seem extremely hard
to solve at the first sight. For example: There are no global IDs for threads
and other kernel objects. So how to address the destination for an IPC message?
Or another example: A thread does not know its own identity per se and there is
no system call similar to 'getpid' or 'l4_myself', not even a way to get a
pointer to a thread's own user-level thread-control block (UTCB). The UTCB,
however, is needed to invoke system calls. So how can a thread obtain its UTCB
in order to use system calls? The answers to these questions must be provided by
user-level concepts. Fortunately, Genode was designed for a capability kernel
right from the beginning so that we already had solutions to most of these
questions. In the following, we give a brief summary of the specifics of Genode
on NOVA:
* We maintain our own system-call bindings for NOVA ('base-nova/include/nova/')
derived from the NOVA specification. We put the bindings under MIT license
to encourage their use outside of Genode.
* Core runs directly as roottask on the NOVA hypervisor. On startup, core
maps the complete I/O port range to itself and implements debug output via
comport 0.
* Because NOVA does not allow rootask to have a BSS segment, we need a slightly
modified linker script for core (see 'src/platform/roottask.ld').
All other Genode programs use Genode's generic linker script.
* The Genode 'Capability' type consists of a portal selector expressing the
destination of a capability invocation and a global object ID expressing
the identity of the object when the capability is specified as an invocation
argument. In the latter case, the global ID is needed because of a limitation
of the current system-call interface. In the future, we are going to entirely
remove the global ID.
* Thread-local data such as the UTCB pointer is provided by the new thread
context management introduced with the Genode release 10.02. It enables
each thread to determine its thread-local data using the current stack
pointer.
* NOVA provides threads without time called local execution contexts (EC).
Local ECs are intended as server-side RPC handlers. The processing time
needed to perform RPC requests is provided by the client during the RPC call.
This way, RPC semantics becomes very similar to function call semantics with
regard to the accounting of CPU time. Genode already distinguishes normal
threads (with CPU time) and server-side RPC handlers ('Server_activation')
and, therefore, can fully utilize this elegant mechanism without changing the
Genode API.
* On NOVA, there are no IPC send or IPC receive operations. Hence, this part
of Genode's IPC framework cannot be implemented on NOVA. However, the
corresponding classes 'Ipc_istream' and 'Ipc_ostream' are never used directly
but only as building blocks for the actually used 'Ipc_client' and
'Ipc_server' classes. Compared with the other Genode base platforms, Genode's
API for synchronous IPC communication maps more directly onto the NOVA
system-call interface.
* The Lock implementation utilizes NOVA's semaphore as a utility to let a
thread block in the attempt to get a contended lock. In contrast to the
intuitive way of using one kernel semaphore for each user lock, we use only
one kernel semaphore per thread and the peer-to-peer wake-up mechanism we
introduced in the release 9.08. This has two advantages: First, a lock does
not consume a kernel resource, and second, the full semantics of the Genode
lock including the 'cancel-blocking' semantics are preserved.
* NOVA does not support server-side out-of-order processing of RPC requests.
This is particularly problematic in three cases: Page-fault handling, signal
delivery, and the timer service.
A page-fault handler can receive a page fault request only if the previous
page fault has been answered. However, if there is no answer for a
page-fault, the page-fault handler has to decide whether to reply with a
dummy answer (in this case, the faulter will immediately raise the same page
fault again) or block until the page-fault can be resolved. But in the latter
case, the page-fault handler cannot handle any other page faults. This is
unfeasible if there is only one page-fault handler in the system. Therefore,
we instantiate one pager per user thread. This way, we can block and unblock
individual threads when faulting.
Another classical use case for out-of-order RPC processing is signal
delivery. Each process has a signal-receiver thread that blocks at core's
signal service using an RPC call. This way, core can selectively deliver
signals by replying to one of these in-flight RPCs with a zero-timeout
response (preserving the fire-and-forget signal semantics). On NOVA however,
a server cannot have multiple RPCs in flight. Hence, we use a NOVA semaphore
shared between core and the signal-receiver thread to wakeup the
signal-receiver on the occurrence of a signal. Because a semaphore-up
operation does not carry payload, the signal has to perform a non-blocking
RPC call to core to pick up the details about the signal. Thanks to Genode's
RPC framework, the use of the NOVA semaphore is hidden in NOVA-specific stub
code for the signal interface and remains completely transparent at API
level.
For the timer service, we currently use one thread per client to avoid the need
for out-of-order RPC processing.
* Because NOVA provides no time source, we use the x86 PIT as user-level time
source, similar as on OKL4.
* On the current version of NOVA, kernel capabilities are delegated using IPC.
Genode supports this scheme by being able to marshal 'Capability' objects as
RPC message payload. In contrast to all other Genode base platforms where
the 'Capability' object is just plain data, the NOVA version must marshal
'Capability' objects such that the kernel translates the sender-local name to
the receiver-local name. This special treatment is achieved by overloading
the marshalling and unmarshalling operators of Genode's RPC framework. The
transfer of capabilities is completely transparent at API level and no
modification of existing RPC stub code was needed.
Manually booting Genode on NOVA
###############################
NOVA supports multi-boot-compliant boot loaders such as GRUB, Pulsar, or gPXE.
For example, a GRUB configuration entry for booting the Genode demo scenario
with NOVA looks as follows, whereas 'genode/' is a symbolic link to the 'bin/'
subdirectory of the Genode build directory and the 'config' file is a copy of
'os/config/demo'.
! title Genode demo scenario
! kernel /hypervisor noapic
! module /genode/core
! module /genode/init
! module /config/demo/config
! module /genode/timer
! module /genode/ps2_drv
! module /genode/pci_drv
! module /genode/vesa_drv
! module /genode/launchpad
! module /genode/nitpicker
! module /genode/liquid_fb
! module /genode/nitlog
! module /genode/testnit
! module /genode/scout
Limitations
###########
The current NOVA version of Genode is able to run the complete Genode demo
scenario including several device drivers (PIT, PS/2, VESA, PCI) and the GUI.
Still the NOVA support is not on par with some of the other platforms.
The current limitations are:
* No real-time priority support: NOVA supports priority-based scheduling
but, in the current version, it allows each thread to create scheduling
contexts with arbitrary scheduling parameters. This makes it impossible
to enforce priority assignment from a central point as facilitated with
Genode's priority concept.
* No multi-processor support: NOVA supports multi-processor CPUs through
binding each execution context (ECs) to a particular CPU. Because everyone
can create ECs, every process could use multiple CPUs. However, Genode's API
devises a more restrictive way of allocating and assigning resources. In
short, physical resource usage should be arbitrated by core and the creation
of physical ECs should be performed by core only. However, Remote EC creation
is not yet supported by NOVA. Even though, multiple CPU can be used with
Genode on NOVA right now by using NOVA system calls directly, there is no
support at the Genode API level.
* No cancel-blocking semantics: The cancellation of locks is not support,
yet. Because of this missing functionality, applications can freeze
in situations where a subsystems that blocks for a service is attempted
to get destroyed.

5
base-nova/etc/specs.conf Normal file
View File

@@ -0,0 +1,5 @@
#
# Description of build platform
#
SPECS ?= genode nova x86_32

View File

@@ -0,0 +1,72 @@
/*
* \brief Interface for process-local capability-selector allocation
* \author Norman Feske
* \date 2010-01-19
*
* This interface is NOVA-specific and not part of the Genode API. It should
* only be used internally by the framework or by NOVA-specific code. The
* implementation of the interface is part of the environment library.
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__BASE__CAP_SEL_ALLOC_H_
#define _INCLUDE__BASE__CAP_SEL_ALLOC_H_
#include <base/stdint.h>
namespace Genode {
class Cap_selector_allocator
{
public:
/**
* Constructor
*/
Cap_selector_allocator();
/**
* Allocate range of capability selectors
*
* \param num_caps_log2 number of capability selectors specified as
* as the power of two. By default, the function
* returns a single capability selector.
* \return first capability selector of allocated range,
* or 0 if allocation failed
*
* The allocated range will be naturally aligned according to the
* specified 'num_cap_log2' value.
*/
addr_t alloc(size_t num_caps_log2 = 0);
/**
* Release range of capability selectors
*
* \param cap first capability selector of range
* \param num_caps_log2 number of capability selectors specified
* as the power of two
*/
void free(addr_t cap, size_t num_caps_log2);
/**
* Capability selector of local protection domain
*
* \return PD selector
*/
static unsigned pd_sel();
};
/**
* Return singleton instance of 'Cap_selector_allocator'
*/
Cap_selector_allocator *cap_selector_allocator();
}
#endif /* _INCLUDE__BASE__CAP_SEL_ALLOC_H_ */

View File

@@ -0,0 +1,36 @@
/*
* \brief NOVA-specific supplements to the IPC framework
* \author Norman Feske
* \date 2010-01-27
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__BASE__IPC_H_
#define _INCLUDE__BASE__IPC_H_
#include <base/ipc_generic.h>
inline void Genode::Ipc_ostream::_marshal_capability(Genode::Native_capability const &cap)
{
long unique_id = cap.unique_id();
_write_to_buf(unique_id);
_snd_msg->snd_append_pt_sel(cap.pt_sel());
}
inline void Genode::Ipc_istream::_unmarshal_capability(Genode::Native_capability &cap)
{
long unique_id = 0;
_read_from_buf(unique_id);
int pt_sel = _rcv_msg->rcv_pt_sel();
cap = Native_capability(pt_sel, unique_id);
}
#endif /* _INCLUDE__BASE__IPC_H_ */

View File

@@ -0,0 +1,186 @@
/*
* \brief IPC message buffer layout for NOVA
* \author Norman Feske
* \date 2009-10-02
*
* On NOVA, we use IPC to transmit plain data and for capability delegation.
* Therefore the message buffer contains both categories of payload. The
* capability-specific part are the members '_snd_pt*' (sending capability
* selectors) and '_rcv_pt*' (receiving capability selectors).
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__BASE__IPC_MSGBUF_H_
#define _INCLUDE__BASE__IPC_MSGBUF_H_
/* Genode includes */
#include <base/cap_sel_alloc.h>
/* NOVA includes */
#include <nova/syscalls.h>
namespace Genode {
class Msgbuf_base
{
public:
enum { MAX_CAP_ARGS_LOG2 = 2, MAX_CAP_ARGS = 1 << MAX_CAP_ARGS_LOG2 };
protected:
size_t _size;
/**
* Number of portal-capability selectors to send
*/
size_t _snd_pt_sel_cnt;
/**
* Portal capability selectors to delegate
*/
int _snd_pt_sel[MAX_CAP_ARGS];
/**
* Base of portal receive window
*/
int _rcv_pt_base;
/**
* Read counter for unmarshalling portal capability selectors
*/
int _rcv_pt_sel_cnt;
/**
* Flag set to true if receive window must be re-initialized
*/
bool _rcv_dirty;
char _msg_start[]; /* symbol marks start of message */
public:
/**
* Constructor
*/
Msgbuf_base() : _rcv_dirty(true)
{
rcv_reset();
snd_reset();
}
/*
* Begin of actual message buffer
*/
char buf[];
/**
* Return size of message buffer
*/
inline size_t size() const { return _size; }
/**
* Return address of message buffer
*/
inline void *addr() { return &_msg_start[0]; }
/**
* Reset portal capability selector payload
*/
inline void snd_reset() { _snd_pt_sel_cnt = 0; }
/**
* Append portal capability selector to message buffer
*/
inline bool snd_append_pt_sel(int pt_sel)
{
if (_snd_pt_sel_cnt >= MAX_CAP_ARGS - 1)
return false;
_snd_pt_sel[_snd_pt_sel_cnt++] = pt_sel;
return true;
}
/**
* Return number of marshalled portal-capability selectors
*/
inline size_t snd_pt_sel_cnt() { return _snd_pt_sel_cnt; }
/**
* Return portal capability selector
*
* \param i index (0 ... 'pt_sel_cnt()' - 1)
* \return portal-capability selector, or
* -1 if index is invalid
*/
int snd_pt_sel(unsigned i) { return i < _snd_pt_sel_cnt ? _snd_pt_sel[i] : -1; }
/**
* Request current portal-receive window
*/
int rcv_pt_base() { return _rcv_pt_base; }
/**
* Reset portal-capability receive window
*/
void rcv_reset() { _rcv_pt_sel_cnt = 0; }
/**
* Return received portal-capability selector
*/
int rcv_pt_sel()
{
_rcv_dirty = true;
return _rcv_pt_base + _rcv_pt_sel_cnt++;
}
/**
* Return true if receive window must be re-initialized
*
* After reading portal selectors from the message buffer using
* 'rcv_pt_sel()', we assume that the IDC call populared the
* current receive window with one or more portal capabilities.
* To enable the reception of portal capability selectors for the
* next IDC, we need a fresh receive window.
*/
bool rcv_dirty() { return _rcv_dirty; }
/**
* Initialize receive window for portal capability selectors
*
* \param utcb UTCB of designated receiver thread
*
* Depending on the 'rcv_dirty' state of the message buffer, this
* function allocates a fresh receive window and clears 'rcv_dirty'.
*/
void rcv_prepare_pt_sel_window(Nova::Utcb *utcb)
{
if (rcv_dirty()) {
_rcv_pt_base = cap_selector_allocator()->alloc(MAX_CAP_ARGS_LOG2);
_rcv_dirty = false;
}
/* register receive window at the UTCB */
utcb->crd_rcv = Nova::Obj_crd(rcv_pt_base(),MAX_CAP_ARGS_LOG2);
}
};
template <unsigned BUF_SIZE>
class Msgbuf : public Msgbuf_base
{
public:
char buf[BUF_SIZE];
Msgbuf() { _size = BUF_SIZE; }
};
}
#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */

View File

@@ -0,0 +1,137 @@
/*
* \brief Low-level page-fault handling
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__BASE__IPC_PAGER_H_
#define _INCLUDE__BASE__IPC_PAGER_H_
/* Genode includes */
#include <base/ipc.h>
#include <base/stdint.h>
#include <base/native_types.h>
#include <base/printf.h>
/* NOVA includes */
#include <nova/syscalls.h>
namespace Genode {
class Mapping
{
private:
addr_t _dst_addr;
addr_t _core_local_addr;
bool _write_combined;
size_t _size_log2;
bool _rw;
enum { PAGE_SIZE_LOG2 = 12 };
public:
/**
* Constructor
*/
Mapping(addr_t dst_addr, addr_t map_addr,
bool write_combined, unsigned size_log2 = PAGE_SIZE_LOG2,
bool rw = true)
:
_dst_addr(dst_addr), _core_local_addr(map_addr),
_write_combined(write_combined), _size_log2(size_log2),
_rw(rw)
{ }
/**
* Construct invalid mapping
*/
Mapping() : _size_log2(0) { }
void prepare_map_operation() { }
Nova::Mem_crd mem_crd()
{
return Nova::Mem_crd(_core_local_addr >> PAGE_SIZE_LOG2,
_size_log2 - PAGE_SIZE_LOG2,
Nova::Rights(true, _rw, true));
}
addr_t dst_addr() { return _dst_addr; }
};
class Ipc_pager
{
private:
/**
* Page-fault type
*/
enum Pf_type {
TYPE_READ = 0x4,
TYPE_WRITE = 0x2,
TYPE_EXEC = 0x1,
};
addr_t _fault_ip;
addr_t _fault_addr;
Pf_type _fault_type;
public:
/**
* Wait for page-fault info
*
* After returning from this call, 'fault_ip' and 'fault_addr'
* have a defined state.
*/
void wait_for_fault();
/**
* Answer current page fault
*/
void reply_and_wait_for_fault();
/**
* Request instruction pointer of current fault
*/
addr_t fault_ip() { return _fault_ip; }
/**
* Request page-fault address of current fault
*/
addr_t fault_addr() { return _fault_addr; }
/**
* Set page-fault reply parameters
*/
void set_reply_mapping(Mapping m);
/**
* Return true if fault was a write fault
*/
bool is_write_fault() const { return _fault_type == TYPE_WRITE; }
/**
* Return true if last fault was an exception
*/
bool is_exception() const
{
/*
* Reflection of exceptions is not supported on this platform.
*/
return false;
}
};
}
#endif /* _INCLUDE__BASE__IPC_PAGER_H_ */

View File

@@ -0,0 +1,88 @@
/*
* \brief Platform-specific type definitions
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__BASE__NATIVE_TYPES_H_
#define _INCLUDE__BASE__NATIVE_TYPES_H_
namespace Genode {
typedef volatile int Native_lock;
struct Native_thread
{
int ec_sel; /* NOVA cap selector for execution context */
int sc_sel; /* NOVA cap selector for scheduling context */
int rs_sel; /* NOVA cap selector for running semaphore */
int pd_sel; /* NOVA cap selector of protection domain */
int exc_pt_sel; /* base of event portal window */
};
typedef Native_thread Native_thread_id;
inline bool operator == (Native_thread_id t1, Native_thread_id t2) { return t1.ec_sel == t2.ec_sel; }
inline bool operator != (Native_thread_id t1, Native_thread_id t2) { return t1.ec_sel != t2.ec_sel; }
class Native_utcb
{
private:
/**
* Size of the NOVA-specific user-level thread-control block
*/
enum { UTCB_SIZE = 4096 };
/**
* User-level thread control block
*
* The UTCB is one 4K page, shared between the kernel and the
* user process. It is not backed by a dataspace but provided
* by the kernel.
*/
long _utcb[UTCB_SIZE/sizeof(long)];
};
class Native_capability
{
private:
int _pt_sel;
int _unique_id;
public:
/**
* Default constructor creates an invalid capability
*/
Native_capability() : _pt_sel(0), _unique_id(0) { }
/**
* Construct capability manually
*
* This constructor should be called only from the platform-specific
* part of the Genode framework.
*/
Native_capability(int pt_sel, int unique_id)
: _pt_sel(pt_sel), _unique_id(unique_id) { }
bool valid() const { return _pt_sel != 0 && _unique_id != 0; }
int local_name() const { return _unique_id; }
int dst() const { return _pt_sel; }
int unique_id() const { return _unique_id; }
int pt_sel() const { return _pt_sel; }
};
typedef int Native_connection_state;
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@@ -0,0 +1,154 @@
/*
* \brief Paging-server framework
* \author Norman Feske
* \date 2006-04-28
*/
/*
* Copyright (C) 2006-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__BASE__PAGER_H_
#define _INCLUDE__BASE__PAGER_H_
#include <base/thread.h>
#include <base/object_pool.h>
#include <base/ipc_pager.h>
#include <base/capability.h>
#include <cap_session/cap_session.h>
#include <pager/capability.h>
namespace Genode {
class Pager_entrypoint;
/*
* On NOVA, each pager object is an EC that corresponds to one user thread.
*/
class Pager_object : public Object_pool<Pager_object>::Entry,
Thread_base
{
private:
void entry() { }
void start() { }
unsigned long _badge; /* used for debugging */
/**
* User-level signal handler registered for this pager object via
* 'Cpu_session::exception_handler()'.
*/
Signal_context_capability _exception_sigh;
int _exc_pt_sel; /* base of event portal window */
int _pt_sel; /* portal selector for object identity */
addr_t _initial_esp;
addr_t _initial_eip;
static void _page_fault_handler();
static void _startup_handler();
static void _invoke_handler();
public:
Pager_object(unsigned long badge);
virtual ~Pager_object();
unsigned long badge() const { return _badge; }
virtual int pager(Ipc_pager &ps) = 0;
/**
* Assign user-level exception handler for the pager object
*/
void exception_handler(Signal_context_capability sigh)
{
_exception_sigh = sigh;
}
/**
* Return base of initial portal window
*/
int exc_pt_sel() { return _exc_pt_sel; }
/**
* Set initial stack pointer used by the startup handler
*/
void initial_esp(addr_t esp) { _initial_esp = esp; }
/**
* Set initial instruction pointer used by the startup handler
*/
void initial_eip(addr_t eip) { _initial_eip = eip; }
/**
* Return portal capability selector used for object identity
*/
int pt_sel() { return _pt_sel; }
/**
* Continue execution of pager object
*/
void wake_up();
/**
* Notify exception handler about the occurrence of an exception
*/
void submit_exception_signal()
{
if (!_exception_sigh.valid()) return;
Signal_transmitter transmitter(_exception_sigh);
transmitter.submit();
}
};
/**
* Dummy pager activation
*
* Because on NOVA each pager object can be invoked separately,
* there is no central pager activation.
*/
class Pager_activation_base { };
template <int STACK_SIZE>
class Pager_activation : public Pager_activation_base
{ };
/**
* Dummy pager entrypoint
*/
class Pager_entrypoint : public Object_pool<Pager_object>
{
private:
Cap_session *_cap_session;
public:
Pager_entrypoint(Cap_session *cap_session,
Pager_activation_base *a = 0)
: _cap_session(cap_session) { }
/**
* Return capability for 'Pager_object'
*/
Pager_capability manage(Pager_object *obj);
/**
* Dissolve 'Pager_object' from entry point
*/
void dissolve(Pager_object *obj);
};
}
#endif /* _INCLUDE__BASE__PAGER_H_ */

View File

@@ -0,0 +1,34 @@
/*
* \brief Lay back and relax
* \author Norman Feske
* \date 2010-02-01
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__BASE__SLEEP_H_
#define _INCLUDE__BASE__SLEEP_H_
/* Genode includes */
#include <base/cap_sel_alloc.h>
#include <base/thread.h>
/* NOVA includes */
#include <nova/syscalls.h>
namespace Genode {
__attribute__((noreturn)) inline void sleep_forever()
{
int sleep_sm_sel = cap_selector_allocator()->alloc();
Nova::create_sm(sleep_sm_sel, Cap_selector_allocator::pd_sel(), 0);
while (1) Nova::sm_ctrl(sleep_sm_sel, Nova::SEMAPHORE_DOWN);
}
}
#endif /* _INCLUDE__BASE__SLEEP_H_ */

View File

@@ -0,0 +1,28 @@
/*
* \brief Integer type definitions used by NOVA syscall bindings
* \author Norman Feske
* \date 2010-01-15
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _PLATFORM__NOVA_STDINT_H_
#define _PLATFORM__NOVA_STDINT_H_
#include <base/fixed_stdint.h>
namespace Nova {
typedef long mword_t;
typedef unsigned char uint8_t;
typedef Genode::uint16_t uint16_t;
typedef Genode::uint32_t uint32_t;
typedef Genode::uint64_t uint64_t;
}
#endif /* _PLATFORM__NOVA_STDINT_H_ */

View File

@@ -0,0 +1,673 @@
/*
* \brief Syscall bindings for the NOVA microhypervisor
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2009-12-27
*/
/*
* Copyright (c) 2009 Genode Labs
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _PLATFORM__NOVA_SYSCALLS_H_
#define _PLATFORM__NOVA_SYSCALLS_H_
#include <nova/stdint.h>
#include <base/printf.h>
#define ALWAYS_INLINE __attribute__((always_inline))
namespace Nova {
enum {
PAGE_SIZE_LOG2 = 12,
PAGE_SIZE = 1 << PAGE_SIZE_LOG2,
PAGE_MASK = ~(PAGE_SIZE - 1)
};
/**
* NOVA sytem-call IDs
*/
enum Syscall {
NOVA_CALL = 0x0,
NOVA_REPLY = 0x1,
NOVA_CREATE_PD = 0x2,
NOVA_CREATE_EC = 0x3,
NOVA_CREATE_SC = 0x4,
NOVA_CREATE_PT = 0x5,
NOVA_CREATE_SM = 0x6,
NOVA_REVOKE = 0x7,
NOVA_LOOKUP = 0x8,
NOVA_EC_CTRL = 0x9,
NOVA_SC_CTRL = 0xa,
NOVA_SM_CTRL = 0xb,
NOVA_ASSIGN_PCI = 0xc,
NOVA_ASSIGN_GSI = 0xd,
};
/**
* Hypervisor information page
*/
struct Hip
{
struct Mem_desc
{
enum Type {
MULTIBOOT_MODULE = -2,
MICROHYPERVISOR = -1,
AVAILABLE_MEMORY = 1,
RESERVED_MEMORY = 2,
ACPI_RECLAIM_MEMORY = 3,
ACPI_NVS_MEMORY = 4
};
uint64_t const addr;
uint64_t const size;
Type const type;
uint32_t const aux;
};
uint32_t const signature; /* magic value 0x41564f4e */
uint16_t const hip_checksum;
uint16_t const hip_length;
uint16_t const cpu_desc_offset;
uint16_t const cpu_desc_size;
uint16_t const mem_desc_offset;
uint16_t const mem_desc_size;
uint32_t const feature_flags;
uint32_t const api_version;
uint32_t const sel; /* number of cap selectors */
uint32_t const sel_exc; /* number of cap selectors for exceptions */
uint32_t const sel_vm; /* number of cap selectors for VM handling */
uint32_t const sel_gsi; /* number of global system interrupts */
uint32_t const page_sizes; /* supported page sizes */
uint32_t const utcb_sizes; /* supported utcb sizes */
uint32_t const tsc_freq; /* time-stamp counter frequency in kHz */
uint32_t const bus_freq; /* bus frequency in kHz */
bool has_feature_vmx() const { return feature_flags & (1 << 1); }
bool has_feature_svm() const { return feature_flags & (1 << 2); }
};
class Descriptor
{
protected:
unsigned _value;
/**
* Assign bitfield to descriptor
*/
template<int MASK, int SHIFT>
void _assign(unsigned new_bits)
{
_value &= ~(MASK << SHIFT);
_value |= (new_bits & MASK) << SHIFT;
}
/**
* Query bitfield from descriptor
*/
template<int MASK, int SHIFT>
unsigned _query() const { return (_value >> SHIFT) & MASK; }
public:
unsigned value() const { return _value; }
};
/**
* Message-transfer descriptor
*/
class Mtd
{
private:
unsigned const _value;
public:
enum {
ACDB = 1 << 0, /* eax, ecx, edx, ebx */
ESP = 1 << 2,
EIP = 1 << 3,
EFL = 1 << 4, /* eflags */
QUAL = 1 << 15, /* exit qualification */
CTRL = 1 << 16, /* execution controls */
INJ = 1 << 17, /* injection info */
STA = 1 << 18, /* interruptibility state */
TSC = 1 << 19, /* time-stamp counter */
IRQ = EFL | STA | INJ | TSC,
ALL = 0x000fffff & ~CTRL,
};
Mtd(unsigned value) : _value(value) { }
unsigned value() const { return _value; }
};
class Crd : public Descriptor
{
protected:
/**
* Bitfield holding the descriptor type
*/
enum {
TYPE_MASK = 0x3, TYPE_SHIFT = 0,
BASE_MASK = 0xfffff, BASE_SHIFT = 12,
ORDER_MASK = 0x1f, ORDER_SHIFT = 7,
RIGHTS_MASK = 0x7c
};
/**
* Capability-range-descriptor types
*/
enum {
NULL_CRD_TYPE = 0,
MEM_CRD_TYPE = 1,
IO_CRD_TYPE = 2,
OBJ_CRD_TYPE = 3,
RIGHTS_ALL = 0x7c,
IO_CRD_ALL = IO_CRD_TYPE | RIGHTS_ALL,
OBJ_CRD_ALL = OBJ_CRD_TYPE | RIGHTS_ALL,
};
void _base(unsigned base)
{ _assign<BASE_MASK, BASE_SHIFT>(base); }
void _order(unsigned order)
{ _assign<ORDER_MASK, ORDER_SHIFT>(order); }
public:
Crd(unsigned base, unsigned order) {
_value = 0; _base(base), _order(order); }
Crd(unsigned value) { _value = value; }
unsigned hotspot(unsigned sel_hotspot) const
{
if ((value() & TYPE_MASK) == MEM_CRD_TYPE)
return sel_hotspot & PAGE_MASK;
return sel_hotspot << 12;
}
unsigned base() const { return _query<BASE_MASK, BASE_SHIFT>(); }
unsigned order() const { return _query<ORDER_MASK, ORDER_SHIFT>(); }
bool is_null() const { return (_value & TYPE_MASK) == NULL_CRD_TYPE; }
};
class Rights
{
private:
bool const _readable, _writeable, _executable;
public:
Rights(bool readable, bool writeable, bool executable)
: _readable(readable), _writeable(writeable),
_executable(executable) { }
Rights() : _readable(false), _writeable(false), _executable(false) {}
bool readable() const { return _readable; }
bool writeable() const { return _writeable; }
bool executable() const { return _executable; }
};
/**
* Memory-capability-range descriptor
*/
class Mem_crd : public Crd
{
private:
enum {
EXEC_MASK = 0x1, EXEC_SHIFT = 4,
WRITE_MASK = 0x1, WRITE_SHIFT = 3,
READ_MASK = 0x1, READ_SHIFT = 2
};
void _rights(Rights r)
{
_assign<EXEC_MASK, EXEC_SHIFT>(r.executable());
_assign<WRITE_MASK, WRITE_SHIFT>(r.writeable());
_assign<READ_MASK, READ_SHIFT>(r.readable());
}
public:
Mem_crd(unsigned base, unsigned order, Rights rights = Rights())
: Crd(base, order)
{
_rights(rights);
_assign<TYPE_MASK, TYPE_SHIFT>(MEM_CRD_TYPE);
}
Rights rights() const
{
return Rights(_query<READ_MASK, READ_SHIFT>(),
_query<WRITE_MASK, WRITE_SHIFT>(),
_query<EXEC_MASK, EXEC_SHIFT>());
}
};
/**
* I/O-capability-range descriptor
*/
class Io_crd : public Crd
{
public:
Io_crd(unsigned base, unsigned order)
: Crd(base, order)
{
_assign<TYPE_MASK | RIGHTS_MASK, TYPE_SHIFT>(IO_CRD_ALL);
}
};
class Obj_crd : public Crd
{
public:
Obj_crd(unsigned base, unsigned order)
: Crd(base, order)
{
_assign<TYPE_MASK | RIGHTS_MASK, TYPE_SHIFT>(OBJ_CRD_ALL);
}
};
/**
* Quantum-priority descriptor
*/
class Qpd : public Descriptor
{
private:
enum {
QUANTUM_MASK = 0xfffff, QUANTUM_SHIFT = 12,
PRIORITY_MASK = 0xff, PRIORITY_SHIFT = 0
};
void _quantum(unsigned quantum)
{ _assign<QUANTUM_MASK, QUANTUM_SHIFT>(quantum); }
void _priority(unsigned priority)
{ _assign<PRIORITY_MASK, PRIORITY_SHIFT>(priority); }
public:
enum { DEFAULT_QUANTUM = 10000, DEFAULT_PRIORITY = 1 };
Qpd(unsigned quantum = DEFAULT_QUANTUM,
unsigned priority = DEFAULT_PRIORITY)
{
_value = 0;
_quantum(quantum), _priority(priority);
}
unsigned quantum() const { return _query<QUANTUM_MASK, QUANTUM_SHIFT>(); }
unsigned priority() const { return _query<PRIORITY_MASK, PRIORITY_SHIFT>(); }
};
/**
* User-level thread-control block
*/
struct Utcb
{
unsigned short ui; /* number of untyped items */
unsigned short ti; /* number of typed itmes */
Crd crd_xlt; /* receive capability-range descriptor for translation */
Crd crd_rcv; /* receive capability-range descriptor for delegation */
unsigned tls;
/**
* Data area
*
* The UTCB entries following the header hold message payload (normal
* IDC operations) or architectural state (exception handling).
*/
union {
/* message payload */
unsigned msg[];
/* exception state */
struct {
unsigned mtd, instr_len, eip, eflags;
unsigned misc[4];
unsigned eax, ecx, edx, ebx;
unsigned esp, ebp, esi, edi;
long long qual[2]; /* exit qualification */
unsigned misc2[4];
unsigned cr0, cr2, cr3, cr4;
unsigned misc3[44];
};
};
struct Item {
unsigned crd;
unsigned hotspot;
};
/**
* Set number of untyped message words
*
* Calling this function has the side effect of removing all typed
* message items from the message buffer.
*/
void set_msg_word(unsigned num) { ui = num; ti = 0; }
/**
* Return current number of message word in UTCB
*/
unsigned msg_words() { return ui; }
/**
* Append message-transfer item to message buffer
*
* \param exception true to append the item to an exception reply
*/
void append_item(Crd crd, unsigned sel_hotspot,
bool kern_pd = false,
bool update_guest_pt = false)
{
/* transfer items start at the end of the UTCB */
Item *item = reinterpret_cast<Item *>(this) + (PAGE_SIZE / sizeof(struct Item)) - ++ti;
/* map from hypervisor or current pd */
unsigned h = kern_pd ? (1 << 11) : 0;
/* update guest page table */
unsigned g = update_guest_pt ? (1 << 10) : 0;
item->hotspot = crd.hotspot(sel_hotspot) | g | h | 1;
item->crd = crd.value();
}
unsigned mtd_value() const { return static_cast<Mtd>(mtd).value(); }
};
/**
* Size of event-specific portal window mapped at PD creation time
*/
enum {
NUM_INITIAL_PT_LOG2 = 5,
NUM_INITIAL_PT = 1 << NUM_INITIAL_PT_LOG2
};
/**
* Event-specific capability selectors
*/
enum {
PT_SEL_PAGE_FAULT = 0xe,
PT_SEL_PARENT = 0x1a, /* convention on Genode */
PT_SEL_STARTUP = 0x1e,
PD_SEL = 0x1b,
};
ALWAYS_INLINE
inline unsigned eax(Syscall s, uint8_t flags, unsigned sel)
{
return sel << 8 | (flags & 0xf) << 4 | s;
}
ALWAYS_INLINE
inline uint8_t syscall_0(Syscall s, uint8_t flags, unsigned sel = 0)
{
mword_t status = eax(s, flags, sel);
asm volatile (" mov %%esp, %%ecx;"
" call 0f;"
"0:"
" addl $(1f-0b), (%%esp);"
" mov (%%esp), %%edx;"
" sysenter;"
"1:"
: "+a" (status)
:
: "ecx", "edx", "memory");
return status;
}
ALWAYS_INLINE
inline uint8_t syscall_1(Syscall s, uint8_t flags, mword_t p1)
{
mword_t status = eax(s, flags, 0);
asm volatile (" mov %%esp, %%ecx;"
" call 0f;"
"0:"
" addl $(1f-0b), (%%esp);"
" mov (%%esp), %%edx;"
" sysenter;"
"1:"
: "+a" (status)
: "D" (p1)
: "ecx", "edx");
return status;
}
ALWAYS_INLINE
inline uint8_t syscall_2(Syscall s, uint8_t flags, unsigned sel, mword_t p1, mword_t p2)
{
mword_t status = eax(s, flags, sel);
asm volatile (" mov %%esp, %%ecx;"
" call 0f;"
"0:"
" addl $(1f-0b), (%%esp);"
" mov (%%esp), %%edx;"
" sysenter;"
"1:"
: "+a" (status)
: "D" (p1), "S" (p2)
: "ecx", "edx");
return status;
}
ALWAYS_INLINE
inline uint8_t syscall_3(Syscall s, uint8_t flags, unsigned sel,
mword_t p1, mword_t p2, mword_t p3)
{
mword_t status = eax(s, flags, sel);
asm volatile (" push %%ebx;"
" mov %%edx, %%ebx;"
" mov %%esp, %%ecx;"
" call 0f;"
"0:"
" addl $(1f-0b), (%%esp);"
" mov (%%esp), %%edx;"
" sysenter;"
"1:"
" pop %%ebx;"
: "+a" (status)
: "D" (p1), "S" (p2), "d" (p3)
: "ecx");
return status;
}
ALWAYS_INLINE
inline uint8_t syscall_4(Syscall s, uint8_t flags, unsigned sel,
mword_t p1, mword_t p2, mword_t p3, mword_t p4)
{
mword_t status = eax(s, flags, sel);
asm volatile (" push %%ebp;"
" push %%ebx;"
" mov %%ecx, %%ebx;"
" mov %%esp, %%ecx;"
" mov %%edx, %%ebp;"
" call 0f;"
"0:"
" addl $(1f-0b), (%%esp);"
" mov (%%esp), %%edx;"
"sysenter;"
"1:"
" pop %%ebx;"
" pop %%ebp;"
: "+a" (status)
: "D" (p1), "S" (p2), "c" (p3), "d" (p4)
: "memory");
return status;
}
ALWAYS_INLINE
inline uint8_t call(unsigned pt)
{
return syscall_0(NOVA_CALL, 0, pt);
}
ALWAYS_INLINE
inline void reply(void *next_sp)
{
asm volatile ("sysenter;"
:
: "a" (NOVA_REPLY), "c" (next_sp)
: "memory");
}
ALWAYS_INLINE
inline uint8_t create_pd(unsigned pd0, unsigned pd, Crd crd)
{
return syscall_2(NOVA_CREATE_PD, 0, pd0, pd, crd.value());
}
ALWAYS_INLINE
inline uint8_t create_ec(unsigned ec, unsigned pd,
mword_t cpu, mword_t utcb,
mword_t esp, mword_t evt,
bool global = 0)
{
return syscall_4(NOVA_CREATE_EC, global, ec, pd,
(cpu & 0xfff) | (utcb & ~0xfff),
esp, evt);
}
ALWAYS_INLINE
inline uint8_t ec_ctrl(unsigned ec)
{
return syscall_1(NOVA_EC_CTRL, 0, ec);
}
ALWAYS_INLINE
inline uint8_t create_sc(unsigned sc, unsigned pd, unsigned ec, Qpd qpd)
{
return syscall_3(NOVA_CREATE_SC, 0, sc, pd, ec, qpd.value());
}
ALWAYS_INLINE
inline uint8_t create_pt(unsigned pt, unsigned pd, unsigned ec, Mtd mtd, mword_t eip)
{
return syscall_4(NOVA_CREATE_PT, 0, pt, pd, ec, mtd.value(), eip);
}
ALWAYS_INLINE
inline uint8_t create_sm(unsigned sm, unsigned pd, mword_t cnt)
{
return syscall_2(NOVA_CREATE_SM, 0, sm, pd, cnt);
}
ALWAYS_INLINE
inline uint8_t revoke(Crd crd, bool self = true)
{
return syscall_1(NOVA_REVOKE, self, crd.value());
}
ALWAYS_INLINE
inline uint8_t lookup(Crd *crd)
{
mword_t status = eax(NOVA_LOOKUP, 0, 0);
mword_t raw = crd->value();
asm volatile (" mov %%esp, %%ecx;"
" call 0f;"
"0:"
" addl $(1f-0b), (%%esp);"
" mov (%%esp), %%edx;"
" sysenter;"
"1:"
: "+a" (status), "+D" (raw)
:
: "ecx", "edx", "memory");
*crd = Crd(raw);
return status;
}
/**
* Semaphore operations
*/
enum Sem_op { SEMAPHORE_UP = 0, SEMAPHORE_DOWN = 1 };
ALWAYS_INLINE
inline uint8_t sm_ctrl(unsigned sm, Sem_op op)
{
return syscall_0(NOVA_SM_CTRL, op, sm);
}
ALWAYS_INLINE
inline uint8_t assign_gsi(unsigned sm, mword_t dev, mword_t cpu)
{
return syscall_2(NOVA_ASSIGN_GSI, 0, sm, dev, cpu);
}
}
#endif /* _PLATFORM__NOVA_SYSCALLS_H_ */

View File

@@ -0,0 +1,34 @@
/*
* \brief NOVA-specific signal source RPC interface
* \author Norman Feske
* \date 2011-04-12
*/
/*
* Copyright (C) 2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__SIGNAL_SESSION__NOVA_SOURCE_H_
#define _INCLUDE__SIGNAL_SESSION__NOVA_SOURCE_H_
#include <base/rpc.h>
#include <signal_session/source.h>
namespace Genode {
struct Nova_signal_source : Signal_source
{
/*********************
** RPC declaration **
*********************/
GENODE_RPC(Rpc_request_semaphore, Native_capability, _request_semaphore);
GENODE_RPC_INTERFACE_INHERIT(Signal_source, Rpc_request_semaphore);
};
}
#endif /* _INCLUDE__SIGNAL_SESSION__NOVA_SOURCE_H_ */

View File

@@ -0,0 +1,82 @@
/*
* \brief NOVA-specific signal-source client interface
* \author Norman Feske
* \date 2010-02-03
*
* On NOVA, the signal source server does not provide a blocking
* 'wait_for_signal' function because this kernel does no support
* out-of-order IPC replies. Instead, we use a shared semaphore
* to let the client block until a signal is present at the
* server. The shared semaphore gets initialized with the first
* call of 'wait_for_signal()'.
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__SIGNAL_SESSION__SOURCE_CLIENT_H_
#define _INCLUDE__SIGNAL_SESSION__SOURCE_CLIENT_H_
#include <nova/syscalls.h>
#include <base/rpc_client.h>
#include <signal_session/nova_source.h>
namespace Genode {
class Signal_source_client : public Rpc_client<Nova_signal_source>
{
private:
/**
* Capability with 'pt_sel' referring to a NOVA semaphore
*/
Native_capability _sem;
/**
* Request NOVA semaphore from signal-source server
*/
void _init_sem()
{
/* initialize semaphore only once */
if (_sem.valid()) return;
/* request mapping of semaphore capability selector */
_sem = call<Rpc_request_semaphore>();
}
public:
/**
* Constructor
*/
Signal_source_client(Signal_source_capability cap)
: Rpc_client<Nova_signal_source>(static_cap_cast<Nova_signal_source>(cap)) { }
/*****************************
** Signal source interface **
*****************************/
Signal wait_for_signal()
{
/* make sure that we have aquired the semaphore from the server */
_init_sem();
/* block on semaphore, will be unblocked if signal is available */
Nova::sm_ctrl(_sem.pt_sel(), Nova::SEMAPHORE_DOWN);
/*
* Now that the server has unblocked the semaphore, we are sure
* that there is a signal pending. The following 'wait_for_signal'
* request will be immediately answered.
*/
return call<Rpc_wait_for_signal>();
}
};
}
#endif /* _INCLUDE__SIGNAL_SESSION__SOURCE_CLIENT_H_ */

View File

@@ -0,0 +1,39 @@
/*
* \brief Signal-source server interface
* \author Norman Feske
* \date 2010-02-03
*
* This file is only included by 'signal_session/server.h' and relies on the
* headers included there. No include guards are needed. It is a separate
* header file to make it easily replaceable by a platform-specific
* implementation.
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__SIGNAL_SESSION__SOURCE_SERVER_H_
#define _INCLUDE__SIGNAL_SESSION__SOURCE_SERVER_H_
#include <base/rpc_server.h>
#include <signal_session/nova_source.h>
namespace Genode {
struct Signal_source_rpc_object : Rpc_object<Nova_signal_source, Signal_source_rpc_object>
{
protected:
Native_capability _blocking_semaphore;
public:
Native_capability _request_semaphore() { return _blocking_semaphore; }
};
}
#endif /* _INCLUDE__SIGNAL_SESSION__SOURCE_SERVER_H_ */

View File

@@ -0,0 +1,5 @@
SRC_CC = core_printf.cc
LIBS = cxx console
INC_DIR += $(REP_DIR)/src/base/console
vpath core_printf.cc $(BASE_DIR)/src/base/console

7
base-nova/lib/mk/env.mk Normal file
View File

@@ -0,0 +1,7 @@
SRC_CC = env.cc cap_sel_alloc.cc main_thread.cc context_area.cc
LIBS = ipc heap lock log_console
vpath env.cc $(BASE_DIR)/src/base/env
vpath cap_sel_alloc.cc $(REP_DIR)/src/base/env
vpath main_thread.cc $(REP_DIR)/src/base/env
vpath context_area.cc $(BASE_DIR)/src/base/env

6
base-nova/lib/mk/ipc.mk Normal file
View File

@@ -0,0 +1,6 @@
SRC_CC = ipc.cc pager.cc
LIBS = thread_context
INC_DIR += $(REP_DIR)/src/platform
vpath ipc.cc $(REP_DIR)/src/base/ipc
vpath pager.cc $(REP_DIR)/src/base/ipc

5
base-nova/lib/mk/lock.mk Normal file
View File

@@ -0,0 +1,5 @@
SRC_CC = lock.cc
INC_DIR += $(REP_DIR)/src/base/lock
INC_DIR += $(REP_DIR)/src/platform
vpath lock.cc $(BASE_DIR)/src/base/lock

View File

@@ -0,0 +1,3 @@
SRC_CC = pager.cc
vpath pager.cc $(REP_DIR)/src/base/pager

View File

@@ -0,0 +1,3 @@
SRC_CC = printf_stdio.cc
vpath printf_stdio.cc $(REP_DIR)/src/lib/printf_stdio

View File

@@ -0,0 +1,4 @@
SRC_CC = server.cc
INC_DIR = $(REP_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base/server

View File

@@ -0,0 +1,3 @@
LIBS = thread
include $(REP_DIR)/lib/mk/raw_server.mk

View File

@@ -0,0 +1,11 @@
SRC_CC = cap_sel_alloc.cc main_thread.cc context_area.cc echo.cc \
thread_nova.cc thread.cc
LIBS += thread_context
INC_DIR += $(REP_DIR)/src/core/include
vpath cap_sel_alloc.cc $(REP_DIR)/src/base/env
vpath main_thread.cc $(REP_DIR)/src/base/env
vpath thread.cc $(BASE_DIR)/src/base/thread
vpath thread_nova.cc $(REP_DIR)/src/test
vpath context_area.cc $(REP_DIR)/src/test
vpath echo.cc $(REP_DIR)/src/core

View File

@@ -0,0 +1,6 @@
SRC_CC = thread.cc thread_nova.cc
LIBS = thread_context
vpath thread.cc $(BASE_DIR)/src/base/thread
vpath thread_nova.cc $(REP_DIR)/src/base/thread

View File

@@ -0,0 +1,3 @@
SRC_CC = thread_context.cc
vpath thread_context.cc $(REP_DIR)/src/base/thread

View File

@@ -0,0 +1,8 @@
REQUIRES = nova x86
LIBS = cxx lock
SRC_S = crt0.s
SRC_CC = _main.cc
INC_DIR += $(REP_DIR)/src/platform
vpath crt0.s $(BASE_DIR)/src/platform/x86_32
vpath _main.cc $(dir $(call select_from_repositories,src/platform/_main.cc))

16
base-nova/mk/spec-nova.mk Normal file
View File

@@ -0,0 +1,16 @@
#
# Specifics for the NOVA kernel API
#
LD_TEXT_ADDR ?= 0x01000000
#
# Startup code to be used when building a program
#
STARTUP_LIB ?= startup
PRG_LIBS += $(STARTUP_LIB)
#
# NOVA only runs on x86, enable x86 devices
#
SPECS += pci ps2 vesa

21
base-nova/patches/README Normal file
View File

@@ -0,0 +1,21 @@
This directory contains patches for the Nova Hypervisor prerelease 0.3
:'utcb.patch':
It is not possible to destroy UTCBs in NOVA 0.3. Therefore UTCBs cannot be
re-used which may lead to the exhaustion of contexts within Genode. This patch
simply causes NOVA to ignore this issue.
Applying the patches
--------------------
To apply a patch to the NOVA hypervisor, use the 'patch' command. First check
the directory given at the header of the patch. It may contain a directory
prefix (such as 'a/'), which does not actually exist. This prefix is usually
generated by the tool used to create the patch. In this case, use the '-p'
option of the patch command. To apply the patch with the first part of the
path stripped, issue the following command (make sure that you changed to
the base directory of the NOVA hypervisor):
! patch -p1 < /path/to/utcb.patch

View File

@@ -0,0 +1,18 @@
diff -r 11c290b5edf9 src/syscall.cpp
--- a/src/syscall.cpp Wed Nov 09 14:50:18 2011 +0100
+++ b/src/syscall.cpp Wed Nov 09 15:07:03 2011 +0100
@@ -240,11 +240,13 @@
}
Pd *pd = static_cast<Pd *>(cap.obj());
- if (EXPECT_FALSE (r->utcb() >= USER_ADDR || r->utcb() & PAGE_MASK || !pd->insert_utcb (r->utcb()))) {
+ if (EXPECT_FALSE (r->utcb() >= USER_ADDR || r->utcb() & PAGE_MASK)) {
trace (TRACE_ERROR, "%s: Invalid UTCB address (%#lx)", __func__, r->utcb());
sys_finish<Sys_regs::BAD_PAR>();
}
+ pd->insert_utcb (r->utcb());
+
Ec *ec = new Ec (Pd::current, r->sel(), pd, r->flags() & 1 ? static_cast<void (*)()>(send_msg<ret_user_iret>) : 0, r->cpu(), r->evt(), r->utcb(), r->esp());
if (!Space_obj::insert_root (ec)) {

82
base-nova/run/env Normal file
View File

@@ -0,0 +1,82 @@
#
# \brief NOVA-specific test-environment supplements
# \author Norman Feske
# \date 2010-08-31
#
# This file is meant to be used as '--include' argument for 'tool/run'.
#
##
# Read the location of the Pistachio user directory from 'etc/pistachio.conf'
#
proc nova_kernel { } {
global _nova_kernel
if {![info exists _nova_kernel]} {
if {[file exists etc/nova.conf]} {
set _nova_kernel [exec sed -n "/^NOVA_KERNEL/s/^.*=\\s*//p" etc/nova.conf]
} else {
set _nova_kernel "[pwd]/kernel/hypervisor"
}
}
return $_nova_kernel
}
##
# Return whether nova is provided from the outside
#
proc nova_external { } {
if {[nova_kernel] == "[pwd]/kernel/hypervisor"} { return 0 }
return 1
}
##################################
## Test framework API functions ##
##################################
proc create_boot_directory { } {
exec rm -rf [run_dir]
exec mkdir -p [run_dir]/genode
}
proc build_boot_image {binaries} {
#
# Collect contents of the ISO image
#
copy_and_strip_genode_binaries_to_run_dir $binaries
if {![nova_external] && ![file exists [nova_kernel]]} { build { kernel } }
puts "using NOVA kernel at [nova_kernel]"
exec cp [nova_kernel] [run_dir]/hypervisor
install_iso_bootloader_to_run_dir
#
# Generate grub config file
#
# The core binary is part of the 'binaries' list but it must
# appear right after 'sigma0' as boot module. Hence the special case.
#
set fh [open "[run_dir]/boot/grub/menu.lst" "WRONLY CREAT TRUNC"]
puts $fh "timeout 0"
puts $fh "default 0"
puts $fh "\ntitle Genode on NOVA"
puts $fh " kernel /hypervisor serial"
puts $fh " module /genode/core"
puts $fh " module /genode/config"
foreach binary $binaries {
if {$binary != "core"} {
puts $fh " module /genode/$binary" } }
close $fh
create_iso_image_from_run_dir
}
proc run_genode_until {{wait_for_re forever} {timeout_value 0}} {
spawn_qemu $wait_for_re $timeout_value }

View File

@@ -0,0 +1,129 @@
/*
* \brief Console backend for NOVA
* \author Norman Feske
* \date 2009-12-28
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/cap_sel_alloc.h>
#include <base/console.h>
/* NOVA includes */
#include <nova/syscalls.h>
typedef unsigned char uint8_t;
/**
* Read byte from I/O port
*/
inline uint8_t inb(unsigned short port)
{
uint8_t res;
asm volatile ("inb %%dx, %0" :"=a"(res) :"Nd"(port));
return res;
}
/**
* Write byte to I/O port
*/
inline void outb(unsigned short port, uint8_t val)
{
asm volatile ("outb %b0, %w1" : : "a" (val), "Nd" (port));
}
/**
* Definitions of PC serial ports
*/
enum Comport { COMPORT_0, COMPORT_1, COMPORT_2, COMPORT_3 };
enum {
// COMPORT_0_BASE = 0x1010, /* comport of serial PCI card */
COMPORT_0_BASE = 0x3f8, /* default comport 0, used wiht Qemu */
COMPORT_1_BASE = 0x2f8,
COMPORT_2_BASE = 0x3e8,
COMPORT_3_BASE = 0x2e8,
COMPORT_DATA_OFFSET = 0,
COMPORT_STATUS_OFFSET = 5
};
/**
* Initialize serial port
*
* Based on 'init_serial' of L4ka::Pistachio's 'kdb/platform/pc99/io.cc'
*/
static void init_comport(unsigned short port, unsigned baud)
{
const unsigned
IER = port + 1,
EIR = port + 2,
LCR = port + 3,
MCR = port + 4,
LSR = port + 5,
MSR = port + 6,
DLLO = port + 0,
DLHI = port + 1;
outb(LCR, 0x80); /* select bank 1 */
for (volatile int i = 10000000; i--; );
outb(DLLO, (115200/baud) >> 0);
outb(DLHI, (115200/baud) >> 8);
outb(LCR, 0x03); /* set 8,N,1 */
outb(IER, 0x00); /* disable interrupts */
outb(EIR, 0x07); /* enable FIFOs */
outb(MCR, 0x0b); /* force data terminal ready */
outb(IER, 0x01); /* enable RX interrupts */
inb(IER);
inb(EIR);
inb(LCR);
inb(MCR);
inb(LSR);
inb(MSR);
}
/**
* Output character to serial port
*/
inline void serial_out_char(Comport comport, uint8_t c)
{
static int io_port[] = { COMPORT_0_BASE, COMPORT_1_BASE,
COMPORT_2_BASE, COMPORT_3_BASE };
/* wait until serial port is ready */
while (!(inb(io_port[comport] + COMPORT_STATUS_OFFSET) & 0x60));
/* output character */
outb(io_port[comport] + COMPORT_DATA_OFFSET, c);
}
namespace Genode {
class Core_console : public Console
{
protected:
void _out_char(char c)
{
if (c == '\n')
serial_out_char(COMPORT_0, '\r');
serial_out_char(COMPORT_0, c);
}
public:
Core_console() { init_comport(COMPORT_0_BASE, 115200); }
};
}

121
base-nova/src/base/env/cap_sel_alloc.cc vendored Normal file
View File

@@ -0,0 +1,121 @@
/*
* \brief Capability-selector allocator
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2010-01-19
*
* This is a NOVA-specific addition to the process enviroment.
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/cap_sel_alloc.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
/**
* First available capability selector for custom use
*
* Must be initialized by the startup code
*/
int __first_free_cap_selector;
int __local_pd_sel;
/**
* Low-level lock to protect the allocator
*
* We cannot use a normal Genode lock because this lock is used by code
* executed prior the initialization of Genode.
*/
class Alloc_lock
{
private:
int _sm_cap;
public:
/**
* Constructor
*
* \param sm_cap capability selector for the used semaphore
*/
Alloc_lock(int sm_cap) : _sm_cap(sm_cap)
{
Nova::create_sm(_sm_cap, __local_pd_sel, 1);
}
void lock() { Nova::sm_ctrl(_sm_cap, Nova::SEMAPHORE_DOWN); }
void unlock() { Nova::sm_ctrl(_sm_cap, Nova::SEMAPHORE_UP); }
};
/**
* Return lock used to protect capability selector allocations
*/
static Alloc_lock *alloc_lock()
{
static Alloc_lock alloc_lock_inst(__first_free_cap_selector);
return &alloc_lock_inst;
}
static int _cap_free;
addr_t Cap_selector_allocator::alloc(size_t num_caps_log2)
{
alloc_lock()->lock();
int num_caps = 1 << num_caps_log2;
int ret_base = (_cap_free + num_caps - 1) & ~(num_caps - 1);
_cap_free = ret_base + num_caps;
alloc_lock()->unlock();
return ret_base;
}
void Cap_selector_allocator::free(addr_t cap, size_t num_caps_log2)
{
/*
* We don't free capability selectors because revoke is not supported
* on NOVA yet, anyway.
*/
}
unsigned Cap_selector_allocator::pd_sel() { return __local_pd_sel; }
Cap_selector_allocator::Cap_selector_allocator()
{
/* initialize lock */
alloc_lock();
/* the first free selector is used for the lock */
_cap_free = __first_free_cap_selector + 1;
}
namespace Genode {
/**
* This function must not be called prior the initialization of
* '__first_free_cap_selector'.
*/
Cap_selector_allocator *cap_selector_allocator()
{
static Cap_selector_allocator inst;
return &inst;
}
}

43
base-nova/src/base/env/main_thread.cc vendored Normal file
View File

@@ -0,0 +1,43 @@
/*
* \brief Information about the main thread
* \author Norman Feske
* \date 2010-01-19
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/native_types.h>
#include <base/cap_sel_alloc.h>
#include <base/printf.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
/**
* Location of the main thread's UTCB, initialized by the startup code
*/
Nova::mword_t __main_thread_utcb;
Native_utcb *main_thread_utcb() { return (Native_utcb *)__main_thread_utcb; }
int main_thread_running_semaphore()
{
static int sm;
if (!sm) {
sm = cap_selector_allocator()->alloc();
int res = Nova::create_sm(sm, Cap_selector_allocator::pd_sel(), 0);
if (res)
PERR("create_sm returned %d", res);
}
return sm;
}

View File

@@ -0,0 +1,200 @@
/*
* \brief Implementation of the IPC API for NOVA
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/ipc.h>
#include <base/thread.h>
#include <base/printf.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
using namespace Nova;
/***************
** Utilities **
***************/
/**
* Copy message registers from UTCB to destination message buffer
*/
static void copy_utcb_to_msgbuf(Nova::Utcb *utcb, Msgbuf_base *rcv_msg)
{
size_t num_msg_words = utcb->msg_words();
if (num_msg_words == 0) return;
/* look up and validate destination message buffer to receive the payload */
mword_t *msg_buf = (mword_t *)rcv_msg->buf;
if (num_msg_words*sizeof(mword_t) > rcv_msg->size()) {
PERR("receive message buffer too small msg size=%x, buf size=%zd",
num_msg_words*sizeof(mword_t), rcv_msg->size());
num_msg_words = rcv_msg->size()/sizeof(mword_t);
}
/* read message payload into destination message buffer */
mword_t *src = (mword_t *)(void *)(&utcb->msg[0]);
mword_t *dst = (mword_t *)&msg_buf[0];
for (unsigned i = 0; i < num_msg_words; i++)
*dst++ = *src++;
rcv_msg->rcv_reset();
}
/**
* Copy message payload to UTCB message registers
*/
static void copy_msgbuf_to_utcb(Nova::Utcb *utcb, Msgbuf_base *snd_msg,
unsigned num_msg_words, mword_t local_name)
{
/* look up address and size of message payload */
mword_t *msg_buf = (mword_t *)snd_msg->buf;
/*
* XXX determine correct number of message registers
*/
enum { NUM_MSG_REGS = 256 };
if (num_msg_words > NUM_MSG_REGS) {
PERR("Message does not fit into UTCB message registers\n");
num_msg_words = NUM_MSG_REGS;
}
msg_buf[0] = local_name;
/* store message into UTCB message registers */
mword_t *src = (mword_t *)&msg_buf[0];
mword_t *dst = (mword_t *)(void *)&utcb->msg[0];
for (unsigned i = 0; i < num_msg_words; i++)
*dst++ = *src++;
utcb->set_msg_word(num_msg_words);
/* append portal capability selectors */
for (unsigned i = 0; i < snd_msg->snd_pt_sel_cnt(); i++) {
int pt_sel = snd_msg->snd_pt_sel(i);
if (pt_sel < 0) continue;
utcb->append_item(Nova::Obj_crd(pt_sel, 0), i);
}
/* we have consumed portal capability selectors, reset message buffer */
snd_msg->snd_reset();
}
/*****************
** Ipc_ostream **
*****************/
Ipc_ostream::Ipc_ostream(Native_capability dst, Msgbuf_base *snd_msg)
:
Ipc_marshaller(&snd_msg->buf[0], snd_msg->size()),
_snd_msg(snd_msg), _dst(dst)
{
_write_offset = sizeof(mword_t);
}
/*****************
** Ipc_istream **
*****************/
void Ipc_istream::_wait() { }
Ipc_istream::Ipc_istream(Msgbuf_base *rcv_msg)
: Ipc_unmarshaller(&rcv_msg->buf[0], rcv_msg->size()), _rcv_msg(rcv_msg)
{
_read_offset = sizeof(mword_t);
}
Ipc_istream::~Ipc_istream() { }
/****************
** Ipc_client **
****************/
void Ipc_client::_call()
{
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
copy_msgbuf_to_utcb(utcb, _snd_msg, _write_offset/sizeof(mword_t),
_dst.local_name());
_rcv_msg->rcv_prepare_pt_sel_window(utcb);
/* establish the mapping via a portal traversal */
if (_dst.pt_sel() == 0)
PWRN("destination portal is zero");
int res = Nova::call(_dst.pt_sel());
if (res)
PERR("call returned %d", res);
copy_utcb_to_msgbuf(utcb, _rcv_msg);
_snd_msg->snd_reset();
_write_offset = _read_offset = sizeof(mword_t);
}
Ipc_client::Ipc_client(Native_capability const &srv,
Msgbuf_base *snd_msg, Msgbuf_base *rcv_msg)
: Ipc_istream(rcv_msg), Ipc_ostream(srv, snd_msg), _result(0)
{ }
/****************
** Ipc_server **
****************/
void Ipc_server::_wait()
{
/*
* This function is only called by the portal dispatcher of server
* entrypoint'. When the dispatcher is called, the incoming message already
* arrived so that we do not need to block. The only remaining thing to do
* is unmarshalling the arguments.
*/
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
copy_utcb_to_msgbuf(utcb, _rcv_msg);
/* reset unmarshaller */
_read_offset = sizeof(mword_t);
_write_offset = 2*sizeof(mword_t); /* leave space for the return value */
}
void Ipc_server::_reply()
{
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
copy_msgbuf_to_utcb(utcb, _snd_msg, _write_offset/sizeof(mword_t),
_dst.local_name());
Nova::reply(Thread_base::myself()->stack_top());
}
void Ipc_server::_reply_wait() { }
Ipc_server::Ipc_server(Msgbuf_base *snd_msg,
Msgbuf_base *rcv_msg)
: Ipc_istream(rcv_msg), Ipc_ostream(Native_capability(), snd_msg)
{ }

View File

@@ -0,0 +1,67 @@
/*
* \brief Low-level page-fault handling
* \author Norman Feske
* \date 2010-01-25
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/ipc_pager.h>
#include <base/thread.h>
/* NOVA includes */
#include <nova/syscalls.h>
enum { verbose_page_fault = false };
using namespace Genode;
/**
* Print page-fault information in a human-readable form
*/
inline void print_page_fault(unsigned type, addr_t addr, addr_t ip)
{
enum { TYPE_READ = 0x4, TYPE_WRITE = 0x2, TYPE_EXEC = 0x1, };
printf("page (%s%s%s) fault at fault_addr=%lx, fault_ip=%lx\n",
type & TYPE_READ ? "r" : "-",
type & TYPE_WRITE ? "w" : "-",
type & TYPE_EXEC ? "x" : "-",
addr, ip);
}
void Ipc_pager::wait_for_fault()
{
/*
* When this function is called from the page-fault handler EC, a page
* fault already occurred. So we never wait but immediately read the
* page-fault information from our UTCB.
*/
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
_fault_type = (Pf_type)utcb->qual[0];
_fault_addr = utcb->qual[1];
_fault_ip = utcb->eip;
if (verbose_page_fault)
print_page_fault(_fault_type, _fault_addr, _fault_ip);
}
void Ipc_pager::set_reply_mapping(Mapping m)
{
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
utcb->set_msg_word(0);
utcb->append_item(m.mem_crd(), m.dst_addr());
}
void Ipc_pager::reply_and_wait_for_fault()
{
Nova::reply(Thread_base::myself()->stack_top());
}

View File

@@ -0,0 +1,88 @@
/*
* \brief Helper functions for the Lock implementation
* \author Norman Feske
* \date 2009-10-02
*
* For documentation about the interface, please revisit the 'base-pistachio'
* implementation.
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/native_types.h>
#include <base/thread.h>
/* NOVA includes */
#include <nova/syscalls.h>
extern int main_thread_running_semaphore();
/**
* Resolve 'Thread_base::myself' when not linking the thread library
*
* This weak symbol is primarily used by test cases. Most other Genode programs
* use the thread library. If the thread library is not used, 'myself' can only
* be called by the main thread, for which 'myself' is defined as zero.
*/
Genode::Thread_base * __attribute__((weak)) Genode::Thread_base::myself() { return 0; }
static inline void thread_yield() { }
static bool thread_check_stopped_and_restart(Genode::Native_thread_id tid)
{
int sem = tid.rs_sel == 0 ? main_thread_running_semaphore()
: tid.rs_sel;
Nova::sm_ctrl(sem, Nova::SEMAPHORE_UP);
return true;
}
static inline Genode::Native_thread_id thread_get_my_native_id()
{
/*
* We encode the main thread as tid { 0, 0, 0 } because we cannot
* call 'main_thread_running_semaphore()' here.
*/
Genode::Thread_base *myself = Genode::Thread_base::myself();
if (myself == 0) {
Genode::Native_thread_id main_tid = { 0, 0, 0 };
return main_tid;
} else
return myself->tid();
}
static inline Genode::Native_thread_id thread_invalid_id()
{
Genode::Native_thread_id tid = { 0, 0, -1 };
return tid;
}
static inline bool thread_id_valid(Genode::Native_thread_id tid)
{
return tid.rs_sel != -1;
}
static inline void thread_switch_to(Genode::Native_thread_id tid) { }
static inline void thread_stop_myself()
{
Genode::Thread_base *myself = Genode::Thread_base::myself();
int sem = myself ? myself->tid().rs_sel : main_thread_running_semaphore();
Nova::sm_ctrl(sem, Nova::SEMAPHORE_DOWN);
}

View File

@@ -0,0 +1,177 @@
/*
* \brief Pager framework
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2010-01-25
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/cap_sel_alloc.h>
#include <base/pager.h>
#include <base/sleep.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
using namespace Nova;
enum { PF_HANDLER_STACK_SIZE = 4096 };
static Lock *pf_lock() { static Lock inst; return &inst; }
void Pager_object::_page_fault_handler()
{
Ipc_pager ipc_pager;
ipc_pager.wait_for_fault();
/* serialize page-fault handling */
pf_lock()->lock();
Thread_base *myself = Thread_base::myself();
if (!myself) {
PWRN("unexpected page-fault for non-existing pager object, going to sleep forever");
sleep_forever();
}
Pager_object *obj = static_cast<Pager_object *>(myself);
int ret = obj->pager(ipc_pager);
pf_lock()->unlock();
if (ret) {
PWRN("page-fault resolution for for address 0x%lx failed, going to sleep forever",
ipc_pager.fault_addr());
sleep_forever();
}
ipc_pager.reply_and_wait_for_fault();
}
void Pager_object::_startup_handler()
{
Pager_object *obj = static_cast<Pager_object *>(Thread_base::myself());
Utcb *utcb = (Utcb *)Thread_base::myself()->utcb();
printf("start new pager object with EIP=0x%p, ESP=0x%p\n",
(void *)obj->_initial_eip, (void *)obj->_initial_esp);
utcb->eip = obj->_initial_eip;
utcb->esp = obj->_initial_esp;
utcb->mtd = Mtd::EIP | Mtd::ESP;
reply(Thread_base::myself()->stack_top());
}
void Pager_object::_invoke_handler()
{
Utcb *utcb = (Utcb *)Thread_base::myself()->utcb();
Pager_object *obj = static_cast<Pager_object *>(Thread_base::myself());
/* send single portal as reply */
int event = utcb->msg[0];
utcb->mtd = 0;
if (event == PT_SEL_STARTUP || event == PT_SEL_PAGE_FAULT)
utcb->append_item(Obj_crd(obj->_exc_pt_sel + event, 0), 0);
reply(Thread_base::myself()->stack_top());
}
void Pager_object::wake_up() { PDBG("not yet implemented"); }
Pager_object::Pager_object(unsigned long badge)
: Thread_base("pager", PF_HANDLER_STACK_SIZE), _badge(badge)
{
_tid.ec_sel = cap_selector_allocator()->alloc();
unsigned pd_sel = cap_selector_allocator()->pd_sel();
enum { CPU_NO = 0, GLOBAL = false, EXC_BASE = 0 };
mword_t *thread_sp = (mword_t *)&_context->stack[-4];
mword_t thread_utcb = (mword_t) &_context->utcb;
/* create local EC */
int res = create_ec(_tid.ec_sel, pd_sel,
CPU_NO, thread_utcb,
(mword_t)thread_sp, /* <- delivered to the startup handler */
EXC_BASE, GLOBAL);
if (res)
PDBG("create_ec returned %d", res);
/* allocate capability-selector range for event portals */
_exc_pt_sel = cap_selector_allocator()->alloc(NUM_INITIAL_PT_LOG2);
/* create portal for page-fault handler */
res = create_pt(_exc_pt_sel + PT_SEL_PAGE_FAULT, pd_sel, _tid.ec_sel,
Mtd(Mtd::QUAL | Mtd::EIP), (mword_t)_page_fault_handler);
if (res) {
PERR("could not create page-fault portal, create_pt returned %d\n",
res);
class Create_page_fault_pt_failed { };
throw Create_page_fault_pt_failed();
}
/* create portal for startup handler */
res = create_pt(_exc_pt_sel + PT_SEL_STARTUP, pd_sel, _tid.ec_sel,
Mtd(Mtd::ESP | Mtd::EIP), (mword_t)_startup_handler);
if (res) {
PERR("could not create startup portal, create_pt returned %d\n",
res);
class Create_startup_pt_failed { };
throw Create_startup_pt_failed();
}
/*
* Create object identity representing the pager object. It is used as
* argument to 'Cpu_session::set_pager'. Furthermore it can be invoked to
* request the mapping of the event capability selector window
* corresponding to the pager object.
*/
_pt_sel = cap_selector_allocator()->alloc();
res = create_pt(_pt_sel, pd_sel, _tid.ec_sel, Mtd(0), (mword_t)_invoke_handler);
if (res)
PERR("could not create pager object identity, create_pt returned %d\n", res);
}
Pager_object::~Pager_object()
{
revoke(Obj_crd(_tid.ec_sel, 0));
/* revoke utcb */
Rights rwx(true, true, true);
revoke(Nova::Mem_crd((unsigned)Thread_base::myself()->utcb() >> 12, 0, rwx));
}
Pager_capability Pager_entrypoint::manage(Pager_object *obj)
{
/* supplement capability with object ID obtained from CAP session */
obj->Object_pool<Pager_object>::Entry::cap(_cap_session->alloc(Native_capability(obj->pt_sel(), 0)));
/* add server object to object pool */
insert(obj);
/* return capability that uses the object id as badge */
return reinterpret_cap_cast<Pager_object>(obj->Object_pool<Pager_object>::Entry::cap());
}
void Pager_entrypoint::dissolve(Pager_object *obj)
{
pf_lock()->lock();
remove(obj);
pf_lock()->unlock();
}

View File

@@ -0,0 +1,187 @@
/*
* \brief NOVA-specific support code for the server-side RPC API
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2010-01-13
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <base/rpc_server.h>
#include <base/cap_sel_alloc.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
/***********************
** Server entrypoint **
***********************/
Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
{
using namespace Nova;
int ec_sel = tid().ec_sel;
int pt_sel = cap_selector_allocator()->alloc();
int pd_sel = cap_selector_allocator()->pd_sel();
/* create portal */
int res = create_pt(pt_sel, pd_sel, ec_sel, Mtd(0),
(mword_t)_activation_entry);
if (res) {
PERR("could not create server-object portal, create_pt returned %d\n",
res);
return Untyped_capability();
}
/* create capability to portal as destination address */
Untyped_capability ep_cap = Native_capability(pt_sel, 0);
/* supplement capability with object ID obtained from CAP session */
Untyped_capability new_obj_cap = _cap_session->alloc(ep_cap);
/* add server object to object pool */
obj->cap(new_obj_cap);
insert(obj);
/* return capability that uses the object id as badge */
return new_obj_cap;
}
void Rpc_entrypoint::_dissolve(Rpc_object_base *obj)
{
/* make sure nobody is able to find this object */
remove(obj);
/*
* The activation may execute a blocking operation
* in a dispatch function. Before resolving the
* corresponding object, we need to ensure that
* it is no longer used by an activation. Therefore,
* we to need cancel an eventually blocking operation
* and let the activation leave the context of the
* object.
*/
_leave_server_object(obj);
/* wait until nobody is inside dispatch */
obj->lock();
/* now the object may be safely destructed */
}
void Rpc_entrypoint::_activation_entry()
{
/* retrieve portal id from eax */
int id_pt; asm volatile ("" : "=a" (id_pt));
Rpc_entrypoint *ep = static_cast<Rpc_entrypoint *>(Thread_base::myself());
Ipc_server srv(&ep->_snd_buf, &ep->_rcv_buf);
/* destination of next reply */
srv.dst(Native_capability(id_pt, srv.badge()));
int opcode = 0;
srv >> IPC_WAIT >> opcode;
/* set default return value */
srv.ret(ERR_INVALID_OBJECT);
/* atomically lookup and lock referenced object */
{
Lock::Guard lock_guard(ep->_curr_obj_lock);
ep->_curr_obj = ep->obj_by_id(srv.badge());
if (!ep->_curr_obj) {
PERR("could not look up server object, return from call");
srv << IPC_REPLY;
}
ep->_curr_obj->lock();
}
/* dispatch request */
try { srv.ret(ep->_curr_obj->dispatch(opcode, srv, srv)); }
catch (Blocking_canceled) { }
ep->_curr_obj->unlock();
ep->_curr_obj = 0;
ep->_rcv_buf.rcv_prepare_pt_sel_window((Nova::Utcb *)ep->utcb());
srv << IPC_REPLY;
}
void Rpc_entrypoint::entry()
{
/*
* Thread entry is not used for activations on NOVA
*/
}
void Rpc_entrypoint::_leave_server_object(Rpc_object_base *obj) { }
void Rpc_entrypoint::_block_until_cap_valid() { }
void Rpc_entrypoint::activate()
{
/*
* In contrast to a normal thread, a server activation is created at
* construction time. However, it executes no code because processing time
* is always provided by the caller of the server activation. To delay the
* processing of requests until the 'activate' function is called, we grab the
* '_curr_obj_lock' on construction and release it here.
*/
_curr_obj_lock.unlock();
}
Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
const char *name, bool start_on_construction)
:
Thread_base(name, stack_size),
_curr_obj(0),
_curr_obj_lock(Lock::LOCKED),
_cap_session(cap_session)
{
using namespace Nova;
/*
* Create EC here to ensure that 'tid()' returns a valid 'ec_sel'
* portal selector even before 'activate' is called.
*/
mword_t *sp = (mword_t *)&_context->stack[-4];
mword_t utcb = (mword_t) &_context->utcb;
/* create local EC */
enum { CPU_NO = 0, GLOBAL = false };
int res = create_ec(_tid.ec_sel, Cap_selector_allocator::pd_sel(),
CPU_NO, utcb, (mword_t)sp,
_tid.exc_pt_sel, GLOBAL);
if (res)
PDBG("create_ec returned %d", res);
_rcv_buf.rcv_prepare_pt_sel_window((Utcb *)utcb);
if (start_on_construction)
activate();
}

View File

@@ -0,0 +1,38 @@
/*
* \brief Thread-context specific part of the thread library
* \author Norman Feske
* \date 2010-01-19
*
* This part of the thread library is required by the IPC framework
* also if no threads are used.
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/thread.h>
using namespace Genode;
Native_utcb *main_thread_utcb();
Native_utcb *Thread_base::utcb()
{
/*
* If 'utcb' is called on the object returned by 'myself',
* the 'this' pointer may be NULL (if the calling thread is
* the main thread). Therefore we allow this special case
* here.
*/
if (this == 0) return main_thread_utcb();
return &_context->utcb;
}

View File

@@ -0,0 +1,141 @@
/*
* \brief NOVA-specific implementation of the Thread API
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2010-01-19
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/thread.h>
#include <base/cap_sel_alloc.h>
#include <base/printf.h>
#include <base/sleep.h>
#include <base/env.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
/**
* Entry point entered by new threads
*/
void Thread_base::_thread_start()
{
Genode::Thread_base::myself()->entry();
Genode::sleep_forever();
}
static void request_event_portal(Pager_capability pager_cap,
int exc_base, int event)
{
using namespace Nova;
Utcb *utcb = (Utcb *)Thread_base::myself()->utcb();
/* save original receive window */
Crd orig_crd = utcb->crd_rcv;
/* request event-handler portal */
utcb->msg[0] = event;
utcb->set_msg_word(1);
utcb->crd_rcv = Obj_crd(exc_base + event, 0);
int res = call(pager_cap.pt_sel());
if (res)
PERR("request of event (%d) capability selector failed", event);
/* restore original receive window */
utcb->crd_rcv = orig_crd;
}
/*****************
** Thread base **
*****************/
void Thread_base::_init_platform_thread()
{
using namespace Nova;
/*
* Allocate capability selectors for the thread's execution context,
* scheduling context, running semaphore and exception handler portals.
*/
_tid.ec_sel = cap_selector_allocator()->alloc();
_tid.sc_sel = cap_selector_allocator()->alloc();
_tid.rs_sel = cap_selector_allocator()->alloc();
_tid.pd_sel = cap_selector_allocator()->pd_sel();
_tid.exc_pt_sel = cap_selector_allocator()->alloc(NUM_INITIAL_PT_LOG2);
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
Thread_capability thread_cap = env()->cpu_session()->create_thread(buf);
/* create new pager object and assign it to the new thread */
Pager_capability pager_cap = env()->rm_session()->add_client(thread_cap);
env()->cpu_session()->set_pager(thread_cap, pager_cap);
/* register initial IP and SP at core */
mword_t thread_sp = (mword_t)&_context->stack[-4];
env()->cpu_session()->start(thread_cap, (addr_t)_thread_start, thread_sp);
request_event_portal(pager_cap, _tid.exc_pt_sel, PT_SEL_STARTUP);
request_event_portal(pager_cap, _tid.exc_pt_sel, PT_SEL_PAGE_FAULT);
/* create running semaphore required for locking */
int res = create_sm(_tid.rs_sel, _tid.pd_sel, 0);
if (res)
PERR("create_sm returned %d", res);
}
void Thread_base::_deinit_platform_thread()
{
Nova::revoke(Nova::Obj_crd(_tid.sc_sel, 0));
Nova::revoke(Nova::Obj_crd(_tid.ec_sel, 0));
Nova::revoke(Nova::Obj_crd(_tid.rs_sel, 0));
/* revoke utcb */
Nova::Rights rwx(true, true, true);
Nova::revoke(Nova::Mem_crd((unsigned)Thread_base::myself()->utcb() >> 12, 0, rwx));
}
void Thread_base::start()
{
using namespace Nova;
/* create execution context */
enum { THREAD_CPU_NO = 0, THREAD_GLOBAL = true };
int res = create_ec(_tid.ec_sel, _tid.pd_sel, THREAD_CPU_NO, (mword_t)&_context->utcb,
0, _tid.exc_pt_sel, THREAD_GLOBAL);
if (res)
PDBG("create_ec returned %d", res);
/*
* Create scheduling context
*
* With assigning a scheduling context to the execution context, the new
* thread will immediately start, enter the startup portal, and receives
* the configured initial IP and SP from core.
*/
res = create_sc(_tid.sc_sel, _tid.pd_sel, _tid.ec_sel, Qpd());
if (res)
PERR("create_sc returned %d", res);
}
void Thread_base::cancel_blocking()
{
Nova::sm_ctrl(_tid.rs_sel, Nova::SEMAPHORE_UP);
}

View File

@@ -0,0 +1,53 @@
/*
* \brief Core-local RM session
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
/* core includes */
#include <core_rm_session.h>
#include <platform.h>
#include <util.h>
#include <nova_util.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
Rm_session::Local_addr
Core_rm_session::attach(Dataspace_capability ds_cap, size_t size,
off_t offset, bool use_local_addr,
Rm_session::Local_addr local_addr)
{
Dataspace_component *ds = static_cast<Dataspace_component *>(_ds_ep->obj_by_cap(ds_cap));
if (!ds)
throw Invalid_dataspace();
if (size == 0)
size = ds->size();
if (use_local_addr) {
PERR("Parameter 'use_local_addr' not supported within core");
return 0;
}
if (offset) {
PERR("Parameter 'offset' not supported within core");
return 0;
}
/* allocate range in core's virtual address space */
return ds->core_local_addr();
}

View File

@@ -0,0 +1,62 @@
/*
* \brief Echo implementation
* \author Norman Feske
* \date 2010-01-19
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/cap_sel_alloc.h>
/* local includes */
#include <echo.h>
enum {
ECHO_UTCB_ADDR = 0x50000000,
ECHO_STACK_SIZE = 1024,
ECHO_CPU_NO = 0,
ECHO_GLOBAL = false,
ECHO_EXC_BASE = 0
};
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(){ Nova::reply(echo_stack_top()); }
Echo::Echo(Genode::addr_t utcb_addr)
:
_ec_sel(Genode::cap_selector_allocator()->alloc()),
_pt_sel(Genode::cap_selector_allocator()->alloc()),
_utcb((Nova::Utcb *)utcb_addr)
{
using namespace Nova;
/* create echo EC */
int pd_sel = Genode::Cap_selector_allocator::pd_sel();
int res = create_ec(_ec_sel, pd_sel, ECHO_CPU_NO, utcb_addr,
(mword_t)echo_stack_top(), ECHO_EXC_BASE, ECHO_GLOBAL);
/* make error condition visible by raising an unhandled page fault */
if (res) { ((void (*)())(res*0x10000))(); }
/* set up echo portal to ourself */
res = create_pt(_pt_sel, pd_sel, _ec_sel, Mtd(0), (mword_t)echo_reply);
if (res) { ((void (*)())(res*0x10001))(); }
}
Echo *echo() { static Echo inst(ECHO_UTCB_ADDR); return &inst; }

View File

@@ -0,0 +1,48 @@
/*
* \brief Capability allocation service
* \author Norman Feske
* \date 2006-06-26
*/
/*
* Copyright (C) 2006-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__CAP_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__CAP_SESSION_COMPONENT_H_
#include <cap_session/cap_session.h>
#include <base/rpc_server.h>
#include <base/lock.h>
namespace Genode {
class Cap_session_component : public Rpc_object<Cap_session>
{
private:
static long _unique_id_cnt;
static Lock &_lock()
{
static Lock static_lock;
return static_lock;
}
public:
Native_capability alloc(Native_capability ep)
{
Lock::Guard lock_guard(_lock());
return Native_capability(ep.pt_sel(), ++_unique_id_cnt);
}
void free(Native_capability cap) { }
};
}
#endif /* _CORE__INCLUDE__CAP_SESSION_COMPONENT_H_ */

View File

@@ -0,0 +1,52 @@
/*
* \brief Core-local region manager session
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__CORE_RM_SESSION_H_
#define _CORE__INCLUDE__CORE_RM_SESSION_H_
/* Genode includes */
#include <rm_session/rm_session.h>
/* core includes */
#include <dataspace_component.h>
namespace Genode {
class Core_rm_session : public Rm_session
{
private:
Rpc_entrypoint *_ds_ep;
public:
Core_rm_session(Rpc_entrypoint *ds_ep) : _ds_ep(ds_ep) { }
Local_addr attach(Dataspace_capability ds_cap, size_t size=0,
off_t offset=0, bool use_local_addr = false,
Local_addr local_addr = 0);
void detach(Local_addr) { }
Pager_capability add_client(Thread_capability thread) {
return Pager_capability(); }
void fault_handler(Signal_context_capability handler) { }
State state() { return State(); }
Dataspace_capability dataspace() { return Dataspace_capability(); }
};
}
#endif /* _CORE__INCLUDE__CORE_RM_SESSION_H_ */

View File

@@ -0,0 +1,54 @@
/*
* \brief Echo interface
* \author Norman Feske
* \date 2010-01-19
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _ECHO_H_
#define _ECHO_H_
/* NOVA includes */
#include <nova/syscalls.h>
class Echo
{
private:
int _ec_sel; /* execution context */
int _pt_sel; /* portal */
Nova::Utcb *_utcb;
public:
/**
* 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 /* _ECHO_H_ */

View File

@@ -0,0 +1,74 @@
/*
* \brief IRQ session interface for NOVA
* \author Norman Feske
* \date 2010-01-30
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#include <base/lock.h>
#include <base/rpc_server.h>
#include <util/list.h>
#include <irq_session/capability.h>
namespace Genode {
class Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
unsigned _irq_number;
Range_allocator *_irq_alloc;
/*
* Each IRQ session uses a dedicated server activation
*/
enum { STACK_SIZE = 2048 };
Rpc_entrypoint _ep;
Irq_session_capability _irq_cap;
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/**
* Return capability to this session
*
* If an initialization error occurs, returned capability is invalid.
*/
Irq_session_capability cap() const { return _irq_cap; }
/***************************
** Irq session interface **
***************************/
void wait_for_irq();
};
}
#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@@ -0,0 +1,45 @@
/*
* \brief Core-local mapping
* \author Norman Feske
* \date 2010-02-15
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__MAP_LOCAL_H_
#define _CORE__INCLUDE__MAP_LOCAL_H_
/* Genode includes */
#include <base/printf.h>
#include <base/thread.h>
/* core includes */
#include <nova_util.h>
namespace Genode {
/**
* Map pages locally within core
*
* On NOVA, address-space mappings from core to core originate always from
* the physical address space.
*
* \param from_phys physical source address
* \param to_addr core-local destination address
* \param num_pages number of pages to map
*
* \return true on success
*/
inline bool map_local(addr_t from_phys, addr_t to_virt, size_t num_pages)
{
return ::map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
from_phys, to_virt, num_pages, true);
}
}
#endif /* _CORE__INCLUDE__MAP_LOCAL_H_ */

View File

@@ -0,0 +1,141 @@
/*
* \brief NOVA-specific convenience functions
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2010-01-19
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _NOVA_UTIL_H_
#define _NOVA_UTIL_H_
/* Genode includes */
#include <base/printf.h>
/* NOVA includes */
#include <nova/syscalls.h>
/* local includes */
#include <echo.h>
#include <util.h>
enum { verbose_local_map = false };
/**
* Establish a one-to-one mapping
*
* \param utcb UTCB of the calling EC
* \param src_crd capability range descriptor of source
* resource to map locally
* \param dst_crd capability range descriptor of mapping
* target
*
* This functions sends a mapping from the calling EC to the echo EC.
* In order to successfully transfer the mapping, we have to open a
* corresponding receive window at the echo EC. We do this by poking
* a receive-capability-range descriptor directly onto the echo UTCB.
*/
static int map_local(Nova::Utcb *utcb, Nova::Crd src_crd, Nova::Crd dst_crd,
bool kern_pd = false)
{
/* open receive window at the echo EC */
echo()->utcb()->crd_rcv = dst_crd;
/* reset message transfer descriptor */
utcb->set_msg_word(0);
/* append capability-range as message-transfer item */
utcb->append_item(src_crd, 0, kern_pd);
/* establish the mapping via a portal traversal */
if (echo()->pt_sel() == 0)
PWRN("call to pt 0");
return Nova::call(echo()->pt_sel());
}
static inline int unmap_local(Nova::Crd crd, bool self = true) {
return Nova::revoke(crd, self); }
inline int map_local_one_to_one(Nova::Utcb *utcb, Nova::Crd crd) {
return map_local(utcb, crd, crd, true); }
/**
* Remap pages in the local address space
*
* \param utcb UTCB of the main thread
* \param from_start physical source address
* \param to_start local virtual destination address
* \param num_pages number of pages to map
*/
inline int map_local(Nova::Utcb *utcb,
Genode::addr_t from_start, Genode::addr_t to_start,
Genode::size_t num_pages,
bool kern_pd = false)
{
if (verbose_local_map)
Genode::printf("::map_local: from %lx to %lx, %zd pages from kernel %u\n",
from_start, to_start, num_pages, kern_pd);
using namespace Nova;
using namespace Genode;
Rights const rwx(true, true, true);
size_t const size = num_pages << get_page_size_log2();
addr_t const from_end = from_start + size;
addr_t const to_end = to_start + size;
for (addr_t offset = 0; offset < size; ) {
addr_t const from_curr = from_start + offset;
addr_t const to_curr = to_start + offset;
/*
* The common alignment corresponds to the number of least significant
* zero bits in both addresses.
*/
addr_t const common_bits = from_curr | to_curr;
/*
* Find highest clear bit in 'diff', starting from the least
* significant candidate. We can skip all bits lower then
* 'get_page_size_log2()' because they are not relevant as flexpage
* size (and are always zero).
*/
size_t order = get_page_size_log2();
for (; order < 32 && !(common_bits & (1 << order)); order++);
/*
* Look if flexpage fits into both 'from' and 'to' address range
*/
if (from_curr + (1 << order) > from_end)
order = log2(from_end - from_curr);
if (to_curr + (1 << order) > to_end)
order = log2(to_end - to_curr);
int const res = map_local(utcb,
Mem_crd((from_curr >> 12), order - get_page_size_log2(), rwx),
Mem_crd((to_curr >> 12), order - get_page_size_log2(), rwx),
kern_pd);
if (res) return res;
/* advance offset by current flexpage size */
offset += (1 << order);
}
return 0;
}
#endif /* _NOVA_UTIL_H_ */

View File

@@ -0,0 +1,81 @@
/*
* \brief Platform interface
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__PLATFORM_H_
#define _CORE__INCLUDE__PLATFORM_H_
/* core includes */
#include <platform_generic.h>
#include <core_mem_alloc.h>
#include <base/printf.h>
namespace Genode {
class Platform : public Platform_generic
{
typedef Core_mem_allocator::Phys_allocator Phys_allocator;
Core_mem_allocator _core_mem_alloc; /* core-accessible memory */
Phys_allocator _io_mem_alloc; /* MMIO allocator */
Phys_allocator _io_port_alloc; /* I/O port allocator */
Phys_allocator _irq_alloc; /* IRQ allocator */
Rom_fs _rom_fs; /* ROM file system */
int _gsi_base_sel; /* cap selector of 1st IRQ */
/**
* Virtual address range usable by non-core processes
*/
addr_t _vm_base;
size_t _vm_size;
void _preserve_page(addr_t phys_page);
public:
/**
* Constructor
*/
Platform();
/********************************
** Generic platform interface **
********************************/
Range_allocator *ram_alloc() { return _core_mem_alloc.phys_alloc(); }
Range_allocator *io_mem_alloc() { return &_io_mem_alloc; }
Range_allocator *io_port_alloc() { return &_io_port_alloc; }
Range_allocator *irq_alloc() { return &_irq_alloc; }
Range_allocator *region_alloc() { return _core_mem_alloc.virt_alloc(); }
Allocator *core_mem_alloc() { return &_core_mem_alloc; }
addr_t vm_start() const { return _vm_base; }
size_t vm_size() const { return _vm_size; }
Rom_fs *rom_fs() { return &_rom_fs; }
void wait_for_exit();
bool supports_unmap() { return true; }
/*******************
** NOVA specific **
*******************/
/**
* Return capability selector of first global system interrupt
*/
int gsi_base_sel() const { return _gsi_base_sel; }
};
}
#endif /* _CORE__INCLUDE__PLATFORM_H_ */

View File

@@ -0,0 +1,79 @@
/*
* \brief Protection-domain facility
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__PLATFORM_PD_H_
#define _CORE__INCLUDE__PLATFORM_PD_H_
#include <platform_thread.h>
namespace Genode {
class Platform_thread;
class Platform_pd
{
private:
int _thread_cnt;
Native_capability _parent;
int _id;
int _pd_sel;
public:
/**
* Constructors
*/
Platform_pd(signed pd_id = -1, bool create = true);
/**
* Destructor
*/
~Platform_pd();
/**
* Bind thread to protection domain
*
* \return 0 on success or
* -1 if thread ID allocation failed.
*/
int bind_thread(Platform_thread *thread);
/**
* Unbind thread from protection domain
*
* Free the thread's slot and update thread object.
*/
void unbind_thread(Platform_thread *thread);
/**
* Assign parent interface to protection domain
*/
int assign_parent(Native_capability parent);
/**
* Return portal capability selector for parent interface
*/
int parent_pt_sel() { return _parent.pt_sel(); }
/**
* Assign PD selector to PD
*/
void assign_pd(int pd_sel) { _pd_sel = pd_sel; }
int pd_sel() { return _pd_sel; }
int id() { return _id; }
};
}
#endif /* _CORE__INCLUDE__PLATFORM_PD_H_ */

View File

@@ -0,0 +1,125 @@
/*
* \brief Thread facility
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__PLATFORM_THREAD_H_
#define _CORE__INCLUDE__PLATFORM_THREAD_H_
/* Genode includes */
#include <thread/capability.h>
#include <base/thread_state.h>
#include <base/native_types.h>
#include <base/thread.h>
#include <base/pager.h>
namespace Genode {
class Platform_pd;
class Platform_thread
{
private:
Platform_pd *_pd;
Pager_object *_pager;
bool _is_main_thread;
int _id;
public:
enum { THREAD_INVALID = -1 }; /* invalid thread number */
/**
* Constructor
*/
Platform_thread(const char *name = 0, unsigned priority = 0,
int thread_id = THREAD_INVALID);
/**
* Destructor
*/
~Platform_thread();
/**
* Start thread
*
* \param ip instruction pointer to start at
* \param sp stack pointer to use
* \param cpu_no target cpu
*
* \retval 0 successful
* \retval -1 thread could not be started
*/
int start(void *ip, void *sp, unsigned int cpu_no = 0);
/**
* Pause this thread
*/
void pause();
/**
* Resume this thread
*/
void resume();
/**
* Cancel currently blocking operation
*/
void cancel_blocking();
/**
* Request thread state
*
* \param state_dst destination state buffer
*
* \retval 0 successful
* \retval -1 thread state not accessible
*/
int state(Genode::Thread_state *state_dst);
/************************
** Accessor functions **
************************/
/**
* Set pager
*/
void pager(Pager_object *pager) { _pager = pager; }
Pager_object *pager() { return _pager; }
/**
* Return identification of thread when faulting
*/
unsigned long pager_object_badge() const;
/**
* Set the executing CPU for this thread.
*/
void set_cpu(unsigned int cpu_no);
/**
* Get thread name
*/
const char *name() const { return "noname"; }
/**
* Associate thread with protection domain
*/
void bind_to_pd(Platform_pd *pd, bool is_main_thread)
{
_pd = pd, _is_main_thread = is_main_thread;
}
};
}
#endif /* _CORE__INCLUDE__PLATFORM_THREAD_H_ */

View File

@@ -0,0 +1,74 @@
/*
* \brief Core-internal utilities
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__UTIL_H_
#define _CORE__INCLUDE__UTIL_H_
/* Genode includes */
#include <rm_session/rm_session.h>
#include <base/printf.h>
namespace Genode {
inline size_t get_page_size_log2() { return 12; }
inline size_t get_page_size() { return 1 << get_page_size_log2(); }
inline addr_t get_page_mask() { return ~(get_page_size() - 1); }
inline size_t get_super_page_size_log2() { return 22; }
inline size_t get_super_page_size() { return 1 << get_super_page_size_log2(); }
inline addr_t trunc_page(addr_t addr) { return addr & get_page_mask(); }
inline addr_t round_page(addr_t addr) { return trunc_page(addr + get_page_size() - 1); }
inline addr_t map_src_addr(addr_t core_local, addr_t phys) { return core_local; }
inline size_t constrain_map_size_log2(size_t size_log2) { return size_log2; }
inline void print_page_fault(const char *msg, addr_t pf_addr, addr_t pf_ip,
Rm_session::Fault_type pf_type,
unsigned long faulter_badge)
{
printf("%s (%s pf_addr=%p pf_ip=%p from %02lx)\n", msg,
pf_type == Rm_session::WRITE_FAULT ? "WRITE" : "READ",
(void *)pf_addr, (void *)pf_ip,
faulter_badge);
}
inline void backtrace()
{
using namespace Genode;
printf("\nbacktrace\n");
printf(" %p\n", __builtin_return_address(0));
printf(" %p\n", __builtin_return_address(1));
printf(" %p\n", __builtin_return_address(2));
printf(" %p\n", __builtin_return_address(3));
printf(" %p\n", __builtin_return_address(4));
}
inline void hexdump(void *addr)
{
unsigned char *s = (unsigned char *)addr;
printf("\nhexdump at 0x%p:\n", addr);
for (unsigned j = 0; j < 4; j++) {
printf(" ");
for (unsigned i = 0; i < 16; i++)
printf("0x%02x ", s[j*16 + i]);
printf("\n");
}
}
}
#endif /* _CORE__INCLUDE__UTIL_H_ */

View File

@@ -0,0 +1,59 @@
/*
* \brief Implementation of the IO_MEM session interface
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2009-03-29
*
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <io_mem_session_component.h>
#include <platform.h>
#include <nova_util.h>
using namespace Genode;
void Io_mem_session_component::_unmap_local(addr_t base, size_t size)
{
size_t page_rounded_size = (size + get_page_size() - 1) & get_page_mask();
Nova::Rights rwx(true, true, true);
int count = page_rounded_size >> 12;
for (int i = 0; i < count; i++)
unmap_local(Nova::Mem_crd((base >> 12) + i, 0, rwx));
}
addr_t Io_mem_session_component::_map_local(addr_t base, size_t size)
{
size_t page_rounded_size = (size + get_page_size() - 1) & get_page_mask();
/* align large I/O dataspaces on a super-page boundary within core */
size_t alignment = (size >= get_super_page_size()) ? get_super_page_size_log2()
: get_page_size_log2();
/* allocate range in core's virtual address space */
void *virt_addr;
if (!platform()->region_alloc()->alloc_aligned(page_rounded_size,
&virt_addr, alignment)) {
PERR("Could not allocate virtual address range in core of size %zd\n",
page_rounded_size);
return 0;
}
/* map the dataspace's physical pages to local addresses */
map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
base, (addr_t)virt_addr,
page_rounded_size >> get_page_size_log2(), true);
return (addr_t)virt_addr;
}

View File

@@ -0,0 +1,74 @@
/*
* \brief Implementation of IRQ session component
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
/* core includes */
#include <irq_root.h>
#include <platform.h>
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova_util.h>
using namespace Genode;
void Irq_session_component::wait_for_irq()
{
Nova::sm_ctrl(_irq_number, Nova::SEMAPHORE_DOWN);
}
Irq_session_component::Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args)
:
_irq_alloc(irq_alloc),
_ep(cap_session, STACK_SIZE, "irq")
{
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (irq_number == -1 || !irq_alloc ||
irq_alloc->alloc_addr(1, irq_number) != Range_allocator::ALLOC_OK) {
PERR("Unavailable IRQ %lx requested", irq_number);
throw Root::Invalid_args();
}
/* alloc slector where IRQ will be mapped */
_irq_number = cap_selector_allocator()->alloc();
/* since we run in APIC mode translate IRQ 0 (PIT) to 2 */
if (!irq_number)
irq_number = 2;
/* map IRQ number to selector */
int ret = map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
Nova::Obj_crd(platform_specific()->gsi_base_sel() + irq_number, 0),
Nova::Obj_crd(_irq_number, 0),
true);
if (ret) {
PERR("Could not map IRQ %d", _irq_number);
throw Root::Unavailable();
}
/* assign IRQ to CPU */
enum { CPU = 0 };
Nova::assign_gsi(_irq_number, 0, CPU);
/* initialize capability */
_irq_cap = _ep.manage(this);
}
Irq_session_component::~Irq_session_component() { }

View File

@@ -0,0 +1,352 @@
/*
* \brief Platform interface implementation
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <base/sleep.h>
#include <base/thread.h>
/* core includes */
#include <core_parent.h>
#include <platform.h>
#include <nova_util.h>
#include <util.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
using namespace Nova;
enum { verbose_boot_info = true };
/**
* Initial value of esp register, saved by the crt0 startup code
*
* This value contains the address of the hypervisor information page.
*/
extern long __initial_sp;
/**
* First available capability selector for custom use
*/
extern int __first_free_cap_selector;
/**
* Pointer to the UTCB of the main thread
*/
extern Utcb *__main_thread_utcb;
/**
* Virtual address range consumed by core's program image
*/
extern unsigned _prog_img_beg, _prog_img_end;
/**
* Capability selector of root PD
*/
extern int __local_pd_sel;
/**
* Preserve physical page for the exclusive (read-only) use by core
*/
void Platform::_preserve_page(addr_t phys_page)
{
/* locally map page one-to-one */
map_local_one_to_one(__main_thread_utcb,
Mem_crd(phys_page, 0,
Rights(true, true, false)));
/* remove page with command line from physical-memory allocator */
addr_t addr = phys_page*get_page_size();
_core_mem_alloc.phys_alloc()->remove_range(addr, get_page_size());
_core_mem_alloc.virt_alloc()->remove_range(addr, get_page_size());
}
/*****************************
** Core page-fault handler **
*****************************/
enum { CORE_PAGER_UTCB_ADDR = 0x50002000 };
/**
* IDC handler for the page-fault portal
*/
static void page_fault_handler()
{
Utcb *utcb = (Utcb *)CORE_PAGER_UTCB_ADDR;
addr_t pf_addr = utcb->qual[1];
addr_t pf_eip = utcb->eip;
addr_t pf_esp = utcb->esp;
printf("\nPAGE-FAULT IN CORE: ADDR %lx IP %lx SP %lx stack trace follows...\n",
pf_addr, pf_eip, pf_esp);
/* dump stack trace */
struct Core_img
{
addr_t _beg;
addr_t _end;
addr_t *_ip;
Core_img(addr_t sp)
{
extern addr_t _dtors_end;
_beg = (addr_t)&_prog_img_beg;
_end = (addr_t)&_dtors_end;
_ip = (addr_t *)sp;
for (;!ip_valid(); _ip++) {}
}
addr_t *ip() { return _ip; }
void next_ip() { _ip = ((addr_t *)*(_ip - 1)) + 1;}
bool ip_valid() { return *_ip >= _beg && *_ip < _end; }
};
int count = 1;
printf(" #%d %08lx %08lx\n", count++, pf_esp, pf_eip);
Core_img dump(pf_esp);
while (dump.ip_valid()) {
printf(" #%d %p %08lx\n", count++, dump.ip(), *dump.ip());
dump.next_ip();
}
sleep_forever();
}
static void init_core_page_fault_handler()
{
/* create echo EC */
enum {
STACK_SIZE = 4*1024,
CPU_NO = 0,
GLOBAL = false,
EXC_BASE = 0
};
static char stack[STACK_SIZE];
mword_t sp = (long)&stack[STACK_SIZE - sizeof(long)];
int ec_sel = cap_selector_allocator()->alloc();
int ret = create_ec(ec_sel, __local_pd_sel, CPU_NO, CORE_PAGER_UTCB_ADDR,
(mword_t)sp, EXC_BASE, GLOBAL);
if (ret)
PDBG("create_ec returned %d", ret);
/* set up page-fault portal */
create_pt(PT_SEL_PAGE_FAULT, __local_pd_sel, ec_sel,
Mtd(Mtd::QUAL | Mtd::ESP | Mtd::EIP),
(mword_t)page_fault_handler);
}
/**************
** Platform **
**************/
Platform::Platform() :
_io_mem_alloc(core_mem_alloc()), _io_port_alloc(core_mem_alloc()),
_irq_alloc(core_mem_alloc()),
_vm_base(0), _vm_size(0)
{
Hip *hip = (Hip *)__initial_sp;
/* register UTCB of main thread */
__main_thread_utcb = (Utcb *)(__initial_sp - get_page_size());
/* register start of usable capability range */
__first_free_cap_selector = hip->sel_exc + hip->sel_gsi + 3;
/* set core pd selector */
__local_pd_sel = hip->sel_exc;
/* 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));
/*
* Now that we can access the I/O ports for comport 0, printf works...
*/
/* set up page fault handler for core - for debugging */
init_core_page_fault_handler();
if (verbose_boot_info) {
printf("Hypervisor %s VMX\n", hip->has_feature_vmx() ? "features" : "does not feature");
printf("Hypervisor %s SVM\n", hip->has_feature_svm() ? "features" : "does not feature");
}
/* initialize core allocators */
size_t num_mem_desc = (hip->hip_length - hip->mem_desc_offset)
/ hip->mem_desc_size;
if (verbose_boot_info)
printf("Hypervisor info page contains %zd memory descriptors:\n", num_mem_desc);
addr_t mem_desc_base = ((addr_t)hip + hip->mem_desc_offset);
/* define core's virtual address space */
addr_t virt_beg = get_page_size();
addr_t virt_end = Thread_base::CONTEXT_AREA_VIRTUAL_BASE;
_core_mem_alloc.virt_alloc()->add_range(virt_beg,
virt_end - virt_beg);
/* exclude core image from core's virtual address allocator */
addr_t core_virt_beg = trunc_page((addr_t)&_prog_img_beg),
core_virt_end = round_page((addr_t)&_prog_img_end);
size_t core_size = core_virt_end - core_virt_beg;
_core_mem_alloc.virt_alloc()->remove_range(core_virt_beg, core_size);
/* preserve context area in core's virtual address space */
_core_mem_alloc.virt_alloc()->remove_range(Thread_base::CONTEXT_AREA_VIRTUAL_BASE,
Thread_base::CONTEXT_AREA_VIRTUAL_SIZE);
/* initialize core's physical-memory and I/O memory allocator */
_io_mem_alloc.add_range(0, ~0xfff);
Hip::Mem_desc *mem_desc = (Hip::Mem_desc *)mem_desc_base;
for (unsigned i = 0; i < num_mem_desc; i++, mem_desc++) {
if (mem_desc->type != Hip::Mem_desc::AVAILABLE_MEMORY) continue;
addr_t base = round_page(mem_desc->addr);
size_t size = trunc_page(mem_desc->addr + mem_desc->size - 1) - base;
if (verbose_boot_info)
printf("detected physical memory: 0x%lx - 0x%zx\n", base, size);
_io_mem_alloc.remove_range(base, size);
_core_mem_alloc.phys_alloc()->add_range(base, size);
}
/* exclude all non-available memory from physical allocator */
mem_desc = (Hip::Mem_desc *)mem_desc_base;
for (unsigned i = 0; i < num_mem_desc; i++, mem_desc++) {
if (mem_desc->type == Hip::Mem_desc::AVAILABLE_MEMORY) continue;
addr_t base = trunc_page(mem_desc->addr);
size_t size = round_page(mem_desc->addr + mem_desc->size - 1) - base;
_io_mem_alloc.add_range(base, size);
_core_mem_alloc.phys_alloc()->remove_range(base, size);
}
/* needed as I/O memory by the VESA driver */
_io_mem_alloc.add_range(0, 0x1000);
_core_mem_alloc.phys_alloc()->remove_range(0, 0x1000);
/* exclude pages holding multi-boot command lines from core allocators */
mem_desc = (Hip::Mem_desc *)mem_desc_base;
addr_t prev_cmd_line_page = 0, curr_cmd_line_page = 0;
for (unsigned i = 0; i < num_mem_desc; i++, mem_desc++) {
if (mem_desc->type != Hip::Mem_desc::MULTIBOOT_MODULE) continue;
curr_cmd_line_page = mem_desc->aux >> get_page_size_log2();
if (curr_cmd_line_page == prev_cmd_line_page) continue;
_preserve_page(curr_cmd_line_page);
prev_cmd_line_page = curr_cmd_line_page;
}
/* preserve page following the last multi-boot command line */
_preserve_page(curr_cmd_line_page + 1);
/*
* From now on, it is save to use the core allocators...
*/
/* build ROM file system */
mem_desc = (Hip::Mem_desc *)mem_desc_base;
for (unsigned i = 0; i < num_mem_desc; i++, mem_desc++) {
if (mem_desc->type != Hip::Mem_desc::MULTIBOOT_MODULE) continue;
const char *name = commandline_to_basename((char *)mem_desc->aux);
printf("detected multi-boot module: %s 0x%lx-0x%lx\n", name,
(long)mem_desc->addr, (long)(mem_desc->addr + mem_desc->size - 1));
void *core_local_addr = (void*)0x234;
if (!region_alloc()->alloc(round_page(mem_desc->size), &core_local_addr))
PERR("could not locally map multi-boot module");
int res = map_local(__main_thread_utcb, mem_desc->addr, (addr_t)core_local_addr,
round_page(mem_desc->size) >> get_page_size_log2(), true);
if (res)
PERR("map_local failed res=%d", res);
Rom_module *rom_module = new (core_mem_alloc())
Rom_module((addr_t)core_local_addr, mem_desc->size, name);
_rom_fs.insert(rom_module);
/* zero remainder of last ROM page */
size_t count = 0x1000 - rom_module->size() % 0x1000;
if (count != 0x1000)
memset(reinterpret_cast<void *>(rom_module->addr() + rom_module->size()), 0, count);
}
/* export hypervisor info page as ROM module */
_rom_fs.insert(new (core_mem_alloc())
Rom_module((addr_t)hip, get_page_size(), "hypervisor_info_page"));
/* configure non-core virtual address spaces as 2G-2G split */
_vm_base = get_page_size();
_vm_size = 2*1024*1024*1024UL - _vm_base;
/* I/O port allocator (only meaningful for x86) */
_io_port_alloc.add_range(0, 0x10000);
/* IRQ allocator */
_irq_alloc.add_range(0, hip->sel_gsi - 1);
_gsi_base_sel = hip->sel_exc;
if (verbose_boot_info) {
printf(":virt_alloc: "); _core_mem_alloc.virt_alloc()->raw()->dump_addr_tree();
printf(":phys_alloc: "); _core_mem_alloc.phys_alloc()->raw()->dump_addr_tree();
printf(":io_mem_alloc: "); _io_mem_alloc.raw()->dump_addr_tree();
}
}
/****************************************
** Support for core memory management **
****************************************/
bool Core_mem_allocator::Mapped_mem_allocator::_map_local(addr_t virt_addr,
addr_t phys_addr,
unsigned size_log2)
{
map_local((Utcb *)Thread_base::myself()->utcb(), phys_addr,
virt_addr, 1 << (size_log2 - get_page_size_log2()), true);
return true;
}
/********************************
** Generic platform interface **
********************************/
void Platform::wait_for_exit() { sleep_forever(); }
void Core_parent::exit(int exit_value) { }

View File

@@ -0,0 +1,57 @@
/*
* \brief Protection-domain facility
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
/* core includes */
#include <platform_pd.h>
using namespace Genode;
/***************************
** Public object members **
***************************/
int Platform_pd::bind_thread(Platform_thread *thread)
{
thread->bind_to_pd(this, _thread_cnt == 0);
_thread_cnt++;
return 0;
}
void Platform_pd::unbind_thread(Platform_thread *thread)
{
PDBG("not implemented");
}
int Platform_pd::assign_parent(Native_capability parent)
{
if (_parent.valid()) return -1;
_parent = parent;
return 0;
}
static int id_cnt;
Platform_pd::Platform_pd(signed pd_id, bool create)
: _thread_cnt(0), _id(++id_cnt), _pd_sel(0) { }
Platform_pd::~Platform_pd()
{ }

View File

@@ -0,0 +1,143 @@
/*
* \brief Thread facility
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <base/cap_sel_alloc.h>
#include <base/ipc_pager.h>
/* core includes */
#include <platform_thread.h>
#include <platform_pd.h>
#include <util.h>
#include <nova_util.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
/*********************
** Platform thread **
*********************/
void Platform_thread::set_cpu(unsigned int cpu_no)
{
PERR("not yet implemented");
}
int Platform_thread::start(void *ip, void *sp, unsigned int cpu_no)
{
using namespace Nova;
if (!_pager) {
PERR("pager undefined");
return -1;
}
enum { PD_EC_CPU_NO = 0, PD_UTCB = 0x6000000 };
_pager->initial_eip((addr_t)ip);
if (!_is_main_thread || !_pd) {
_pager->initial_esp((addr_t)sp);
return 0;
}
/*
* For the first thread of a new PD, use the initial stack pointer for
* reporting the thread's UTCB address.
*/
_pager->initial_esp(PD_UTCB + get_page_size());
/* locally map parent portal to initial portal window */
int res = map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
Obj_crd(_pd->parent_pt_sel(), 0),
Obj_crd(_pager->exc_pt_sel() + PT_SEL_PARENT, 0));
if (res)
PERR("could not locally remap parent portal");
Obj_crd initial_pts(_pager->exc_pt_sel(), Nova::NUM_INITIAL_PT_LOG2);
int pd_sel = cap_selector_allocator()->pd_sel();
int pd0_sel = _pager->exc_pt_sel() + Nova::PD_SEL;
_pd->assign_pd(pd0_sel);
res = create_pd(pd0_sel, pd_sel, initial_pts);
if (res)
PERR("create_pd returned %d", res);
int ec_sel = cap_selector_allocator()->alloc();
int sc_sel = cap_selector_allocator()->alloc();
enum { THREAD_GLOBAL = true };
res = create_ec(ec_sel, pd0_sel, PD_EC_CPU_NO, PD_UTCB, 0, 0,
THREAD_GLOBAL);
if (res)
PDBG("create_ec returned %d", res);
res = create_sc(sc_sel, pd0_sel, ec_sel, Qpd());
if (res)
PERR("create_sc returned %d", res);
return 0;
}
void Platform_thread::pause()
{
PDBG("not implemented");
}
void Platform_thread::resume()
{
PDBG("not implemented");
}
int Platform_thread::state(Thread_state *state_dst)
{
PWRN("not implemented");
return -1;
}
void Platform_thread::cancel_blocking() { PWRN("not implemented"); }
unsigned long Platform_thread::pager_object_badge()
const
{
return _pd ? ((_pd->id() << 16) || _id) : ~0;
}
static int id_cnt;
Platform_thread::Platform_thread(const char *name, unsigned, int thread_id)
: _pd(0), _id(++id_cnt) { }
Platform_thread::~Platform_thread()
{
using namespace Nova;
if (_is_main_thread)
revoke(Obj_crd(_pd->pd_sel(), 0));
}

View File

@@ -0,0 +1,77 @@
/*
* \brief Export RAM dataspace as shared memory object
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <base/thread.h>
/* core includes */
#include <ram_session_component.h>
#include <platform.h>
#include <util.h>
#include <nova_util.h>
/* NOVA includes */
#include <nova/syscalls.h>
enum { verbose_ram_ds = false };
using namespace Genode;
void Ram_session_component::_export_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_clear_ds(Dataspace_component *ds)
{
/*
* Map dataspace core-locally and clear its content
*/
size_t page_rounded_size = (ds->size() + get_page_size() - 1) & get_page_mask();
/*
* Allocate range in core's virtual address space
*
* Start with trying to use natural alignment. If this does not work,
* successively weaken the alignment constraint until we hit the page size.
*/
void *virt_addr;
bool virt_alloc_succeeded = false;
size_t align_log2 = log2(ds->size());
for (; align_log2 >= get_page_size_log2(); align_log2--) {
if (platform()->region_alloc()->alloc_aligned(page_rounded_size,
&virt_addr, align_log2)) {
virt_alloc_succeeded = true;
break;
}
}
if (!virt_alloc_succeeded) {
PERR("Could not allocate virtual address range in core of size %zd\n",
page_rounded_size);
return;
}
if (verbose_ram_ds)
printf("-- ram ds size=%x phys %lx has core-local addr %p\n",
page_rounded_size, ds->phys_addr(), virt_addr);
/* map the dataspace's physical pages to local addresses */
map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
ds->phys_addr(), (addr_t)virt_addr,
page_rounded_size >> get_page_size_log2(), true);
memset(virt_addr, 0, page_rounded_size);
ds->assign_core_local_addr(virt_addr);
}

View File

@@ -0,0 +1,55 @@
/*
* \brief RM-session implementation
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <base/ipc_pager.h>
/* core includes */
#include <rm_session_component.h>
#include <nova_util.h>
using namespace Genode;
static const bool verbose = false;
void Rm_client::unmap(addr_t core_local_base, addr_t virt_base, size_t size)
{
addr_t const core_local_end = core_local_base + (size - 1);
off_t const core_to_virt = virt_base - core_local_base;
Nova::Rights rwx(true, true, true);
while (true) {
Nova::Mem_crd crd(core_local_base >> 12, 32, rwx);
Nova::lookup(&crd);
if (crd.is_null()) {
PERR("Invalid unmap at local: %08lx virt: %08lx",
core_local_base, core_local_base + core_to_virt);
return;
}
if (verbose)
PINF("Lookup core_addr: %08lx base: %x order: %x is null %d", core_local_base, crd.base(), crd.order(), crd.is_null());
unmap_local(crd, false);
core_local_base = (crd.base() << 12) /* base address of mapping */
+ (0x1000 << crd.order()); /* size of mapping */
if (core_local_base > core_local_end)
return;
}
}

View File

@@ -0,0 +1,73 @@
/*
* \brief Implementation of the SIGNAL interface
* \author Norman Feske
* \date 2009-08-11
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/ipc.h>
#include <base/printf.h>
#include <base/cap_sel_alloc.h>
/* core includes */
#include <signal_session_component.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
/*****************************
** Signal-source component **
*****************************/
void Signal_source_component::submit(Signal_context_component *context,
Ipc_ostream *ostream,
int cnt)
{
/* enqueue signal to context */
context->increment_signal_cnt(cnt);
if (!context->is_enqueued()) {
_signal_queue.enqueue(context);
/* wake up client */
Nova::sm_ctrl(_blocking_semaphore.pt_sel(), Nova::SEMAPHORE_UP);
}
}
Signal_source::Signal Signal_source_component::wait_for_signal()
{
if (_signal_queue.empty()) {
PWRN("unexpected call of wait_for_signal");
return Signal(0, 0);
}
/* dequeue and return pending signal */
Signal_context_component *context = _signal_queue.dequeue();
Signal result(context->imprint(), context->cnt());
context->reset_signal_cnt();
return result;
}
Signal_source_component::Signal_source_component(Rpc_entrypoint *ep)
: _entrypoint(ep)
{
/* initialized blocking semaphore */
int sem_sel = cap_selector_allocator()->alloc();
int ret = Nova::create_sm(sem_sel, cap_selector_allocator()->pd_sel(), 0);
if (ret)
PERR("create_sm returned %d", ret);
_blocking_semaphore = Native_capability(sem_sel, 0);
}

View File

@@ -0,0 +1,56 @@
TARGET = core
LIBS = cxx ipc heap core_printf process pager lock \
raw_signal raw_server
GEN_CORE_DIR = $(BASE_DIR)/src/core
SRC_CC = \
main.cc \
ram_session_component.cc \
ram_session_support.cc \
rom_session_component.cc \
cpu_session_component.cc \
pd_session_component.cc \
io_mem_session_component.cc \
io_mem_session_support.cc \
thread.cc \
thread_start.cc \
platform_thread.cc \
platform_pd.cc \
platform.cc \
core_mem_alloc.cc \
dataspace_component.cc \
rm_session_component.cc \
rm_session_support.cc \
io_port_session_component.cc \
irq_session_component.cc \
signal_session_component.cc \
signal_source_component.cc \
core_rm_session.cc \
cap_sel_alloc.cc \
main_thread.cc \
context_area.cc \
echo.cc \
dump_alloc.cc
INC_DIR = $(REP_DIR)/src/core/include \
$(GEN_CORE_DIR)/include
vpath main.cc $(GEN_CORE_DIR)
vpath ram_session_component.cc $(GEN_CORE_DIR)
vpath rom_session_component.cc $(GEN_CORE_DIR)
vpath cpu_session_component.cc $(GEN_CORE_DIR)
vpath pd_session_component.cc $(GEN_CORE_DIR)
vpath rm_session_component.cc $(GEN_CORE_DIR)
vpath signal_session_component.cc $(GEN_CORE_DIR)
vpath io_port_session_component.cc $(GEN_CORE_DIR)/x86
vpath io_mem_session_component.cc $(GEN_CORE_DIR)
vpath io_mem_session_support.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath core_mem_alloc.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath context_area.cc $(GEN_CORE_DIR)
vpath %.cc $(REP_DIR)/src/core
vpath thread.cc $(BASE_DIR)/src/base/thread
vpath cap_sel_alloc.cc $(REP_DIR)/src/base/env
vpath main_thread.cc $(REP_DIR)/src/base/env

View File

@@ -0,0 +1,4 @@
include $(PRG_DIR)/target.inc
LD_SCRIPT_STATIC = $(REP_DIR)/src/platform/roottask.ld
LD_TEXT_ADDR = 0x100000

View File

@@ -0,0 +1,63 @@
/*
* \brief NOVA-specific implementation of the Thread API for core
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2010-01-19
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/thread.h>
#include <base/cap_sel_alloc.h>
#include <base/printf.h>
#include <base/sleep.h>
#include <base/env.h>
/* NOVA includes */
#include <nova/syscalls.h>
/* core includes */
#include <nova_util.h>
using namespace Genode;
/**
* This function is called for constructing server activations and pager
* objects. It allocates capability selectors for the thread's execution
* context and a synchronization-helper semaphore needed for 'Lock'.
*/
void Thread_base::_init_platform_thread()
{
_tid.ec_sel = cap_selector_allocator()->alloc();
_tid.sc_sel = ~0; /* not needed within core */
_tid.rs_sel = cap_selector_allocator()->alloc();
_tid.pd_sel = cap_selector_allocator()->pd_sel();
/* create running semaphore required for locking */
int res = Nova::create_sm(_tid.rs_sel, _tid.pd_sel, 0);
if (res)
PERR("create_sm returned %d", res);
}
void Thread_base::_deinit_platform_thread()
{
unmap_local(Nova::Obj_crd(_tid.sc_sel, 0));
unmap_local(Nova::Obj_crd(_tid.ec_sel, 0));
unmap_local(Nova::Obj_crd(_tid.rs_sel, 0));
}
void Thread_base::start()
{
/*
* On NOVA, core never starts regular threads.
*/
}

View File

@@ -0,0 +1,35 @@
TARGET = hypervisor
REQUIRES = x86 32bit nova
NOVA_SRC_DIR = $(REP_DIR)/contrib
NOVA_BUILD_DIR = $(BUILD_BASE_DIR)/kernel
STARTUP_LIB =
SRC_CC = $(sort $(notdir $(wildcard $(NOVA_SRC_DIR)/src/*.cpp)))
SRC_S = $(sort $(notdir $(wildcard $(NOVA_SRC_DIR)/src/*.S)))
INC_DIR = $(NOVA_SRC_DIR)/include
CC_OLEVEL = -Os
CC_WARN = -Wall -Wextra -Waggregate-return -Wcast-align -Wcast-qual \
-Wconversion -Wdisabled-optimization -Wformat=2 \
-Wmissing-format-attribute -Wmissing-noreturn -Wpacked \
-Wpointer-arith -Wredundant-decls -Wshadow -Wwrite-strings \
-Wabi -Wctor-dtor-privacy -Wno-non-virtual-dtor \
-Wold-style-cast -Woverloaded-virtual -Wsign-promo \
-Wframe-larger-than=64 -Wlogical-op -Wstrict-null-sentinel \
-Wstrict-overflow=5 -Wvolatile-register-var
CC_OPT += -pipe -mpreferred-stack-boundary=2 -mregparm=3 -m32 \
-fdata-sections -fomit-frame-pointer -freg-struct-return \
-freorder-blocks -funit-at-a-time -fno-exceptions -fno-rtti \
-fno-stack-protector -fvisibility-inlines-hidden
CXX_LINK_OPT = -Wl,--gc-sections -Wl,--warn-common -Wl,-static -Wl,-n
LD_TEXT_ADDR = 0xc0000000
LD_SCRIPT_STATIC = hypervisor.o
$(TARGET): hypervisor.o
hypervisor.o: $(NOVA_SRC_DIR)/src/hypervisor.ld
$(VERBOSE)$(CC) $(INCLUDES) -MP -MMD -pipe -m32 -xc -E -P $< -o $@
clean cleanall:
$(VERBOSE)rm -rf $(NOVA_BUILD_DIR)
vpath %.cpp $(NOVA_SRC_DIR)/src
vpath %.S $(NOVA_SRC_DIR)/src

View File

@@ -0,0 +1,35 @@
/*
* \brief Genode::printf back-end for stdio
* \author Norman Feske
* \date 2009-10-06
*
* This library can be used by unit test executed on the host platform to
* direct output from the Genode framework to stdout.
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <stdio.h>
#include <base/printf.h>
void Genode::printf(const char *format, ...)
{
va_list list;
va_start(list, format);
::vprintf(format, list);
va_end(list);
}
void Genode::vprintf(const char *format, va_list list)
{
::vprintf(format, list);
}

View File

@@ -0,0 +1,58 @@
/*
* \brief Platform-specific helper functions for the _main() function
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2009-12-28
*/
/*
* Copyright (C) 2009-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _PLATFORM___MAIN_HELPER_H_
#define _PLATFORM___MAIN_HELPER_H_
#include <nova/syscalls.h>
/**
* Location of the main thread's UTCB, initialized by the startup code
*/
extern Nova::mword_t __main_thread_utcb;
/**
* Initial value of esp register, saved by the crt0 startup code
*
* This value contains the address of the hypervisor information page.
*/
extern long __initial_sp;
/**
* First available capability selector for custom use
*/
extern int __first_free_cap_selector;
/**
* Selector of local protection domain
*/
extern int __local_pd_sel;
static void main_thread_bootstrap()
{
/* register UTCB of main thread */
__main_thread_utcb = __initial_sp - Nova::PAGE_SIZE;
/* register start of usable capability range */
enum { FIRST_FREE_PORTAL = 0x1000 };
/* this variable may be set by the dynamic linker (ldso) */
if (!__first_free_cap_selector)
__first_free_cap_selector = FIRST_FREE_PORTAL;
/* register pd selector at cap allocator */
__local_pd_sel = Nova::PD_SEL;
}
#endif /* _PLATFORM___MAIN_HELPER_H_ */

View File

@@ -0,0 +1,46 @@
/*
* \brief Obtain parent capability
* \author Norman Feske
* \date 2010-01-26
*
* On NOVA, the parent capability consists of two parts, a local portal
* capability selector (as invokation address) and a global unique object ID.
* The parent portal is, by convention, capability selector 'PT_CAP_PARENT'
* supplied with the initial portals when the PD is created. The object ID is
* provided at the begin of the data segment of the loaded ELF image.
*/
/*
* Copyright (C) 2010-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _PLATFORM__MAIN_PARENT_CAP_H_
#define _PLATFORM__MAIN_PARENT_CAP_H_
/* Genode includes */
#include <util/string.h>
/* NOVA includes */
#include <nova/syscalls.h>
namespace Genode {
/**
* Return constructed parent capability
*/
Parent_capability parent_cap()
{
/* read capability from start of data section, containing object ID */
Native_capability cap;
memcpy(&cap, (void *)&_parent_cap, sizeof(cap));
/* assemble parent capability from object ID and portal */
return reinterpret_cap_cast<Parent>(Native_capability(Nova::PT_SEL_PARENT,
cap.unique_id()));
}
}
#endif /* _PLATFORM__MAIN_PARENT_CAP_H_ */

View File

@@ -0,0 +1,104 @@
/*
* \brief Linker script for Genode programs
* \author Christian Helmuth
* \date 2006-04-12
*/
/*
* Copyright (C) 2006-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*
* NOVA-specific change: NOVA does not support the BSS segment for
* roottask. Therefore, we have to place all BSS content into the
* data section.
*/
ENTRY(_start)
PHDRS
{
ro PT_LOAD;
rw PT_LOAD;
}
SECTIONS
{
.text : {
/* begin of program image (link address) */
_prog_img_beg = .;
*(.init)
*(.text .text.* .gnu.linkonce.t.*)
*(.fini)
*(.rodata .rodata.* .gnu.linkonce.r.*)
. = ALIGN(0x08);
_ctors_start = .;
KEEP (*(.ctors))
KEEP (*(SORT(.ctors.*)))
_ctors_end = .;
_dtors_start = .;
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
_dtors_end = .;
} : ro = 0x90909090
/* Linux: exception section for uaccess mechanism */
__ex_table : { *(__ex_table) }
.eh_frame_hdr : { *(.eh_frame_hdr) }
. = ALIGN(0x1000);
_prog_img_data = .;
.data : {
/*
* Leave space for parent capability parameters at start of data
* section. The protection domain creator is reponsible for storing
* sane values here.
*/
_parent_cap = .;
_parent_cap_thread_id = .;
LONG(0xffffffff);
_parent_cap_local_name = .;
LONG(0xffffffff);
*(.data .data.* .gnu.linkonce.d.*)
*(.bss .bss.* .gnu.linkonce.b.* COMMON)
} : rw
/* exception frames for C++ */
.eh_frame : {
__eh_frame_start__ = .;
KEEP (*(.eh_frame))
LONG(0)
} : rw
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
}
.gcc_except_table : {
KEEP(*(.gcc_except_table))
KEEP(*(.gcc_except_table.*))
}
.dynamic : { *(.dynamic) }
/* end of program image -- must be after last section */
_prog_img_end = .;
/DISCARD/ : {
*(.note)
*(.note.ABI-tag)
*(.comment)
}
}