mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 20:42:56 +01:00
Imported Genode release 11.11
This commit is contained in:
committed by
Christian Helmuth
parent
6bcc9aef0e
commit
da4e1feaa5
47
base-nova/Makefile
Normal file
47
base-nova/Makefile
Normal 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
10
base-nova/README
Normal 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
254
base-nova/doc/nova.txt
Normal 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
5
base-nova/etc/specs.conf
Normal file
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# Description of build platform
|
||||
#
|
||||
|
||||
SPECS ?= genode nova x86_32
|
||||
72
base-nova/include/base/cap_sel_alloc.h
Normal file
72
base-nova/include/base/cap_sel_alloc.h
Normal 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_ */
|
||||
|
||||
36
base-nova/include/base/ipc.h
Normal file
36
base-nova/include/base/ipc.h
Normal 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_ */
|
||||
186
base-nova/include/base/ipc_msgbuf.h
Normal file
186
base-nova/include/base/ipc_msgbuf.h
Normal 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_ */
|
||||
137
base-nova/include/base/ipc_pager.h
Normal file
137
base-nova/include/base/ipc_pager.h
Normal 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_ */
|
||||
88
base-nova/include/base/native_types.h
Normal file
88
base-nova/include/base/native_types.h
Normal 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_ */
|
||||
154
base-nova/include/base/pager.h
Normal file
154
base-nova/include/base/pager.h
Normal 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_ */
|
||||
34
base-nova/include/base/sleep.h
Normal file
34
base-nova/include/base/sleep.h
Normal 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_ */
|
||||
28
base-nova/include/nova/stdint.h
Normal file
28
base-nova/include/nova/stdint.h
Normal 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_ */
|
||||
673
base-nova/include/nova/syscalls.h
Normal file
673
base-nova/include/nova/syscalls.h
Normal 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_ */
|
||||
34
base-nova/include/signal_session/nova_source.h
Normal file
34
base-nova/include/signal_session/nova_source.h
Normal 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_ */
|
||||
82
base-nova/include/signal_session/source_client.h
Normal file
82
base-nova/include/signal_session/source_client.h
Normal 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_ */
|
||||
39
base-nova/include/signal_session/source_rpc_object.h
Normal file
39
base-nova/include/signal_session/source_rpc_object.h
Normal 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_ */
|
||||
5
base-nova/lib/mk/core_printf.mk
Normal file
5
base-nova/lib/mk/core_printf.mk
Normal 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
7
base-nova/lib/mk/env.mk
Normal 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
6
base-nova/lib/mk/ipc.mk
Normal 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
5
base-nova/lib/mk/lock.mk
Normal 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
|
||||
3
base-nova/lib/mk/pager.mk
Normal file
3
base-nova/lib/mk/pager.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
SRC_CC = pager.cc
|
||||
|
||||
vpath pager.cc $(REP_DIR)/src/base/pager
|
||||
3
base-nova/lib/mk/printf_stdio.mk
Normal file
3
base-nova/lib/mk/printf_stdio.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
SRC_CC = printf_stdio.cc
|
||||
|
||||
vpath printf_stdio.cc $(REP_DIR)/src/lib/printf_stdio
|
||||
4
base-nova/lib/mk/raw_server.mk
Normal file
4
base-nova/lib/mk/raw_server.mk
Normal file
@@ -0,0 +1,4 @@
|
||||
SRC_CC = server.cc
|
||||
INC_DIR = $(REP_DIR)/src/platform
|
||||
|
||||
vpath %.cc $(REP_DIR)/src/base/server
|
||||
3
base-nova/lib/mk/server.mk
Normal file
3
base-nova/lib/mk/server.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
LIBS = thread
|
||||
|
||||
include $(REP_DIR)/lib/mk/raw_server.mk
|
||||
11
base-nova/lib/mk/test_env.mk
Normal file
11
base-nova/lib/mk/test_env.mk
Normal 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
|
||||
6
base-nova/lib/mk/thread.mk
Normal file
6
base-nova/lib/mk/thread.mk
Normal 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
|
||||
|
||||
3
base-nova/lib/mk/thread_context.mk
Normal file
3
base-nova/lib/mk/thread_context.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
SRC_CC = thread_context.cc
|
||||
|
||||
vpath thread_context.cc $(REP_DIR)/src/base/thread
|
||||
8
base-nova/lib/mk/x86_32/startup.mk
Normal file
8
base-nova/lib/mk/x86_32/startup.mk
Normal 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
16
base-nova/mk/spec-nova.mk
Normal 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
21
base-nova/patches/README
Normal 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
|
||||
18
base-nova/patches/utcb.patch
Normal file
18
base-nova/patches/utcb.patch
Normal 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
82
base-nova/run/env
Normal 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 }
|
||||
|
||||
129
base-nova/src/base/console/core_console.h
Normal file
129
base-nova/src/base/console/core_console.h
Normal 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
121
base-nova/src/base/env/cap_sel_alloc.cc
vendored
Normal 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
43
base-nova/src/base/env/main_thread.cc
vendored
Normal 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;
|
||||
}
|
||||
200
base-nova/src/base/ipc/ipc.cc
Normal file
200
base-nova/src/base/ipc/ipc.cc
Normal 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)
|
||||
{ }
|
||||
67
base-nova/src/base/ipc/pager.cc
Normal file
67
base-nova/src/base/ipc/pager.cc
Normal 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());
|
||||
}
|
||||
88
base-nova/src/base/lock/lock_helper.h
Normal file
88
base-nova/src/base/lock/lock_helper.h
Normal 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);
|
||||
}
|
||||
177
base-nova/src/base/pager/pager.cc
Normal file
177
base-nova/src/base/pager/pager.cc
Normal 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();
|
||||
}
|
||||
|
||||
187
base-nova/src/base/server/server.cc
Normal file
187
base-nova/src/base/server/server.cc
Normal 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();
|
||||
}
|
||||
38
base-nova/src/base/thread/thread_context.cc
Normal file
38
base-nova/src/base/thread/thread_context.cc
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
141
base-nova/src/base/thread/thread_nova.cc
Normal file
141
base-nova/src/base/thread/thread_nova.cc
Normal 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);
|
||||
}
|
||||
53
base-nova/src/core/core_rm_session.cc
Normal file
53
base-nova/src/core/core_rm_session.cc
Normal 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();
|
||||
}
|
||||
62
base-nova/src/core/echo.cc
Normal file
62
base-nova/src/core/echo.cc
Normal 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; }
|
||||
48
base-nova/src/core/include/cap_session_component.h
Normal file
48
base-nova/src/core/include/cap_session_component.h
Normal 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_ */
|
||||
52
base-nova/src/core/include/core_rm_session.h
Normal file
52
base-nova/src/core/include/core_rm_session.h
Normal 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_ */
|
||||
54
base-nova/src/core/include/echo.h
Normal file
54
base-nova/src/core/include/echo.h
Normal 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_ */
|
||||
74
base-nova/src/core/include/irq_session_component.h
Normal file
74
base-nova/src/core/include/irq_session_component.h
Normal 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_ */
|
||||
45
base-nova/src/core/include/map_local.h
Normal file
45
base-nova/src/core/include/map_local.h
Normal 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_ */
|
||||
141
base-nova/src/core/include/nova_util.h
Normal file
141
base-nova/src/core/include/nova_util.h
Normal 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_ */
|
||||
81
base-nova/src/core/include/platform.h
Normal file
81
base-nova/src/core/include/platform.h
Normal 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_ */
|
||||
79
base-nova/src/core/include/platform_pd.h
Normal file
79
base-nova/src/core/include/platform_pd.h
Normal 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_ */
|
||||
125
base-nova/src/core/include/platform_thread.h
Normal file
125
base-nova/src/core/include/platform_thread.h
Normal 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_ */
|
||||
74
base-nova/src/core/include/util.h
Normal file
74
base-nova/src/core/include/util.h
Normal 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_ */
|
||||
59
base-nova/src/core/io_mem_session_support.cc
Normal file
59
base-nova/src/core/io_mem_session_support.cc
Normal 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;
|
||||
}
|
||||
74
base-nova/src/core/irq_session_component.cc
Normal file
74
base-nova/src/core/irq_session_component.cc
Normal 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() { }
|
||||
352
base-nova/src/core/platform.cc
Normal file
352
base-nova/src/core/platform.cc
Normal 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) { }
|
||||
57
base-nova/src/core/platform_pd.cc
Normal file
57
base-nova/src/core/platform_pd.cc
Normal 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()
|
||||
{ }
|
||||
143
base-nova/src/core/platform_thread.cc
Normal file
143
base-nova/src/core/platform_thread.cc
Normal 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));
|
||||
}
|
||||
77
base-nova/src/core/ram_session_support.cc
Normal file
77
base-nova/src/core/ram_session_support.cc
Normal 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);
|
||||
}
|
||||
55
base-nova/src/core/rm_session_support.cc
Normal file
55
base-nova/src/core/rm_session_support.cc
Normal 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;
|
||||
}
|
||||
}
|
||||
73
base-nova/src/core/signal_source_component.cc
Normal file
73
base-nova/src/core/signal_source_component.cc
Normal 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);
|
||||
}
|
||||
56
base-nova/src/core/target.inc
Normal file
56
base-nova/src/core/target.inc
Normal 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
|
||||
4
base-nova/src/core/target.mk
Normal file
4
base-nova/src/core/target.mk
Normal file
@@ -0,0 +1,4 @@
|
||||
include $(PRG_DIR)/target.inc
|
||||
|
||||
LD_SCRIPT_STATIC = $(REP_DIR)/src/platform/roottask.ld
|
||||
LD_TEXT_ADDR = 0x100000
|
||||
63
base-nova/src/core/thread_start.cc
Normal file
63
base-nova/src/core/thread_start.cc
Normal 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.
|
||||
*/
|
||||
}
|
||||
35
base-nova/src/kernel/target.mk
Normal file
35
base-nova/src/kernel/target.mk
Normal 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
|
||||
35
base-nova/src/lib/printf_stdio/printf_stdio.cc
Normal file
35
base-nova/src/lib/printf_stdio/printf_stdio.cc
Normal 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);
|
||||
}
|
||||
58
base-nova/src/platform/_main_helper.h
Normal file
58
base-nova/src/platform/_main_helper.h
Normal 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_ */
|
||||
46
base-nova/src/platform/_main_parent_cap.h
Normal file
46
base-nova/src/platform/_main_parent_cap.h
Normal 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_ */
|
||||
104
base-nova/src/platform/roottask.ld
Normal file
104
base-nova/src/platform/roottask.ld
Normal 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user