Remove base-mb platform

This base platform is no longer maintained.

For supporting the Microblaze CPU in the future, we might consider
integrating support for this architecture into base-hw. Currently
though, there does not seem to be any demand for it.
This commit is contained in:
Norman Feske 2013-02-20 13:17:39 +01:00
parent ce67b73dca
commit ebc73f66df
116 changed files with 9 additions and 12415 deletions

18
README
View File

@ -14,13 +14,13 @@ the project's official website:
The current implementation can be compiled for 8 different kernels: Linux,
L4ka::Pistachio, L4/Fiasco, OKL4, NOVA, Fiasco.OC, Codezero, and a custom
kernel for the MicroBlaze architecture. Whereas the Linux version serves us as
development vehicle and enables us to rapidly develop the generic parts of the
system, the actual target platforms of the framework are microkernels. There
is no "perfect" microkernel - and neither should there be one. If a microkernel
pretended to be fit for all use cases, it wouldn't be "micro". Hence, all
microkernels differ in terms of their respective features, complexity, and
supported hardware architectures.
kernel for running Genode directly on ARM-based hardware. Whereas the Linux
version serves us as development vehicle and enables us to rapidly develop the
generic parts of the system, the actual target platforms of the framework are
microkernels. There is no "perfect" microkernel - and neither should there be
one. If a microkernel pretended to be fit for all use cases, it wouldn't be
"micro". Hence, all microkernels differ in terms of their respective features,
complexity, and supported hardware architectures.
Genode allows the use of each of the kernels listed above with a rich set of
device drivers, protocol stacks, libraries, and applications in a uniform way.
@ -106,10 +106,6 @@ The Genode source tree is composed of the following subdirectories:
Codezero microkernel developed by B-Labs
See [http://genode.org/documentation/platforms/codezero]
:'mb':
Support for running Genode natively on the MicroBlaze softcore CPU.
See [http://genode.org/documentation/platforms/microblaze]
:'host':
Pseudo platform documenting the interface between the generic and
platform-specific parts of the base framework. This is not a functional

View File

@ -1,11 +0,0 @@
This repository contains the port of Genode for Xilinx MicroBlaze-based
platforms. It is based on an custom microkernel implementation, which is also
part of this repository. To get an overview on the this platform and the
underlying microkernel please refer to the introduction located at:
! <GENODE_DIR>/base-mb/doc/microblaze.txt
To get a quick overview about how to work with this platform, you may read the
getting-started guide located at:
! <GENODE_DIR>/base-mb/doc/getting_started.txt

View File

@ -1,249 +0,0 @@
=========================================================
Getting started with Genode on MicroBlaze based platforms
=========================================================
Martin Stein
This file describes in a practical manner how to work with Genode on platforms
which are based on the Xilinx MicroBlaze. It approaches the following aspects:
* Build Genode with an existing static scenario of programs which are interacting
on with each other and printing information about it to the serial port.
* Run this Genode scenario on Qemu and on the Xilinx Spartan 3A Starter Kit
* Implement basic support aspects for new MicroBlaze-based platforms
If you're not familar with the Genode OS framework, you can read the online
documentation:
[http://genode.org/documentation/]
If you need further information about the Xilinx MicroBlaze, you can read an
introduction written by the Genode developers inside your Genode directory:
'base-mb/doc/microblaze.txt'
It also covers general issues and limitations respecting the status quo of the
Genode porting for MicroBlaze-based platforms. To go in detail about the Xilinx
MicroBlaze, you may refer to the Xilinx documentation:
[http://www.xilinx.com/tools/microblaze.htm]
Prerequisites
=============
The MicroBlaze tool chain
~~~~~~~~~~~~~~~~~~~~~~~~~
To build Genode for MicroBlaze, it is recommended to use the following
GCC/binutils-compliant tools:
* mb-g++ (GCC) 4.1.1 20060524 (Xilinx 11.2 Build EDK_LS2.2 20 Apr 2009 Xilinx
11.2 Build EDK_LS2.2 23 Apr 2009)
* GNU ld version 2.16 Xilinx 11.2 Build EDK_LS2.2 23 Apr 2009
* GNU assembler 2.16 Xilinx 11.2 Build EDK_LS2.2 23 Apr 2009
These tools come with the Xilinx Embedded Development Kit (EDK).
Expect
~~~~~~
To run the given test scenarios on Genode, you have to install the Tcl-based
testing-tool Expect, for example using 'apt-get' on Debian-based Linux
distributions:
! sudo apt-get install expect
Qemu
~~~~
To run Genode's MicroBlaze port on Qemu, the following Qemu-version is recommended:
QEMU emulator version 0.14.50, Copyright (c) 2003-2008 Fabrice Bellard
You can get the source code of the latest version via GIT as follows:
! git clone git://git.qemu.org/qemu.git
For the scenarios described in here, you have to compile qemu via:
! configure --target-list=microblaze-softmmu
! make
Hardware
~~~~~~~~
The tutorial that runs Genode on hardware uses the Xilinx Spartan 3A Starter Kit
Revision D board with the FPGA 'xc3s700a', package 'fg484' on speed grade '-4'.
It has to be connected to your machine via USB and a serial port RS-232.
Tutorial: Build and run Genode's MicroBlaze port
================================================
Initially go to your Genode directory and ensure that the value of the 'QEMU' variable
within 'tool/builddir/etc/build.conf.mb-s3a_starter_kit' conforms to the path
of your 'qemu-system-microblaze' command. Now build a build directory with the
following shell commands:
! ./tool/create_builddir mb-s3a_starter_kit \
! BUILD_DIR=build.mb-s3a_starter_kit \
On Qemu
~~~~~~~
Change to '<GENODE_DIR>/build.mb-s3a_starter_kit'. In this directory,
build and run the Genode scenario 'nested_init' for Qemu as follows:
! make run/nested_init
This instructs the Genode build system to act according to the run-script
'<GENODE_DIR>/base-mb/run/nested_init.run'. This script initiates the build of
the Genode's core, the program 'init', and a configuration that describes the
scenario init start. Then it constructs a bootable image of these 3 files and
finally starts Qemu to boot the image virtually. Genode then starts 2 nested
'init' programs, each 'init' instance prints some information about its
capabilities.
On Hardware
~~~~~~~~~~~
Ensure that the Xilinx Spartan 3A Starter Kit jumpers are set as described for
the board-intern demo. Connect the board via USB to your machine and turn it
on. Wait till the LED next to the USB connector on board lights up, then list
all connected USB devices:
! lsusb
This should print, among others, one line like this 'Bus XXX Device XXX: ID XXXX:0008
Xilinx, Inc.' (any X is a wildcard for a number 0-9). Now connect the Serial port that
is labeled on board with 'J27' with your computer, this allows us to track debugging
output from Genode later. Go to '<GENODE_DIR>/build.mb-s3a_starter_kit'.
First we have to configure the Spartan 3A with an appropriate MicroBlaze SoC as follows:
! make -C ../base-mb/platform/mb-s3a_starter_kit
If it has finished successfully, we can build and run the 'nested_init' scenario by
typing the following command from within the build directory:
! RUN_OPT="--target jtag" make run/nested_init
After this, the build chain leaves an XMD command prompt to you, which is connected
to the SoC on the FPGA via JTAG, so you can steer it as you wish. Genode isn't started
already, you can now run a program like 'gtkterm' which intercepts the serial port that
Genode will print to. The parameters of the serial port according to 'gtkterm' are:
* Speed = 9600
* Parity = none
* Bits = 8
* Stopbits = 1
* Flowcontrol = none
To start the execution of the 'nested_init' scenario type
! run
to the open XMD prompt. The serial port interception should show output similar
to that of the Qemu-run. You should avoid uploading multiple times to a once
configured platform, it can lead to memory inconsistency. In contrast when
configuring the FPGA in between the RAM gets reset.
Other scenarios
~~~~~~~~~~~~~~~
You can also find a simple hello-world program at 'base-mb/src/test/hello'.
An appropriate 'run' script also exists and can be build from within a build
directory via:
! RUN_OPT="--target <TARGET>" make run/hello
Hints: How to add support for other MicroBlaze-based platforms
==============================================================
The steps described in here don't claim to be complete. They solely should
cover the basic of aspects to be considered when implementing support for new
platforms and reflect main conventions Genode's MicroBlaze port relies to.
New MicroBlaze-based platforms have to fulfill several considerations for now
to be compliant to the Genode port. The core expects:
* A MicroBlaze SoC with software-loaded MMU that has 64 entries,
RAM accessibility and no instruction- and data- caches
* The RAM address space to be mapped to 0x90000000
* The CPUs IRQ controller to be an XPS interrupt controller,
mapped to 0x81800000
* An XPS Timer mapped to 0x83c00000 with IRQ 0
* An XPS UART Lite mapped to 0x84000000
Basics
~~~~~~
Add a file 'base-mb/mk/spec-<PLATFORM>.mk' with the content
! SPECS += <SPECS>
! STARTUP_LIB ?= startup
! PRG_LIBS += $(STARTUP_LIB)
This file contains aspects to be integrated if 'PLATFORM' occurs in the
make-variable 'SPECS' during the build process. It also can add 'SPECS' by
itself to provide further details to the build system. For example,
the word-width of the CPU like '32bit'. Any other program or library
can depend on 'PLATFORM' later by adding it to its 'SPECS'. The second and third
lines specify a library that all userland-programs on Genode use to start on
'PLATFORM'. The denoted one is the default '<GENODE_DIR>/base-mb/lib/mk/startup.mk'
used by the currently supported platforms.
You can influence the build-process for 'PLATFORM' furthermore by adding additional
lines to this file, for according documentation please refer to:
[http://genode.org/documentation/]
FPGA Configuration and support by the tool 'run'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To automate testing via the 'run' tool, you have to create a Makefile
'<GENODE_DIR>/base-mb/platform/<PLATFORM>/Makefile' that provides a target
'upload'. This target should upload an ELF-image, whose absolute path is
given by the make argument 'IMAGE', to the according hardware.
The above mentioned Makefile should also provide by convention a target
'configure' which prepares the according hardware for the upload of
boot images. Typically it configures the FPGA with an appropriate
SoC. Therefore, whose source should also be located within
'<GENODE_DIR>/base-mb/platform/<PLATFORM>/'.
Finally you have to edit '<GENODE_DIR>/base-mb/run/env' to hint 'run' to
your platform. Add inside the function definition 'proc hardware { } {'
an additional:
! if { [have_spec {<PLATFORM>}] } {
! set _hardware <PLATFORM>
! return $_hardware
! }
'run' then calls 'upload' on '<GENODE_DIR>/base-mb/platform/<PLATFORM>/Makefile'
and gives the boot image when 'run_genode_until' is called by the according
'run'-script. But first you should create an according build directory as described
next.
Support for the tool 'create_builddir'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Add a file 'tool/builddir/etc/build.conf.<PLATFORM>' with at least the content
! REPOSITORIES = base-mb
! QEMU = <QEMU>
Where 'QEMU' denotes your Qemu command to emulate 'PLATFORM' for Genode
Now add a make-target '<PLATFORM>::' to 'tool/create_builddir' that should
describe additional things to do for your build directory. A good point to
start is to overwrite the default specifications the build process should take
into account when selecting and build targets and libraries.
! @echo "SPECS = genode <PLATFORM>" > $(BUILD_DIR)/etc/specs.conf
This adds the specifics for basic Genode settings, libraries and programs as
well as to the contents of your previously created
'base-mb/mk/spec-<PLATFORM>.mk'.

View File

@ -1,124 +0,0 @@
==========================================================
Introduction into the Genode porting for Xilinx MicroBlaze
==========================================================
Norman Feske
Martin Stein
This file gives an overview to the Genode porting for MicroBlaze-based
platforms. To get a quick introduction in how to build and run Genode on
such platforms, please refer to:
! <GENODE_DIR/base-mb/doc/getting_started.txt>
Xilinx MicroBlaze is a so-called softcore CPU, which is commonly used as part
of FPGA-based System-on-Chip designs. At Genode Labs, we are regularly using
this IP core, in particular for our Genode FPGA Graphics Project, which is a
GUI software stack and a set of IP cores for implementing fully-fledged
windowed GUIs on FPGAs:
:Website of the Genode FPGA Graphics Project:
[http://genode-labs.com/products/fpga-graphics]
Ever since we first released the Genode FPGA project, we envisioned to combine
it with the Genode OS Framework. In Spring 2010, Martin Stein joined our team
at Genode Labs and accepted the challenge to bring the Genode OS Framework to
the realms of FPGA-based SoCs. Technically, this implies porting the framework
to the MicroBlaze CPU architecture. In contrast to most softcore CPUs such as
the popular Lattice Mico32, the MicroBlaze features a MMU, which is a fundamental
requirement for implementing a microkernel-based system. Architecturally-wise
MicroBlaze is a RISC CPU similar to MIPS. Many system parameters of the CPU
(caches, certain arithmetic and shift instructions) can be parametrized at
synthesizing time of the SoC. We found that the relatively simple architecture
of this CPU provides a perfect playground for pursuing some of our ideas about
kernel design that go beyond the scope of current microkernels. So instead of
adding MicroBlaze support into one of the existing microkernels already
supported by Genode, we went for a new kernel design. Deviating from the typical
microkernel, which is a self-sufficient program running in kernel mode that
executes user-level processes on top, our design regards the kernel as a part of
Genode's core. It is not a separate program but a library that implements the
glue between user-level core and the raw CPU. Specifically, it provides the
entrypoint for hardware exceptions, a thread scheduler, an IPC mechanism, and
functions to manipulate virtual address spaces (loading and flushing entries
from the CPU's software-loaded TLB). It does not manage any physical memory
resources or the relationship between processes. This is the job of core.
From the kernel-developer's point of view, the kernel part can be summarized as
follows:
* The kernel provides user-level threads that are scheduled in a round-robin
fashion.
* Threads can communicate via synchronous IPC.
* There is a mechanism for blocking and waking up threads. This mechanism
can be used by Genode to implement locking as well as asynchronous
inter-process communication.
* There is a single kernel thread, which never blocks in the kernel code paths.
So the kernel acts as a state machine. Naturally, there is no concurrency in the
execution paths traversed in kernel mode, vastly simplifying these code parts.
However, all code paths are extremely short and bounded with regard to
execution time. Hence, we expect the interference with interrupt latencies
to be low.
* The IPC operation transfers payload between UTCBs only. Each thread has a
so-called user-level thread control block which is mapped transparently by
the kernel. Because of this mapping, user-level page faults cannot occur
during IPC transfers.
* There is no mapping database. Virtual address spaces are manipulated by
loading and flushing physical TLB entries. There is no caching of mappings
done in the kernel. All higher-level information about the interrelationship
of memory and processes is managed by the user-level core.
* Core runs in user mode, mapped 1-to-1 from the physical address space
except for its virtual thread-context area.
* The kernel paths are executed in physical address space (MicroBlaze).
Because both kernel code and user-level core code are observing the same
address-space layout, both worlds appear to run within a single address
space.
* User processes can use the entire virtual address space (4G) except for a
helper page for invoking syscalls and a page containing atomic operations.
There is no reservation used for the kernel.
* The MicroBlaze architecture lacks an atomic compare-and-swap instruction. On
user-level, this functionality is emulated via delayed preemption. A kernel-
provided page holds the sequence of operations to be executed atomically and
prevents (actually delays) the preemption of a thread that is currently
executing instructions at that page.
* The MicroBlaze MMU supports several different page sizes (1K up to 16MB).
Genode fully supports this feature for page sizes >= 4K. This way, the TLB
footprint can be minimized by choosing sensible alignments of memory
objects.
Current state
#############
The MicroBlaze platform support resides in the 'base-mb' repository. At the
current stage, core is able to successfully start multiple nested instances of
the init process. Most of the critical kernel functionality is working. This
includes inter-process communication, address-space creation, multi-threading,
thread synchronization, page-fault handling, and TLB eviction.
The nested init scenario runs on Qemu, emulating the Petalogix Spartan 3A
DSP1800 design, as well as on real hardware, tested with the Xilinx Spartan
3A Starter Kit configured with an appropriate Microblaze SoC.
This simple scenario already illustrates the vast advantage of
using different page sizes supported by the MicroBlaze CPU. If using
4KB pages only, a scenario with three nested init processes produces more than
300.000 page faults. There is an extremely high pressure on the TLB, which
only contains 64 entries. Those entries are constantly evicted so that
threshing effects are likely to occur. By making use of flexible page
sizes (4K, 16K, 64K, 256K, 1M, 4M, 16M), the number of page faults gets
slashed to only 1.800, speeding up the boot time by factor 10.
On hardware the capability remains to increase execution speed significantly
by turning on instruction- and data-caches. However this feature has not been
tested for now.
The kernel provides, beyond the requirements of the nested init scenario,
allocation, handling and deallocation of IRQs to the userland to enable
core to offer IRQ and IO Memory session services. This allows
custom device-driver implementations within the userland.
Currently, there is no restriction of IPC communication rights. Threads are
addressed using their global thread IDs (in fact, using their respective
indices in the KTCB array). For the future, we are planning to add
capabilty-based delegation of communication rights.

View File

@ -1 +0,0 @@
SPECS ?= genode mb-s3a_starter_kit

View File

@ -1,14 +0,0 @@
# Microblaze toolchain command prefix
CROSS_DEV_PREFIX ?= mb-
# GCC code optimization level
CC_OLEVEL = -O2
# Disable garbage collection of sections by LD because the MicroBlaze toolchain
# would produce corrupted code with this option enabled.
LD_OPT_GC_SECTIONS =
# Microblaze toolchain doesn't support #pragma GCC diagnostic,
# so avoid correspondig warnings.
CC_WARN += -Wno-pragmas

View File

@ -1,62 +0,0 @@
/*
* \brief Dummy IPC message buffer
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2013 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_
namespace Genode {
/**
* IPC message buffer layout
*/
class Msgbuf_base
{
protected:
size_t _size;
char _msg_start[]; /* symbol marks start of message */
public:
/*
* 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]; }
};
/**
* Instance of IPC message buffer with specified buffer size
*/
template <unsigned BUF_SIZE>
class Msgbuf : public Msgbuf_base
{
public:
char buf[BUF_SIZE];
Msgbuf() { _size = BUF_SIZE; }
};
}
#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */

View File

@ -1,207 +0,0 @@
/*
* \brief Dummy pager support for Genode
* \author Norman Feske,
* Martin Stein
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2013 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/thread.h>
/* Kernel includes */
#include <kernel/config.h>
#include <kernel/syscalls.h>
namespace Genode {
namespace Paging {
typedef Kernel::Paging::Resolution Native_resolution;
/**
* Used by Genode's IPC Pager and RM Session Component
*/
class Resolution : public Native_resolution{
public:
typedef Kernel::Paging::Physical_page Physical_page;
typedef Kernel::Paging::Virtual_page Virtual_page;
private:
enum {
INVALID_SIZE = Physical_page::INVALID_SIZE,
NO_PROTECTION_ID = 0,
DEFAULT_SIZE_LOG2 = Kernel::DEFAULT_PAGE_SIZE_LOG2,
DEFAULT_WRITEABLE = true,
DEFAULT_EXECUTABLE = true
};
bool _valid;
public:
::Genode::Native_page_size _native_size(unsigned const size_log2)
{
using namespace Kernel;
using namespace Kernel::Paging;
Physical_page::size_t s;
return Physical_page::size_by_size_log2(s, size_log2) ?
Physical_page::INVALID_SIZE : s;
}
Native_page_permission _native_permission(bool const writeable,
bool const executable)
{
typedef Kernel::Paging::Physical_page Physical_page;
if (writeable){
if (executable) return Physical_page::RWX;
else return Physical_page::RW;}
else{
if (executable) return Physical_page::RX;
else return Physical_page::R;}
}
Resolution(addr_t virtual_page_address,
addr_t physical_page_address,
bool write_combined, bool io_mem,
unsigned size_log2 = DEFAULT_SIZE_LOG2,
bool writeable = DEFAULT_WRITEABLE)
: _valid(true)
{
virtual_page = Virtual_page(virtual_page_address,
NO_PROTECTION_ID);
physical_page = Physical_page(physical_page_address,
_native_size(size_log2),
_native_permission(writeable,
DEFAULT_EXECUTABLE));
}
Resolution() : _valid(false) { }
void prepare_map_operation() { }
inline bool valid() { return _valid; }
};
}
typedef Paging::Resolution Mapping;
/**
* Special paging server class
*/
class Ipc_pager : public Native_capability
{
typedef Kernel::Paging::Request Request;
Mapping _mapping;
Request _request;
public:
/**
* Constructor
*/
Ipc_pager()
: Native_capability(Genode::my_thread_id(), 0)
{
_request.source.tid = 0;
}
/**
* Wait for a new fault received as short message IPC
*/
void wait_for_fault();
/**
* Reply current fault and wait for a new one
*
* Send short flex page and wait for next short-message (register)
* IPC -- pagefault
*/
void reply_and_wait_for_fault();
bool resolved();
/**
* Request instruction pointer of current fault
*/
addr_t fault_ip() { return _request.source.ip; }
/**
* Request fault address of current page fault
*/
addr_t fault_addr() { return _request.virtual_page.address(); }
/**
* Set parameters for next reply
*/
inline void set_reply_mapping(Mapping m) { _mapping=m; }
/**
* Set destination for next reply
*/
inline void set_reply_dst(Native_capability pager_object) { }
/**
* Answer call without sending a flex-page mapping
*
* This function is used to acknowledge local calls from one of
* core's region-manager sessions.
*/
inline void acknowledge_wakeup()
{
Kernel::thread_wake(_request.source.tid);
}
/**
* Return thread ID of last faulter
*/
inline Native_thread_id last() const { return _request.source.tid; }
/**
* Return badge for faulting thread
*/
inline unsigned long badge() const { return _request.source.tid; }
/**
* Was last fault a write fault?
*/
bool is_write_fault() const
{
return _request.access==Kernel::Paging::Request::RW ||
_request.access==Kernel::Paging::Request::RWX;
}
/**
* Return true if last fault was an exception
*/
bool is_exception() const
{
/*
* Reflection of exceptions is not supported on this platform.
*/
return false;
}
};
}
#endif /* _INCLUDE__BASE__IPC_PAGER_H_ */

View File

@ -1,70 +0,0 @@
/*
* \brief Dummy definitions for native types used for compiling unit tests
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2013 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_
#include <kernel/types.h>
#include <base/native_capability.h>
#include <base/stdint.h>
namespace Genode {
typedef Kernel::Thread_id Native_thread_id;
typedef Native_thread_id Native_thread;
typedef Kernel::Protection_id Native_process_id;
typedef Kernel::Utcb_unaligned Native_utcb;
typedef Kernel::Paging::Physical_page::Permissions Native_page_permission;
typedef Kernel::Paging::Physical_page::size_t Native_page_size;
Native_thread_id my_thread_id();
struct Cap_dst_policy
{
typedef Kernel::Thread_id Dst;
static bool valid(Dst tid) {
return tid != Kernel::INVALID_THREAD_ID; }
static Dst invalid()
{ return Kernel::INVALID_THREAD_ID; }
static void copy(void* dst, Native_capability_tpl<Cap_dst_policy>* src);
};
typedef Native_capability_tpl<Cap_dst_policy> Native_capability;
typedef int Native_connection_state;
struct Native_config
{
enum {
CONTEXT_AREA_VIRTUAL_BASE = 0x40000000,
CONTEXT_AREA_VIRTUAL_SIZE = 0x10000000,
CONTEXT_VIRTUAL_SIZE = 0x00100000,
};
/**
* Thread-context area configuration.
*/
static addr_t context_area_virtual_base() { return CONTEXT_AREA_VIRTUAL_BASE; }
static addr_t context_area_virtual_size() { return CONTEXT_AREA_VIRTUAL_SIZE; }
/**
* Size of virtual address region holding the context of one thread
*/
static addr_t context_virtual_size() { return CONTEXT_VIRTUAL_SIZE; }
};
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -1,71 +0,0 @@
/*
* \brief Atomic Userland operations for Microblaze
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2013 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__CPU__ATOMIC_H_
#define _INCLUDE__CPU__ATOMIC_H_
#include <kernel/syscalls.h>
namespace Genode {
extern void* const _atomic_cmpxchg;
/**
* Executes compare and exchange as atomic operation
*
* This function compares the value at dest with cmp_val.
* If both values are equal, dest is set to new_val. If
* both values are different, the value at dest remains
* unchanged.
*
* \return 1 if the value was successfully changed to new_val,
* 0 if cmp_val and the value at dest differ.
*/
inline int cmpxchg(volatile int *dest,
unsigned int cmp_val,
unsigned int new_val)
{
int result = 0;
unsigned int r15_buf = 0;
/**
* r27-r30 are arguments/return-values
* for _atomic_cmpxchg in r31 kernel denotes if
* interrupt has occured while executing atomic code
*/
asm volatile ("lwi r30, %[dest] \n"
"lwi r29, %[cmp_val] \n"
"lwi r28, %[new_val] \n"
"lwi r27, %[dest_val] \n"
"or r31, r0, r0 \n"
"swi r15, %[r15_buf] \n"
"bralid r15, _atomic_cmpxchg \n"
"or r0, r0, r0 \n"
"lwi r15, %[r15_buf] \n"
"swi r28, %[result] "
:
[result] "=m" (result),
[r15_buf] "+m" (r15_buf),
[dest] "+m" (dest),
[cmp_val] "+m" (cmp_val),
[new_val] "+m" (new_val),
[dest_val] "+m" (*dest)
:: "r31", "r30", "r29", "r28", "r27", "memory");
return result;
}
}
#endif /* _INCLUDE__CPU__ATOMIC_H_ */

View File

@ -1,116 +0,0 @@
/*
* \brief Configuration of underlying hardware
* \author Martin stein
* \date 07-05-2010
*/
/*
* Copyright (C) 07-2013 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__CPU__CONFIG_H_
#define _INCLUDE__CPU__CONFIG_H_
#define ALWAYS_INLINE __attribute__((always_inline))
#define BITFIELD_ENUMS(name, bit_significancy_offset, bit_width) \
name ## _LSH = bit_significancy_offset, \
name ## _WID = bit_width, \
name ## _MSK = ~((~0) << bit_width) << bit_significancy_offset,
namespace Cpu {
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef uint8_t byte_t;
typedef uint32_t word_t;
typedef unsigned long addr_t;
typedef __SIZE_TYPE__ size_t;
enum {
BYTE_WIDTH_LOG2 = 3,
WORD_WIDTH_LOG2 = 5,
BYTE_WIDTH = 1 << BYTE_WIDTH_LOG2,
WORD_WIDTH = 1 << WORD_WIDTH_LOG2,
BYTE_SIZE = sizeof(byte_t),
WORD_SIZE = sizeof(word_t),
_16B_SIZE_LOG2 = 1*WORD_SIZE,
_256B_SIZE_LOG2 = 2*WORD_SIZE,
_4KB_SIZE_LOG2 = 3*WORD_SIZE,
_64KB_SIZE_LOG2 = 4*WORD_SIZE,
_1MB_SIZE_LOG2 = 5*WORD_SIZE,
_16MB_SIZE_LOG2 = 6*WORD_SIZE,
_256MB_SIZE_LOG2 = 7*WORD_SIZE,
_16B_SIZE = 1 << _16B_SIZE_LOG2,
_256B_SIZE = 1 << _256B_SIZE_LOG2,
_4KB_SIZE = 1 << _4KB_SIZE_LOG2,
_64KB_SIZE = 1 << _64KB_SIZE_LOG2,
_1MB_SIZE = 1 << _1MB_SIZE_LOG2,
_16MB_SIZE = 1 << _16MB_SIZE_LOG2,
_256MB_SIZE = 1 << _256MB_SIZE_LOG2,
};
enum {
RAM_BASE = 0x90000000,
RAM_SIZE = 0x06000000,
XPS_INTC_BASE = 0x81800000,
XPS_TIMER_0_BASE = 0x83c00000,
XPS_TIMER_0_IRQ = 0,
XPS_ETHERNETLITE_BASE = 0x81000000,
XPS_ETHERNETLITE_IRQ = 1,
XPS_UARTLITE_BASE = 0x84000000,
XPS_UARTLITE_IRQ = 3,
XPS_TIMER_1_BASE = 0x70000000,
XPS_TIMER_1_IRQ = 4,
};
typedef uint8_t Irq_id;
typedef uint8_t Exception_id;
enum {
FAST_SIMPLEX_LINK = 0,
UNALIGNED = 1,
ILLEGAL_OPCODE = 2,
INSTRUCTION_BUS = 3,
DATA_BUS = 4,
DIV_BY_ZERO_EXCEPTON = 5,
FPU = 6,
PRIVILEGED_INSTRUCTION = 7,
INTERRUPT = 10,
EXTERNAL_NON_MASKABLE_BREAK = 11,
EXTERNAL_MASKABLE_BREAK = 12,
DATA_STORAGE = 16,
INSTRUCTION_STORAGE = 17,
DATA_TLB_MISS = 18,
INSTRUCTION_TLB_MISS = 19,
MIN_EXCEPTION_ID = 0,
MAX_EXCEPTION_ID = 19,
INVALID_EXCEPTION_ID = 20
};
enum {
MIN_IRQ_ID = 0,
MAX_IRQ_ID = 31,
INVALID_IRQ_ID = 32,
};
}
#endif /* _INCLUDE__CPU__CONFIG_H_ */

View File

@ -1,36 +0,0 @@
/*
* \brief CPU state
* \author Martin Stein
* \date 2012-11-26
*/
/*
* Copyright (C) 2012-2013 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 _BASE_MB__INCLUDE__CPU__CPU_STATE_H_
#define _BASE_MB__INCLUDE__CPU__CPU_STATE_H_
/* Genode includes */
#include <base/stdint.h>
namespace Genode {
/**
* Basic CPU state
*/
struct Cpu_state
{
/**
* Registers
*/
addr_t sp; /* stack pointer */
addr_t ip; /* instruction pointer */
};
}
#endif /* _BASE_MB__INCLUDE__CPU__CPU_STATE_H_ */

View File

@ -1,54 +0,0 @@
/*
* \brief Cpu specifi memcpy
* \author Martin Stein
* \date 2012-11-27
*/
/*
* Copyright (C) 2012-2013 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 _BASE_MB__INCLUDE__CPU__STRING_H_
#define _BASE_MB__INCLUDE__CPU__STRING_H_
#include <base/stdint.h>
namespace Genode
{
/**
* Copy memory block
*
* \param dst destination memory block
* \param src source memory block
* \param size number of bytes to copy
*
* \return Number of bytes not copied
*/
inline size_t memcpy_cpu(void *dst, const void *src, size_t size)
{
unsigned char *d = (unsigned char *)dst, *s = (unsigned char *)src;
/* check 4 byte; alignment */
size_t d_align = (size_t)d & 0x3;
size_t s_align = (size_t)s & 0x3;
/* at least 32 bytes, 4 byte aligned, same alignment */
if (size < 32 || (d_align ^ s_align))
return size;
/* copy to 4 byte alignment */
for (size_t i = 0; i < s_align; i++, *d++ = *s++, size--);
/* copy words */
uint32_t * dw = (uint32_t *)d;
uint32_t * sw = (uint32_t *)s;
for (; size >= 4; size -= 4, dw++, sw++) *dw = *sw;
return size;
}
}
#endif /* _BASE_MB__INCLUDE__CPU__STRING_H_ */

View File

@ -1,79 +0,0 @@
/*
* \brief Configuration of kernel features
* \author Martin stein
* \date 24-06-2010
*/
/*
* Copyright (C) 24-2013 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__KERNEL__CONFIG_H_
#define _INCLUDE__KERNEL__CONFIG_H_
#include <cpu/config.h>
namespace Kernel
{
enum {
SCHEDULING_MS_INTERVAL = 10,
SCHEDULING_TIMER_BASE = Cpu::XPS_TIMER_0_BASE,
SCHEDULING_TIMER_IRQ = Cpu::XPS_TIMER_0_IRQ,
DEFAULT_PAGE_SIZE_LOG2 = Cpu::_4KB_SIZE_LOG2,
};
typedef Cpu::uint8_t Thread_id;
typedef Cpu::uint8_t Protection_id;
enum{
MIN_THREAD_ID = 1,
MAX_THREAD_ID = 64,
MIN_PROTECTION_ID = 1,
MAX_PROTECTION_ID = 64,
INVALID_THREAD_ID = 0,
INVALID_PROTECTION_ID = 0 };
}
namespace Roottask
{
enum {
MAIN_STACK_SIZE = 1024*1024*Cpu::WORD_SIZE,
MAIN_THREAD_ID = 2,
PROTECTION_ID = 1,
};
}
namespace User
{
enum {
UART_BASE = Cpu::XPS_UARTLITE_BASE,
UART_IRQ = Cpu::XPS_UARTLITE_IRQ,
IO_MEM_BASE = 0x70000000,
IO_MEM_SIZE = 0x10000000,
XPS_TIMER_0_BASE = 0x70000000,
XPS_TIMER_0_IRQ = 4,
MIN_IRQ = 4,
MAX_IRQ = 31,
MIN_PROTECTION_ID = Roottask::PROTECTION_ID+1,
MAX_PROTECTION_ID = Kernel::MAX_PROTECTION_ID,
MIN_THREAD_ID = Roottask::MAIN_THREAD_ID+1,
MAX_THREAD_ID = Kernel::MAX_THREAD_ID,
VADDR_BASE = 0 + 1*(1<<Kernel::DEFAULT_PAGE_SIZE_LOG2),
VADDR_SIZE = 0xf0000000,
};
}
#endif /* _INCLUDE__KERNEL__CONFIG_H_ */

View File

@ -1,568 +0,0 @@
/*
* \brief Kernels syscall frontend
* \author Martin stein
* \date 2010.07.02
*/
#ifndef _INCLUDE__KERNEL__SYSCALLS_H_
#define _INCLUDE__KERNEL__SYSCALLS_H_
/* Kernel includes */
#include <kernel/types.h>
#include <cpu/config.h>
/**
* Inline assembly clobber lists for syscalls with no arguments
*/
#define SYSCALL_7_ASM_CLOBBER "r24", SYSCALL_6_ASM_CLOBBER
#define SYSCALL_6_ASM_CLOBBER "r25", SYSCALL_5_ASM_CLOBBER
#define SYSCALL_5_ASM_CLOBBER "r26", SYSCALL_4_ASM_CLOBBER
#define SYSCALL_4_ASM_CLOBBER "r27", SYSCALL_3_ASM_CLOBBER
#define SYSCALL_3_ASM_CLOBBER "r28", SYSCALL_2_ASM_CLOBBER
#define SYSCALL_2_ASM_CLOBBER "r29", SYSCALL_1_ASM_CLOBBER
#define SYSCALL_1_ASM_CLOBBER SYSCALL_0_ASM_CLOBBER
#define SYSCALL_0_ASM_CLOBBER "r31", "r30"
/**
* Inline assembly list for write access during syscalls with no arguments
*/
#define SYSCALL_0_ASM_WRITE \
[result] "=m" (result), \
[r15_buf] "+m" (r15_buf), \
[opcode] "+m" (opcode)
/**
* Inline assembly lists for write access during syscalls with arguments
*/
#define SYSCALL_1_ASM_WRITE [arg_0] "+m" (arg_0), SYSCALL_0_ASM_WRITE
#define SYSCALL_2_ASM_WRITE [arg_1] "+m" (arg_1), SYSCALL_1_ASM_WRITE
#define SYSCALL_3_ASM_WRITE [arg_2] "+m" (arg_2), SYSCALL_2_ASM_WRITE
#define SYSCALL_4_ASM_WRITE [arg_3] "+m" (arg_3), SYSCALL_3_ASM_WRITE
#define SYSCALL_5_ASM_WRITE [arg_4] "+m" (arg_4), SYSCALL_4_ASM_WRITE
#define SYSCALL_6_ASM_WRITE [arg_5] "+m" (arg_5), SYSCALL_5_ASM_WRITE
#define SYSCALL_7_ASM_WRITE [arg_6] "+m" (arg_6), SYSCALL_6_ASM_WRITE
/**
* Inline assembly ops for syscalls with no arguments
* - r19-r31 are save when occuring in the clobber list
* r15 is a 'dedicated' register and so we have to save it manually
*/
#define SYSCALL_0_ASM_OPS \
"lwi r31, %[opcode] \n" \
"swi r15, %[r15_buf] \n" \
"brki r15, 0x8 \n" \
"or r0, r0, r0 \n" \
"lwi r15, %[r15_buf] \n" \
"swi r30, %[result] "
/**
* Inline assembly ops for syscalls with arguments
*/
#define SYSCALL_1_ASM_OPS "lwi r30, %[arg_0]\n" SYSCALL_0_ASM_OPS
#define SYSCALL_2_ASM_OPS "lwi r29, %[arg_1]\n" SYSCALL_1_ASM_OPS
#define SYSCALL_3_ASM_OPS "lwi r28, %[arg_2]\n" SYSCALL_2_ASM_OPS
#define SYSCALL_4_ASM_OPS "lwi r27, %[arg_3]\n" SYSCALL_3_ASM_OPS
#define SYSCALL_5_ASM_OPS "lwi r26, %[arg_4]\n" SYSCALL_4_ASM_OPS
#define SYSCALL_6_ASM_OPS "lwi r25, %[arg_5]\n" SYSCALL_5_ASM_OPS
#define SYSCALL_7_ASM_OPS "lwi r24, %[arg_6]\n" SYSCALL_6_ASM_OPS
/**
* Inline assembly lists for read access during syscalls with arguments
*/
#define SYSCALL_0_ASM_READ
#define SYSCALL_1_ASM_READ SYSCALL_0_ASM_READ
#define SYSCALL_2_ASM_READ SYSCALL_1_ASM_READ
#define SYSCALL_3_ASM_READ SYSCALL_2_ASM_READ
#define SYSCALL_4_ASM_READ SYSCALL_3_ASM_READ
#define SYSCALL_5_ASM_READ SYSCALL_4_ASM_READ
#define SYSCALL_6_ASM_READ SYSCALL_5_ASM_READ
#define SYSCALL_7_ASM_READ SYSCALL_6_ASM_READ
namespace Kernel {
using namespace Cpu;
typedef unsigned int Syscall_arg;
/**
* Syscall with 1 Argument
*/
ALWAYS_INLINE inline int syscall(Syscall_id opcode);
/**
* Syscall with 2 Arguments
*/
ALWAYS_INLINE inline int syscall(Syscall_id opcode,
Syscall_arg arg_0);
/**
* Syscall with 3 Arguments
*/
ALWAYS_INLINE inline int syscall(Syscall_id opcode,
Syscall_arg arg_0,
Syscall_arg arg_1);
/**
* Syscall with 4 Arguments
*/
ALWAYS_INLINE inline int syscall(Syscall_id opcode,
Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2);
/**
* Syscall with 5 Arguments
*/
ALWAYS_INLINE inline int syscall(Syscall_id opcode,
Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3);
/**
* Syscall with 6 Arguments
*/
ALWAYS_INLINE inline int syscall(Syscall_id opcode,
Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4);
/**
* Syscall with 7 Arguments
*/
ALWAYS_INLINE inline int syscall(Syscall_id opcode,
Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4,
Syscall_arg arg_5);
/**
* Syscall with 8 Arguments
*/
ALWAYS_INLINE inline int syscall(Syscall_id opcode,
Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4,
Syscall_arg arg_5,
Syscall_arg arg_6);
/**
* Yield thread execution and coninue with next
*/
inline void thread_yield();
/**
* Block thread that calls this
*/
inline void thread_sleep();
/**
* Create and start threads
*
* \param tid ident that thread should get
* \param pid threads protection domain
* \param pager_id threads page fault handler thread
* \param utcb_p virtual address of utcb
* \param vip initial virtual ip
* \param vsp initial virtual sp
* \param param scheduling parameters, not used by now
* \return 0 if new thread was created
* n > 0 if any error has occured (errorcodes planned)
*/
inline int thread_create(Thread_id tid,
Protection_id pid,
Thread_id pager_tid,
Utcb* utcb_p,
Cpu::addr_t vip,
Cpu::addr_t vsp,
unsigned int params);
/**
* Kill thread - only with root rights
*
* \param tid ident of thread
* \return 0 if thread is awake after syscall
* n > 0 if any error has occured (errorcodes planned)
*/
inline int thread_kill(Thread_id tid);
/**
* Unblock denoted thread
*
* \param tid ident of thread thats blocked
* \detail works only if destination has same protection
* domain or caller has rootrights
* \return 0 if thread is awake after syscall
* n > 0 if any error has occured (errorcodes planned)
*/
inline int thread_wake(Thread_id tid);
/**
* Re-set pager of another thread
*
* \param dst_tid thread whose pager shall be changed
* \param pager_tid ident of pager thread
* \detail works only if caller has rootrights
* \return 0 if new pager of thread is successfully set
* n > 0 if any error has occured (errorcodes planned)
*/
inline int thread_pager(Thread_id dst_tid,
Thread_id pager_tid);
/**
* Reply last and wait for new ipc request
*
* \param msg_length length of reply message
* \return length of received message
*/
inline int ipc_serve(unsigned int reply_size);
/**
* Send ipc request denoted in utcb to specific thread
*
* \param dest_id ident of destination thread
* \param msg_length number of request-message words
* \return number of reply-message words, or
* zero if request was not successfull
*/
inline int ipc_request(Thread_id dest_tid, unsigned int msg_size);
/**
* Load pageresolution to memory managment unit
*
* \param p_addr physical page address
* \param v_addr virtual page address
* \param pid protection domain ident
* \param size size of page
* \param permissions permission flags for page
* \return 0 if thread is awake after syscall
* n > 0 if any error has occured (errorcodes planned)
*/
inline int tlb_load(Cpu::addr_t p_address,
Cpu::addr_t v_address,
Protection_id pid,
Paging::Physical_page::size_t size,
Paging::Physical_page::Permissions permissions);
/**
* Flush page resolution area from tlb
*
* \param pid protection domain id
* \param start startaddress of area
* \param size_kbyte size of area in 1KB units
* \return 0 if new thread was created
* n > 0 if any error has occured (errorcodes planned)
*/
inline int tlb_flush(Protection_id pid,
Cpu::addr_t start,
unsigned size);
/**
* Print char to serial ouput
*
* \param c char to print
*/
inline void print_char(char c);
/**
* Print various informations about a specific thread
* \param i Unique ID of the thread, if it remains 0 take our own ID
*/
inline void print_info(Thread_id const & i = 0);
/**
* Allocate an IRQ to the calling thread if the IRQ is
* not allocated yet to another thread
*
* \param i Unique ID of the IRQ
* \return 0 If the IRQ is allocated to this thread now
* n != 0 If the IRQ is not allocated to this thread already
* (code of the error that has occured)
*/
inline int irq_allocate(Irq_id i);
/**
* Free an IRQ from allocation if it is allocated by the
* calling thread
*
* \param i Unique ID of the IRQ
* \return 0 If the IRQ is free now
* n != 0 If the IRQ is allocated already
* (code of the error that has occured)
*/
inline int irq_free(Irq_id i);
/**
* Sleep till the 'Irq_message'-queue of this thread is not
* empty. For any IRQ that is allocated by this thread and occures
* between the kernel-entrance inside 'irq_wait' and the next time this
* thread wakes up, an 'Irq_message' with metadata about the according
* IRQ is added to the threads 'Irq_message'-queue.
* When returning from 'irq_wait' the first message from the threads
* 'Irq_message'-queue is dequeued and written to the threads UTCB-base.
*/
inline void irq_wait();
}
void Kernel::print_info(Thread_id const & i)
{
syscall(PRINT_INFO, (Syscall_arg) i);
}
void Kernel::irq_wait() { syscall(IRQ_WAIT); }
int Kernel::irq_allocate(Irq_id i)
{
return syscall(IRQ_ALLOCATE, (Syscall_arg) i);
}
int Kernel::irq_free(Irq_id i) { return syscall(IRQ_FREE, (Syscall_arg) i); }
void Kernel::thread_yield() { syscall(THREAD_YIELD); }
void Kernel::thread_sleep() { syscall(THREAD_SLEEP); }
int Kernel::thread_create(Thread_id tid,
Protection_id pid,
Thread_id pager_tid,
Utcb* utcb_p,
Cpu::addr_t vip,
Cpu::addr_t vsp,
unsigned int params)
{
return syscall(THREAD_CREATE,
(Syscall_arg) tid,
(Syscall_arg) pid,
(Syscall_arg) pager_tid,
(Syscall_arg) utcb_p,
(Syscall_arg) vip,
(Syscall_arg) vsp,
(Syscall_arg) params);
}
int Kernel::thread_kill(Thread_id tid)
{
return syscall(THREAD_KILL, (Syscall_arg) tid);
}
int Kernel::thread_wake(Thread_id tid)
{
return syscall(THREAD_WAKE, (Syscall_arg) tid);
}
int Kernel::thread_pager(Thread_id dst_tid,
Thread_id pager_tid)
{
return syscall(
THREAD_PAGER,
(Syscall_arg) dst_tid,
(Syscall_arg) pager_tid);
}
int Kernel::ipc_serve(unsigned int reply_size)
{
return syscall(IPC_SERVE, (Syscall_arg) reply_size);
}
int Kernel::ipc_request(Thread_id dest_tid,
unsigned int msg_size)
{
return syscall(
IPC_REQUEST,
(Syscall_arg) dest_tid,
(Syscall_arg) msg_size);
}
int Kernel::tlb_load(Cpu::addr_t p_address,
Cpu::addr_t v_address,
Protection_id pid,
Paging::Physical_page::size_t size,
Paging::Physical_page::Permissions permissions)
{
return syscall(
TLB_LOAD,
(Syscall_arg) p_address,
(Syscall_arg) v_address,
(Syscall_arg) pid,
(Syscall_arg) size,
(Syscall_arg) permissions);
}
int Kernel::tlb_flush(Protection_id pid,
Cpu::addr_t start,
unsigned size)
{
return syscall(
TLB_FLUSH,
(Syscall_arg) pid,
(Syscall_arg) start,
(Syscall_arg) size);
}
void Kernel::print_char(char c) { syscall(PRINT_CHAR, (Syscall_arg) c); }
int Kernel::syscall(Syscall_id opcode)
{
int result;
unsigned int r15_buf;
asm volatile(SYSCALL_0_ASM_OPS
: SYSCALL_0_ASM_WRITE
: SYSCALL_0_ASM_READ
: SYSCALL_0_ASM_CLOBBER);
return result;
}
int Kernel::syscall(Syscall_id opcode, Syscall_arg arg_0)
{
int result;
unsigned int r15_buf;
asm volatile(SYSCALL_1_ASM_OPS
: SYSCALL_1_ASM_WRITE
: SYSCALL_1_ASM_READ
: SYSCALL_1_ASM_CLOBBER);
return result;
}
int Kernel::syscall(Syscall_id opcode,
Syscall_arg arg_0,
Syscall_arg arg_1)
{
int result;
unsigned int r15_buf;
asm volatile(SYSCALL_2_ASM_OPS
: SYSCALL_2_ASM_WRITE
: SYSCALL_2_ASM_READ
: SYSCALL_2_ASM_CLOBBER);
return result;
}
int Kernel::syscall(Syscall_id opcode,
Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2)
{
int result;
unsigned int r15_buf;
asm volatile(SYSCALL_3_ASM_OPS
: SYSCALL_3_ASM_WRITE
: SYSCALL_3_ASM_READ
: SYSCALL_3_ASM_CLOBBER);
return result;
}
int Kernel::syscall(Syscall_id opcode,
Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3)
{
int result;
unsigned int r15_buf;
asm volatile(SYSCALL_4_ASM_OPS
: SYSCALL_4_ASM_WRITE
: SYSCALL_4_ASM_READ
: SYSCALL_4_ASM_CLOBBER);
return result;
}
int Kernel::syscall(Syscall_id opcode,
Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4)
{
int result;
unsigned int r15_buf;
asm volatile(SYSCALL_5_ASM_OPS
: SYSCALL_5_ASM_WRITE
: SYSCALL_5_ASM_READ
: SYSCALL_5_ASM_CLOBBER);
return result;
}
int Kernel::syscall(Syscall_id opcode,
Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4,
Syscall_arg arg_5)
{
int result;
unsigned int r15_buf;
asm volatile(SYSCALL_6_ASM_OPS
: SYSCALL_6_ASM_WRITE
: SYSCALL_6_ASM_READ
: SYSCALL_6_ASM_CLOBBER);
return result;
}
int Kernel::syscall(Syscall_id opcode,
Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4,
Syscall_arg arg_5,
Syscall_arg arg_6)
{
int result;
unsigned int r15_buf;
asm volatile(SYSCALL_7_ASM_OPS
: SYSCALL_7_ASM_WRITE
: SYSCALL_7_ASM_READ
: SYSCALL_7_ASM_CLOBBER);
return result;
}
#endif /* _INCLUDE__KERNEL__SYSCALLS_H_ */

View File

@ -1,329 +0,0 @@
/*
* \brief Kernel specific data types
* \author Martin stein
* \date 2010-10-01
*/
/*
* Copyright (C) 2010-2013 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__KERNEL__TYPES_H_
#define _INCLUDE__KERNEL__TYPES_H_
#include <base/fixed_stdint.h>
#include <base/stdint.h>
#include <kernel/config.h>
namespace Kernel {
using namespace Cpu;
enum {THREAD_CREATE_PARAMS_ROOTRIGHT_LSHIFT=0};
struct Utcb_unaligned
{
enum {
ALIGNMENT_LOG2 = 0,
SIZE_LOG2 = Cpu::_4KB_SIZE_LOG2,
};
union
{
volatile Cpu::byte_t byte[1<<SIZE_LOG2];
volatile Cpu::word_t word[];
};
static inline Cpu::size_t size();
static inline unsigned int size_log2();
};
struct Utcb : Utcb_unaligned
{
enum {
ALIGNMENT_LOG2 = Kernel::DEFAULT_PAGE_SIZE_LOG2,
};
} __attribute__((aligned(1 << Kernel::DEFAULT_PAGE_SIZE_LOG2)));
/* syscall type idents */
/* XXX changes at THREAD_YIELD have to be manually XXX
* XXX commited to src/platform/xmb/atomic.s XXX
* XXX in _atomic_syscall_yield XXX
*/
enum Syscall_id{
TLB_LOAD = 1,
TLB_FLUSH = 2,
THREAD_CREATE = 3,
THREAD_KILL = 4,
THREAD_SLEEP = 5,
THREAD_WAKE = 6,
THREAD_YIELD = 7,
THREAD_PAGER = 8,
IPC_REQUEST = 9,
IPC_SERVE = 10,
PRINT_CHAR = 11,
PRINT_INFO = 12,
IRQ_ALLOCATE = 13,
IRQ_FREE = 14,
IRQ_WAIT = 15,
IRQ_RELEASE = 16,
INVALID_SYSCALL_ID = 17 };
enum{THREAD_CREATE__PARAM__IS_ROOT_LSHIFT=0};
namespace Thread_create_types {
enum Result {
SUCCESS = 0,
INSUFFICIENT_PERMISSIONS = -1,
INAPPROPRIATE_THREAD_ID = -2 };
}
namespace Thread_kill_types {
enum Result {
SUCCESS = 0,
INSUFFICIENT_PERMISSIONS = -1,
SUICIDAL = -2 };
}
namespace Thread_wake_types {
enum Result{
SUCCESS = 0,
INSUFFICIENT_PERMISSIONS = -1,
INAPPROPRIATE_THREAD_ID = -2 };
}
namespace Ipc {
typedef unsigned Payload_size;
}
namespace Ipc_serve_types {
typedef Ipc::Payload_size Result;
struct Argument{ Ipc::Payload_size reply_size; };
}
namespace Paging {
enum { UNIVERSAL_PROTECTION_ID = 0 };
class Virtual_page
{
addr_t _address;
Protection_id _protection_id;
bool _valid;
public:
void *operator new(size_t, void *addr) { return addr; }
/**
* Invalid construction
*/
Virtual_page() : _valid(false) { }
/**
* Construction
*/
Virtual_page(addr_t a, Protection_id pid)
: _address(a), _protection_id(pid), _valid(true) { }
bool valid(){ return _valid; }
addr_t address(){ return _address; }
Protection_id protection_id(){ return _protection_id; }
void invalidate(){ _valid=false; }
};
class Physical_page
{
public:
enum size_t{
_1KB = 0,
_4KB = 1,
_16KB = 2,
_64KB = 3,
_256KB = 4,
_1MB = 5,
_4MB = 6,
_16MB = 7,
MIN_VALID_SIZE = _4KB,
MAX_VALID_SIZE = _16MB,
INVALID_SIZE = 8};
enum { MAX_SIZE = INVALID_SIZE, MAX_SIZE_LOG2 = 24 };
enum Permissions{ R, RW, RX, RWX };
private:
addr_t _address;
size_t _size;
Permissions _permissions;
bool _valid;
public:
void *operator new(Kernel::size_t, void *addr) { return addr; }
static inline int size_by_size_log2(size_t& s, int const &size_log2);
/**
* Invalid construction
*/
Physical_page() : _valid(false) { }
/**
* Construction
*/
Physical_page(addr_t a, size_t ps, Permissions pp) :
_address(a),
_size(ps),
_permissions(pp),
_valid(true) { }
bool valid() { return _valid; }
size_t size() { return _size; }
addr_t address() { return _address; }
Permissions permissions() { return _permissions; }
void invalidate() { _valid = false; }
};
static unsigned const
size_log2_by_physical_page_size [Physical_page::MAX_SIZE + 1] =
{ 10, 12, 14, 16, 18, 20, 22, 24, 0 };
struct Resolution
{
Virtual_page virtual_page;
Physical_page physical_page;
bool write_access;
Resolution() { }
Resolution(Virtual_page* vp, Physical_page* pp) :
virtual_page(*vp),
physical_page(*pp),
write_access(false)
{ }
Resolution(Virtual_page vp, Physical_page pp) :
virtual_page(vp),
physical_page(pp),
write_access(false)
{ }
void invalidate()
{
virtual_page.invalidate();
physical_page.invalidate();
}
bool valid()
{
return virtual_page.valid() & physical_page.valid();
}
};
struct Request
{
void *operator new(Kernel::size_t, void *addr) { return addr; }
enum Access { R, RW, RX, RWX };
struct Source
{
Thread_id tid;
addr_t ip;
};
Virtual_page virtual_page;
Source source;
Access access;
Request(){}
Request(Virtual_page *vp, Source s, Access as)
: virtual_page(*vp), source(s), access(as) { }
};
}
}
int Kernel::Paging::Physical_page::size_by_size_log2(size_t &s, int const& size_log2)
{
static size_t const size_by_size_log2[MAX_SIZE_LOG2 + 1] = {
/* Index 0..9 */
INVALID_SIZE, INVALID_SIZE,
INVALID_SIZE, INVALID_SIZE,
INVALID_SIZE, INVALID_SIZE,
INVALID_SIZE, INVALID_SIZE,
INVALID_SIZE, INVALID_SIZE,
/* Index 10..19 */
_1KB, INVALID_SIZE,
_4KB, INVALID_SIZE,
_16KB, INVALID_SIZE,
_64KB, INVALID_SIZE,
_256KB, INVALID_SIZE,
/* Index 20..24 */
_1MB, INVALID_SIZE,
_4MB, INVALID_SIZE,
_16MB
};
if (size_log2 < 0)
return -1;
if ((unsigned)size_log2 >= sizeof(size_by_size_log2) / sizeof(size_by_size_log2[0]))
return -2;
if (size_by_size_log2[size_log2] == INVALID_SIZE)
return -3;
s = size_by_size_log2[(unsigned)size_log2];
return 0;
}
Cpu::size_t Kernel::Utcb_unaligned::size()
{
return (Cpu::size_t)1<<size_log2();
}
unsigned int Kernel::Utcb_unaligned::size_log2()
{
return (Cpu::size_t)SIZE_LOG2;
}
#endif /* _INCLUDE__KERNEL__TYPES_H_ */

View File

@ -1,226 +0,0 @@
/*
* \brief Driver for the Xilinx LogiCORE IP XPS Interrupt Controller 2.01
* \author Martin stein
* \date 2010-06-21
*/
/*
* Copyright (C) 2010-2013 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__DEVICES__XILINX_XPS_INTC_H_
#define _INCLUDE__DEVICES__XILINX_XPS_INTC_H_
#include <cpu/config.h>
namespace Xilinx {
/**
* Driver for the Xilinx LogiCORE IP XPS Interrupt Controller 2.01
*/
class Xps_intc
{
public:
typedef Cpu::uint32_t Register;
typedef Cpu::uint8_t Irq;
enum {
REGISTER_WIDTH = sizeof(Register)*Cpu::BYTE_WIDTH,
MIN_IRQ = Cpu::MIN_IRQ_ID,
MAX_IRQ = Cpu::MAX_IRQ_ID,
INVALID_IRQ = Cpu::INVALID_IRQ_ID,
};
/**
* Constructor argument
*/
struct Constr_arg
{
Cpu::addr_t base;
Constr_arg(Cpu::addr_t const & b) : base(b) { }
};
/**
* Probe if IRQ ID is valid at this controller
*/
inline bool valid(Irq const & i);
/**
* Enable propagation of all IRQ inputs
*/
inline void unmask();
/**
* Enable propagation of all IRQ inputs
*/
inline void unmask(Irq const & i);
/**
* Disable propagation of all IRQ inputs
* (anyhow the occurency of IRQ's gets noticed in ISR)
*/
inline void mask();
/**
* Disable propagation of an IRQ input
* (anyhow the occurency of the IRQ's gets noticed in ISR)
*/
inline void mask(Irq const & i);
/**
* Constructor
* All IRQ's are masked initially
*/
inline Xps_intc(Constr_arg const & ca);
/**
* Destructor
* All IRQ's are left masked
*/
inline ~Xps_intc();
/**
* Get the pending IRQ with
* the highest priority (that one with the lowest IRQ ID)
*/
inline Irq next_irq();
/**
* Release IRQ input so it can occure again
* (in general IRQ source gets acknowledged thereby)
*/
inline void release(Irq const & i);
/**
* Probe if IRQ is pending (unmasked and active)
*/
inline bool pending(Irq const & i);
private:
/**
* Register mapping offsets relative to the device base address
*/
enum {
RISR_OFFSET = 0 * Cpu::WORD_SIZE,
RIPR_OFFSET = 1 * Cpu::WORD_SIZE,
RIER_OFFSET = 2 * Cpu::WORD_SIZE,
RIAR_OFFSET = 3 * Cpu::WORD_SIZE,
RSIE_OFFSET = 4 * Cpu::WORD_SIZE,
RCIE_OFFSET = 5 * Cpu::WORD_SIZE,
RIVR_OFFSET = 6 * Cpu::WORD_SIZE,
RMER_OFFSET = 7 * Cpu::WORD_SIZE,
RMAX_OFFSET = 8 * Cpu::WORD_SIZE,
RMER_ME_LSHIFT = 0,
RMER_HIE_LSHIFT = 1
};
/**
* Short register description (no optional registers)
*
* ISR IRQ status register, a bit in here is '1' as long as the
* according IRQ-input is '1', IRQ/bit correlation: [MAX_IRQ,...,1,0]
* IER IRQ unmask register, as long as a bit is '1' in IER the controller
* output equals the according bit in ISR as long as MER[ME] is '1'
* IAR IRQ acknowledge register, writing a '1' to a bit in IAR writes
* '0' to the according bit in ISR and '0' to bit in IAR
* SIE Set IRQ unmask register, writing a '1' to a bit in SIE sets the
* according bit in IER to '1' and writes '0' to the bit in SIE
* CIE Clear IRQ unmask register, writing a '1' to a bit in SIE sets the
* according bit in IER to '0' and writes '0' to the bit in CIE
* MER Master unmask register, structure: [0,...,0,HIE,ME], controller
* output is '0' as long as ME is '0', HIE is '0' initally so
* software IRQ mode is active writing '1' to HIE switches to
* hardware IRQ mode and masks writing to HIE
*/
volatile Register* const _risr;
volatile Register* const _rier;
volatile Register* const _riar;
volatile Register* const _rsie;
volatile Register* const _rcie;
volatile Register* const _rmer;
};
}
void Xilinx::Xps_intc::unmask() { *_rsie = ~0; }
void Xilinx::Xps_intc::unmask(Irq const & i)
{
if (!valid(i)) { return; }
*_rsie = 1 << i;
}
void Xilinx::Xps_intc::mask() { *_rcie = ~0; }
void Xilinx::Xps_intc::mask(Irq const & i)
{
if (!valid(i)) { return; }
*_rcie = 1 << i;
}
bool Xilinx::Xps_intc::pending(Irq const & i)
{
if (!valid(i)) { return false; }
Register const pending = *_risr & *_rier;
return pending & (1 << i);
}
bool Xilinx::Xps_intc::valid(Irq const & i)
{
return !(i == INVALID_IRQ || i > MAX_IRQ);
}
Xilinx::Xps_intc::Xps_intc(Constr_arg const & ca) :
_risr((Register*)(ca.base + RISR_OFFSET)),
_rier((Register*)(ca.base + RIER_OFFSET)),
_riar((Register*)(ca.base + RIAR_OFFSET)),
_rsie((Register*)(ca.base + RSIE_OFFSET)),
_rcie((Register*)(ca.base + RCIE_OFFSET)),
_rmer((Register*)(ca.base + RMER_OFFSET))
{
*_rmer = 1 << RMER_HIE_LSHIFT | 1 << RMER_ME_LSHIFT;
mask();
}
Xilinx::Xps_intc::~Xps_intc()
{
mask();
}
Xilinx::Xps_intc::Irq Xilinx::Xps_intc::next_irq()
{
Register const pending = *_risr & *_rier;
Register bit_mask = 1;
for (unsigned int i=0; i<REGISTER_WIDTH; i++) {
if (bit_mask & pending) { return i; }
bit_mask = bit_mask << 1;
}
return INVALID_IRQ;
}
void Xilinx::Xps_intc::release(Irq const & i)
{
if (!valid(i)) { return; }
*_riar = 1 << i;
}
#endif /* _INCLUDE__DEVICES__XILINX_XPS_INTC_H_ */

View File

@ -1,399 +0,0 @@
/*
* \brief Driver for the Xilinx LogiCORE XPS Timer/Counter IP 1.02
* \author Martin stein
* \date 2010-06-22
*/
/*
* Copyright (C) 2010-2013 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__DEVICES__XILINX_XPS_TIMER_H_
#define _INCLUDE__DEVICES__XILINX_XPS_TIMER_H_
#include <cpu/config.h>
namespace Xilinx {
/**
* Driver for the Xilinx LogiCORE XPS Timer/Counter IP 1.02
*/
class Xps_timer
{
public:
/**
* CPU dependencies
*/
typedef Cpu::word_t word_t;
typedef Cpu::addr_t addr_t;
typedef Cpu::size_t size_t;
typedef Cpu::uint32_t uint32_t;
/**
* MMIO register
*/
typedef uint32_t Register;
/**
* Constructor, resets timer, overwrites timer value with '0'
*/
inline Xps_timer(addr_t const &base);
/**
* Destructor, resets timer, overwrites timer value with '0'
*/
inline ~Xps_timer();
/**
* Overwrite timer value with X>0, count downwards to '0', set the
* IRQ output to '1' for one cycle and simultaneously start counting
* downwards again from X, and so on ...
*
* \param value the value X
*/
inline void run_periodic(unsigned int const &value);
/**
* Overwrite timer value with X>0, count downwards to '0', set the
* IRQ output to '1' for one cycle and simultaneously start counting
* downwards from max_value() to '0', and so on ...
*
* \param value the value X
*/
inline void run_circulating(unsigned int const &value);
/**
* Overwrite timer value with X>0, count downwards to '0', set the
* IRQ output to '1' for one cycle, timer value remains '0'
*
* \param value the value X
*/
inline void run_oneshot(unsigned int const &value);
/**
* Prepare a 'run_oneshot()'-like run that shall be triggered with
* simple means. Useful for starting the timer out of assembly-code.
*
* \param value native time-value used to assess the delay
* of the timer IRQ as of the triggering
* \param start_val at this address the start value gets deposited
* \param start_reg at this address an address X gets deposited
* writing the start value to X later starts the
* timer as prepared
*/
inline void prepare_oneshot(unsigned int const & value,
volatile Register * & start_reg,
Register & start_val);
/**
* Current timer value
*/
inline unsigned int value();
/**
* Return the timers current value and determine if the timer has hit '0'
* before the returned value and after the last time we started it or called
* 'period_value' on it. Called during non-periodic runs 'rolled_over'
* becomes 'true' if value is '0' and 'false' otherwise
*
* Enable exclusive access only to this function to ensure correct behavior!
* This function delays the timer about the duration of a few cpu cycles!
*/
inline unsigned int period_value(bool * const & rolled_over);
/**
* Size of the MMIO provided by the timer device
*/
static inline size_t size();
/**
* Maximum timer value
*/
static inline unsigned int max_value();
/**
* Converting a native time value to milliseconds
*/
static inline unsigned int native_to_msec(unsigned int const &v);
/**
* Converting milliseconds to a native time value
*/
static inline unsigned int msec_to_native(unsigned int const &v);
/**
* Converting a native time value to microseconds
*/
static inline unsigned int native_to_usec(unsigned int const &v);
/**
* Converting microseconds to a native time value
*/
static inline unsigned int usec_to_native(unsigned int const &v);
private:
/**
* General constraints
*/
enum {
WORD_SIZE = sizeof(word_t),
BYTE_WIDTH = Cpu::BYTE_WIDTH,
FREQUENCY_PER_US = 62,
};
/**
* Registers
*/
enum {
/* Control/status register */
RTCSR0_OFFSET = 0*WORD_SIZE,
/* Load register, written to RTCR when RTCSR[LOAD]='1' */
RTLR0_OFFSET = 1*WORD_SIZE,
/* On timer/counter register the counting is done */
RTCR0_OFFSET = 2*WORD_SIZE,
/* Respectively for the second timer/counter module */
RTCSR1_OFFSET = 4*WORD_SIZE,
RTLR1_OFFSET = 5*WORD_SIZE,
RTCR1_OFFSET = 6*WORD_SIZE,
MMIO_SIZE = 8*WORD_SIZE,
/* r/w '0': generate timer mode
* r/w '1': capture timer mode */
RTCSR_MDT_LSHIFT = 0,
/* r/w '0': count upward mode
* r/w '1': count downward mode */
RTCSR_UDT_LSHIFT = 1,
/* r/w '0': external generate signal disabled mode
* r/w '1': external generate signal enabled mode */
RTCSR_GENT_LSHIFT = 2,
/* r/w '0': external capture trigger disabled mode
* r/w '1': external capture trigger enabled mode */
RTCSR_CAPT_LSHIFT = 3,
/* r/w '0': hold values mode
* r/w '0': auto reload (generate timer) / overwrite (capture timer) mode */
RTCSR_ARHT_LSHIFT = 4,
/* w/r '0': disable loading mode
* w/r '1': loading timer mode (RTCR=RTLR) */
RTCSR_LOAD_LSHIFT = 5,
/* w/r '0': throw no IRQ mode (doesn't affect RTCSR[TINT])
* w/r '1': throw IRQ on 0-1-edge at RTCSR[TINT] mode */
RTCSR_ENIT_LSHIFT = 6,
/* w/r '0': don't count (RTCR remains constant)
* w/r '1': count on RTCR */
RTCSR_ENT_LSHIFT = 7,
/* r '0': no IRQ has occured
* r '1': IRQ has occured
* w '0': no effect
* w '1': RTCSR[TINT]=0 */
RTCSR_TINT_LSHIFT = 8,
/* r/w '0': pulse width modulation disabled mode
* r/w '1': pulse width modulation enabled mode */
RTCSR_PWM_LSHIFT = 9,
/* w/r '0': nothing
* w/r '1': RTCSR[ENT]='1' for all timer/counter modules */
RTCSR_ENALL_LSHIFT = 10,
};
/**
* Controls for RTCSR
*/
enum {
RUN_ONCE = 0
| 0 << RTCSR_MDT_LSHIFT
| 1 << RTCSR_UDT_LSHIFT
| 0 << RTCSR_CAPT_LSHIFT
| 0 << RTCSR_GENT_LSHIFT
| 0 << RTCSR_ARHT_LSHIFT
| 0 << RTCSR_LOAD_LSHIFT
| 1 << RTCSR_ENIT_LSHIFT
| 1 << RTCSR_ENT_LSHIFT
| 1 << RTCSR_TINT_LSHIFT
| 0 << RTCSR_PWM_LSHIFT
| 0 << RTCSR_ENALL_LSHIFT
,
STOP_N_LOAD = 0
| 0 << RTCSR_MDT_LSHIFT
| 1 << RTCSR_UDT_LSHIFT
| 0 << RTCSR_CAPT_LSHIFT
| 0 << RTCSR_GENT_LSHIFT
| 0 << RTCSR_ARHT_LSHIFT
| 1 << RTCSR_LOAD_LSHIFT
| 0 << RTCSR_ENIT_LSHIFT
| 0 << RTCSR_ENT_LSHIFT
| 0 << RTCSR_TINT_LSHIFT
| 0 << RTCSR_PWM_LSHIFT
| 0 << RTCSR_ENALL_LSHIFT
,
RUN_PERIODIC = RUN_ONCE
| 1 << RTCSR_ARHT_LSHIFT
,
STOP_N_RESET = STOP_N_LOAD
| 1 << RTCSR_TINT_LSHIFT
,
};
/**
* Absolute register addresses
*/
volatile Register *const _rtcsr0;
volatile Register *const _rtlr0;
volatile Register *const _rtcr0;
volatile Register *const _rtcsr1;
volatile Register *const _rtlr1;
volatile Register *const _rtcr1;
};
}
Xilinx::Xps_timer::Xps_timer(addr_t const &base)
:
_rtcsr0((Register *)(base + RTCSR0_OFFSET)),
_rtlr0((Register *)(base + RTLR0_OFFSET)),
_rtcr0((Register *)(base + RTCR0_OFFSET)),
_rtcsr1((Register *)(base + RTCSR1_OFFSET)),
_rtlr1((Register *)(base + RTLR1_OFFSET)),
_rtcr1((Register *)(base + RTCR1_OFFSET))
{
*_rtcsr0 = STOP_N_RESET;
*_rtcsr1 = STOP_N_RESET;
*_rtlr0 = 0;
}
Xilinx::Xps_timer::size_t Xilinx::Xps_timer::size()
{
return (size_t)MMIO_SIZE;
}
unsigned int Xilinx::Xps_timer::max_value() { return ((unsigned int)~0); }
void Xilinx::Xps_timer::prepare_oneshot(unsigned int const & value,
volatile Register * & start_reg,
Register & start_val)
{
*_rtcsr0 = STOP_N_LOAD;
*_rtlr0 = value;
start_reg = _rtcsr0;
start_val = RUN_ONCE;
}
void Xilinx::Xps_timer::run_circulating(unsigned int const &value)
{
*_rtcsr0 = STOP_N_LOAD;
*_rtlr0 = value;
*_rtcsr0 = RUN_PERIODIC;
*_rtlr0 = max_value();
}
void Xilinx::Xps_timer::run_periodic(unsigned int const &value)
{
*_rtcsr0 = STOP_N_LOAD;
*_rtlr0 = value;
*_rtcsr0 = RUN_PERIODIC;
}
void Xilinx::Xps_timer::run_oneshot(unsigned int const &value)
{
*_rtcsr0 = STOP_N_LOAD;
*_rtlr0 = value;
*_rtcsr0 = RUN_ONCE;
}
unsigned int Xilinx::Xps_timer::value() { return *_rtcr0; }
unsigned int Xilinx::Xps_timer::period_value(bool * const &rolled_over)
{
if(!(*_rtcsr0 & (1 << RTCSR_ARHT_LSHIFT))){
/* this is no periodic run */
unsigned int const v = *_rtcr0;
*rolled_over = !(v);
return value();
}
/* 2 measurements are necessary to ensure that
* 'rolled_over' and the returned value are fit together
* because we can not halt the timer or read both simulanously */
unsigned int const v1 = *_rtcr0;
*rolled_over = (bool)(*_rtcsr0 & (1 << RTCSR_TINT_LSHIFT));
unsigned int const v2 = *_rtcr0;
if(*rolled_over) {
/* v2 must be a value the timer had after rolling over, so restart
* the timer with the current value but RTCSR[TINT] reset */
unsigned int const initial_rtlr = *_rtlr0;
unsigned int const restart_n_reset = *_rtcsr0 | (1 << RTCSR_TINT_LSHIFT);
*_rtlr0 = *_rtcr0; // timer gets delayed about the
*_rtcsr0 = restart_n_reset; // duration of these two operations
*_rtlr0 = initial_rtlr;
return v2;
}
/* v1 must be a value that the timer had before rolling
* over, so we don't have to reset the "rolled over" status even
* if the timer has rolled over till now */
return v1;
}
Xilinx::Xps_timer::~Xps_timer()
{
*_rtcsr0 = STOP_N_RESET;
*_rtcsr1 = STOP_N_RESET;
}
unsigned int Xilinx::Xps_timer::native_to_msec(unsigned int const &v)
{
return 1000*native_to_usec(v);
}
unsigned int Xilinx::Xps_timer::msec_to_native(unsigned int const &v)
{
return 1000*usec_to_native(v);
}
unsigned int Xilinx::Xps_timer::native_to_usec(unsigned int const &v)
{
return v/FREQUENCY_PER_US;
}
unsigned int Xilinx::Xps_timer::usec_to_native(unsigned int const &v)
{
return v*FREQUENCY_PER_US;
}
#endif /* _INCLUDE__DEVICES__XILINX_XPS_TIMER_H_ */

View File

@ -1,111 +0,0 @@
/*
* \brief Driver for the Xilinx LogiCORE IP XPS UART Lite 1.01a
* \author Martin stein
* \date 2011-05-06
*/
/*
* Copyright (C) 2011-2013 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__DEVICES__XILINX_XPS_UARTL_H_
#define _INCLUDE__DEVICES__XILINX_XPS_UARTL_H_
#include <cpu/config.h>
namespace Xilinx {
/**
* Driver for the Xilinx LogiCORE IP XPS UART Lite 1.01a
*/
class Xps_uartl
{
public:
/**
* Constructor
*/
Xps_uartl(Cpu::addr_t const & base);
/**
* Send one ASCII char over the UART interface
*/
inline void send(char const & c);
private:
/**
* Relative MMIO structure
*/
typedef Cpu::uint32_t Register;
enum {
RX_FIFO_OFF = 0 * Cpu::WORD_SIZE,
TX_FIFO_OFF = 1 * Cpu::WORD_SIZE,
STAT_REG_OFF = 2 * Cpu::WORD_SIZE,
CTRL_REG_OFF = 3 * Cpu::WORD_SIZE,
};
struct Rx_fifo {
enum {
BITFIELD_ENUMS(RX_DATA, 0, 8)
};
};
struct Tx_fifo {
enum {
BITFIELD_ENUMS(TX_DATA, 0, 8)
};
};
struct Ctrl_reg {
enum {
BITFIELD_ENUMS(RST_TX_FIFO, 0, 1)
BITFIELD_ENUMS(RST_RX_FIFO, 1, 1)
BITFIELD_ENUMS(ENABLE_INTR, 4, 1)
};
};
struct Stat_reg {
enum {
BITFIELD_ENUMS(RX_FIFO_VALID_DATA, 0, 1)
BITFIELD_ENUMS(RX_FIFO_FULL, 1, 1)
BITFIELD_ENUMS(TX_FIFO_EMPTY, 2, 1)
BITFIELD_ENUMS(TX_FIFO_FULL, 3, 1)
BITFIELD_ENUMS(INTR_ENABLED, 4, 1)
BITFIELD_ENUMS(OVERRUN_ERROR, 5, 1)
BITFIELD_ENUMS(FRAME_ERROR, 6, 1)
BITFIELD_ENUMS(PARITY_ERROR, 7, 1)
};
};
/**
* Absolute register pointers
*/
volatile Register* const _rx_fifo;
volatile Register* const _tx_fifo;
volatile Register* const _stat_reg;
volatile Register* const _ctrl_reg;
};
}
Xilinx::Xps_uartl::Xps_uartl(Cpu::addr_t const & base) :
_rx_fifo((Register*)(base + RX_FIFO_OFF)),
_tx_fifo((Register*)(base + TX_FIFO_OFF)),
_stat_reg((Register*)(base + STAT_REG_OFF)),
_ctrl_reg((Register*)(base + CTRL_REG_OFF))
{}
void Xilinx::Xps_uartl::send(char const & c){
while(*_stat_reg & Stat_reg::TX_FIFO_FULL_MSK);
*_tx_fifo = c;
}
#endif /* _INCLUDE__DEVICES__XILINX_XPS_UARTL_H_ */

View File

@ -1,87 +0,0 @@
LIBS = allocator_avl
CXX_SRC_CC += misc.cc new_delete.cc malloc_free.cc exception.cc guard.cc
vpath %.cc $(BASE_DIR)/src/base/cxx
#
# Microblaze-specific supplement
#
CXX_SRC_CC += atexit.cc
vpath %.cc $(REP_DIR)/src/base/cxx
#
# Here we define all symbols we want to hide in libsupc++ and libgcc_eh
#
LIBC_SYMBOLS += malloc free calloc realloc \
abort fputc fputs fwrite \
stderr strcat strcpy strlen up \
memcmp strncmp strcmp sprintf
#
# Take the right system libraries
#
# Normally, we never include build-system-internal files from library-
# description files. For building the 'cxx' library, however, we need the
# information about the used 'gcc' for resolving the location of the C++
# support libraries. This definition is performed by 'mk/lib.mk' after
# including this library description file. Hence, we need to manually
# include 'global.mk' here.
#
include $(BASE_DIR)/mk/global.mk
LIBCXX_GCC = $(shell $(CUSTOM_CXX_LIB) -print-file-name=libsupc++.a) \
$(shell $(CUSTOM_CXX_LIB) -print-libgcc-file-name)
# $(shell $(CUSTOM_CXX_LIB) -print-file-name=libgcc_eh.a)
#
# Dummy target used by the build system
#
SRC_S = supc++.o
CXX_SRC = $(sort $(CXX_SRC_CC))
CXX_OBJECTS = $(addsuffix .o,$(basename $(CXX_SRC)))
LOCAL_SYMBOLS = $(patsubst %,--localize-symbol=%,$(LIBC_SYMBOLS))
#
# Prevent symbols of the gcc support libs from being discarded during 'ld -r'
#
KEEP_SYMBOLS += __cxa_guard_acquire
KEEP_SYMBOLS += __moddi3 __divdi3 __umoddi3 __udivdi3
KEEP_SYMBOLS += _ZTVN10__cxxabiv116__enum_type_infoE
KEEP_SYMBOLS += __fixunsdfdi
KEEP_SYMBOLS += __udivsi3 __divsi3
#
# Keep symbols additionally needed for linking the libc on ARM
#
KEEP_SYMBOLS += __muldi3 __eqdf2 __fixdfsi __ltdf2 __ltdf2 __nedf2 __ltdf2 \
__gtdf2 __ltdf2 __ledf2 __fixdfsi __ltdf2 __ltdf2 __eqdf2 \
__fixdfsi __ltdf2 __fixdfsi __eqdf2 __gtdf2 __ltdf2 __gtdf2 \
__eqdf2 __muldi3 __muldi3
#
# Keep symbols needed for floating-point support on ARM
#
KEEP_SYMBOLS += __addsf3 __gtsf2 __ltsf2
#
# Additional symbols we need to keep when using the arm-none-linux-gnueabi
# tool chain
#
KEEP_SYMBOLS += __aeabi_ldivmod __aeabi_uldivmod __dynamic_cast
KEEP_SYMBOLS += _ZN10__cxxabiv121__vmi_class_type_infoD0Ev
KEEP_SYMBOLS += __aeabi_idiv __aeabi_ulcmp __aeabi_fmul __aeabi_dcmpun \
__aeabi_d2lz __aeabi_f2lz __aeabi_d2f __aeabi_fcmpun \
__aeabi_f2iz ctx_done sincos sincosf tgamma
#
# Rule to link all libc definitions and libsupc++ libraries
# and to hide after that the exported libc symbols
#
$(SRC_S): $(CXX_OBJECTS)
$(MSG_MERGE)$@
$(VERBOSE)$(LD) $(addprefix -u ,$(KEEP_SYMBOLS)) -r $(CXX_OBJECTS) $(LIBCXX_GCC) -o $@.tmp
$(MSG_CONVERT)$@
$(VERBOSE)$(OBJCOPY) $(LOCAL_SYMBOLS) $@.tmp $@
$(VERBOSE)$(RM) $@.tmp

View File

@ -1,7 +0,0 @@
SRC_CC = ipc.cc ipc_marshal_cap.cc
SRC_CC += pager.cc
LIBS += thread_context cap_copy
vpath ipc.cc $(REP_DIR)/src/base/ipc
vpath pager.cc $(REP_DIR)/src/base/ipc
vpath ipc_marshal_cap.cc $(BASE_DIR)/src/base/ipc

View File

@ -1,41 +0,0 @@
KERNEL_DIR = $(REP_DIR)/src/kernel
INC_DIR += $(KERNEL_DIR)/include
INC_DIR += $(REP_DIR)/src/core/include
##
## Platform-specific kernel parts
##
PLATFORM = petalogix_s3adsp1800_mmu
#
# Basic platform support
#
include $(LIBINC_DIR)/$(PLATFORM)__kernel_support.inc
#
# Enable atomic operations for this platform
#
LIBS += $(PLATFORM)__atomic_operations
##
## Generic kernel parts
##
GENERIC_DIR = $(KERNEL_DIR)/generic
SRC_CC += kernel.cc
SRC_CC += scheduler.cc
SRC_CC += thread.cc
SRC_CC += blocking.cc
SRC_CC += syscall_events.cc
vpath kernel.cc $(GENERIC_DIR)
vpath scheduler.cc $(GENERIC_DIR)
vpath thread.cc $(GENERIC_DIR)
vpath blocking.cc $(GENERIC_DIR)
vpath syscall_events.cc $(GENERIC_DIR)

View File

@ -1,13 +0,0 @@
LIBINC_DIR = $(REP_DIR)/lib/mk
include $(LIBINC_DIR)/kernel.inc
INC_DIR += $(REP_DIR)/src/platform
INC_DIR += $(REP_DIR)/src/core
INC_DIR += $(BASE_DIR)/src/platform
include $(LIBINC_DIR)/kernel.inc
CC_OPT += -DROOTTASK_ENTRY=_main
SRC_CC += _main.cc
vpath _main.cc $(BASE_DIR)/src/platform

View File

@ -1,7 +0,0 @@
LIBINC_DIR = $(REP_DIR)/lib/mk
include $(LIBINC_DIR)/kernel.inc
INC_DIR += $(REP_DIR)/src/platform
INC_DIR += $(REP_DIR)/src/core
INC_DIR += $(BASE_DIR)/src/platform

View File

@ -1,6 +0,0 @@
PLATFORM = petalogix_s3adsp1800_mmu
LIBS = thread_context $(PLATFORM)__atomic_operations
SRC_CC = lock.cc
INC_DIR += $(REP_DIR)/src/base/lock
vpath lock.cc $(BASE_DIR)/src/base/lock

View File

@ -1,4 +0,0 @@
SRC_CC = pager.cc
INC_DIR += $(REP_DIR)/include/codezero/dummies
vpath pager.cc $(REP_DIR)/src/base/pager

View File

@ -1,6 +0,0 @@
PLATFORM_DIR = $(REP_DIR)/src/kernel/platforms/petalogix_s3adsp1800_mmu
INC_DIR += $(PLATFORM_DIR)/include
SRC_S += atomic.s
vpath atomic.s $(PLATFORM_DIR)

View File

@ -1,29 +0,0 @@
##
## Platform
##
PLATFORM = petalogix_s3adsp1800_mmu
#
# Assembly include paths
#
INC_DIR += $(KERNEL_DIR)/platforms/$(PLATFORM)/include
#
# C++ include paths
#
INC_DIR += $(KERNEL_DIR)/include/$(PLATFORM)
#
# Sources
#
PLATFORM_DIR = $(KERNEL_DIR)/platforms/$(PLATFORM)
SRC_CC += platform.cc
SRC_S += crt0_kernel.s
SRC_S += kernel_entry.s
SRC_S += userland_entry.s
vpath platform.cc $(PLATFORM_DIR)
vpath crt0_kernel.s $(PLATFORM_DIR)
vpath kernel_entry.s $(PLATFORM_DIR)
vpath userland_entry.s $(PLATFORM_DIR)

View File

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

View File

@ -1,13 +0,0 @@
PLATFORM = petalogix_s3adsp1800_mmu
KERNEL_DIR = $(REP_DIR)/src/kernel
PLATFORM_DIR = $(KERNEL_DIR)/platforms/$(PLATFORM)
LIBS = cxx lock
SRC_S = crt0.s
SRC_CC += _main.cc
INC_DIR += $(REP_DIR)/src/platform
INC_DIR += $(BASE_DIR)/src/platform
INC_DIR += $(PLATFORM_DIR)/include
vpath crt0.s $(PLATFORM_DIR)
vpath _main.cc $(dir $(call select_from_repositories,src/platform/_main.cc))

View File

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

View File

@ -1,8 +0,0 @@
SRC_CC = thread.cc thread_start.cc thread_bootstrap.cc
INC_DIR += $(REP_DIR)/include/codezero/dummies
INC_DIR += $(REP_DIR)/src/core/include
vpath thread.cc $(REP_DIR)/src/base/thread
vpath thread_start.cc $(REP_DIR)/src/base/thread
vpath thread_bootstrap.cc $(REP_DIR)/src/base/thread
vpath %.cc $(BASE_DIR)/src/base/thread

View File

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

View File

@ -1,7 +0,0 @@
SPECS += 32bit mb_timer
STARTUP_LIB ?= startup
PRG_LIBS += $(STARTUP_LIB)
include $(call select_from_repositories,mk/spec-32bit.mk)

View File

@ -1,7 +0,0 @@
SPECS += 32bit mb_timer
STARTUP_LIB ?= startup
PRG_LIBS += $(STARTUP_LIB)
include $(call select_from_repositories,mk/spec-32bit.mk)

View File

@ -1,22 +0,0 @@
#
# \brief Prepare the Xilinx Spartan 3A Starter Kit to run Genode on it
# \author Martin Stein
# \date 2011-05-23
#
HW = s3a_starter_kit
WORK_DIR = $(shell pwd)
BIT_FILE = $(WORK_DIR)/system.bit
VERBOSE ?= @
REP_DIR = ../..
MK_DIR = $(REP_DIR)/platform/mk/
all: configure
clean:
$(VERBOSE) rm -f $(TMP_FILES)
.PHONY: all clean
include $(MK_DIR)/$(HW).mk
include $(MK_DIR)/microblaze.mk

View File

@ -1,19 +0,0 @@
#
# \brief Upload an image to the supported Microblaze SoC's
# \author Martin Stein
# \date 2011-05-23
#
UPLOAD_XMD = $(WORK_DIR)/upload.xmd
upload: $(UPLOAD_XMD)
$(VERBOSE) xmd -opt $(UPLOAD_XMD)
$(UPLOAD_XMD):
$(VERBOSE)echo \
"connect mb mdm"\
"\ndow $(IMAGE)"\
> $(UPLOAD_XMD)
.INTERMEDIATE: $(UPLOAD_XMD)
.PHONY: upload

View File

@ -1,19 +0,0 @@
#
# \brief Configure support for the Xilinx ML507 Development Kit via JTAG
# \author Martin Stein
# \date 2011-05-23
#
$(CONFIGURE_IMPACT):
$(VERBOSE) echo \
"setMode -bscan"\
"\nsetCable -p auto"\
"\nidentify"\
"\nassignfile -p 5 -file $(BIT_FILE)"\
"\nprogram -p 5"\
"\nquit"\
> $@
.INTERMEDIATE: $(CONFIGURE_IMPACT)
include $(MK_DIR)/xilinx.mk

View File

@ -1,22 +0,0 @@
#
# \brief Configure support for the Xilinx Spartan 3A Starter Kit via JTAG
# \author Martin Stein
# \date 2011-05-23
#
CONFIGURE_IMPACT = $(WORK_DIR)/configure.impact
$(CONFIGURE_IMPACT):
$(VERBOSE) echo \
"\nsetMode -bs"\
"\nsetCable -port auto"\
"\nIdentify -inferir"\
"\nidentifyMPM"\
"\nassignFile -p 1 -file \"$(BIT_FILE)\""\
"\nProgram -p 1"\
"\nquit"\
> $@
.INTERMEDIATE: $(CONFIGURE_IMPACT)
include $(MK_DIR)/xilinx.mk

View File

@ -1,24 +0,0 @@
#
# \brief Configure the supported Xilinx FPGAs
# \author Martin Stein
# \date 2011-05-23
#
TMP_FILES += $(WORK_DIR)/_impactbatch.log
CLEANLOCK_IMPACT = $(WORK_DIR)/cleanlock.impact
configure: $(CONFIGURE_IMPACT) cleanlock
$(VERBOSE) impact -batch $(CONFIGURE_IMPACT)
$(VERBOSE) make clean
cleanlock: $(CLEANLOCK_IMPACT)
$(VERBOSE) impact -batch $(CLEANLOCK_IMPACT) || true
$(CLEANLOCK_IMPACT):
$(VERBOSE) echo \
"cleancablelock"\
"\nexit"\
> $@
.INTERMEDIATE: $(UPLOAD_XMD) $(CLEANLOCK_IMPACT)
.PHONY: configure cleanlock

View File

@ -1,211 +0,0 @@
#
# \brief Environment for executing Genode on Microblaze
# \author Norman Feske
# \author Martin Stein
# \date 2010-09-01
#
# For the documentation of the implemented API functions,
# please refer to the comments in 'tool/run'.
#
proc create_boot_directory { } {
catch {
exec rm -rf [run_dir]
exec mkdir -p [run_dir]
}
}
proc build {targets {build_core 0}} {
if {[get_cmd_switch --skip-build]} return
regsub -all {\s\s+} $targets " " targets
# Save building 'core' until last
if {$build_core == 0} {
regsub -all {\mcore\M} $targets "" targets
}
puts "building targets: $targets"
set timeout 10000
set pid [eval "spawn make $targets"]
expect { eof { } }
if {[lindex [wait $pid] end] != 0} {
puts "Error: Genode build failed"
exit -4
}
puts "genode build completed"
}
proc stripped_copy {binary} {
exec mkdir -p bin/stripped/
exec rm -rf bin/stripped/$binary
exec cp bin/${binary} bin/stripped/${binary}
catch {exec [cross_dev_prefix]strip bin/stripped/${binary}}
}
#
# Microblaze needs a single boot image, thus this function creates an temporary assembly file that
# includes all images wich are needed by the boot image to be included by it
#
proc build_boot_modules {} {
global boot_modules
global boot_modules_s
set boot_modules_s "[genode_dir]/base-mb/src/core/boot_modules.s"
exec echo -e \
"\n/**"\
"\n * This file was generated by the expect procedure"\
"\n * 'build_boot_modules' in 'run/env'"\
"\n */"\
"\n\n"\
"\n.global _boot_modules_meta_start" \
"\n.global _boot_modules_meta_end" \
"\n\n" \
"\n.section .data" \
"\n.string \"GROM\"" \
"\n.long header_end" \
"\n.align 4" \
"\n_boot_modules_meta_start:" > $boot_modules_s
# Header, pointers part
set i 1
foreach module $boot_modules {
exec echo -e \
"\n.long mod${i}_name" \
"\n.long mod${i}_start" \
"\n.long mod${i}_end - mod${i}_start" >> $boot_modules_s
incr i
}
exec echo -e \
"\n.align 4"\
"\n_boot_modules_meta_end:" >> $boot_modules_s
# Header, names part
set i 1
foreach module $boot_modules {
exec echo -e \
"\nmod${i}_name:" \
"\n.string \"${module}\"" \
"\n.byte 0" >> $boot_modules_s
incr i
}
exec echo -e "header_end:" >> $boot_modules_s
# Modulecontents
set i 1
foreach module $boot_modules {
exec echo -e ".align 12" >> $boot_modules_s
# Stripped images the boot image depends on are not enabled because 'mb-strip' destroys
# the file offset alignments and Genode needs a specific minimum file offset alignment
#
# if { [catch {exec [cross_dev_prefix]readelf -h bin/${module}}] } {
exec echo -e "mod${i}_start: .incbin \"../bin/${module}\"" >> $boot_modules_s
# } else {
# exec echo -e "mod${i}_start: .incbin \"../bin/stripped/${module}\"" >> $boot_modules_s
# }
exec echo -e "mod${i}_end:" >> $boot_modules_s
incr i
}
exec echo -e ".align 12" >> $boot_modules_s
}
proc build_boot_image {images} {
global boot_modules
global boot_modules_s
foreach image $images {
if {$image != "core"} {
# Stripped images the boot image depends on are not enabled because 'mb-strip' destroys
# the file offset alignments and Genode needs a specific minimum file offset alignment
#
# if { [catch {exec [cross_dev_prefix]readelf -h bin/${image}}] == 0 } {
# stripped_copy $image
# }
append boot_modules "${image}" " "
}
}
build_boot_modules
build "core" 1
stripped_copy "core"
catch {
exec ln -sf ../../../bin/stripped/core [run_dir]/image.elf
}
exec rm -f $boot_modules_s
}
proc run_genode_until {{wait_for_re forever} {timeout_value 0}} {
set image [pwd]/[run_dir]/image.elf
set target [get_cmd_arg --target "qemu"]
if { $target == "jtag" } {
# try to run on device via jtag
spawn make -C [genode_dir]/base-mb/platform/[hardware] upload IMAGE=$image VERBOSE=
interact
} elseif { $target == "qemu" } {
# run on qemu
global output
set timeout $timeout_value
set pid [spawn [qemu] -kernel $image -serial stdio]
if {$wait_for_re == "forever"} { interact $pid }
expect {
-re $wait_for_re { }
timeout { puts stderr "Error: Test execution timed out"; exit -2 }
}
set output $expect_out(buffer)
} else {
puts stderr "Error: Target '${target}' is not supported"
puts stderr " Supported targets are: 'jtag' and 'qemu'"; exit -3
}
}
proc install_config {config} {
global boot_modules
append boot_modules "config" " "
set fh [open "bin/config" "WRONLY CREAT TRUNC"]
puts $fh $config
close $fh
exec touch [genode_dir]/base-mb/src/core/boot_modules.s
}
proc qemu { } {
global _qemu
set _qemu [get_cmd_arg --qemu "qemu-system-microblaze"]
return $_qemu
}
proc hardware { } {
global _hardware
#
# Test on all supported platforms
#
if { [have_spec {mb_s3a_starter_kit}] } {
set _hardware mb_s3a_starter_kit
return $_hardware
}
if { [have_spec {mb_ml507}] } {
set _hardware mb_ml507
return $_hardware
}
}

View File

@ -1,15 +0,0 @@
build "core init test/hello"
install_config {
<config verbose="yes">
<parent-provides> <service name="LOG"/> </parent-provides>
<start name="hello">
<resource name="RAM" quantum="3M"/>
<route><any-service><parent/></any-service></route>
</start>
</config>
}
create_boot_directory
build_boot_image "core init hello"
run_genode_until "child exited with exit value 0" 20

View File

@ -1,34 +0,0 @@
build "init core"
install_config {
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
<start name="init">
<resource name="RAM" quantum="10M"/>
<route><any-service><parent/></any-service></route>
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
</config>
</start>
</config>
}
create_boot_directory
build_boot_image "init core"
run_genode_until forever

View File

@ -1,64 +0,0 @@
/*
* \brief Console backend for Microblaze
* \author Martin Stein
* \date 2011-02-22
*/
/*
* Copyright (C) 2011-2013 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/console.h>
#include <base/printf.h>
#include <xilinx/xps_uartl.h>
namespace Genode {
class Microblaze_console : public Console
{
private:
Xilinx::Xps_uartl _uart;
protected:
virtual void _out_char(char c)
{
_uart.send(c);
}
public:
Microblaze_console() : _uart(0x84000000) {}
};
}
using namespace Genode;
static Microblaze_console &microblaze_console()
{
static Microblaze_console static_microblaze_console;
return static_microblaze_console;
}
void Genode::printf(const char *format, ...)
{
va_list list;
va_start(list, format);
microblaze_console().vprintf(format, list);
va_end(list);
}
void Genode::vprintf(const char *format, va_list list)
{
microblaze_console().vprintf(format, list);
}

View File

@ -1,19 +0,0 @@
/*
* \brief C++ support for Microblaze cross compiler
* \author Norman Feske
* \date 2010-07-21
*/
/*
* Copyright (C) 2010-2013 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.
*/
/*
* The mb-gcc generates calls to 'atexit' instead of '__cxa_atexit' as
* usual.
*/
extern "C" __attribute__((weak))
void *atexit() { return 0; }

View File

@ -1,201 +0,0 @@
/*
* \brief Implementation of the IPC API
* \author Norman Feske
* \date 2010-09-06
*/
/*
* Copyright (C) 2010-2013 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>
/* kernel includes */
#include <kernel/syscalls.h>
using namespace Genode;
/***************
** Utilities **
***************/
template<typename T>
static unsigned size_to_size_in(unsigned s)
{
return (unsigned)(s+sizeof(T)-1)/sizeof(T);
}
/**
* Copy message registers from UTCB to destination message buffer
*/
static void copy_utcb_to_msgbuf(unsigned message_size,
Msgbuf_base *receive_buffer)
{
if (!message_size) return;
if (message_size > receive_buffer->size())
message_size = receive_buffer->size();
Cpu::word_t *message_buffer = (Cpu::word_t*)receive_buffer->buf;
Native_utcb *utcb = Thread_base::myself()->utcb();
unsigned msg_size_in_words = size_to_size_in<Cpu::word_t>(message_size);
for (unsigned i=0; i < msg_size_in_words; i++)
message_buffer[i] = utcb->word[i];
}
/**
* Copy message payload to UTCB message registers
*/
static void copy_msgbuf_to_utcb(Msgbuf_base *send_buffer,
unsigned message_size,
unsigned local_name)
{
typedef Kernel::Utcb Utcb;
if (!message_size) return;
Native_utcb *utcb = Thread_base::myself()->utcb();
unsigned header_size = sizeof(local_name);
if (message_size + header_size > utcb->size()) {
if (header_size > utcb->size())
return;
message_size = utcb->size()-header_size;
}
Cpu::word_t *message_buffer = (Cpu::word_t*)send_buffer->buf;
unsigned msg_size_in_words = size_to_size_in<Cpu::word_t>(message_size);
unsigned h_size_in_words = size_to_size_in<Cpu::word_t>(header_size);
utcb->word[0] = local_name;
for (unsigned i = h_size_in_words; i < msg_size_in_words; i++) {
utcb->word[i] = message_buffer[i];
}
}
/*****************
** 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(umword_t);
}
/*****************
** Ipc_istream **
*****************/
void Ipc_istream::_wait() { Kernel::thread_sleep(); }
Ipc_istream::Ipc_istream(Msgbuf_base *rcv_msg)
:
Ipc_unmarshaller(&rcv_msg->buf[0], rcv_msg->size()),
Native_capability(Genode::my_thread_id(), 0),
_rcv_msg(rcv_msg),
_rcv_cs(-1)
{
_read_offset = sizeof(umword_t);
}
Ipc_istream::~Ipc_istream() { }
/****************
** Ipc_client **
****************/
void Ipc_client::_call()
{
unsigned request_size = _write_offset;
copy_msgbuf_to_utcb(_snd_msg, request_size, Ipc_ostream::_dst.local_name());
unsigned reply_size = Kernel::ipc_request(Ipc_ostream::_dst.dst(), request_size);
copy_utcb_to_msgbuf(reply_size, _rcv_msg);
/* reset marshalling / unmarshalling pointers */
_write_offset = _read_offset=sizeof(umword_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::_prepare_next_reply_wait()
{
/* now we have a request to reply */
_reply_needed = true;
enum { RETURN_VALUE_SIZE = sizeof(umword_t) };
_write_offset = sizeof(umword_t)+RETURN_VALUE_SIZE;
_read_offset = sizeof(umword_t);
}
void Ipc_server::_wait()
{
/* wait for new request */
Cpu::size_t reply_size = 0;
Cpu::size_t request_size = Kernel::ipc_serve(reply_size);
copy_utcb_to_msgbuf(request_size, _rcv_msg);
_prepare_next_reply_wait();
}
void Ipc_server::_reply() { _prepare_next_reply_wait(); }
void Ipc_server::_reply_wait()
{
unsigned reply_size = 0;
if (_reply_needed) {
reply_size = _write_offset;
copy_msgbuf_to_utcb(_snd_msg, reply_size, Ipc_ostream::_dst.local_name());
}
unsigned request_size = Kernel::ipc_serve(reply_size);
copy_utcb_to_msgbuf(request_size, _rcv_msg);
_prepare_next_reply_wait();
}
Ipc_server::Ipc_server(Msgbuf_base *snd_msg,
Msgbuf_base *rcv_msg)
:
Ipc_istream(rcv_msg),
Ipc_ostream(Native_capability(my_thread_id(), 0), snd_msg),
_reply_needed(false)
{ }

View File

@ -1,74 +0,0 @@
/*
* \brief Pager support for Microblaze Kernel
* \author Norman Feske
* \author Martin Stein
* \date 2010-09-23
*/
/*
* Copyright (C) 2010-2013 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/printf.h>
/* kernel includes */
#include <kernel/syscalls.h>
using namespace Genode;
void Ipc_pager::wait_for_fault()
{
typedef Kernel::Paging::Request Request;
while (1) {
/* wait for fault message */
unsigned const msg_length=Kernel::ipc_serve(0);
/* check message format */
if (msg_length==sizeof(Request)){
_request=*((Request*)Thread_base::myself()->utcb());
// PERR(
// "Recieved pagefault, va=%p, tid=%i, pid=%i",
// _request.virtual_page.address(),
// _request.source.tid,
// _request.virtual_page.protection_id());
return;
}
}
}
void Ipc_pager::reply_and_wait_for_fault()
{
/* load mapping to tlb (not to be considered permanent) */
if (_mapping.valid())
Kernel::tlb_load(
_mapping.physical_page.address(),
_mapping.virtual_page.address(),
_request.virtual_page.protection_id(),
_mapping.physical_page.size(),
_mapping.physical_page.permissions());
// PERR(
// "Resoluted, pa=%p, va=%p, tid=%i, pid=%i",
// _mapping.physical_page.address(),
// _mapping.virtual_page.address(),
// _request.source.tid,
// _request.virtual_page.protection_id());
/* wake up faulter if mapping succeeded */ acknowledge_wakeup();
/* wait for next page fault */ wait_for_fault();
}

View File

@ -1,57 +0,0 @@
/*
* \brief Dummy 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-2013 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>
/* kernel includes */
#include <kernel/syscalls.h>
#include <base/capability.h>
static inline void thread_yield() { Kernel::thread_yield(); }
static bool thread_check_stopped_and_restart(Genode::Native_thread_id tid)
{
Kernel::thread_wake(tid);
return true;
}
static inline Genode::Native_thread_id thread_get_my_native_id()
{
return Genode::my_thread_id();
}
static inline Genode::Native_thread_id thread_invalid_id() { return -1; }
static inline bool thread_id_valid(Genode::Native_thread_id tid)
{
return tid != thread_invalid_id();
}
static inline void thread_switch_to(Genode::Native_thread_id tid)
{
thread_yield();
}
static inline void thread_stop_myself() { Kernel::thread_sleep(); }

View File

@ -1,122 +0,0 @@
/*
* \brief Dummy pager framework
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2013 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/pager.h>
using namespace Genode;
/**********************
** Pager activation **
**********************/
void Pager_activation_base::entry()
{
Ipc_pager pager;
_cap = pager;
_cap_valid.unlock();
// PINF("Ready for page faults");
Pager_object * obj;
bool reply = false;
while (1) {
if (reply)
pager.reply_and_wait_for_fault();
else
pager.wait_for_fault();
/* lookup referenced object */
Object_pool<Pager_object>::Guard _obj(_ep ? _ep->lookup_and_lock(pager.badge()) : 0);
obj = _obj;
reply = false;
/* handle request */
if (obj) {
// PINF("Pagefault request from a common pager object");
if (pager.resolved()) {
reply = true;
continue;
}
reply = !obj->pager(pager);
if (!reply) {
/* something strange occured - leave thread in pagefault */
// PINF("Leave unresolved, wait for next page fault");
} else {
// PINF("Resolved, reply and wait for next page fault");
}
continue;
}
else {
// PINF("Pagefault request from one of cores region manager sessions");
/*
* We got a request from one of cores region-manager sessions
* to answer the pending page fault of a resolved region-manager
* client. Hence, we have to send the page-fault reply to the
* specified thread and answer the call of the region-manager
* session.
*
* When called from a region-manager session, we receive the
* core-local address of the targeted pager object via the
* first message word, which corresponds to the 'fault_ip'
* argument of normal page-fault messages.
*/
obj = reinterpret_cast<Pager_object *>(pager.fault_ip());
/* send reply to the calling region-manager session */
pager.acknowledge_wakeup();
/* answer page fault of resolved pager object */
pager.set_reply_dst(obj->cap());
pager.acknowledge_wakeup();
// PINF("Wait for next page fault");
}
}
}
/**********************
** Pager entrypoint **
**********************/
Pager_entrypoint::Pager_entrypoint(Cap_session *, Pager_activation_base *a)
: _activation(a)
{
_activation->ep(this);
}
void Pager_entrypoint::dissolve(Pager_object *obj) { remove_locked(obj); }
Pager_capability Pager_entrypoint::manage(Pager_object *obj)
{
/* return invalid capability if no activation is present */
if (!_activation) return Pager_capability();
Native_capability cap = Native_capability(_activation->cap().dst(), obj->badge());
/* add server object to object pool */
obj->cap(cap);
insert(obj);
/* return capability that uses the object id as badge */
return reinterpret_cap_cast<Pager_object>(cap);
}

View File

@ -1,215 +0,0 @@
/*
* \brief Implementation of the Thread API
* \author Norman Feske
* \date 2010-01-11
*/
/*
* Copyright (C) 2010-2013 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>
#include <base/env.h>
#include <base/snprintf.h>
#include <util/string.h>
#include <util/misc_math.h>
#include <xilinx/microblaze.h>
using namespace Genode;
/**
* Return the managed dataspace holding the thread context area
*
* This function is provided by the process environment.
*/
namespace Genode {
Rm_session *env_context_area_rm_session();
Ram_session *env_context_area_ram_session();
}
static addr_t context_virtual_base_mask() {
return ~(Native_config::context_virtual_size() - 1); }
/******************************
** Thread-context allocator **
******************************/
Thread_base::Context *Thread_base::Context_allocator::base_to_context(addr_t base)
{
addr_t result = base + Native_config::context_virtual_size() - sizeof(Context);
return reinterpret_cast<Context *>(result);
}
addr_t Thread_base::Context_allocator::addr_to_base(void *addr)
{
return ((addr_t)addr) & context_virtual_base_mask();
}
bool Thread_base::Context_allocator::_is_in_use(addr_t base)
{
List_element<Thread_base> *le = _threads.first();
for (; le; le = le->next())
if (base_to_context(base) == le->object()->_context)
return true;
return false;
}
Thread_base::Context *Thread_base::Context_allocator::alloc(Thread_base *thread_base)
{
Lock::Guard _lock_guard(_threads_lock);
/*
* Find slot in context area for the new context
*/
addr_t base = Native_config::context_area_virtual_base();
for (; _is_in_use(base); base += Native_config::context_virtual_size()) {
/* check upper bound of context area */
if (base >= Native_config::context_area_virtual_base() + Native_config::context_area_virtual_size())
return 0;
}
_threads.insert(&thread_base->_list_element);
return base_to_context(base);
}
void Thread_base::Context_allocator::free(Thread_base *thread_base)
{
Lock::Guard _lock_guard(_threads_lock);
_threads.remove(&thread_base->_list_element);
}
/*****************
** Thread base **
*****************/
Thread_base::Context_allocator *Thread_base::_context_allocator()
{
static Context_allocator context_allocator_inst;
return &context_allocator_inst;
}
Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
{
/*
* Synchronize context list when creating new threads from multiple threads
*
* XXX: remove interim fix
*/
static Lock alloc_lock;
Lock::Guard _lock_guard(alloc_lock);
/* allocate thread context */
Context *context = _context_allocator()->alloc(this);
if (!context) throw Context_alloc_failed();
/* determine size of dataspace to allocate for context members and stack */
enum { PAGE_SIZE_LOG2 = 12 };
size_t ds_size = align_addr(stack_size, PAGE_SIZE_LOG2);
if (stack_size >= Native_config::context_virtual_size() - sizeof(Native_utcb) - (1 << PAGE_SIZE_LOG2))
throw Stack_too_large();
/*
* Calculate base address of the stack
*
* The stack is always located at the top of the context.
*/
addr_t ds_addr = Context_allocator::addr_to_base(context) + Native_config::context_virtual_size()
- ds_size;
/* add padding for UTCB if defined for the platform */
if (sizeof(Native_utcb) >= (1 << PAGE_SIZE_LOG2))
ds_addr -= sizeof(Native_utcb);
/* allocate and attach backing store for the stack */
Ram_dataspace_capability ds_cap;
try {
ds_cap = env_context_area_ram_session()->alloc(ds_size);
addr_t attach_addr = ds_addr - Native_config::context_area_virtual_base();
env_context_area_rm_session()->attach_at(ds_cap, attach_addr, ds_size);
} catch (Ram_session::Alloc_failed) {
throw Stack_alloc_failed();
}
_init_context(context);
/*
* Now the thread context is backed by memory, so it is safe to access its
* members.
*/
context->thread_base = this;
context->stack_base = ds_addr;
context->ds_cap = ds_cap;
return context;
}
void Thread_base::_free_context()
{
addr_t ds_addr = _context->stack_base - Native_config::context_area_virtual_base();
Ram_dataspace_capability ds_cap = _context->ds_cap;
Genode::env_context_area_rm_session()->detach((void *)ds_addr);
Genode::env_context_area_ram_session()->free(ds_cap);
_context_allocator()->free(this);
}
void Thread_base::name(char *dst, size_t dst_len)
{
snprintf(dst, min(dst_len, (size_t)Context::NAME_LEN), _context->name);
}
Thread_base *Thread_base::myself()
{
addr_t sp = Xilinx::Microblaze::stack_pointer();
/*
* If the stack pointer is outside the thread-context area, we assume that
* we are the main thread because this condition can never met by any other
* thread.
*/
if (sp < Native_config::context_area_virtual_base()
|| sp >= Native_config::context_area_virtual_base() + Native_config::context_area_virtual_size())
return 0;
addr_t base = Context_allocator::addr_to_base((void*)sp);
return Context_allocator::base_to_context(base)->thread_base;
}
Thread_base::Thread_base(const char *name, size_t stack_size)
: _list_element(this), _context(_alloc_context(stack_size))
{
strncpy(_context->name, name, sizeof(_context->name));
_init_platform_thread();
}
Thread_base::~Thread_base()
{
_deinit_platform_thread();
_free_context();
}
void Thread_base::join()
{
_join_lock.lock();
}

View File

@ -1,22 +0,0 @@
/*
* \brief Default thread bootstrap code
* \author Norman Feske
* \date 2009-04-02
*/
/*
* Copyright (C) 2009-2013 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>
#include <kernel/print.h>
using namespace Genode;
void Thread_base::_thread_bootstrap()
{
myself()->_tid=*((Native_thread_id*)myself()->utcb());
}

View File

@ -1,57 +0,0 @@
/*
* \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-2013 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>
/* kernel includes */
#include <kernel/syscalls.h>
#include <base/capability.h>
#include <xilinx/microblaze.h>
using namespace Genode;
extern Genode::Native_utcb* _main_utcb_addr;
Genode::Native_thread_id _main_thread_id;
bool is_this_main_thread() { return Thread_base::myself() == 0; }
Native_utcb* Thread_base::utcb()
{
if (is_this_main_thread())
return _main_utcb_addr;
return &_context->utcb;
}
Native_thread_id Genode::my_thread_id()
{
if (!is_this_main_thread())
return Thread_base::myself()->tid();
unsigned pid = (unsigned)Xilinx::Microblaze::protection_id();
if (pid == Roottask::PROTECTION_ID)
return Roottask::MAIN_THREAD_ID;
return _main_thread_id;
}

View File

@ -1,75 +0,0 @@
/*
* \brief Implementation of the Thread API
* \author Norman Feske
* \date 2010-01-19
*/
/*
* Copyright (C) 2010-2013 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/printf.h>
#include <base/sleep.h>
#include <base/env.h>
using namespace Genode;
/**
* Entry point entered by new threads
*/
void Thread_base::_thread_start()
{
Thread_base::myself()->_thread_bootstrap();
Thread_base::myself()->entry();
Thread_base::myself()->_join_lock.unlock();
Genode::sleep_forever();
}
/*****************
** Thread base **
*****************/
void Thread_base::_init_context(Context* c) { }
void Thread_base::_init_platform_thread() { }
void Thread_base::_deinit_platform_thread()
{
env()->cpu_session()->kill_thread(_thread_cap);
env()->rm_session()->remove_client(_pager_cap);
}
void Thread_base::start()
{
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
_thread_cap = env()->cpu_session()->create_thread(buf);
/* assign thread to protection domain */
env()->pd_session()->bind_thread(_thread_cap);
/* create new pager object and assign it to the new thread */
_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 */
addr_t thread_sp = (addr_t)&_context->stack[-4];
thread_sp &= ~0xf; /* align initial stack to 16 byte boundary */
env()->cpu_session()->start(_thread_cap, (addr_t)_thread_start, thread_sp);
}
void Thread_base::cancel_blocking()
{
env()->cpu_session()->cancel_blocking(_thread_cap);
}

View File

@ -1,148 +0,0 @@
/*
* \brief Support code for the thread API
* \author Norman Feske
* \date 2010-01-13
*/
/*
* Copyright (C) 2010-2013 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 <rm_session/rm_session.h>
#include <ram_session/ram_session.h>
#include <base/printf.h>
#include <base/thread.h>
/* local includes */
#include <platform.h>
#include <map_local.h>
#include <dataspace_component.h>
using namespace Genode;
/**
* Pointer to dataspace used to hold core contexts
*/
enum { MAX_CORE_CONTEXTS = 256 };
static Dataspace_component *context_ds[MAX_CORE_CONTEXTS];
/**
* Region-manager session for allocating thread contexts
*
* This class corresponds to the managed dataspace that is normally
* used for organizing thread contexts with the thread context area.
* It "emulates" the sub address space by adjusting the local address
* argument to 'attach' with the offset of the thread context area.
*/
class Context_area_rm_session : public Rm_session
{
public:
/**
* Attach backing store to thread-context area
*/
Local_addr attach(Dataspace_capability ds_cap,
size_t size, off_t offset,
bool use_local_addr, Local_addr local_addr, bool)
{
Dataspace_component *ds = context_ds[ds_cap.local_name()];
if (!ds) {
PERR("dataspace for core context does not exist");
return 0;
}
if (!map_local(ds->phys_addr(),
(addr_t)local_addr + Native_config::context_area_virtual_base(),
ds->size() >> get_page_size_log2()))
return 0;
return local_addr;
}
void detach(Local_addr) { }
Pager_capability add_client(Thread_capability) {
return Pager_capability(); }
void fault_handler(Signal_context_capability) { }
State state() { return State(); }
Dataspace_capability dataspace() { return Dataspace_capability(); }
};
class Context_area_ram_session : public Ram_session
{
public:
Ram_dataspace_capability alloc(size_t size, bool)
{
/* find free context */
unsigned i;
for (i = 0; i < MAX_CORE_CONTEXTS; i++)
if (!context_ds[i])
break;
if (i == MAX_CORE_CONTEXTS) {
PERR("maximum number of core contexts (%d) reached", MAX_CORE_CONTEXTS);
return Ram_dataspace_capability();
}
/* allocate physical memory */
size = round_page(size);
void *phys_base;
if (platform_specific()->ram_alloc()->alloc_aligned(size, &phys_base,
get_page_size_log2()).is_error()) {
PERR("could not allocate backing store for new context");
return Ram_dataspace_capability();
}
context_ds[i] = new (platform()->core_mem_alloc())
Dataspace_component(size, 0, (addr_t)phys_base, false, true, 0);
/*
* We do not manage the dataspace via an entrypoint because it will
* only be used by the 'context_area_rm_session'. Therefore, we
* construct a "capability" by hand using the context ID as local
* name.
*/
Native_capability cap;
return reinterpret_cap_cast<Ram_dataspace>(Native_capability(cap.dst(), i));
}
void free(Ram_dataspace_capability ds) { PDBG("not yet implemented"); }
int ref_account(Ram_session_capability ram_session) { return 0; }
int transfer_quota(Ram_session_capability ram_session, size_t amount) { return 0; }
size_t quota() { return 0; }
size_t used() { return 0; }
};
/**
* Return single instance of the context-area RM and RAM session
*/
namespace Genode {
Rm_session *env_context_area_rm_session()
{
static Context_area_rm_session inst;
return &inst;
}
Ram_session *env_context_area_ram_session()
{
static Context_area_ram_session inst;
return &inst;
}
}

View File

@ -1,37 +0,0 @@
/*
* \brief Core-local RM session
* \author MArtin Stein
* \date 2010-09-09
*/
/*
* Copyright (C) 2010-2013 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 <map_local.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,
bool executable)
{
Object_pool<Dataspace_component>::Guard ds(_ds_ep->lookup_and_lock(ds_cap));
if (!ds)
throw Invalid_dataspace();
/* roottask is mapped identically */
return ds->phys_addr();
}

View File

@ -1,27 +0,0 @@
/*
* \brief Platform specific parts of CPU session
* \author Martin Stein
* \date 2012-11-27
*/
/*
* Copyright (C) 2012-2013 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 <dataspace/capability.h>
/* core includes */
#include <cpu_session_component.h>
using namespace Genode;
Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability) {
PDBG("Not implemented");
return Ram_dataspace_capability();
};

View File

@ -1,53 +0,0 @@
/*
* \brief Core-local region manager session
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2013 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,
bool executable = false);
void detach(Local_addr) { }
Pager_capability add_client(Thread_capability thread) {
return Pager_capability(); }
void fault_handler(Signal_context_capability handler) { }
State state() { return State(); }
Dataspace_capability dataspace() { return Dataspace_capability(); }
};
}
#endif /* _CORE__INCLUDE__CORE_RM_SESSION_H_ */

View File

@ -1,67 +0,0 @@
/*
* \brief Saver print methods than the luxury dynamic-number/type-of-arguments one's
* \author Martin Stein
* \date 2010-09-16
*/
/*
* Copyright (C) 2010-2013 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__XMB__PRINTS_H_
#define _INCLUDE__XMB__PRINTS_H_
#include <cpu/config.h>
enum { UART_OUT_REGISTER=0x84000004 };
inline static void _prints_chr1(volatile char chr1)
{
unsigned volatile* uart = (volatile unsigned*)UART_OUT_REGISTER;
*uart = chr1;
}
inline static void _prints_hex2(volatile char hex2)
{
volatile char hex1 = ((hex2 >> 4) & 0xf);
if (hex1 > 9) hex1 += 39;
hex1 += 48;
_prints_chr1((volatile char)hex1);
hex1 = hex2 & 0xf;
if (hex1 > 9) hex1 += 39;
hex1 += 48;
_prints_chr1((volatile char)hex1);
}
inline static void _prints_hex8(unsigned volatile hex8)
{
_prints_hex2((volatile char)(hex8 >> 24));
_prints_hex2((volatile char)(hex8 >> 16));
_prints_hex2((volatile char)(hex8 >> 8));
_prints_hex2((volatile char)(hex8 >> 0));
}
inline static void _prints_hex8l(unsigned volatile hex8)
{
_prints_hex8(hex8);
_prints_chr1('\n');
}
inline static void _prints_str0(const char* volatile str0)
{
while (*str0) _prints_chr1(*str0++);
}
#endif /* _INCLUDE__XMB__PRINTS_H_ */

View File

@ -1,73 +0,0 @@
/*
* \brief IRQ session interface for the Microblaze Kernel
* \author Norman Feske
* \author Martin Stein
* \date 2010-01-30
*/
/*
* Copyright (C) 2010-2013 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 <util/list.h>
#include <base/rpc_server.h>
#include <irq_session/capability.h>
namespace Genode {
class Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
enum { STACK_SIZE = 4096 };
unsigned _irq_number;
Range_allocator *_irq_alloc;
Rpc_entrypoint _entrypoint;
Irq_session_capability _cap;
bool _attached;
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 _cap; }
/***************************
** Irq session interface **
***************************/
void wait_for_irq();
};
}
#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@ -1,98 +0,0 @@
/*
* \brief Kernels syscall frontend
* \author Martin stein
* \date 2010.07.02
*/
#ifndef _INCLUDE__KERNEL__PRINT_H_
#define _INCLUDE__KERNEL__PRINT_H_
#include <kernel/syscalls.h>
namespace Kernel {
class Serial_port
{
/**
* Print constant integer < 2^4 as hexadecimal value
* to serial port via syscalls
*/
inline void _print_hex_4(unsigned char x);
public:
/**
* Print constant zero-terminated string via syscalls to serial port
*/
inline Serial_port &operator << (char const *s);
/**
* Print constant integer < 2^32 as hexadecimal value
* to serial port via syscalls (no leading zeros)
*/
inline Serial_port &operator << (unsigned int const &x);
};
/**
* Give static 'Serial_port' reference as target for stream operators
*/
inline Serial_port& serial_port();
}
Kernel::Serial_port& Kernel::serial_port()
{
static Serial_port _sp;
return _sp;
}
void Kernel::Serial_port::_print_hex_4(unsigned char x)
{
x &= 0x0f;
if (x > 9)
x += 39;
x += 48;
Kernel::print_char(x);
}
Kernel::Serial_port& Kernel::Serial_port::operator << (char const *s)
{
while (*s) print_char(*s++);
return *this;
}
Kernel::Serial_port& Kernel::Serial_port::operator << (unsigned int const &x)
{
enum{
BYTE_WIDTH = 8,
CW = sizeof(unsigned char)*BYTE_WIDTH,
IW = sizeof(unsigned int)*BYTE_WIDTH
};
bool leading = true;
for (int i = IW - CW; i >= 0; i = i - CW){
unsigned char c =(char)((x >> i) & 0xff);
if (leading) {
if (c == 0x00) {
if (i == 0)
_print_hex_4(c);
continue;
}
leading = false;
if (c < 0x10) {
_print_hex_4(c);
continue;
}
}
_print_hex_4(c >> 4);
_print_hex_4(c);
}
return *this;
}
#endif /* _INCLUDE__KERNEL__PRINT_H_ */

View File

@ -1,49 +0,0 @@
/*
* \brief Core-local mapping
* \author Norman Feske
* \date 2010-02-15
*
* These functions are normally doing nothing because core's using 1-to-1 paging at kernel
*/
/*
* Copyright (C) 2010-2013 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 _SRC__CORE__INCLUDE__MAP_LOCAL_H_
#define _SRC__CORE__INCLUDE__MAP_LOCAL_H_
/* Genode includes */
#include <base/printf.h>
/* core includes */
#include <util.h>
namespace Genode {
/**
* Map physical pages to core-local virtual address range
*
* Always true because roottask pager handles all core page faults
*/
inline bool map_local(addr_t from_phys, addr_t to_virt, size_t num_pages)
{
return true;
}
/**
* Unmap virtual pages from core-local virtual address range
*
* Does nothing because roottask pager handles all core page faults
*/
inline bool unmap_local(addr_t virt_addr, size_t num_pages)
{
return true;
}
}
#endif /* _SRC__CORE__INCLUDE__MAP_LOCAL_H_ */

View File

@ -1,118 +0,0 @@
/*
* \brief Platform interface
* \author Martin Stein
* \date 2010-09-08
*/
/*
* Copyright (C) 2010-2013 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 _SRC__CORE__INCLUDE__PLATFORM_H_
#define _SRC__CORE__INCLUDE__PLATFORM_H_
#include <base/printf.h>
#include <base/sleep.h>
#include <base/thread.h>
#include <base/sync_allocator.h>
#include <base/allocator_avl.h>
#include <platform_generic.h>
#include <kernel/syscalls.h>
#include <platform_pd.h>
#include <cpu/config.h>
namespace Roottask
{
enum {
PAGER_TID = User::MIN_THREAD_ID,
CONTEXT_PAGE_SIZE_LOG2 = Kernel::Utcb::ALIGNMENT_LOG2,
CONTEXT_PAGE_SIZE = 1<<CONTEXT_PAGE_SIZE_LOG2,
STACK_SIZE = Cpu::_4KB_SIZE,
CONTEXT_SIZE = STACK_SIZE + sizeof(Genode::Thread_base::Context),
};
/**
* The 'Platform_pd' instance according to roottask
*/
Genode::Platform_pd* platform_pd();
/**
* Baseaddress of the downward directed physical stack and the
* immediately following upward directed misc area belonging to
* a specific thread within the roottask
*/
Genode::Thread_base::Context * physical_context(Genode::Native_thread_id tid);
}
namespace Genode {
class Platform : public Platform_generic
{
private:
typedef Synchronized_range_allocator<Allocator_avl> Phys_allocator;
/*
* Core is mapped 1-to-1 physical-to-virtual except for the thread
* context area. mapping out of context area. So a single memory
* allocator suffices for both, assigning physical RAM to
* dataspaces and allocating core-local memory.
*/
Phys_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 */
/**
* Virtual address range usable by non-core processes
*/
addr_t _vm_base;
size_t _vm_size;
void _optimize_init_img_rom(long int & base, size_t const & size);
public:
virtual ~Platform() {}
/**
* Constructor
*/
Platform();
/********************************
** Generic platform interface **
********************************/
inline Range_allocator *ram_alloc() { return &_core_mem_alloc; }
inline Range_allocator *io_mem_alloc() { return &_io_mem_alloc; }
inline Range_allocator *io_port_alloc() { return &_io_port_alloc; }
inline Range_allocator *irq_alloc() { return &_irq_alloc; }
inline Range_allocator *region_alloc() { return 0; }
/**
* We need a 'Range_allocator' instead of 'Allocator' as in
* 'Platform_generic' to allocate aligned space for e.g. UTCB's
*/
inline Range_allocator *core_mem_alloc() { return &_core_mem_alloc; }
inline addr_t vm_start() const { return _vm_base; }
inline size_t vm_size() const { return _vm_size; }
inline Rom_fs *rom_fs() { return &_rom_fs; }
inline void wait_for_exit() { sleep_forever(); }
};
}
#endif /* _SRC__CORE__INCLUDE__PLATFORM_H_ */

View File

@ -1,267 +0,0 @@
/*
* \brief Protection-domain facility
* \author Martin Stein
* \date 2010-09-13
*/
/*
* Copyright (C) 2010-2013 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 _SRC__CORE__INCLUDE__PLATFORM_PD_H_
#define _SRC__CORE__INCLUDE__PLATFORM_PD_H_
/* core includes */
#include <platform_thread.h>
#include <base/thread.h>
#include <kernel/config.h>
namespace Genode {
class Platform_pd;
typedef Id_allocator<Platform_pd, Native_process_id, Cpu::BYTE_WIDTH> Pid_allocator;
Pid_allocator *pid_allocator();
class Platform_thread;
class Platform_pd
{
public:
typedef unsigned Context_id;
typedef Thread_base::Context Context;
private:
addr_t context_area_base() {
return Native_config::context_area_virtual_base();
}
addr_t context_area_size() {
return Native_config::context_area_virtual_size();
}
addr_t context_area_top() {
return context_area_base() + context_area_size();
}
addr_t context_size() {
return Native_config::context_virtual_size();
}
addr_t context_base_mask() {
return ~(Native_config::context_virtual_size() - 1);
}
addr_t context_offset_mask() {
return ~context_base_mask();
}
enum {
CONTEXT_SIZE = Native_config::CONTEXT_VIRTUAL_SIZE,
CONTEXT_AREA_SIZE = Native_config::CONTEXT_AREA_VIRTUAL_SIZE,
MAX_CONTEXT_ID = CONTEXT_AREA_SIZE / CONTEXT_SIZE - 1
};
Native_process_id _pid;
Native_thread_id owner_tid_by_context_id[MAX_CONTEXT_ID + 1];
void _free_context(Native_thread_id const & t)
{
for (Context_id cid = 0; cid <= MAX_CONTEXT_ID; cid++) {
if (owner_tid_by_context_id[cid] == t) {
owner_tid_by_context_id[cid] = 0;
}
}
}
public:
/**
* Constructors
*/
Platform_pd(signed pid = 0, bool create = true) : _pid(pid)
{
static bool const verbose = false;
if ((unsigned)User::MAX_THREAD_ID>(unsigned)MAX_CONTEXT_ID) {
PERR("More threads allowed than context areas available");
return;
}
if (!_pid)
_pid=pid_allocator()->allocate(this);
if (!_pid) {
PERR("Allocating new Process ID failed");
return;
}
if (verbose)
PDBG("Create protection domain %i", (unsigned int)_pid);
}
/**
* Destructor
*/
~Platform_pd() { }
enum Context_part{ NO_CONTEXT_PART = 0,
MISC_AREA = 1,
UTCB_AREA = 2,
STACK_AREA = 3 };
bool cid_if_context_address(addr_t a, Context_id* cid)
{
if (a < context_area_base() || a >= context_area_top())
return false;
addr_t context_base = a & context_base_mask();
*cid = (Context_id)((context_base-context_area_base()) / context_size());
return true;
}
Context *context(Context_id i)
{
return (Context*)(context_area_base()+(i+1)*context_size()-sizeof(Context));
}
Context *context_by_tid(Native_thread_id tid)
{
for (unsigned cid = 0; cid <= MAX_CONTEXT_ID; cid++)
if (owner_tid_by_context_id[cid] == tid)
return context(cid);
return 0;
}
bool metadata_if_context_address(addr_t a, Native_thread_id *context_owner_tid,
Context_part *cp, unsigned *stack_offset)
{
Context_id cid;
if (!cid_if_context_address(a, &cid))
return false;
if (cid > MAX_CONTEXT_ID) {
PERR("Context ID %i out of range", (unsigned int)cid);
return false;
}
*context_owner_tid = owner_tid_by_context_id[cid];
if (!*context_owner_tid) {
if (_pid == Roottask::PROTECTION_ID)
PERR("Context %p is not in use", (void*)a);
return false;
}
addr_t offset = a & context_offset_mask();
Context *context = (Context *)(context_size() - sizeof(Context));
if ((void*)offset >= &context->utcb) {
*cp = UTCB_AREA;
} else if ((void*)offset < &context->stack) {
*cp = STACK_AREA;
*stack_offset = (((unsigned)&(context->stack)) - (unsigned)offset);
} else {
*cp = MISC_AREA;
}
return true;
}
bool allocate_context(Native_thread_id tid, Context_id cid)
{
static bool const verbose = false;
if (cid > MAX_CONTEXT_ID)
return 0;
if (owner_tid_by_context_id[cid]){
PERR("Context is already in use");
return false;
}
owner_tid_by_context_id[cid] = tid;
if (verbose)
PDBG("Thread %i owns Context %i (0x%p) of PD %i",
tid, cid, context(cid), _pid);
return true;
}
Context *allocate_context(Native_thread_id tid)
{
static bool const verbose = false;
/*
* First thread is assumed to be the main thread and gets last
* context-area by convention
*/
if (!owner_tid_by_context_id[MAX_CONTEXT_ID]){
owner_tid_by_context_id[MAX_CONTEXT_ID] = tid;
if (verbose)
PDBG("Thread %i owns Context %i (0x%p) of Protection Domain %i",
tid, MAX_CONTEXT_ID, context(MAX_CONTEXT_ID), _pid);
return context(MAX_CONTEXT_ID);
}
for (unsigned i = 0; i <= MAX_CONTEXT_ID - 1; i++) {
if (!owner_tid_by_context_id[i]) {
owner_tid_by_context_id[i] = tid;
if (verbose)
PDBG("Thread %i owns Context %i (0x%p) of Protection Domain %i",
tid, MAX_CONTEXT_ID, context(MAX_CONTEXT_ID), _pid);
return context(i);
}
}
return 0;
}
/**
* Bind thread to protection domain
*
* \return 0 on success
*/
inline int bind_thread(Platform_thread* pt)
{
Context *context = allocate_context(pt->tid());
if (!context) {
PERR("Context allocation failed");
return -1;
}
Native_utcb *utcb = &context->utcb;
pt->_assign_physical_thread(_pid, utcb, this);
return 0;
}
/**
* Unbind thread from protection domain
*
* Free the thread's slot and update thread object.
*/
inline void unbind_thread(Platform_thread *pt)
{
_free_context(pt->tid());
}
/**
* Free a context so it is allocatable again
* \param c PD wide unique context ID
*/
void free_context(Context_id const & c)
{
if (c > MAX_CONTEXT_ID) { return; }
owner_tid_by_context_id[c] = Kernel::INVALID_THREAD_ID;
}
/**
* Assign parent interface to protection domain
*/
inline int assign_parent(Native_capability parent) { return 0; }
};
}
#endif /* _SRC__CORE__INCLUDE__PLATFORM_PD_H */

View File

@ -1,166 +0,0 @@
/*
* \brief Thread facility
* \author Martin Stein
* \date 2010-09-13
*/
/*
* Copyright (C) 2010-2013 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 _SRC__CORE__INCLUDE__PLATFORM_THREAD_H_
#define _SRC__CORE__INCLUDE__PLATFORM_THREAD_H_
#include <base/pager.h>
#include <base/thread_state.h>
#include <base/thread.h>
#include <base/native_types.h>
#include <kernel/config.h>
#include <util/id_allocator.h>
namespace Genode {
class Platform_thread;
typedef Id_allocator<Platform_thread, Native_thread_id, Cpu::BYTE_WIDTH> Tid_allocator;
Tid_allocator* tid_allocator();
/**
* Base of the physical UTCB belonging to a specific thread
*/
Kernel::Utcb* physical_utcb(Native_thread_id tid);
/**
* Set physical UTCB address according to a specific thread ID.
* Useful to propagate UTCB address when allocating the whole context
* at a stretch as e.g. in core
*/
int physical_utcb(Native_thread_id const &tid, Kernel::Utcb * const &utcb);
class Platform_pd;
class Platform_thread
{
private:
friend class Platform_pd;
Native_thread_id _tid; /* global kernel thread ID */
Native_process_id _pid;
Native_utcb* _utcb;
Pager_object *_pager;
uint32_t _params;
/* for debugging purpose only */
Platform_pd* _pd;
/**
* Assign physical thread ID and UTCB address to thread
*
* This function is called from 'Platform_pd::bind_thread'.
*/
void _assign_physical_thread(int pid, Native_utcb* utcb, Platform_pd* pd)
{
_utcb = utcb;
_pid = pid;
_pd = pd;
}
public:
unsigned pid(){ return (unsigned)_pid; }
unsigned tid(){ return (unsigned)_tid; }
enum { THREAD_INVALID = -1 }; /* invalid thread number */
/**
* Constructor
*/
Platform_thread(const char *name = 0, unsigned priority = 0,
int thread_id = THREAD_INVALID, uint32_t params = 0);
/**
* 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();
/**
* Override thread state with 's'
*
* \throw Cpu_session::State_access_failed
*/
void state(Thread_state s);
/**
* Read thread state
*
* \throw Cpu_session::State_access_failed
*/
Thread_state state();
/************************
** Accessor functions **
************************/
/**
* Set pager capability
*/
inline Pager_object *pager() { return _pager; }
inline void pager(Pager_object *pager) { _pager = pager; }
/**
* Return identification of thread when faulting
*/
inline unsigned long pager_object_badge() const { return _tid; }
/**
* Set the executing CPU for this thread
*/
void affinity(unsigned cpu);
/**
* Get thread name
*/
inline const char *name() const { return "noname"; }
/*********************
** Kernel specific **
*********************/
inline addr_t utcb() const { return (addr_t)_utcb; }
};
}
#endif /* _SRC__CORE__INCLUDE__PLATFORM_THREAD_H_ */

View File

@ -1,55 +0,0 @@
/*
* \brief Core-internal utilities
* \author Martin Stein
* \date 2010-09-08
*/
/*
* Copyright (C) 2010-2013 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 _SRC__CORE__INCLUDE__UTIL_H_
#define _SRC__CORE__INCLUDE__UTIL_H_
/* Genode includes */
#include <rm_session/rm_session.h>
#include <base/printf.h>
/* Kernel includes */
#include <kernel/syscalls.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 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 phys; }
inline size_t constrain_map_size_log2(size_t size_log2)
{
if (size_log2<14) return 12;
if (size_log2<16) return 14;
if (size_log2<18) return 16;
if (size_log2<20) return 18;
if (size_log2<22) return 20;
if (size_log2<24) return 22;
return 24;
}
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);
}
}
#endif /* _CORE__INCLUDE__UTIL_H_ */

View File

@ -1,21 +0,0 @@
/*
* \brief Utils to ease the work with arrays
* \author Martin stein
* \date 2011-03-22
*/
/*
* Copyright (C) 2011-2013 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__UTIL__ARRAY_H_
#define _INCLUDE__UTIL__ARRAY_H_
#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
#define MAX_ARRAY_ID(array) (ARRAY_SIZE(array)-1)
#define LAST_ARRAY_ELEM(array) array[MAX_ARRAY_ID(array)]
#endif /* _INCLUDE__UTIL__ARRAY_H_ */

View File

@ -1,62 +0,0 @@
/*
* \brief Some tools for general purpose debugging
* \author Martin stein
* \date 2011-04-06
*/
/*
* Copyright (C) 2011-2013 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__UTIL__DEBUG_H_
#define _INCLUDE__UTIL__DEBUG_H_
#include <cpu/config.h>
#include <base/printf.h>
namespace Debug {
/**
* Print out address and the according 32 bit memory-value
* XXX Should print a word instead of a fixed bitwidth XXX
*/
inline void dump(Cpu::addr_t const & a);
/**
* Print memory-contents of a given area over the local addressspace
* as list with the according addresses in front
*/
inline void dump(Cpu::addr_t const & base, Cpu::size_t const & size,
bool downward = false);
};
void Debug::dump(Cpu::addr_t const & a) {
printf("%8X: %8X", (Cpu::uint32_t)a, *((Cpu::uint32_t*)a));
}
void Debug::dump(Cpu::addr_t const & base, Cpu::size_t const & size,
bool downward)
{
using namespace Genode;
Cpu::addr_t top = base + size;
if(!downward) {
for(Cpu::addr_t i=base; i<top;) {
dump(i);
i = i+Cpu::WORD_SIZE;
}
return;
}
for(Cpu::addr_t i=top; i>=base;) {
i = i-Cpu::WORD_SIZE;
dump(i);
}
}
#endif /* _INCLUDE__UTIL__DEBUG_H_ */

View File

@ -1,122 +0,0 @@
/*
* \brief Allocator for ID-labeled resources
* \author Martin Stein
* \date 2010-09-13
*/
/*
* Copyright (C) 2010-2013 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__UTIL__ID_ALLOCATOR_H_
#define _INCLUDE__UTIL__ID_ALLOCATOR_H_
/**
* \param HOLDER_T type that should hold ID's
* \param ID_T type of the allocatable ID's should be
* an enumeration type that expresses a variety
* less than the CPUs word width to the power of 2
* \param BYTE_WIDTH the CPU's bytewidth
*/
template<typename HOLDER_T, typename ID_T, unsigned BYTE_WIDTH>
class Id_allocator
{
enum {
ID_WIDTH = sizeof(ID_T)*BYTE_WIDTH,
ID_RANGE = 1 << ID_WIDTH
};
ID_T _first_allocatable;
ID_T _last_allocatable;
bool _id_in_use[ID_RANGE];
HOLDER_T *_holder_by_id[ID_RANGE];
public:
Id_allocator() :
_first_allocatable(0),
_last_allocatable(ID_RANGE-1)
{
for (unsigned i = _first_allocatable;
i <= _last_allocatable; i++)
_id_in_use[i]=false;
}
Id_allocator(ID_T first, ID_T last) :
_first_allocatable(first),
_last_allocatable(last)
{
for (unsigned i = _first_allocatable;
i <= _last_allocatable; i++)
_id_in_use[i]=false;
}
ID_T allocate()
{
for (unsigned i = _first_allocatable;
i <= _last_allocatable; i++) {
if (_id_in_use[i])
continue;
_id_in_use[i] = true;
_holder_by_id[i] = 0;
return (ID_T)i;
}
PERR("All ID's in use");
return (ID_T)0;
}
ID_T allocate(HOLDER_T* o)
{
for (unsigned i = _first_allocatable;
i <= _last_allocatable; i++) {
if (_id_in_use[i])
continue;
_id_in_use[i] = true;
_holder_by_id[i] = o;
return (ID_T)i;
}
PERR("All ID's in use");
return (ID_T)0;
}
bool allocate(HOLDER_T *o, ID_T id)
{
if (id < _first_allocatable || id > _last_allocatable) {
PERR("ID unallocatable");
return false;
}
if (!_id_in_use[id]) {
_id_in_use[id] = true;
_holder_by_id[id] = o;
return true;
}
else{
PERR("ID in use");
return false;
}
}
HOLDER_T *holder(ID_T id) { return _holder_by_id[id]; }
void free(ID_T id)
{
_id_in_use[id]=false;
_holder_by_id[id]=0;
}
};
#endif /*_INCLUDE__UTIL__ID_ALLOCATOR_H_*/

View File

@ -1,40 +0,0 @@
/*
* \brief Core-internal utilities
* \author Martin Stein
* \date 2011-03-17
*/
/*
* Copyright (C) 2011-2013 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__UTIL__MATH_H_
#define _INCLUDE__UTIL__MATH_H_
namespace Math
{
template <typename T>
inline T round_up(T v, T rounding_log2);
template <typename T>
inline T round_down(T v, T rounding_log2);
}
template <typename T>
T Math::round_up(T v, T rounding_log2)
{
return round_down(v + (1<<rounding_log2) - 1, rounding_log2) ;
}
template <typename T>
T Math::round_down(T v, T rounding_log2)
{
return v & ~((1 << rounding_log2) - 1);
}
#endif /* _INCLUDE__UTIL__MATH_H_ */

View File

@ -1,145 +0,0 @@
/*
* \brief Queue with first-in first-out semantics
* \author Norman Feske
* \date 2008-08-15
*/
/*
* Copyright (C) 2008-2013 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__UTIL__QUEUE_H_
#define _INCLUDE__UTIL__QUEUE_H_
namespace Kernel {
/*
* \param QT queue element type
*/
template <typename QT>
class Queue
{
protected:
QT *_head; /* oldest element */
QT *_tail; /* newest element */
public:
class Item
{
protected:
friend class Queue;
QT *_next;
public:
Item() : _next(0) {}
~Item() { }
// /**
// * Return true is fifo element is enqueued in a fifo
// */
// bool is_enqueued() { return _next != 0; }
};
public:
QT* head(){ return _head; }
/**
* Return true if queue is empty
*/
bool empty() { return _tail == 0; }
/**
* Constructor
*
* Start with an empty list.
*/
Queue(): _head(0), _tail(0) { }
/**
* Destructor
*/
virtual ~Queue() { }
/**
* Attach element at the end of the queue
*/
void enqueue(QT *e)
{
e->_next = 0;
if (empty())
_tail = _head = e;
else {
_tail->_next = e;
_tail = e;
}
_enqueue__verbose__success();
}
/**
* Obtain head element of the queue and remove element from queue
*
* \return head element or 0 if queue is empty
*/
QT *dequeue()
{
QT *result = _head;
/* check if queue has only one last element */
if (_head == _tail)
_head = _tail = 0;
else
_head = _head->_next;
/* mark fifo queue element as free */
if (result)
result->_next = 0;
return result;
}
/**
* Remove element from queue if it is enqueued
*/
void remove(QT *e)
{
QT* current=_head;
QT* predecessor=0;
if (current!=e){
while (1){
predecessor=current;
current=current->_next;
if (current==e || !current)
break;
}
} else {
dequeue();
return;
}
if (!current) return;
if (current==_tail) _tail=predecessor;
predecessor->_next=e->_next;
e->_next=0;
}
protected:
virtual void _enqueue__verbose__success(){}
};
}
#endif /* _INCLUDE__UTIL__QUEUE_H_ */

View File

@ -1,403 +0,0 @@
/*
* \brief Implementation of the Microblaze MMU
* \author Martin Stein
* \date 2010-11-08
*/
/*
* Copyright (C) 2010-2013 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__DEVICES__XILINX_MICROBLAZE_H_
#define _INCLUDE__DEVICES__XILINX_MICROBLAZE_H_
#include <cpu/config.h>
#include <base/printf.h>
#include <util/math.h>
#include <util/array.h>
namespace Xilinx {
struct Microblaze
{
typedef Cpu::uint8_t Protection_id;
typedef Cpu::uint32_t Register;
class Mmu {
enum Error {
SUCCESS = 0,
INVALID_ENTRY_ID = -1,
INVALID_PAGE_SIZE = -2,
};
enum {
VERBOSE = 0,
USE_PROTECTION_ZONES = 0,
UTLB_SIZE = 64,
TLBLO_GUARDED_LSHIFT = 0,
TLBLO_MEMCOHER_LSHIFT = 1,
TLBLO_INHIBCACHE_LSHIFT = 2,
TLBLO_WTHROUGH_LSHIFT = 3,
TLBLO_ZONE_LSHIFT = 4,
TLBLO_WRITEABLE_LSHIFT = 8,
TLBLO_EXECUTABLE_LSHIFT = 9,
TLBLO_REALPAGE_LSHIFT = 10, TLBLO_REALPAGE_MASK=0x3fffff,
TLBHI_USER_LSHIFT = 4,
TLBHI_ENDIAN_LSHIFT = 5,
TLBHI_VALID_LSHIFT = 6,
TLBHI_SIZE_LSHIFT = 7, TLBHI_SIZE_MASK = 0x7,
TLBHI_TAG_LSHIFT = 10, TLBHI_TAG_MASK = 0x3fffff,
};
public:
typedef Cpu::uint8_t Entry_id;
enum { MAX_ENTRY_ID = UTLB_SIZE - 1, };
struct Page
{
typedef Cpu::uint8_t Size_id;
enum {
MAX_SIZE_LOG2 = 24,
MAX_SIZE_ID = 7,
INVALID_SIZE_ID = MAX_SIZE_ID+1,
};
/**
* Translation between the native size ID's and the real memory size
* the page covers
*/
static inline unsigned int size_id_to_size_log2(Size_id const & i);
static inline Size_id size_log2_to_size_id(unsigned int const & size_log2);
};
private:
/**
* Focus further operations on a specific entry
*/
inline void _entry(Entry_id & i);
/**
* Read basic informations from a specific TLB entry
*/
inline void _entry(Entry_id & i,
Register & tlblo,
Register & tlbhi,
Protection_id & pid);
/**
* Protection zones constrain access to mappings additionally,
* disable this feature
*/
inline void _disable_protection_zones();
public:
/**
* Constructor
*/
inline Mmu();
/**
* Get some informations about a specific TLB entry
*/
inline signed int get_entry(Entry_id & i, Cpu::addr_t & vbase,
Protection_id & pid, unsigned int & size_log2);
/**
* Get all informations about a specific TLB entry
*/
inline signed int get_entry(Entry_id & i, Cpu::addr_t & pb, Cpu::addr_t & vb,
Protection_id & pid, unsigned int & size_log2,
bool & writeable, bool & executable);
/**
* Overwrite a specific TLB entry with a new resolution
*/
inline signed int set_entry(Entry_id i, Cpu::addr_t const & pb, Cpu::addr_t const & vb,
Protection_id const & pid, unsigned int const & size_log2,
bool const & writeable, bool const & executable);
/**
* Render a specific TLB entry ineffective
*/
inline void clear_entry(Entry_id i);
/**
* Maximum available entry ID
*/
static inline Entry_id max_entry_id() { return (Entry_id) MAX_ENTRY_ID; };
};
/**
* Read the current stack-pointer
*/
ALWAYS_INLINE static inline Cpu::addr_t stack_pointer();
/**
* Read, write and exchange the current protection ID
*/
static inline Protection_id protection_id();
static inline void protection_id(Protection_id i);
static inline void protection_id(Protection_id & o, Protection_id n);
inline Mmu * mmu();
};
}
/**************************************
* Xilinx::Microblaze implementations *
**************************************/
Cpu::addr_t Xilinx::Microblaze::stack_pointer()
{
Register sp;
asm volatile("add %[sp], r1, r0" :[sp]"=r"(sp)::);
return (Cpu::addr_t)sp;
}
Xilinx::Microblaze::Mmu * Xilinx::Microblaze::mmu() {
static Mmu _mmu;
return &_mmu;
}
Xilinx::Microblaze::Protection_id Xilinx::Microblaze::protection_id()
{
Protection_id i;
asm volatile ("mfs %[i], rpid"
: [i] "=r" (i) ::);
return i;
}
void Xilinx::Microblaze::protection_id(Protection_id i)
{
asm volatile ("mts rpid, %[i] \n"
"bri 4"
: [i] "+r" (i) ::);
}
void Xilinx::Microblaze::protection_id(Protection_id & o, Protection_id n)
{
asm volatile ("mfs %[o], rpid \n"
"mts rpid, %[n] \n"
"bri 4"
: [o] "=r" (o),
[n] "+r" (n) ::);
}
/*******************************************
* Xilinx::Microblaze::Mmu implementations *
*******************************************/
Xilinx::Microblaze::Mmu::Mmu()
{
if (!USE_PROTECTION_ZONES) { _disable_protection_zones(); }
else { PERR("Protection zones not supported"); }
}
void Xilinx::Microblaze::Mmu::_disable_protection_zones()
{
asm volatile ("addik r31, r0, 0xC0000000 \n"
"mts rzpr, r31 \n"
"bri 4"
::: "r31" );
}
signed int Xilinx::Microblaze::Mmu::get_entry(Entry_id & i, Cpu::addr_t & vb,
Protection_id & pid, unsigned int & size_log2)
{
if(i>MAX_ENTRY_ID) { return INVALID_ENTRY_ID; };
Protection_id opid = protection_id();
/* Read TLB entry */
asm volatile ("mts rtlbx, %[i] \n"
"bri 4 \n"
"mfs %[vb], rtlbhi \n"
"mfs %[pid], rpid"
: [i] "+r" (i),
[vb] "=r" (vb),
[pid] "=r" (pid) ::);
protection_id(opid);
/**
* Decode informations
*/
Page::Size_id const s = (vb & (TLBHI_SIZE_MASK<<TLBHI_SIZE_LSHIFT))>>TLBHI_SIZE_LSHIFT;
size_log2 = Page::size_id_to_size_log2(s);
vb = Math::round_down<Cpu::addr_t>(vb, size_log2);
return SUCCESS;
}
signed int Xilinx::Microblaze::Mmu::get_entry(Entry_id & i, Cpu::addr_t & pb, Cpu::addr_t & vb,
Protection_id & pid, unsigned int & size_log2,
bool & writeable, bool & executable)
{
if(i>MAX_ENTRY_ID) { return INVALID_ENTRY_ID; };
Protection_id opid = protection_id();
/* Read TLB entry */
asm volatile ("mts rtlbx, %[i] \n"
"bri 4 \n"
"mfs %[pb], rtlblo \n"
"mfs %[vb], rtlbhi \n"
"mfs %[pid], rpid"
: [i] "+r" (i),
[pb] "=r" (pb),
[vb] "=r" (vb),
[pid] "=r" (pid) ::);
protection_id(opid);
/**
* Decode informations
*/
writeable = pb & (1<<TLBLO_WRITEABLE_LSHIFT);
executable = pb & (1<<TLBLO_EXECUTABLE_LSHIFT);
Page::Size_id const s = (vb & (TLBHI_SIZE_MASK<<TLBHI_SIZE_LSHIFT))>>TLBHI_SIZE_LSHIFT;
size_log2 = Page::size_id_to_size_log2(s);
pb = Math::round_down<Cpu::addr_t>(pb, size_log2);
vb = Math::round_down<Cpu::addr_t>(vb, size_log2);
return SUCCESS;
}
signed int Xilinx::Microblaze::Mmu::set_entry(Entry_id i, Cpu::addr_t const & pb, Cpu::addr_t const & vb,
Protection_id const & pid, unsigned int const & size_log2,
bool const & writeable, bool const & executable)
{
Protection_id opid;
protection_id(opid, pid);
/**
* Create TLBLO register value
*/
Register tlblo = (Register)Math::round_down<Cpu::addr_t>(pb, size_log2);
tlblo |= writeable << TLBLO_WRITEABLE_LSHIFT;
tlblo |= executable << TLBLO_EXECUTABLE_LSHIFT;
/**
* Create TLBHI register value
*/
Register tlbhi = Math::round_down<Cpu::addr_t>(vb, size_log2);
tlbhi |= 1 << TLBHI_VALID_LSHIFT;
Page::Size_id s = Page::size_log2_to_size_id(size_log2);
if(s == Page::INVALID_SIZE_ID) { return INVALID_PAGE_SIZE; }
tlbhi |= ((s & TLBHI_SIZE_MASK) << TLBHI_SIZE_LSHIFT);
/* Write TLB entry */
asm volatile ("mts rtlbx, %[i] \n"
"bri 4 \n"
"mts rtlblo, %[tlblo] \n"
"bri 4 \n"
"mts rtlbhi, %[tlbhi] \n"
"bri 4"
: [i] "+r" (i),
[tlblo] "+r" (tlblo),
[tlbhi] "+r" (tlbhi) ::);
if(VERBOSE)
{
PINF("TLB + %2u[0x%8X..0x%8X) r%c%c\n"
" [0x%8X..0x%8X) 2**%i\n",
pid, Math::round_down<Cpu::uint32_t>(vb, size_log2),
Math::round_down<Cpu::uint32_t>(vb+(1<<size_log2), size_log2),
executable ? 'x' : '-', writeable ? 'w' : '-',
Math::round_down<Cpu::uint32_t>(pb, size_log2),
Math::round_down<Cpu::uint32_t>(pb+(1<<size_log2), size_log2),
size_log2);
}
protection_id(opid);
return SUCCESS;
}
void Xilinx::Microblaze::Mmu::clear_entry(Entry_id i)
{
if(i>MAX_ENTRY_ID) { return; };
Protection_id pid = protection_id();
if(VERBOSE) {
Cpu::addr_t page;
Protection_id pid;
unsigned size_log2;
if(!get_entry(i, page, pid, size_log2)) {
PINF("TLB - %i[0x%8X..0x%8X] 2**%i",
pid, (Cpu::uint32_t)page,
(Cpu::uint32_t)page+(1<<size_log2), size_log2);
}
}
/* Zero-fill TLB entry */
asm volatile("mts rtlbx, %[i] \n"
"bri 4 \n"
"mts rpid, r0 \n"
"bri 4 \n"
"mts rtlbhi, r0 \n"
"bri 4 \n"
"mts rtlblo, r0 \n"
"bri 4"
: [i] "+r" (i) ::);
protection_id(pid);
}
/*************************************************
* Xilinx::Microblaze::Mmu::Page implementations *
*************************************************/
Xilinx::Microblaze::Mmu::Page::Size_id
Xilinx::Microblaze::Mmu::Page::size_log2_to_size_id(unsigned int const & size_log2)
{
static signed int const _size_log2_to_size_id [MAX_SIZE_LOG2+1] =
{ INVALID_SIZE_ID, INVALID_SIZE_ID, INVALID_SIZE_ID, INVALID_SIZE_ID, INVALID_SIZE_ID,
INVALID_SIZE_ID, INVALID_SIZE_ID, INVALID_SIZE_ID, INVALID_SIZE_ID, INVALID_SIZE_ID,
0, INVALID_SIZE_ID, 1, INVALID_SIZE_ID,
2, INVALID_SIZE_ID, 3, INVALID_SIZE_ID,
4, INVALID_SIZE_ID, 5, INVALID_SIZE_ID,
6, INVALID_SIZE_ID, 7 };
if(size_log2>MAX_ARRAY_ID(_size_log2_to_size_id)) { return INVALID_SIZE_ID; }
return (unsigned int)_size_log2_to_size_id[size_log2];
}
unsigned int Xilinx::Microblaze::Mmu::Page::size_id_to_size_log2(Size_id const & i)
{
static unsigned const _size_id_to_size_log2 [MAX_SIZE_ID+1] =
{ 10, 12, 14, 16, 18, 20, 22, 24 };
if(i>ARRAY_SIZE(_size_id_to_size_log2)-1) { return 0; }
return (unsigned int)_size_id_to_size_log2[i];
}
#endif /* _INCLUDE__DEVICES__XILINX_MICROBLAZE_H_ */

View File

@ -1,28 +0,0 @@
/*
* \brief Implementation of the IO_MEM session interface
* \author Norman Feske
* \author Martin Stein
* \date 2010-09-09
*/
/*
* Copyright (C) 2010-2013 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 <io_mem_session_component.h>
using namespace Genode;
void Io_mem_session_component::_unmap_local(addr_t base, size_t size)
{ }
addr_t Io_mem_session_component::_map_local(addr_t base, size_t size)
{
/* Core memory gets mapped 1:1 except of the context area */
return base;
}

View File

@ -1,68 +0,0 @@
/*
* \brief Implementation of IRQ session component
* \author Norman Feske
* \author Martin Stein
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2013 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>
#include <base/printf.h>
#include <irq_root.h>
#include <kernel/syscalls.h>
#include <base/sleep.h>
#include <xilinx/xps_timer.h>
using namespace Genode;
void Irq_session_component::wait_for_irq()
{
using namespace Xilinx;
if (!_attached) {
if(Kernel::irq_allocate(_irq_number)) {
PERR("Kernel::irq_allocate(%i) failed", _irq_number);
sleep_forever();
}
_attached = true;
}
Kernel::irq_wait();
}
Irq_session_component::Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args)
:
_irq_alloc(irq_alloc),
_entrypoint(cap_session, STACK_SIZE, "irq"),
_attached(false)
{
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (!_irq_alloc || (irq_number == -1) ||
_irq_alloc->alloc_addr(1, irq_number).is_error())
{
PERR("unavailable IRQ %lx requested", irq_number);
return;
}
_irq_number = irq_number;
_entrypoint.activate();
_cap = Irq_session_capability(_entrypoint.manage(this));
}
Irq_session_component::~Irq_session_component()
{
_irq_alloc->free((void*)_irq_number, 1);
if (_attached) {
if(Kernel::irq_free(_irq_number)){
PERR("Kernel::irq_free failed");
}
}
}

View File

@ -1,312 +0,0 @@
/*
* \brief Platform interface implementation
* \author Martin Stein
* \date 2010-09-08
*/
/*
* Copyright (C) 2010-2013 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/printf.h>
#include <core_parent.h>
#include <platform.h>
#include <map_local.h>
#include <kernel/syscalls.h>
#include <cpu/config.h>
#include <util/math.h>
static bool const verbose = 0;
extern unsigned _program_image_begin;
extern unsigned _program_image_end;
extern unsigned _boot_modules_meta_start;
extern unsigned _boot_modules_meta_end;
namespace Roottask
{
/**
* Entry for the core-pager-thread that handles all
* pagefaults belonging to core-threads. Itself has
* to be paged 1:1 by the kernel. Core pager maps all
* 1:1 except of the thread-context-area
*/
static void pager();
static Kernel::Utcb pager_utcb;
static Cpu::word_t pager_stack[Cpu::_4KB_SIZE];
}
Genode::Thread_base::Context * Roottask::physical_context(Genode::Native_thread_id tid)
{
using namespace Cpu;
using Genode::Thread_base;
static const unsigned int aligned_size =
Math::round_up<unsigned int>(CONTEXT_SIZE,
CONTEXT_PAGE_SIZE_LOG2);
static Thread_base::Context * _context[User::MAX_THREAD_ID];
if (tid >= sizeof(_context)/sizeof(_context[0])) {
PERR("Native thread ID out of range");
return 0;
}
if(!_context[tid]) {
/* Allocate new context */
if (Genode::platform_specific()
->core_mem_alloc()
->alloc_aligned(aligned_size,
(void**)&_context[tid],
CONTEXT_PAGE_SIZE_LOG2).is_error())
{
PERR("Allocate memory for a new stack- and misc-area failed");
return 0;
}
_context[tid] = (Thread_base::Context*)((addr_t)_context[tid] +
aligned_size - sizeof(Thread_base::Context));
/* Synchronize output of 'Genode::physical_utcb' if alignment fits */
if(Math::round_up<addr_t>((addr_t)&_context[tid]->utcb,
Kernel::Utcb::ALIGNMENT_LOG2)!=
(addr_t)&_context[tid]->utcb)
{
PINF("%8X, %8X", (unsigned)Math::round_up<addr_t>((addr_t)&_context[tid]->utcb,
Kernel::Utcb::ALIGNMENT_LOG2), (unsigned)&_context[tid]->utcb);
PWRN("Wrong UTCB alignment in context");
} else {
Genode::physical_utcb(tid, (Kernel::Utcb*)&_context[tid]->utcb);
}
if(verbose) {
PDBG("Context %i: [%p|%p|%p|%p]", tid,
(void*)((addr_t)_context[tid] + sizeof(Thread_base::Context) - aligned_size),
(Thread_base::Context*)((addr_t)_context[tid] - STACK_SIZE),
_context[tid], &_context[tid]->utcb);
}
}
return _context[tid];
}
void Roottask::pager()
{
using namespace Genode;
using namespace Roottask;
typedef Platform_pd::Context_part Context_part;
typedef Kernel::Paging::Request Request;
typedef Kernel::Paging::Physical_page Physical_page;
static Physical_page::size_t context_page_size;
if(Physical_page::size_by_size_log2(context_page_size, CONTEXT_PAGE_SIZE_LOG2)){
PERR("Invalid page size for thread context area");
}
Request *r = (Request*)&pager_utcb;
while (1) {
unsigned request_length = Kernel::ipc_serve(0);
if (request_length != sizeof(Request)) {
PERR("Invalid request");
continue;
}
addr_t pa = 0;
Physical_page::size_t ps = Physical_page::INVALID_SIZE;
addr_t va = r->virtual_page.address();
Native_thread_id context_owner = 0;
Context_part context_part = Platform_pd::NO_CONTEXT_PART;
unsigned stack_offset = 0;
if (platform_pd()->metadata_if_context_address(va, &context_owner,
&context_part,
&stack_offset))
{
switch (context_part) {
case Platform_pd::STACK_AREA:
{
Cpu::word_t* pstack = (Cpu::word_t*)physical_context(context_owner);
pa = (addr_t)(pstack-(stack_offset/sizeof(Cpu::word_t)));
break;
}
case Platform_pd::UTCB_AREA:
pa = (addr_t)physical_utcb(context_owner);
break;
case Platform_pd::MISC_AREA:
pa = (addr_t)physical_context(context_owner)->stack;
break;
default:
PERR("No roottask mapping, "
"vaddr=0x%p, tid=%i, ip=%p\n",
(void*)r->virtual_page.address(),
r->source.tid,
(void*)r->source.ip);
break;
}
ps = context_page_size;
} else {
pa = va;
ps = Physical_page::MAX_VALID_SIZE;
}
Kernel::tlb_load(pa, va, r->virtual_page.protection_id(),
ps, Physical_page::RWX);
Kernel::thread_wake(r->source.tid);
}
}
void Genode::Platform::_optimize_init_img_rom(long int & base, size_t const & size)
{
enum {
INIT_TEXT_SEGM_ALIGN_LOG2 = Cpu::_64KB_SIZE_LOG2,
INIT_TEXT_SEGM_ALIGN = 1 << INIT_TEXT_SEGM_ALIGN_LOG2,
ELF_HEADER_SIZE = Cpu::_4KB_SIZE
};
/* Preserve old location for now */
long int const old_base = base;
_core_mem_alloc.remove_range((addr_t)old_base, size);
/* Search for location where text-segment would be mapable
* with pages of size INIT_TEXT_SEGM_ALIGN */
if (_core_mem_alloc.alloc_aligned(size + 2*INIT_TEXT_SEGM_ALIGN,
(void**)&base, INIT_TEXT_SEGM_ALIGN_LOG2).is_ok())
{
/* Found better location so move */
base = base + INIT_TEXT_SEGM_ALIGN - ELF_HEADER_SIZE;
memcpy((void*)base, (void*)old_base, size);
_core_mem_alloc.add_range((addr_t)old_base, size);
return;
}
/* Keep old location */
base = old_base;
}
Genode::Platform::Platform() :
_core_mem_alloc(0),
_io_mem_alloc(core_mem_alloc()), _io_port_alloc(core_mem_alloc()),
_irq_alloc(core_mem_alloc()), _vm_base(0), _vm_size(0)
{
using namespace Roottask;
using namespace Genode;
_core_mem_alloc.add_range((addr_t)Cpu::RAM_BASE, (size_t)Cpu::RAM_SIZE);
/***************************************************
* Avoid allocations on '_core_mem_alloc' since it *
* contains space yet that is in use *
***************************************************/
/* Preserve core's program image range with page-granularity from allocation */
addr_t const img_base = trunc_page((addr_t)&_program_image_begin);
size_t const img_size = round_page((addr_t)&_program_image_end) - img_base;
_core_mem_alloc.remove_range(img_base, img_size);
/* Preserve core's context area with page-granularity from allocation */
addr_t const ctxt_area_base = trunc_page((addr_t)Native_config::context_area_virtual_base());
size_t const ctxt_area_size = round_page((addr_t)Native_config::context_area_virtual_base());
_core_mem_alloc.remove_range(ctxt_area_base, ctxt_area_size);
/* Preserve UART MMIO with page-granularity from allocation */
addr_t const uart_base = trunc_page(User::UART_BASE);
_core_mem_alloc.remove_range(uart_base, get_page_size());
/* Format of module meta-data as found in the ROM module image */
struct Boot_module
{
long name; /* physical address of null-terminated string */
long base; /* physical address of module data */
long size; /* size of module data in bytes */
};
addr_t const md_base = (addr_t)&_boot_modules_meta_start;
addr_t const md_top = (addr_t)&_boot_modules_meta_end;
size_t const meta_size = md_top - md_base;
if (meta_size > get_page_size()) {
PERR("Boot modules header is larger than supported");
sleep_forever();
}
Boot_module * module = (Boot_module *)md_base;
Boot_module * init_module=0;
/* Preserve boot modules from allocation */
for (; (addr_t)module < md_top; module++) {
const char *name = (const char*)module->name;
/* Init's module will need allocation because we optimize its location */
if (!strcmp(name, "init"))
{
init_module = module;
continue;
}
_core_mem_alloc.remove_range(trunc_page(module->base),
round_page(module->size));
}
_optimize_init_img_rom(init_module->base, init_module->size);
_core_mem_alloc.remove_range(trunc_page(init_module->base),
round_page(init_module->size));
/*****************************************************************
* from now on it's save to allocate memory on '_core_mem_alloc' *
*****************************************************************/
/* Initialize ROM FS with the given boot modules */
module = (Boot_module *)md_base;
for (; (addr_t)module < md_top; module++) {
Rom_module *rom_module = new (core_mem_alloc())
Rom_module(module->base, module->size, (const char*)module->name);
_rom_fs.insert(rom_module);
}
/* Start the core-pager */
if(Kernel::thread_create(PAGER_TID, PROTECTION_ID,
Kernel::INVALID_THREAD_ID,
&pager_utcb,
(addr_t)pager,
(addr_t)&pager_stack[sizeof(pager_stack)/sizeof(pager_stack[0])],
true << Kernel::THREAD_CREATE__PARAM__IS_ROOT_LSHIFT))
{
PERR("Couldn't start cores pager");
sleep_forever();
}
/* Core's mainthread shall be paged by the core-pager */
Kernel::thread_pager(MAIN_THREAD_ID, PAGER_TID);
/* Initialze core's remaining allocators */
_irq_alloc.add_range(User::MIN_IRQ, User::MAX_IRQ-User::MIN_IRQ);
_io_mem_alloc.add_range(User::IO_MEM_BASE, User::IO_MEM_SIZE);
/* Setup virtual memory for common programs */
_vm_base=User::VADDR_BASE;
_vm_size=User::VADDR_SIZE - get_page_size();
if (verbose) {
PINF("Printing core memory layout summary");
printf("[_core_mem_alloc]\n"); _core_mem_alloc.raw()->dump_addr_tree();
printf("[_io_mem_alloc]\n"); _io_mem_alloc.raw()->dump_addr_tree();
printf("[_irq_alloc]\n"); _irq_alloc.raw()->dump_addr_tree();
}
}
void Genode::Core_parent::exit(int exit_value) { }

View File

@ -1,191 +0,0 @@
/*
* \brief Thread facility
* \author Norman Feske
* \author Martin Stein
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2013 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/printf.h>
#include <base/ipc_pager.h>
#include <platform_thread.h>
#include <platform_pd.h>
#include <kernel/syscalls.h>
#include "include/platform.h"
#include <cpu_session/cpu_session.h>
static bool const verbose = 0;
using namespace Genode;
Tid_allocator* Genode::tid_allocator()
{
static Tid_allocator _tida(User::MIN_THREAD_ID+1, User::MAX_THREAD_ID);
return &_tida;
}
Pid_allocator* Genode::pid_allocator()
{
static Pid_allocator _pida(User::MIN_PROTECTION_ID, User::MAX_PROTECTION_ID);
return &_pida;
}
namespace Genode
{
static Kernel::Utcb * phys_utcb[User::MAX_THREAD_ID];
}
int Genode::physical_utcb(Native_thread_id const &tid, Kernel::Utcb * const &utcb)
{
if (tid < sizeof(phys_utcb)/sizeof(phys_utcb[0])) {
Genode::phys_utcb[tid] = utcb;
return true;
}
return false;
}
Kernel::Utcb* Genode::physical_utcb(Native_thread_id tid)
{
if (tid >= sizeof(phys_utcb)/sizeof(phys_utcb[0])) {
PERR("Native thread ID out of range");
return 0;
}
if(!phys_utcb[tid]) {
if (platform_specific()->
core_mem_alloc()->
alloc_aligned(sizeof(Kernel::Utcb),
(void**)&phys_utcb[tid],
Kernel::Utcb::ALIGNMENT_LOG2).is_error())
{
PERR("Allocate memory for a new UTCB failed");
return 0;
}
if(verbose) {
PDBG("UTCB %i: [%p|%p]", tid, phys_utcb[tid],
(void*)((addr_t)phys_utcb[tid] + sizeof(Kernel::Utcb)));
}
}
return phys_utcb[tid];
}
void Platform_thread::affinity(unsigned int cpu_no) { PERR("not implemented"); }
void Platform_thread::cancel_blocking() { PERR("not implemented"); }
void Platform_thread::state(Thread_state s)
{
PDBG("Not implemented");
throw Cpu_session::State_access_failed();
}
Thread_state Platform_thread::state()
{
PDBG("Not implemented");
throw Cpu_session::State_access_failed();
}
int Platform_thread::start(void *ip, void *sp, unsigned int cpu_no)
{
Native_thread_id pager_tid = _pager ? _pager->cap().dst() : 0;
Kernel::Utcb* putcb = physical_utcb(_tid);
/* Hand over arguments for the thread's bootstrap */
*((Native_thread_id*)&putcb->byte[0]) = _tid;
if (verbose) {
PDBG("Start Thread, tid=%i, pid=%i, pager=%i", _tid, _pid, pager_tid);
PDBG("vip=0x%p, vsp=%p, vutcb=0x%p", ip, sp, _utcb);
}
int const error = Kernel::thread_create(_tid, _pid, pager_tid,
putcb, (addr_t)ip, (addr_t)sp, 0);
if (error) {
PERR("Kernel::thread_create failed, error=%di", error);
return -1;
}
return 0;
}
void Platform_thread::pause()
{
PDBG("not implemented");
}
void Platform_thread::resume()
{
PDBG("not implemented");
}
Platform_thread::Platform_thread(const char *name, unsigned, int thread_id,
uint32_t params)
: _tid(0), _utcb(0), _params(params)
{
if (!_tid) {
if (!(_tid = tid_allocator()->allocate(this))) {
PERR("TID allocation failed");
return;
}
}
else if (!tid_allocator()->allocate(this, (Native_thread_id)thread_id)) {
PERR("TID allocation failed");
return;
}
}
Platform_thread::~Platform_thread() {
_pd->unbind_thread(this);
if(Kernel::thread_kill(_tid)){
PERR("Kernel::thread_kill(%i) failed", (unsigned)_tid);
}
tid_allocator()->free(_tid);
}
bool Ipc_pager::resolved()
{
typedef Platform_pd::Context_part Context_part;
typedef Mapping::Physical_page Physical_page;
addr_t va = (addr_t)_request.virtual_page.address();
Native_thread_id context_owner = 0;
Context_part context_part = Platform_pd::NO_CONTEXT_PART;
unsigned stack_offset = 0;
Platform_pd* pd =
pid_allocator()->holder(_request.virtual_page.protection_id());
if (!pd) { return false; }
if (!pd->metadata_if_context_address(va, &context_owner, &context_part,
&stack_offset))
{
return false;
}
if (context_part != Platform_pd::UTCB_AREA) { return false; }
Native_utcb * const putcb = physical_utcb(context_owner);
set_reply_mapping(Genode::Mapping(va, (addr_t)putcb, false,
Native_utcb::size_log2(), true));
return true;
}

View File

@ -1,45 +0,0 @@
/*
* \brief Export RAM dataspace as shared memory object (dummy)
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2013 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 <ram_session_component.h>
using namespace Genode;
static bool const verbose = false;
void Ram_session_component::_export_ram_ds(Dataspace_component *ds)
{
if (verbose) PERR("not implemented");
}
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds)
{
if (verbose) PERR("not implemented");
}
void Ram_session_component::_clear_ds(Dataspace_component *ds)
{
/*
* We don't have to allocate a core local dataspace to get
* virtual access because core is mapped 1-to-1. (except for
* its context-area)
*/
memset((void *)ds->phys_addr(), 0, ds->size());
}

View File

@ -1,38 +0,0 @@
/*
* \brief RM-session implementation
* \author Norman Feske
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-2013 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 <rm_session_component.h>
#include <platform_thread.h>
using namespace Genode;
static bool const verbose = false;
void Rm_client::unmap(addr_t core_local_base, addr_t virt_base, size_t size)
{
if (verbose) {
PDBG("Flush %i B from [%p,%p)",
(unsigned int)size,
(void*)virt_base,
(void*)((unsigned int)virt_base+size));
}
Kernel::Protection_id pid =
tid_allocator()->holder(this->badge())->pid();
Kernel::tlb_flush(pid, virt_base, (unsigned int)size);
}

View File

@ -1,54 +0,0 @@
GEN_CORE_DIR = $(BASE_DIR)/src/core
SPEC_CORE_DIR = $(REP_DIR)/src/core
SPEC_BASE_DIR = $(REP_DIR)/src/base
SRC_CC = \
context_area.cc \
core_rm_session.cc \
cpu_session_component.cc \
dataspace_component.cc \
dump_alloc.cc \
io_mem_session_component.cc \
io_mem_session_support.cc \
irq_session_component.cc \
main.cc \
pd_session_component.cc \
platform.cc \
platform_services.cc \
platform_thread.cc \
cpu_session_support.cc \
ram_session_component.cc \
ram_session_support.cc \
rm_session_component.cc \
rm_session_support.cc \
rom_session_component.cc \
signal_session_component.cc \
signal_source_component.cc \
thread.cc \
thread_bootstrap.cc \
thread_roottask.cc \
INC_DIR = $(SPEC_CORE_DIR)/include \
$(GEN_CORE_DIR)/include
vpath context_area.cc $(SPEC_CORE_DIR)
vpath cpu_session_component.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath io_mem_session_component.cc $(GEN_CORE_DIR)
vpath io_mem_session_support.cc $(SPEC_CORE_DIR)
vpath irq_session_component.cc $(SPEC_CORE_DIR)
vpath main.cc $(GEN_CORE_DIR)
vpath pd_session_component.cc $(GEN_CORE_DIR)
vpath platform.cc $(GEN_CORE_DIR)
vpath platform_services.cc $(GEN_CORE_DIR)
vpath platform_thread.cc $(GEN_CORE_DIR)
vpath ram_session_component.cc $(GEN_CORE_DIR)
vpath rm_session_component.cc $(GEN_CORE_DIR)
vpath rom_session_component.cc $(GEN_CORE_DIR)
vpath signal_session_component.cc $(GEN_CORE_DIR)
vpath signal_source_component.cc $(GEN_CORE_DIR)
vpath thread.cc $(SPEC_BASE_DIR)/thread
vpath thread_bootstrap.cc $(SPEC_BASE_DIR)/thread
vpath thread_roottask.cc $(GEN_CORE_DIR)

View File

@ -1,10 +0,0 @@
TARGET = core
LIBS = kernel_core cxx ipc heap printf_microblaze child pager lock \
raw_signal raw_server
STARTUP_LIB = kernel_core
LD_SCRIPT = $(REP_DIR)/src/platform/genode.ld
SRC_S += boot_modules.s
include $(PRG_DIR)/target.inc

View File

@ -1,111 +0,0 @@
/*
* \brief Implementation of Thread API for roottask
* \author Norman Feske
* \date 2010-09-01
*/
/*
* Copyright (C) 2010-2013 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/printf.h>
#include <base/thread.h>
#include <base/sleep.h>
#include <base/native_types.h>
#include <platform.h>
#include <platform_pd.h>
#include <kernel/syscalls.h>
using namespace Genode;
static bool const verbose = 0;
namespace Roottask {
Platform_pd* platform_pd()
{
static Platform_pd _pd(PROTECTION_ID);
return &_pd;
}
}
void Thread_base::_init_platform_thread() { }
void Thread_base::_deinit_platform_thread()
{
Platform_pd *pd = Roottask::platform_pd();
Platform_pd::Context_id cid;
if (pd->cid_if_context_address((addr_t)_context, &cid)){
pd->free_context(cid);
}
if(Kernel::thread_kill(_tid)){
PERR("Kernel::thread_kill(%i) failed", (unsigned)_tid);
}
tid_allocator()->free(_tid);
}
void Thread_base::_thread_start()
{
myself()->entry();
PDBG("Thread returned, tid=%i, pid=%i",
myself()->tid(), Roottask::PROTECTION_ID);
Thread_base::myself()->_join_lock.unlock();
Genode::sleep_forever();
}
void Thread_base::_init_context(Context* context)
{
_tid=tid_allocator()->allocate();
Platform_pd *pd = Roottask::platform_pd();
Platform_pd::Context_id cid;
if (!pd->cid_if_context_address((addr_t)context, &cid)){
PERR("Invalid context address 0x%p", context);
return;
}
if (!pd->allocate_context(_tid, cid)){
PERR("Allocating context %i failed", cid);
return;
}
}
void Thread_base::start()
{
using namespace Genode;
Native_process_id const pid = Roottask::PROTECTION_ID;
Native_thread_id const pager_tid = Roottask::PAGER_TID;
void * const vsp = &_context->stack;
Native_utcb * const vutcb = &_context->utcb;
Kernel::Utcb * const putcb = physical_utcb(_tid);
void * const vip = (void *)_thread_start;
if(verbose) {
PDBG("Start Thread, tid=%i, pid=%i, pager=%i", _tid, pid, pager_tid);
PDBG(" vip=0x%p, vsp=%p, vutcb=0x%p", vip, vsp, vutcb);
PDBG(" pip=0x%p, psp=%p, putcb=0x%p",
vip, (void*)Roottask::physical_context(_tid)->stack, putcb);
}
if (Kernel::thread_create(_tid, pid, pager_tid,
putcb, (addr_t)vip, (addr_t)vsp,
1 << Kernel::THREAD_CREATE__PARAM__IS_ROOT_LSHIFT))
{
PERR("Kernel::thread_create failed");
}
}
void Thread_base::cancel_blocking() { PERR("not implemented"); }

View File

@ -1,268 +0,0 @@
/*
* \brief Blockings that can prevent a thread from beeing executed
* \author Martin Stein
* \date 2011-02-22
*/
/*
* Copyright (C) 2011-2013 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 <generic/blocking.h>
#include <generic/timer.h>
#include <generic/event.h>
#include "include/thread.h"
#include <generic/irq_controller.h>
#include <kernel/syscalls.h>
Kernel::Data_tlb_miss::On_occurence__result Kernel::Data_tlb_miss::on_occurence()
{
if (!_missing_resolution.virtual_page.valid()) {
_on_occurence__error__virtual_page_invalid(); }
Event::_populate();
if (!_missing_resolution.physical_page.valid()) {
_on_occurence__verbose__waiting_for_resolution();
return EVENT_PENDING; }
tlb()->add(&_missing_resolution);
_missing_resolution.invalidate();
return EVENT_PROCESSED;
}
void Kernel::Data_tlb_miss::Listener::_resolve_identically(Physical_page::size_t s,
Physical_page::Permissions p)
{
new (&_resolution->physical_page)
Physical_page(_resolution->virtual_page.address(), s, p);
}
Kernel::Instruction_tlb_miss::On_occurence__result Kernel::Instruction_tlb_miss::on_occurence()
{
if (!_missing_resolution.virtual_page.valid())
_on_occurence__error__virtual_page_invalid();
Event::_populate();
if (!_missing_resolution.physical_page.valid()) {
_on_occerence__verbose__waiting_for_resolution();
return EVENT_PENDING;
}
tlb()->add(&_missing_resolution);
_missing_resolution.invalidate();
return EVENT_PROCESSED;
}
void Kernel::Instruction_tlb_miss::Listener::_resolve_identically(Physical_page::size_t s,
Physical_page::Permissions p)
{
new (&_resolution->physical_page)
Physical_page(_resolution->virtual_page.address(), s, p);
}
void Kernel::Data_tlb_miss::Listener::_on_event()
{
_on_data_tlb_miss(&_resolution->virtual_page,
_resolution->write_access);
}
void Kernel::Instruction_tlb_miss::Listener::_on_event()
{
_on_instruction_tlb_miss(&_resolution->virtual_page);
}
extern bool irq_occured[];
bool Kernel::Irq::unblock()
{
Thread * const h = irq_allocator()->holder(_id);
if (!h) {
irq_controller()->ack_irq(_id);
return true;
}
h->handle(_id);
return true;
}
bool Kernel::Exception::unblock()
{
int result = false;
switch (_id) {
case INSTRUCTION_TLB_MISS:
new (&Instruction_tlb_miss::_missing_resolution.virtual_page)
Virtual_page(address(), protection_id());
if (Instruction_tlb_miss::on_occurence() == EVENT_PROCESSED)
result = true;
break;
case DATA_TLB_MISS:
new (&Data_tlb_miss::_missing_resolution.virtual_page)
Virtual_page(address(), protection_id());
Data_tlb_miss::_missing_resolution.write_access = attempted_write_access();
if (Data_tlb_miss::on_occurence() == EVENT_PROCESSED)
result = true;
break;
default:
PERR("Unexpected exception %i\n", _id);
halt();
}
return result;
}
bool Kernel::Syscall::unblock()
{
switch (_id){
case PRINT_CHAR:
{
return _source->on_print_char(*_argument_0) == Event::EVENT_PROCESSED ?
true : false;
}
case THREAD_CREATE:
{
Thread_create::Argument a;
a.tid = (Thread_id)*_argument_0;
a.pid = (Protection_id)*_argument_1;
a.pager_tid = (Thread_id)*_argument_2;
a.utcb = (Utcb*)*_argument_3;
a.vip = (addr_t)*_argument_4;
a.vsp = (addr_t)*_argument_5;
a.is_privileged =
(bool)(*_argument_6&(1<<THREAD_CREATE_PARAMS_ROOTRIGHT_LSHIFT));
return _source->on_thread_create(&a, (Thread_create::Result*)_result_0) == Event::EVENT_PROCESSED ?
true : false;
}
case THREAD_KILL:
{
Thread_kill::Argument a;
a.tid = (Thread_id)*_argument_0;
return _source->on_thread_kill(&a, (Thread_kill::Result*)_result_0) == Event::EVENT_PROCESSED ?
true : false;
}
case THREAD_WAKE:
{
Thread_wake::Argument a;
a.tid = (Thread_id)*_argument_0;
return _source->on_thread_wake(&a, (Thread_wake::Result*)_result_0) == Event::EVENT_PROCESSED ?
true : false;
}
case THREAD_SLEEP:
{
return _source->on_thread_sleep() == Event::EVENT_PROCESSED ?
true : false;
}
case IPC_SERVE:
{
return _source->can_reply_and_get_next_request(*_argument_0, _argument_0);
}
case IPC_REQUEST:
{
return _source->can_get_reply(thread_factory()->get(*_argument_0),
*_argument_1,
_argument_0);
}
case TLB_LOAD:
{
using namespace Paging;
Virtual_page vp((addr_t) *_argument_1,
(Protection_id)*_argument_2);
Physical_page pp((addr_t) *_argument_0,
(Physical_page::size_t) *_argument_3,
(Physical_page::Permissions)*_argument_4);
Paging::Resolution r(&vp, &pp);
_source->on_tlb_load(&r);
return true;
}
case IRQ_ALLOCATE:
{
return _source->irq_allocate((Irq_id)*_argument_0, (int *)_argument_0);
}
case IRQ_FREE:
{
return _source->irq_free((Irq_id)*_argument_0, (int *)_argument_0);
}
case IRQ_WAIT:
{
return _source->irq_wait();
}
case THREAD_PAGER:
{
_source->on_thread_pager(*_argument_0, *_argument_1);
return true;
}
case THREAD_YIELD:
{
_source->yield();
return true;
}
case TLB_FLUSH:
{
using namespace Paging;
Virtual_page vp((addr_t) *_argument_1,
(Protection_id)*_argument_0);
_source->on_tlb_flush(&vp, (unsigned)*_argument_2);
return true;
}
case PRINT_INFO:
{
Thread* t;
if((Thread_id)*_argument_0) {
t=thread_factory()->get((Thread_id)*_argument_0);
} else {
t=thread_factory()->get(_source->tid);
}
if(!t) { return true; }
t->print_state();
return true;
}
default:
{
_unblock__warning__unknown_id();
return false;
}
}
}

View File

@ -1,82 +0,0 @@
/*
* \brief Handling of concrete set of hardware-exceptions
* \author Martin stein
* \date 2010-06-23
*/
/*
* Copyright (C) 2010-2013 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 _SRC__CORE__KERNEL__INCLUDE__EXCEPTION_H_
#define _SRC__CORE__KERNEL__INCLUDE__EXCEPTION_H_
#include <base/fixed_stdint.h>
#include "scheduler.h"
using namespace Genode;
/**
* Exception metadata structure
*/
struct Exception
{
uint32_t cause;
uint32_t status;
uint32_t address;
};
/**
* Virtual class that qualifies heirs be exception handler
*/
class Exception_handler
{
protected:
/**
* Enable all hw exceptions and let us be the handler for them
*/
void _alloc_exceptions();
/**
* Relieve us of handling any exception
*
* Dissable all exceptions if we are the current handler.
*/
void _free_exceptions();
public:
/**
* Destructor
*/
virtual ~Exception_handler() {}
/**
* Handle occured exception
*
* \param type type of exception - see xmb/include/config.h
*/
virtual void handle_exception(uint32_t type, uint32_t status, uint32_t address) = 0;
};
/**
* C exception handling, after assembler entry
*/
void handle_exception();
/**
* Clear exception if one is in progress
*/
void _exception_clear();
#endif /* _SRC__CORE__KERNEL__INCLUDE__EXCEPTION_H_ */

View File

@ -1,50 +0,0 @@
/*
* \brief Common lowlevel interrupt handling
* \author Martin stein
* \date 2010-06-23
*/
/*
* Copyright (C) 2010-2013 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 _SRC__CORE__KERNEL__INCLUDE__INTERRUPT_H_
#define _SRC__CORE__KERNEL__INCLUDE__INTERRUPT_H_
/* OS includes */
#include <base/fixed_stdint.h>
/* kernel includes */
#include <kernel/irq_controller.h>
/* platform includes */
#include <xmb/config.h>
using namespace Genode;
/**
* Interrupt handling level 2, calls handler if possible or nop and return
*/
void handle_interrupt();
/**
* Globally enable all interrupts
*
* \param controller interrupt controller that shall be used by handlings
*/
void enable_interrupts(Irq_controller* const controller);
/**
* Globally disable all irq's
*/
void disable_interrupt();
#endif /* _SRC__CORE__KERNEL__INCLUDE__INTERRUPT_H_ */

View File

@ -1,360 +0,0 @@
/*
* \brief Declaration of physical backend to userland thread
* \author Martin stein
* \date 2010-06-24
*/
/*
* Copyright (C) 2010-2013 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 _KERNEL__GENERIC__INCLUDE__THREAD_H_
#define _KERNEL__GENERIC__INCLUDE__THREAD_H_
#include <kernel/types.h>
#include <kernel/syscalls.h>
#include <generic/blocking.h>
#include <generic/scheduler.h>
#include <util/queue.h>
#include <generic/verbose.h>
#include <platform/platform.h>
#include <generic/tlb.h>
#include <generic/syscall_events.h>
extern bool irq_occured[Kernel::MAX_IRQ_ID];
namespace Kernel {
enum { THREAD__VERBOSE = 0,
THREAD__WARNING = 1 };
enum { ROOTTASK_PAGE_SIZE = Paging::Physical_page::_4KB };
class Thread : public Scheduler::Client,
public Instruction_tlb_miss::Listener,
public Data_tlb_miss::Listener,
public Syscall::Source,
public Paging::Request::Source
{
public:
typedef Tlb::Virtual_page Virtual_page;
typedef Tlb::Physical_page Physical_page;
typedef Tlb::Resolution Resolution;
typedef Thread_create::Argument Constructor_argument;
typedef Kernel::Thread_id Thread_id;
typedef Kernel::Protection_id Protection_id;
void* operator new(size_t, void *addr) { return addr; }
enum State { INVALID = 0,
READY,
WAIT,
WAIT_IPC_REPLY,
WAIT_IPC_REQUEST };
enum Print_mode { BRIEF_STATE, DETAILED_STATE };
private:
Platform_thread _platform_thread;
Thread_id _id;
bool _is_privileged;
Thread_id _pager_tid;
Thread_id _substitute_tid;
State _state;
Paging::Request _paging_request;
bool _waits_for_irq;
bool _any_irq_pending;
bool _irq_pending[Kernel::MAX_IRQ_ID];
void _unblock() { _platform_thread.unblock(); }
void _invalidate() { _state = INVALID; }
Protection_id _protection_id() { return _platform_thread.protection_id(); }
addr_t _instruction_pointer() { return _platform_thread.instruction_pointer(); }
void _sleep() { scheduler()->remove(this); }
void _yield_after_atomic_operation()
{
_platform_thread.yield_after_atomic_operation();
}
inline void _clear_pending_irqs();
public:
inline bool irq_allocate(Irq_id i, int * const result);
inline bool irq_free(Irq_id i, int * const result);
inline bool irq_wait();
inline void handle(Irq_id const & i);
void pager_tid(Thread_id ptid){ _pager_tid=ptid; }
/**
* Constructor
*/
Thread(Constructor_argument* a);
/**
* Constructing invalid thread without parameters
*/
Thread();
/**
* Shows several infos about thread depending on print mode argument
*/
void print_state();
/**********************
** Simple Accessors **
**********************/
Thread_id thread_id() { return _id; }
bool valid() { return _state != INVALID; }
/*********************************
** Scheduler::Client interface **
*********************************/
int label() { return (int)_id; }
void _on_instruction_tlb_miss(Virtual_page* accessed_page);
void _on_data_tlb_miss(Virtual_page* accessed_page, bool write_access);
void yield() { scheduler()->skip_next_time(this); }
protected:
void ipc_sleep() { Scheduler::Client::_sleep(); }
void ipc_wake() { Scheduler::Client::_wake(); }
bool _preemptable()
{
if (!platform()->is_atomic_operation((void*)_instruction_pointer()))
return true;
_yield_after_atomic_operation();
return false;
}
bool _permission_to_do_print_char() { return true; }
bool _permission_to_do_thread_create()
{
return _is_privileged;
}
bool _permission_to_do_thread_kill()
{
return _is_privileged;
}
// bool _print_info(){
// _platform_thread.exec_context()->print_content(2);
// return true;
// }
bool _permission_to_do_tlb_load(){ return _is_privileged; }
bool _permission_to_do_tlb_flush(){ return _is_privileged; }
bool _permission_to_do_thread_pager(Thread_id target_tid)
{
return _is_privileged;
}
bool _permission_to_do_thread_wake(Thread* target)
{
return _is_privileged
|| target->_protection_id()==_protection_id();
}
Context *_context()
{
return _platform_thread.unblocked_exec_context();
}
enum { CONSTRUCTOR__VERBOSE__SUCCESS = THREAD__VERBOSE };
void _on_data_tlb_miss__warning__invalid_pager_tid(Thread_id pager_tid)
{
if (!THREAD__WARNING) return;
printf("Warning in Kernel::Thread::_on_data_tlb_miss, invalid pager_tid=%i\n", pager_tid);
}
void _constructor__verbose__success()
{
if (!CONSTRUCTOR__VERBOSE__SUCCESS) return;
printf("Kernel::Thread::Thread, new valid thread created, printing state\n");
Verbose::indent(2);
printf("_utcb=0x%8X, _platform_thread(", (uint32_t)utcb());
_platform_thread.print_state();
printf(")\n");
}
void _on_instruction_tlb_miss__verbose__roottask_resolution(addr_t v)
{
if (!THREAD__VERBOSE) return;
printf("Kernel::Thread::_on_instruction_tlb_miss, resoluted 0x%p identically\n",
(void*)v);
}
void _on_data_tlb_miss__verbose__roottask_resolution(addr_t v)
{
if (!THREAD__VERBOSE) return;
printf("Kernel::Thread::_on_data_tlb_miss, resoluted 0x%p identically\n",
(void*)v);
}
};
class Thread_factory
{
enum { THREAD_ID_RANGE = 1 << (Platform::BYTE_WIDTH*sizeof(Thread_id)) };
Thread thread[THREAD_ID_RANGE];
bool _steady[THREAD_ID_RANGE];
public:
enum Error {
NO_ERROR = 0,
CANT_KILL_STEADY_THREAD = -1
};
typedef Thread::Constructor_argument Create_argument;
Thread *create(Create_argument *a, bool steady)
{
if(thread[a->tid].valid()) { return 0; }
_steady[a->tid] = steady;
return new(&thread[a->tid])Thread(a);
}
Error kill(Thread_id tid)
{
if(_steady[tid]) return CANT_KILL_STEADY_THREAD;
thread[tid].~Thread();
new (&thread[tid]) Thread();
return NO_ERROR;
}
Thread *get(Thread_id id)
{
return thread[id].valid() ? &thread[id] : (Thread*)0;
}
};
Thread_factory* thread_factory();
}
void Kernel::Thread::handle(Irq_id const & i)
{
if(i>sizeof(_irq_pending)/sizeof(_irq_pending[0])){
printf("Kernel::Thread::handles(Irq_id i): Error");
halt();
}
_irq_pending[i]=true;
_any_irq_pending = true;
if(!_waits_for_irq) { return; }
Scheduler::Client::_wake();
_clear_pending_irqs();
_waits_for_irq=false;
return;
}
bool Kernel::Thread::irq_allocate(Irq_id i, int * const result)
{
if(!_is_privileged){
*result = -1;
return true;
};
if(i == platform()->timer()->irq_id()){
*result = -3;
return true;
};
if(irq_allocator()->allocate(this, i)){
*result = -2;
return true;
};
*result = 0;
return true;
}
bool Kernel::Thread::irq_free(Irq_id i, int * const result)
{
if(!_is_privileged){
*result = -1;
return true;
};
if(irq_allocator()->free(this, i)){
*result = -2;
return true;
};
*result = 0;
return true;
}
bool Kernel::Thread::irq_wait()
{
if(!_any_irq_pending){
_waits_for_irq = true;
Scheduler::Client::_sleep();
return true;
}
_clear_pending_irqs();
return true;
}
void Kernel::Thread::_clear_pending_irqs()
{
for(unsigned int i=0; i<sizeof(_irq_pending)/sizeof(_irq_pending[0]); i++) {
if(_irq_pending[i]) {
irq_controller()->ack_irq(i);
_irq_pending[i]=false;
}
}
_any_irq_pending=false;
}
#endif /* _KERNEL__GENERIC__INCLUDE__THREAD_H_ */

View File

@ -1,189 +0,0 @@
/*
* \brief Kernel initialization
* \author Martin Stein
* \date 2010-07-22
*/
/*
* Copyright (C) 2010-2013 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 <platform/platform.h>
#include <generic/scheduler.h>
#include "include/thread.h"
#include <generic/printf.h>
#include <generic/verbose.h>
#include <generic/blocking.h>
#include <kernel/config.h>
#include <kernel/syscalls.h>
#include <cpu/prints.h>
#include <util/array.h>
using namespace Cpu;
using namespace Kernel;
enum { KERNEL__VERBOSE = 0,
KERNEL__WARNING = 1,
KERNEL__ERROR = 1 };
/* Can be defined via compiler options */
extern "C" void ROOTTASK_ENTRY();
extern Kernel::Exec_context* _userland_context;
extern Utcb* _main_utcb_addr;
extern int _exit_kernel;
Kernel::Thread_factory* Kernel::thread_factory()
{
static Thread_factory _tf;
return &_tf;
}
namespace Kernel {
static Utcb _roottask_utcb, _idle_utcb;
void _roottask_thread__verbose__creation(addr_t vip, addr_t vsp, Utcb* vutcb)
{
if (!KERNEL__VERBOSE) return;
printf("Kernel::roottask_thread, roottask thread created, "
"printing constraints\n");
printf(" vip=0x%8X, vsp=0x%8X, vutcb=0x%8X\n",
(uint32_t)vip, (uint32_t)vsp, (uint32_t)vutcb);
}
void idle()
{
while(1);
}
Thread *idle_thread()
{
enum{
IDLE_STACK_WORD_SIZE=32,
IDLE_TID=1,
};
static word_t _it_stack[IDLE_STACK_WORD_SIZE];
static Thread *_it = thread_factory()->get(IDLE_TID);
if (!_it) {
Thread_factory::Create_argument itca;
itca.tid = (Thread_id)IDLE_TID;
itca.pid = (Protection_id)Roottask::PROTECTION_ID;
itca.utcb = &_idle_utcb;
itca.pager_tid = INVALID_THREAD_ID;
itca.vsp = (addr_t)&LAST_ARRAY_ELEM(_it_stack);
itca.vip = (addr_t)&idle;
itca.is_privileged = true;
_it = thread_factory()->create(&itca, true);
}
return _it;
}
Thread *roottask_thread()
{
static word_t _rt_stack[Roottask::MAIN_STACK_SIZE/WORD_SIZE];
static Thread *_rt = thread_factory()->get(Roottask::MAIN_THREAD_ID);
if (!_rt) {
Thread_factory::Create_argument rtca;
rtca.tid = (Thread_id)Roottask::MAIN_THREAD_ID;
rtca.pid = (Protection_id)Roottask::PROTECTION_ID;
rtca.utcb = &_roottask_utcb;
rtca.pager_tid = INVALID_THREAD_ID;
rtca.vsp = (addr_t)&LAST_ARRAY_ELEM(_rt_stack);
rtca.vip = (addr_t)&ROOTTASK_ENTRY;
rtca.is_privileged = true;
_main_utcb_addr = rtca.utcb;
_rt = thread_factory()->create(&rtca, false);
if (_rt)
_roottask_thread__verbose__creation(
rtca.vip, rtca.vsp, rtca.utcb);
}
return _rt;
}
}
Platform *Kernel::platform() { static Platform _p; return &_p; }
Scheduler *Kernel::scheduler()
{
static bool _init_scheduler = false;
static Scheduler _s = Scheduler(platform(),
platform()->timer(),
idle_thread());
if(_init_scheduler){ return &_s; }
_s.add(roottask_thread());
_init_scheduler = true;
return &_s;
}
Tlb *Kernel::tlb() { return platform()->tlb(); }
Irq_controller * const Kernel::irq_controller()
{
return platform()->irq_controller();
}
Irq_allocator * const Kernel::irq_allocator()
{
static Irq_allocator _ia =
Irq_allocator(platform()->irq_controller());
return &_ia;
}
unsigned Kernel::word_width() { return Platform::WORD_WIDTH; }
void Kernel::halt() { platform()->halt(); }
Kernel::Kernel_entry *Kernel::kernel_entry_event()
{
static Kernel_entry _ke;
return &_ke;
}
Kernel::Kernel_exit *Kernel::kernel_exit_event()
{
static Kernel_exit _kx;
return &_kx;
}
/**
* Kernel main routine, gets called by crt0_kernel.s
*/
extern "C" void _kernel()
{
kernel_entry_event()->on_occurence();
scheduler()->run();
kernel_exit_event()->on_occurence();
}

View File

@ -1,130 +0,0 @@
/*
* \brief Implementation of a round robin scheduler
* \author Martin stein
* \date 2010-06-22
*/
/*
* Copyright (C) 2010-2013 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.
*/
/* Generic includes */
#include <generic/scheduler.h>
#include <kernel/types.h>
#include <kernel/config.h>
#include "generic/verbose.h"
/* Platform includes */
#include <platform/platform.h>
using namespace Kernel;
extern unsigned int _current_context_label;
Scheduler::Scheduler(Ressource * const r, Scheduling_timer * const t,
Client * const idle_client)
:
_timer(t),
_quota_per_round_per_client(_ms_to_quota(MS_PER_ROUND_PER_CLIENT)),
_ressource(r),
_current_client(0),
_idle_client(idle_client)
{
_idle_client->_scheduler=this;
}
void Scheduler::_schedule()
{
_last_client=_current_client;
if (_last_client && _last_client != _idle_client) {
_client_queue.enqueue(_last_client);
}
_current_client=_client_queue.dequeue();
if (!_current_client){
_current_client=_idle_client;
}
}
Kernel::Scheduler::Client::~Client()
{
if (_scheduler)
_scheduler->remove(this);
}
void Scheduler::run()
{
if (!_current_client){
_schedule();
if (!_current_client)
_run__error__no_ready_client();
}
_new_clients = false;
Client* first_client = _current_client;
Client::Context *c = 0;
while (1) {
_run__trace__client_checks();
c = _current_client->_schedulable_context();
if (c && _current_client) {
if (_current_client->_quota) {
break;
} else {
_current_client->_earn_quota(_quota_per_round_per_client);
_new_clients = true;
}
}
_schedule();
if (_new_clients) {
first_client = _current_client;
_new_clients = false;
}
else if (_current_client == first_client){
_prep_idle_round();
}
}
_current_context_label = (unsigned int)_current_client->label();
_timer->track_time(_current_client->_quota, this);
_ressource->lock(c);
_run__verbose__success();
}
void Scheduler::add(Client *c)
{
if (!c) { return; }
if (c == _idle_client) { return; }
if (c->_scheduler == this) { return; }
if (c->_scheduler) { c->_scheduler->remove(c); }
c->_quota = _quota_per_round_per_client;
c->_scheduler = this;
_client_queue.enqueue(c);
_new_clients = true;
}
void Scheduler::remove(Client* c)
{
if (!c) { return; }
if (c->_scheduler != this) { return; }
if (c == _idle_client) { return; }
if (_current_client == c) { _current_client = 0; }
else _client_queue.remove(c);
c->_scheduler = 0;
_new_clients = true;
}

View File

@ -1,187 +0,0 @@
/*
* \brief Syscall handling implementation
* \author Martin Stein
* \date 2011-02-22
*/
/*
* Copyright (C) 2011-2013 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 <generic/syscall_events.h>
#include "include/thread.h"
#include <generic/verbose.h>
#include <generic/printf.h>
using namespace Kernel;
namespace Kernel{
extern Thread* idle_thread();
}
Print_char::On_occurence__result Print_char::on_print_char(char c)
{
printf("%c", c);
return EVENT_PROCESSED;
}
Thread_create::On_occurence__result
Thread_create::on_thread_create(Argument* a, Result* r)
{
using namespace Thread_create_types;
if (!_permission_to_do_thread_create()) {
_on_thread_create__warning__failed();
*r = INSUFFICIENT_PERMISSIONS;
} else {
Thread *t = thread_factory()->create(a, false);
if (!t) {
_on_thread_create__warning__failed();
*r=INAPPROPRIATE_THREAD_ID;
} else{
scheduler()->add(t);
_on_thread_create__verbose__success(t);
*r=SUCCESS;
}
}
return EVENT_PROCESSED;
}
Thread_kill::On_occurence__result
Thread_kill::on_thread_kill(Argument *a, Result *r)
{
using namespace Thread_kill_types;
if (!_permission_to_do_thread_kill()) {
*r = INSUFFICIENT_PERMISSIONS;
_on_thread_kill__warning__failed();
} else {
Thread_factory *tf = thread_factory();
if (tf->get(a->tid) == this) {
*r = SUICIDAL;
_on_thread_kill__warning__failed();
} else {
if(tf->kill(a->tid)){
printf("Warning in Thread_kill::on_thread_kill: Can't kill thread\n");
};
*r=SUCCESS;
_on_thread_kill__verbose__success(a->tid);
}
}
return EVENT_PROCESSED;
}
Thread_sleep::On_occurence__result Thread_sleep::on_thread_sleep()
{
Scheduler *s = scheduler();
s->remove(s->current_client());
_on_thread_sleep__verbose__success();
return EVENT_PROCESSED;
}
Thread_wake::On_occurence__result
Thread_wake::on_thread_wake(Argument *a, Result *r)
{
using namespace Thread_wake_types;
Thread* t = thread_factory()->get(a->tid);
if (!t) {
*r = INAPPROPRIATE_THREAD_ID;
_on_thread_wake__warning__failed();
} else{
if (!_permission_to_do_thread_wake(t)) {
*r = INSUFFICIENT_PERMISSIONS;
_on_thread_wake__warning__failed();
} else {
scheduler()->add(t);
*r = SUCCESS;
_on_thread_wake__verbose__success(a->tid);
}
}
return EVENT_PROCESSED;
}
//void Print_info::on_print_info(){
// _print_info();
//}
void Tlb_flush::on_tlb_flush(Paging::Virtual_page* first_page, unsigned size)
{
if (!_permission_to_do_tlb_flush()) return;
tlb()->flush(first_page, size);
}
void Tlb_load::on_tlb_load(Paging::Resolution* r)
{
if (!_permission_to_do_tlb_load()) return;
tlb()->add(r);
}
void Thread_pager::on_thread_pager(Thread_id target_tid, Thread_id pager_tid)
{
if (!_permission_to_do_thread_pager(target_tid)) {
printf("Warning in Kernel::Thread_pager::on_thread_pager, "
"insufficient permissions\n");
return;
}
Thread *target = thread_factory()->get(target_tid);
if (target && target != idle_thread()) {
target->pager_tid(pager_tid);
} else {
printf("Warning in Kernel::Thread_pager::on_thread_pager, "
"invalid target thread id\n");
}
}
void Thread_wake::_on_thread_wake__verbose__success(Thread_id tid)
{
if (!SYSCALL_EVENT__VERBOSE) return;
printf("Kernel::Thread_wake::on_thread_wake, success, tid=%i\n", tid);
}
void Thread_sleep::_on_thread_sleep__verbose__success()
{
if (!SYSCALL_EVENT__VERBOSE) return;
printf("Kernel::Thread_sleep::on_thread_sleep, success\n");
}
void Thread_kill::_on_thread_kill__verbose__success(Thread_id tid)
{
if (!SYSCALL_EVENT__VERBOSE) return;
printf("Kernel::Thread_kill::on_thread_kill, success, tid=%i\n", tid);
}
void Thread_create::_on_thread_create__verbose__success(Thread* t)
{
if (!SYSCALL_EVENT__VERBOSE) return;
printf("Kernel::Thread_create::on_thread_create, success, printing constraints\n");
t->print_state();
}

View File

@ -1,117 +0,0 @@
/*
* \brief Kernels Userland Thread representation
* \author Martin stein
* \date 2010-06-24
*/
/*
* Copyright (C) 2010-2013 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 "include/thread.h"
using namespace Kernel;
extern bool trace_me;
Thread::Thread(Constructor_argument* a)
:
Syscall::Source(a->utcb, a->tid),
_platform_thread(a->vip, a->vsp, a->pid, this),
_id(a->tid),
_is_privileged(a->is_privileged),
_pager_tid(a->pager_tid),
_substitute_tid(INVALID_THREAD_ID),
_state(READY),
_waits_for_irq(false),
_any_irq_pending(false)
{
_platform_thread.bootstrap_argument_0( (word_t)utcb() );
Instruction_tlb_miss::Listener::_event(_platform_thread.exception()->instruction_tlb_miss());
Data_tlb_miss::Listener::_event(_platform_thread.exception()->data_tlb_miss());
_constructor__verbose__success();
}
Thread::Thread() : Syscall::Source(0, 0)
{
_invalidate();
}
void Thread::print_state()
{
printf("Thread ID: %i, pager: %i, substitute: %i, privileged: %c, state: %i\n"
"Context:\n",
_id, _pager_tid, _substitute_tid, _is_privileged ? 'y' : 'n',
_state);
_platform_thread.print_state();
}
void Thread::_on_data_tlb_miss(Virtual_page *accessed_page, bool write_access)
{
typedef Kernel::Data_tlb_miss::Listener Listener;
using namespace Paging;
if (_protection_id()==Roottask::PROTECTION_ID & !_pager_tid) {
Listener::_resolve_identically((Physical_page::size_t)ROOTTASK_PAGE_SIZE,
Physical_page::RW);
_on_data_tlb_miss__verbose__roottask_resolution(accessed_page->address());
} else {
Ipc::Participates_dialog * pager = thread_factory()->get(_pager_tid);
if (!pager) {
_on_data_tlb_miss__warning__invalid_pager_tid(_pager_tid);
return;
} else {
Request::Source s = {_id, _instruction_pointer() };
Request::Access a = write_access ? Request::RW : Request::R;
_paging_request = Request(accessed_page, s, a);
_send_message(pager, (void*)&_paging_request,
sizeof(_paging_request));
_sleep();
_unblock();
}
}
}
void Thread::_on_instruction_tlb_miss(Virtual_page *accessed_page)
{
typedef Kernel::Instruction_tlb_miss::Listener Listener;
using namespace Paging;
if (_protection_id() == Roottask::PROTECTION_ID & !_pager_tid) {
Listener::_resolve_identically((Physical_page::size_t)ROOTTASK_PAGE_SIZE,
Physical_page::RX);
_on_instruction_tlb_miss__verbose__roottask_resolution(accessed_page->address());
} else {
Ipc::Participates_dialog *pager = thread_factory()->get(_pager_tid);
if (!pager) {
_on_data_tlb_miss__warning__invalid_pager_tid(_pager_tid);
return;
} else{
Paging::Request::Source s = {_id, _instruction_pointer()};
_paging_request = Request(accessed_page, s, Request::RX);
_send_message(pager, (void*)&_paging_request,
sizeof(_paging_request));
_sleep();
_unblock();
}
}
}

View File

@ -1,417 +0,0 @@
/*
* \brief Generic userland execution blockings
* \author Martin Stein
* \date 2010-10-27
*/
/*
* Copyright (C) 2010-2013 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 _KERNEL__INCLUDE__GENERIC__BLOCKING_H_
#define _KERNEL__INCLUDE__GENERIC__BLOCKING_H_
#include <kernel/types.h>
#include <util/queue.h>
#include <generic/verbose.h>
#include <generic/tlb.h>
#include <generic/event.h>
#include <generic/syscall_events.h>
#include <generic/ipc.h>
namespace Kernel {
enum { DATA_TLB_MISS__VERBOSE = 0,
INSTRUCTION_TLB_MISS__VERBOSE = 0 };
struct Blocking
{
virtual bool unblock() = 0;
virtual ~Blocking() { }
};
class Kernel_exit;
/**
* This event is triggered everytime kernels main
* routine is done and returns
*/
Kernel_exit* kernel_exit_event();
/**
* Event occuring when kernel exits execution
*/
struct Kernel_exit : public Event
{
class Listener : public Event::Listener
{
Kernel_exit* _event;
protected:
Listener() : _event(kernel_exit_event()) { _event->add(this); }
virtual ~Listener(){}
virtual void _on_kernel_exit() = 0;
void _on_event() { _on_kernel_exit(); }
};
void add(Listener *l) { Event::_add(l); }
On_occurence__result on_occurence()
{
_populate();
return EVENT_PROCESSED;
}
};
class Kernel_entry;
/**
* This Event triggers everytime kernels main
* routine starts execution
*/
Kernel_entry* kernel_entry_event();
/**
* Event occuring when kernel starts to be executed
*/
struct Kernel_entry : public Event
{
class Listener : public Event::Listener
{
Kernel_entry* _event;
protected:
Listener() : _event(kernel_entry_event()) { _event->add(this); }
virtual ~Listener(){}
virtual void _on_kernel_entry() = 0;
void _on_event() { _on_kernel_entry(); }
};
void add(Listener *l) { Event::_add(l); }
On_occurence__result on_occurence()
{
_populate();
return EVENT_PROCESSED;
}
};
class Instruction_tlb_miss : public Event
{
friend class Exception;
friend class Listener;
void _add(Listener *l) { Event::_add(l); }
public:
typedef Tlb::Virtual_page Virtual_page;
typedef Tlb::Physical_page Physical_page;
typedef Tlb::Resolution Resolution;
class Listener : public Event::Listener
{
typedef Instruction_tlb_miss::Resolution Resolution;
Resolution* _resolution;
protected:
typedef Instruction_tlb_miss::Virtual_page Virtual_page;
typedef Instruction_tlb_miss::Physical_page Physical_page;
virtual ~Listener(){}
void _resolve_identically(Physical_page::size_t s,
Physical_page::Permissions p);
virtual void _on_instruction_tlb_miss(Virtual_page* accessed_page) = 0;
void _on_event();
void _event(Instruction_tlb_miss* itm)
{
itm->_add(this);
_resolution = itm->missing_resolution();
}
/**
* Write read access for listeners
*/
Physical_page* physical_page()
{
return &_resolution->physical_page;
}
};
Resolution *missing_resolution() { return &_missing_resolution; }
protected:
Resolution _missing_resolution;
void _on_occurence__error__virtual_page_invalid()
{
printf("Error in Kernel::Instruction_tlb_miss::on_occurence, "
"virtual page invalid, halt\n");
halt();
}
void _on_occerence__verbose__waiting_for_resolution()
{
if (!INSTRUCTION_TLB_MISS__VERBOSE) return;
printf("Kernel::Instruction_tlb_miss::on_occurence, "
"leaving unresoluted virtual page, address=0x%p, pid=%i\n",
(void*)_missing_resolution.virtual_page.address(),
(int)_missing_resolution.virtual_page.protection_id() );
}
public:
On_occurence__result on_occurence();
};
class Data_tlb_miss : public Event
{
friend class Exception;
friend class Listener;
void _add(Listener* l) {Event::_add(l); }
public:
typedef Tlb::Virtual_page Virtual_page;
typedef Tlb::Physical_page Physical_page;
typedef Tlb::Resolution Resolution;
class Listener : public Event::Listener
{
typedef Data_tlb_miss::Resolution Resolution;
Resolution* _resolution;
protected:
typedef Data_tlb_miss::Virtual_page Virtual_page;
typedef Data_tlb_miss::Physical_page Physical_page;
virtual ~Listener(){}
void _resolve_identically(Physical_page::size_t s,
Physical_page::Permissions p);
virtual void _on_data_tlb_miss(Virtual_page* accessed_page,
bool write_access) = 0;
void _on_event();
void _event(Data_tlb_miss* dtm)
{
dtm->_add(this);
_resolution = dtm->missing_resolution();
}
/**
* Write read access for listeners
*/
Physical_page* physical_page()
{
return &_resolution->physical_page;
}
};
Resolution* missing_resolution() { return &_missing_resolution; }
protected:
Resolution _missing_resolution;
enum{ ON_OCCURENCE__ERROR = 1 };
void _on_occurence__error__virtual_page_invalid()
{
printf("Error in Kernel::Data_tlb_miss::on_occurence, "
"virtual page invalid, halt\n");
halt();
}
void _on_occurence__verbose__waiting_for_resolution()
{
if (!DATA_TLB_MISS__VERBOSE) return;
printf("Kernel::Data_tlb_miss::on_occurence, "
"leaving unresoluted virtual page, address=0x%p, pid=%i)\n",
(void*)_missing_resolution.virtual_page.address(),
(int)_missing_resolution.virtual_page.protection_id() );
}
public:
On_occurence__result on_occurence();
};
class Exception : public Instruction_tlb_miss,
public Data_tlb_miss,
public Blocking
{
typedef Kernel::Tlb::Virtual_page Virtual_page;
protected:
Exception_id _id;
virtual Protection_id protection_id()=0;
virtual addr_t address()=0;
virtual bool attempted_write_access()=0;
public:
enum { UNBLOCK__WARNING = 1 };
enum { UNBLOCK__RETURN__SUCCESS = 0,
UNBLOCK__RETURN__FAILED= - 1};
bool unblock();
Instruction_tlb_miss *instruction_tlb_miss() { return this; }
Data_tlb_miss *data_tlb_miss() { return this; }
};
class Irq : public Blocking
{
public:
enum{ UNBLOCK__WARNING=1 };
enum { UNBLOCK__RETURN__SUCCESS = 0,
UNBLOCK__RETURN__FAILED = -1};
bool unblock();
protected:
Irq_id _id;
void _unblock__error__release_irq_failed()
{
printf("Error in Kernel::Irq::unblock, failed to release IRQ, halt\n");
halt();
}
void _unblock__warning__unknown_id()
{
if (!UNBLOCK__WARNING) return;
printf("Warning in Kernel::Irq::unblock, unexpected _id=%i\n", _id);
}
};
class Syscall : public Blocking
{
public:
class Source;
private:
word_t *_argument_0,
*_argument_1,
*_argument_2,
*_argument_3,
*_argument_4,
*_argument_5,
*_argument_6,
*_result_0;
Source* _source;
protected:
Syscall_id _id;
enum{ UNBLOCK__WARNING = 1 };
void _unblock__warning__unknown_id()
{
if (!UNBLOCK__WARNING) return;
printf("Warning in Kernel::Syscall::unblock, unexpected _id=%i\n", _id);
}
public:
class Source : public Print_char,
public Thread_create,
public Thread_sleep,
public Thread_kill,
public Thread_wake,
public Thread_pager,
public Ipc::Participates_dialog,
public Tlb_load,
public Tlb_flush,
public Thread_yield
// public Print_info
{
protected:
Source(Utcb *utcb, Thread_id i) :
Ipc::Participates_dialog(utcb),
tid(i)
{ }
public:
Thread_id tid;
virtual bool irq_allocate(Irq_id i, int * const result)=0;
virtual bool irq_free(Irq_id i, int * const result)=0;
virtual bool irq_wait()=0;
};
bool unblock();
Syscall(word_t* argument_0,
word_t* argument_1,
word_t* argument_2,
word_t* argument_3,
word_t* argument_4,
word_t* argument_5,
word_t* argument_6,
word_t* result_0,
Source* s)
:
_argument_0(argument_0),
_argument_1(argument_1),
_argument_2(argument_2),
_argument_3(argument_3),
_argument_4(argument_4),
_argument_5(argument_5),
_argument_6(argument_6),
_result_0(result_0),
_source(s)
{ }
};
}
#endif /* _KERNEL__INCLUDE__GENERIC__BLOCKING_H_ */

View File

@ -1,103 +0,0 @@
/*
* \brief Event throwers and listeners
* \author Martin Stein
* \date 2010-10-27
*/
/*
* Copyright (C) 2010-2013 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 _KERNEL__INCLUDE__GENERIC__EVENT_H_
#define _KERNEL__INCLUDE__GENERIC__EVENT_H_
#include <util/queue.h>
#include <generic/verbose.h>
namespace Kernel {
class Event
{
public:
class Listener;
typedef Kernel::Queue<Listener> Listener_queue;
enum On_occurence__result{ EVENT_PROCESSED, EVENT_PENDING };
private:
Listener_queue _listeners;
Listener *_first;
protected:
void _populate()
{
if (!_first) {
_first = _listeners.dequeue();
if (!_first)
return;
}
Listener *i = _first;
while (1) {
i->_on_event();
_listeners.enqueue(i);
i = _listeners.dequeue();
if (i == _first) break;
}
}
void _add(Listener* l) { _listeners.enqueue(l); }
void _remove(Listener* l) { _listeners.remove(l); }
void print_listeners()
{
printf("print_listeners\n");
if (_listeners.empty()) {
printf(" empty\n");
return; }
Listener *current;
Listener *first;
first = _listeners.head();
current = _listeners.dequeue();
printf(" ");
while (1) {
printf("0x%p", current);
_listeners.enqueue(current);
if (first == _listeners.head())
break;
current = _listeners.dequeue();
printf(""); }
printf("\n");
}
public:
virtual ~Event() { }
class Listener : public Listener_queue::Item
{
friend class Event;
protected:
virtual void _on_event() = 0;
public:
virtual ~Listener(){}
};
};
}
#endif /*_KERNEL__INCLUDE__GENERIC__EVENT_H_*/

View File

@ -1,323 +0,0 @@
/*
* \brief IPC Framework inside kernel
* \author Martin Stein
* \date 2011-02-22
*/
/*
* Copyright (C) 2011-2013 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 _KERNEL__INCLUDE__GENERIC__IPC_H_
#define _KERNEL__INCLUDE__GENERIC__IPC_H_
#include <generic/verbose.h>
namespace Kernel {
enum { IPC__VERBOSE = 0 };
namespace Ipc {
class Participates_dialog;
typedef Kernel::Queue<Participates_dialog> Participant_queue;
class Participates_dialog :
public Participant_queue::Item
{
typedef Participates_dialog Participant;
public:
typedef Kernel::Utcb Utcb;
inline unsigned message_size() { return _message_size; }
inline byte_t message(unsigned i) { return _message[i]; }
inline void print_message();
byte_t *_message;
private:
Participant_queue _announced_clients;
Participant* _current_client;
Utcb* _utcb;
unsigned _message_size;
bool _waiting_for_reply;
bool _recieved_reply;
inline void _recieve_message(Participant* sender);
protected:
inline void _send_message(Participant* server,
void* message,
unsigned size);
inline Participates_dialog(Utcb* utcb);
inline Utcb* utcb() { return _utcb; }
inline void recieve_reply(Participant* server);
inline void announce_client(Participant* client);
virtual ~Participates_dialog() { }
virtual void ipc_sleep() = 0;
virtual void ipc_wake() = 0;
public:
inline bool can_get_reply(Participant *server,
unsigned request_size,
unsigned *reply_size);
inline bool can_reply_and_get_next_request(unsigned reply_size,
unsigned* request_size);
protected:
inline void _can_get_reply__error__invalid_server();
inline void _recieve_message__error__invalid_message_size();
inline void _can_reply_and_get_request__verbose__replied_to_request();
inline void _can_reply_and_get_request__verbose__recieved_request();
inline void _can_reply_and_get_request__verbose__waiting_for_request();
inline void _send_message__verbose__success(Participant* server);
inline void _can_get_reply__verbose__waiting_for_reply(Participant* server);
inline void _can_get_reply__verbose__recieved_reply(Participant* server);
};
}
}
Kernel::Ipc::Participates_dialog::Participates_dialog(Utcb* utcb) :
_current_client(0),
_utcb(utcb),
_waiting_for_reply(false),
_recieved_reply(false)
{ }
void Kernel::Ipc::Participates_dialog::print_message()
{
printf(" _message=0x%p\n", _message);
for (unsigned current_byte=0;;){
printf(" offset 0x%2X: 0x%p -> 0x",
current_byte, &_message[current_byte]);
printf("%2X", _message[current_byte]);
if (++current_byte>=_message_size) break;
printf("%2X", _message[current_byte]);
if (++current_byte>=_message_size) break;
printf("%2X", _message[current_byte]);
if (++current_byte>=_message_size) break;
printf("%2X", _message[current_byte]);
printf("\n");
if (++current_byte>=_message_size) break;
}
}
void Kernel::Ipc::Participates_dialog::_can_get_reply__error__invalid_server()
{
printf("Error in Kernel::Ipc::Participates_dialog::can_get_reply, "
"invalid server, halt\n");
halt();
}
void Kernel::Ipc::Participates_dialog::_recieve_message__error__invalid_message_size()
{
printf("Error in Kernel::Ipc::Participates_dialog::recieve_message, "
"invalid message size, halt");
Kernel::halt();
}
void Kernel::Ipc::Participates_dialog::_can_reply_and_get_request__verbose__replied_to_request()
{
if (!IPC__VERBOSE) return;
printf("Kernel::Ipc::Participates_dialog::can_reply_and_get_request, "
"replied to request, this=0x%p, _current_client=0x%p, "
"_message_size=%i\n",
this, _current_client, _message_size);
}
void Kernel::Ipc::Participates_dialog::_can_reply_and_get_request__verbose__recieved_request()
{
if (!IPC__VERBOSE) return;
printf("Kernel::Ipc::Participates_dialog::can_reply_and_get_request, "
"recieved request, this=0x%p, _current_client=0x%p, "
"_message_size=%i\n",
this, _current_client, _message_size);
if (IPC__VERBOSE >= 2)
print_message();
}
void Kernel::Ipc::Participates_dialog::_can_reply_and_get_request__verbose__waiting_for_request()
{
if (!IPC__VERBOSE) return;
printf("Kernel::Ipc::Participates_dialog::can_reply_and_get_request, "
"waiting for request, this=0x%p\n",
this);
}
void Kernel::Ipc::Participates_dialog::_send_message__verbose__success(Participant* server)
{
if (!IPC__VERBOSE) return;
printf("Kernel::Ipc::Participates_dialog::send_message, "
"this=0x%p, server=0x%p, _message_size=%i, print message\n",
this, server, _message_size);
if (IPC__VERBOSE >= 2)
print_message();
}
void Kernel::Ipc::Participates_dialog::_can_get_reply__verbose__waiting_for_reply(Participant* server)
{
if (!IPC__VERBOSE) return;
printf("Kernel::Ipc::Participates_dialog::can_get_reply, waiting for reply, "
"this=0x%p, server=0x%p, _message_size=%i\n",
this, server, _message_size);
}
void Kernel::Ipc::Participates_dialog::_can_get_reply__verbose__recieved_reply(Participant* server)
{
if (!IPC__VERBOSE) return;
printf("Kernel::Ipc::Participates_dialog::can_get_reply, recieved reply, "
"this=0x%p, server=0x%p, _message_size=%i\n",
this, server, _message_size);
}
void Kernel::Ipc::Participates_dialog::_send_message(Participant* server,
void* message,
unsigned size)
{
_message_size = size;
_message = (byte_t*)message;
server->announce_client(this);
_send_message__verbose__success(server);
}
bool Kernel::Ipc::Participates_dialog::can_reply_and_get_next_request(unsigned reply_size,
unsigned* request_size)
{
if (_current_client) {
_message_size = reply_size;
_message = (byte_t*)&_utcb->byte[0];
_can_reply_and_get_request__verbose__replied_to_request();
_current_client->recieve_reply(this);
_current_client = 0;
}
_current_client=_announced_clients.dequeue();
if (!_current_client) {
_can_reply_and_get_request__verbose__waiting_for_request();
return false;
} else{
_recieve_message(_current_client);
*request_size = _message_size;
_can_reply_and_get_request__verbose__recieved_request();
return true;
}
}
void Kernel::Ipc::Participates_dialog::_recieve_message(Participant* sender)
{
if (sender->message_size() > sizeof(Utcb))
_recieve_message__error__invalid_message_size();
_message_size = sender->message_size();
_message = (byte_t*)&_utcb->byte[0];
for (unsigned current_byte = 0; current_byte < _message_size; current_byte++)
_message[current_byte] =
sender->message(current_byte);
}
void Kernel::Ipc::Participates_dialog::announce_client(Participant* client)
{
_announced_clients.enqueue(client);
}
void Kernel::Ipc::Participates_dialog::recieve_reply(Participant* server)
{
if (!_waiting_for_reply || _recieved_reply)
return;
_recieve_message(server);
_recieved_reply = true;
}
bool Kernel::Ipc::Participates_dialog::can_get_reply(Participant * server,
unsigned request_size,
unsigned * reply_size)
{
if (!_waiting_for_reply) {
if (!server)
_can_get_reply__error__invalid_server();
_message_size = request_size;
_message = (byte_t*)&_utcb->byte[0];
_recieved_reply = false;
_waiting_for_reply = true;
server->announce_client(this);
}
if (!_recieved_reply) {
_can_get_reply__verbose__waiting_for_reply(server);
return false;
} else {
_can_get_reply__verbose__recieved_reply(server);
_waiting_for_reply = false;
*reply_size = _message_size;
return true;
}
}
#endif /* _KERNEL__INCLUDE__GENERIC__IPC_H_ */

View File

@ -1,153 +0,0 @@
/*
* \brief Interface for irq controllers
* \author Martin stein
* \date 2010-06-21
*/
/*
* Copyright (C) 2010-2013 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 _KERNEL__INCLUDE__GENERIC__IRQ_CONTROLLER_H_
#define _KERNEL__INCLUDE__GENERIC__IRQ_CONTROLLER_H_
#include <generic/blocking.h>
#include <generic/verbose.h>
#include <util/id_allocator.h>
#include <xilinx/xps_intc.h>
namespace Kernel {
enum {
IRQ_CONTROLLER__VERBOSE = 0,
BYTE_WIDTH=8,
};
template <typename DEVICE_T>
class Irq_controller_tpl : public DEVICE_T
{
protected:
/*************************
* Kernel_exit interface *
*************************/
inline void _on_kernel_exit();
public:
/**
* Returns occured IRQ ID with highest priority and masks it
*/
inline Irq_id get_irq();
/**
* Release IRQ and unmask it
*/
inline void ack_irq(Irq_id const & i);
Irq_controller_tpl(typename DEVICE_T::Constr_arg const & dca);
};
typedef Irq_controller_tpl<Xilinx::Xps_intc> Irq_controller;
class Irq_allocator :
public Id_allocator<Thread, Irq_id, BYTE_WIDTH>
{
typedef Id_allocator<Thread, Irq_id, BYTE_WIDTH> Allocator;
Irq_controller * const _controller;
public:
/**
* Error-codes that are returned by members
*/
enum Error {
NO_ERROR = 0,
HOLDER_DOESNT_OWN_IRQ = -1,
IRQ_IS_PENDING_YET = -2,
ALLOCATOR_ERROR = -3
};
/**
* Constructor
*/
Irq_allocator(Irq_controller * const ic) :
_controller(ic)
{ }
/**
* Free IRQ if the TID-according thread owns it
*/
inline Error free(Thread * const t, Irq_id irq);
/**
* Free IRQ if the TID-according thread owns it
*/
inline Error allocate(Thread * const t, Irq_id irq);
};
/**
* Pointer to kernels static IRQ allocator
*/
Irq_allocator * const irq_allocator();
/**
* Pointer to kernels static IRQ controller
*/
Irq_controller * const irq_controller();
}
template <typename DEVICE_T>
Kernel::Irq_controller_tpl<DEVICE_T>::Irq_controller_tpl(typename DEVICE_T::Constr_arg const & dca) :
DEVICE_T(dca)
{ }
template <typename DEVICE_T>
Kernel::Irq_id Kernel::Irq_controller_tpl<DEVICE_T>::get_irq()
{
Irq_id const i = DEVICE_T::next_irq();
DEVICE_T::mask(i);
return i;
}
template <typename DEVICE_T>
void Kernel::Irq_controller_tpl<DEVICE_T>::ack_irq(Irq_id const & i)
{
DEVICE_T::release(i);
DEVICE_T::unmask(i);
}
Kernel::Irq_allocator::Error
Kernel::Irq_allocator::allocate(Thread * const t, Irq_id irq)
{
if (_controller->pending(irq)) { return IRQ_IS_PENDING_YET; }
if (!Allocator::allocate(t, irq)) { return ALLOCATOR_ERROR; }
_controller->unmask(irq);
return NO_ERROR;
};
Kernel::Irq_allocator::Error
Kernel::Irq_allocator::free(Thread * const t, Irq_id irq)
{
if (_controller->pending(irq)) { return IRQ_IS_PENDING_YET; }
Allocator::free(irq);
_controller->mask(irq);
return NO_ERROR;
};
#endif /* _KERNEL__INCLUDE__GENERIC__IRQ_CONTROLLER_H_ */

View File

@ -1,21 +0,0 @@
/*
* \brief Import printf function
* \author Martin Stein
* \date 2010-10-12
*/
/*
* Copyright (C) 2010-2013 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 _KERNEL__INCLUDE__GENERIC__PRINTF_H_
#define _KERNEL__INCLUDE__GENERIC__PRINTF_H_
#include <base/printf.h>
using Genode::printf;
#endif /* _KERNEL__INCLUDE__GENERIC__PRINTF_H_ */

View File

@ -1,372 +0,0 @@
/*
* \brief Declaration of a round robin scheduler
* \author Martin stein
* \date 2010-06-25
*/
/*
* Copyright (C) 2010-2013 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 _KERNEL__GENERIC__INCLUDE__SCHEDULER_H_
#define _KERNEL__GENERIC__INCLUDE__SCHEDULER_H_
/* generic includes */
#include <generic/timer.h>
#include <generic/verbose.h>
/* util includes */
#include <util/queue.h>
namespace Kernel {
enum { SHOW_SCHEDULING = 0 };
enum { SCHEDULER__TRACE = 1,
SCHEDULER__VERBOSE = 0,
SCHEDULER__ERROR = 1,
SCHEDULER__WARNING = 1 };
class Exec_context;
class Platform;
class Scheduler : public Tracks_time
{
enum { MS_PER_ROUND_PER_CLIENT = SCHEDULING_MS_INTERVAL,
SCHEDULE__VERBOSE__SUCCESS = SCHEDULER__VERBOSE,
SCHEDULE__ERROR = SCHEDULER__ERROR };
public:
typedef Scheduling_timer Timer;
typedef unsigned int Quota;
typedef Kernel::Platform Ressource;
private:
Timer * const _timer;
const Quota _quota_per_round_per_client;
Ressource* _ressource;
bool _new_clients;
void _schedule();
inline Quota _ms_to_quota(unsigned int const &ms);
/**
* Utilise idle client as current client
*/
inline void _prep_idle_round();
public:
inline void time_consumed(Quota const & q);
enum { CLIENT__WARNING = 1,
CLIENT__VERBOSE = SCHEDULER__VERBOSE };
class Client_queue;
class Client : public Kernel::Queue<Client>::Item
{
friend class Scheduler;
friend class Client_queue;
typedef Kernel::Scheduler::Quota Quota;
Quota _quota;
Scheduler *_scheduler;
bool _sleeping;
protected:
typedef Kernel::Exec_context Context;
private:
inline Quota _consume(Quota const &consumed);
inline void _earn_quota(Quota const &q);
inline Context *_schedulable_context();
protected:
enum{ SCHEDULABLE_context__VERBOSE = 1 };
inline Client();
virtual ~Client();
inline void _sleep();
inline void _wake();
virtual Context *_context() = 0;
virtual bool _preemptable() = 0;
public:
virtual int label() = 0;
};
struct Client_queue : public Kernel::Queue<Client>
{
inline void print_state();
};
private:
Client_queue _client_queue;
Client* _current_client;
Client* _last_client;
Client* _idle_client;
public:
enum{ ADD__VERBOSE = SCHEDULER__VERBOSE||SHOW_SCHEDULING,
REMOVE__VERBOSE = SCHEDULER__VERBOSE||SHOW_SCHEDULING,
RUN__VERBOSE = SCHEDULER__VERBOSE||SHOW_SCHEDULING };
/**
* Constructor
* \param r Ressource that is shared by the clients
* \param t Timer to measure exclusive access duration
* \param idle_client this client gets scheduled if there's
* no other client, it can't be removed
*/
Scheduler(Ressource* r, Scheduling_timer * const t, Client* idle_client);
void add(Client* c);
void remove(Client* c);
void run();
inline Client* current_client();
inline void skip_next_time(Client* c);
protected:
/* debugging */
inline void _print_clients_via_labels();
inline void _run__verbose__success();
inline void _run__error__no_ready_client();
inline void _run__trace__client_checks();
inline void _schedule__error__no_clients();
inline void _schedule__verbose__success() ;
inline void _remove__warning__invalid_client();
inline void _remove__verbose__success(Client* c);
inline void _remove__trace(Client *c);
inline void _add__warning__invalid_client();
inline void _add__verbose__success();
};
/**
* Pointer to kernels static scheduler for execution time
*/
Scheduler *scheduler();
}
/***********************************
** Kernel::Scheduler definitions **
***********************************/
void Kernel::Scheduler::_prep_idle_round()
{
if(_current_client) { _client_queue.enqueue(_current_client); }
_current_client=_idle_client;
}
void Kernel::Scheduler::time_consumed(Quota const & q)
{
_current_client->_consume(q);
}
Kernel::Scheduler::Client* Kernel::Scheduler::current_client()
{
return _current_client;
}
void Kernel::Scheduler::skip_next_time(Client *c) { c->_quota=0; }
Kernel::Scheduler::Quota Kernel::Scheduler::_ms_to_quota(unsigned int const & ms)
{
return _timer->msec_to_native(ms);
}
void Kernel::Scheduler::_print_clients_via_labels()
{
printf("scheduled ");
_last_client ? printf("%i", _last_client->label())
: printf("ø");
printf("");
_current_client ? printf("%i", _current_client->label())
: printf("ø");
printf(", queue ");
_client_queue.print_state();
}
void Kernel::Scheduler::_run__verbose__success()
{
if (!RUN__VERBOSE)
return;
printf("Kernel::Scheduler::run, ");
_print_clients_via_labels();
printf("\n");
}
void Kernel::Scheduler::_run__error__no_ready_client()
{
if (!SCHEDULER__ERROR) return;
printf("Error in Kernel::Scheduler::run, no client is ready, halt\n");
halt();
}
void Kernel::Scheduler::_remove__trace(Client* c)
{
if (SCHEDULER__TRACE && Verbose::trace_current_kernel_pass())
printf("rm(%i) ", c->label());
}
void Kernel::Scheduler::_run__trace__client_checks()
{
if (SCHEDULER__TRACE && Verbose::trace_current_kernel_pass())
printf("ask(%i,%i) ",
_current_client->label(), _current_client->_quota);
}
void Kernel::Scheduler::_schedule__error__no_clients()
{
if (!SCHEDULER__ERROR) return;
printf("Error in Kernel::Scheduler::_schedule, no clients registered, halt\n");
halt();
}
void Kernel::Scheduler::_remove__warning__invalid_client()
{
if (!SCHEDULER__WARNING) return;
printf("Warning in Kernel::Scheduler::remove, client invalid, skip\n");
}
void Kernel::Scheduler::_add__warning__invalid_client()
{
if (!SCHEDULER__WARNING) return;
printf("Warning in Kernel::Scheduler::add, client invalid, skip\n");
}
void Kernel::Scheduler::_add__verbose__success()
{
if (!ADD__VERBOSE) return;
printf("Kernel::Scheduler::add, ");
_print_clients_via_labels();
printf(" ← )\n");
}
void Kernel::Scheduler::_remove__verbose__success(Client* c)
{
if (!REMOVE__VERBOSE) return;
printf("Kernel::Scheduler::remove, ");
_print_clients_via_labels();
printf(" → %i\n", c->label());
}
void Kernel::Scheduler::_schedule__verbose__success()
{
if (!SCHEDULER__VERBOSE) return;
Client* const a = _last_client;
Client* const b = _current_client;
Verbose::indent(10);
if (a) printf("from %i", a->label());
else printf("from NULL");
Verbose::indent(10);
printf("to %i\n", b->label());
}
/*******************************************
** Kernel::Scheduler::Client definitions **
*******************************************/
Kernel::Scheduler::Client::Context *
Kernel::Scheduler::Client::_schedulable_context()
{
Context *result = 0;
if (!_sleeping) {
result = _context();
if (_sleeping)
result = 0;
}
return result;
}
Kernel::Scheduler::Client::Quota
Kernel::Scheduler::Client::_consume(Quota const &consumed)
{
if (consumed > _quota) {
_quota = 0;
} else{
_quota = _quota - consumed;
}
return _quota;
}
Kernel::Scheduler::Client::Client()
: _quota(0), _scheduler(0), _sleeping(false) { }
void Kernel::Scheduler::Client::_earn_quota(Quota const &q) { _quota += q; }
void Kernel::Scheduler::Client::_sleep() { _sleeping = true; }
void Kernel::Scheduler::Client::_wake(){ _sleeping = false; }
/*************************************************
** Kernel::Scheduler::Client_queue definitions **
*************************************************/
void Kernel::Scheduler::Client_queue::print_state()
{
Client *i = _head;
if (!i) printf("ø");
while (i) {
printf("%i", i->label());
if (i != _tail) printf("");
i = i->_next;
}
}
#endif /* _KERNEL__INCLUDE__SCHEDULER_H_ */

View File

@ -1,190 +0,0 @@
/*
* \brief Syscall event handling behaviors
* \author Martin Stein
* \date 2010-11-18
*/
/*
* Copyright (C) 2010-2013 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 _KERNEL__INCLUDE__GENERIC__SYSCALL_EVENTS_H_
#define _KERNEL__INCLUDE__GENERIC__SYSCALL_EVENTS_H_
#include <kernel/types.h>
#include <generic/event.h>
namespace Kernel {
enum { SYSCALL_EVENT__ERROR = 1,
SYSCALL_EVENT__WARNING = 1,
SYSCALL_EVENT__VERBOSE = 0 };
class Thread;
class Syscall_event : public Event { };
class Print_char : public Syscall_event {
protected:
virtual bool _permission_to_do_print_char() = 0;
public:
typedef On_occurence__result On_print_char__result;
On_print_char__result on_print_char(char c);
};
class Thread_create : public Syscall_event {
protected:
virtual bool _permission_to_do_thread_create()=0;
void _on_thread_create__warning__failed()
{
if (SYSCALL_EVENT__WARNING)
printf("Warning in Kernel::Thread_create::on_thread_create, syscall failed\n");
}
void _on_thread_create__verbose__success(Thread *t);
public:
struct Argument
{
Thread_id tid;
Protection_id pid;
Thread_id pager_tid;
Utcb* utcb;
addr_t vip;
addr_t vsp;
bool is_privileged;
};
typedef Thread_create_types::Result Result;
typedef On_occurence__result On_thread_create__result;
On_thread_create__result on_thread_create(Argument *a, Result *r);
};
class Thread_kill : public Syscall_event
{
protected:
virtual bool _permission_to_do_thread_kill() = 0;
void _on_thread_kill__warning__failed()
{
if (SYSCALL_EVENT__WARNING)
printf("Warning in Kernel::Thread_kill::on_thread_kill, syscall failed\n");
}
void _on_thread_kill__verbose__success(Thread_id tid);
public:
struct Argument { Thread_id tid; };
typedef Thread_kill_types::Result Result;
typedef On_occurence__result On_thread_kill__result;
On_thread_kill__result on_thread_kill(Argument *a, Result *r);
};
class Thread_sleep : public Syscall_event
{
protected:
void _on_thread_sleep__verbose__success();
public:
typedef On_occurence__result On_thread_sleep__result;
On_thread_sleep__result on_thread_sleep();
};
class Thread_wake : public Syscall_event
{
protected:
virtual bool _permission_to_do_thread_wake(Thread *t) = 0;
void _on_thread_wake__warning__failed()
{
if (SYSCALL_EVENT__WARNING)
printf("Warning in Kernel::Thread_wake::on_thread_wake, syscall failed\n");
}
void _on_thread_wake__verbose__success(Thread_id tid);
public:
struct Argument { Thread_id tid; };
typedef Thread_wake_types::Result Result;
typedef On_occurence__result On_thread_wake__result;
On_thread_wake__result on_thread_wake(Argument* a, Result* r);
};
class Tlb_load : public Syscall_event
{
protected:
virtual bool _permission_to_do_tlb_load() = 0;
public:
void on_tlb_load(Paging::Resolution* r);
};
class Thread_pager : public Syscall_event {
protected:
virtual bool _permission_to_do_thread_pager(Thread_id tid) = 0;
public:
void on_thread_pager(Thread_id target_tid, Thread_id pager_tid);
};
class Tlb_flush : public Syscall_event {
protected:
virtual bool _permission_to_do_tlb_flush() = 0;
public:
void on_tlb_flush(Paging::Virtual_page *first_page, unsigned size);
};
class Thread_yield: public Syscall_event
{
public:
virtual void yield()=0;
};
}
#endif /* _KERNEL__INCLUDE__GENERIC__SYSCALL_EVENTS_H_ */

View File

@ -1,197 +0,0 @@
/*
* \brief Declaration of gecoh timer device interface
* \author Martin stein
* \date 2010-06-23
*/
/*
* Copyright (C) 2010-2013 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 _KERNEL__INCLUDE__GENERIC__TIMER_H_
#define _KERNEL__INCLUDE__GENERIC__TIMER_H_
#include <generic/verbose.h>
#include <generic/event.h>
#include <generic/blocking.h>
#include <generic/irq_controller.h>
#include <xilinx/xps_timer.h>
#include <cpu/config.h>
extern Cpu::uint32_t volatile * _kernel_timer_ctrl;
extern Cpu::uint32_t _kernel_timer_ctrl_start;
namespace Kernel {
enum {
TIMER__ERROR = 1,
TIMER__WARNING = 1,
TIMER__VERBOSE = 0,
TIMER__TRACE = 1,
};
struct Tracks_time {
virtual ~Tracks_time(){}
virtual void time_consumed(unsigned int const & t) = 0;
};
template <typename DEVICE_T>
class Timer : public Kernel_entry::Listener,
public Kernel_exit::Listener,
public DEVICE_T
{
private:
Irq_id const _irq_id;
unsigned int _start_value, _stop_value;
Tracks_time * _client;
protected:
/* Kernel::Kernel_entry_event::Listener interface */
void _on_kernel_entry();
/* Kernel::Kernel_exit_event::Listener interface */
void _on_kernel_exit();
/* debugging */
inline void _on_kernel_exit__error__start_value_invalid();
inline void _on_kernel_entry__verbose__success();
inline void _on_kernel_exit__verbose__success();
public:
Timer(Irq_id const & i, addr_t const & dca);
inline bool is_busy();
inline void track_time(unsigned int const & v, Tracks_time * const c);
inline Irq_id irq_id();
inline unsigned int stop_value();
inline unsigned int start_value();
/* debugging */
void inline _start__trace(unsigned int const &v);
void inline _stop__trace(unsigned int const &v);
};
typedef Timer<Xilinx::Xps_timer> Scheduling_timer;
}
/*******************
** Kernel::Timer **
*******************/
template <typename DEVICE_T>
Kernel::Timer<DEVICE_T>::Timer(Irq_id const & i,
addr_t const & dca) :
DEVICE_T(dca),
_irq_id(i),
_start_value(0),
_stop_value(0)
{
irq_controller()->unmask(_irq_id);
}
template <typename DEVICE_T>
void Kernel::Timer<DEVICE_T>::_start__trace(unsigned int const &v)
{
if (TIMER__TRACE && Verbose::trace_current_kernel_pass())
printf("start(%i) ", v);
}
template <typename DEVICE_T>
void Kernel::Timer<DEVICE_T>::_stop__trace(unsigned int const& v)
{
if (TIMER__TRACE && Verbose::trace_current_kernel_pass())
printf("stop(%i) ", v);
}
template <typename DEVICE_T>
unsigned int Kernel::Timer<DEVICE_T>::stop_value() { return _stop_value; }
template <typename DEVICE_T>
void Kernel::Timer<DEVICE_T>::_on_kernel_exit__error__start_value_invalid()
{
if (TIMER__ERROR)
printf("Error in Kernel::Timer<DEVICE_T>::_on_kernel_exit,"
"_start_value=%i invalid\n", _start_value);
halt();
}
template <typename DEVICE_T>
void Kernel::Timer<DEVICE_T>::_on_kernel_entry__verbose__success()
{
if (!TIMER__VERBOSE) return;
printf("Kernel::Timer<DEVICE_T>::_on_kernel_entry,"
"_stop_value=%i\n", _stop_value);
}
template <typename DEVICE_T>
void Kernel::Timer<DEVICE_T>::_on_kernel_exit__verbose__success()
{
if (!TIMER__VERBOSE) return;
printf("Kernel::Timer<DEVICE_T>::_on_kernel_exit,"
"_start_value=%i\n", _start_value);
}
template <typename DEVICE_T>
Kernel::Irq_id Kernel::Timer<DEVICE_T>::irq_id() { return _irq_id; }
template <typename DEVICE_T>
unsigned int Kernel::Timer<DEVICE_T>::start_value() { return _start_value; }
template <typename DEVICE_T>
void Kernel::Timer<DEVICE_T>::track_time(unsigned int const & v, Tracks_time * const c) {
_start_value=v;
_client = c;
}
template <typename DEVICE_T>
void Kernel::Timer<DEVICE_T>::_on_kernel_entry()
{
_stop_value = DEVICE_T::value();
_stop__trace(_stop_value);
unsigned int t = start_value()- stop_value();
_client->time_consumed(t);
_on_kernel_entry__verbose__success();
}
template <typename DEVICE_T>
void Kernel::Timer<DEVICE_T>::_on_kernel_exit()
{
if (!_start_value)
_on_kernel_exit__error__start_value_invalid();
_start__trace(_start_value);
DEVICE_T::prepare_oneshot(_start_value, _kernel_timer_ctrl, _kernel_timer_ctrl_start);
}
#endif /* _KERNEL__INCLUDE__GENERIC__TIMER_H_ */

View File

@ -1,152 +0,0 @@
/*
* \brief Generic Translation lookaside buffer interface
* \author Martin Stein
* \date 2010-11-08
*/
/*
* Copyright (C) 2010-2013 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 _KERNEL__INCLUDE__GENERIC__TLB_H_
#define _KERNEL__INCLUDE__GENERIC__TLB_H_
#include <kernel/types.h>
#include <xilinx/microblaze.h>
namespace Kernel {
template <typename DEV_T>
class Tlb_tpl : public DEV_T
{
private:
typedef typename DEV_T::Entry_id Entry_id;
Entry_id _current_entry_id;
static Entry_id const fixed_entry_id_1 = 0;
static Entry_id const fixed_entry_id_2 = 1;
void _next_entry_id()
{
_current_entry_id++;
if (_current_entry_id >= DEV_T::max_entry_id()) {
_current_entry_id = 0;
}
}
public:
typedef Paging::Virtual_page Virtual_page;
typedef Paging::Physical_page Physical_page;
typedef Paging::Resolution Resolution;
Tlb_tpl() : _current_entry_id(0) { }
/**
* Add resolution to the tlb (not persistent)
*/
void add(Resolution* r)
{
if (!r->valid()) {
printf("Error in Kernel::Tlb::add, invalid page\n");
}
while (1) {
if (!fixed(_current_entry_id)) { break; }
else { _next_entry_id(); }
}
if(DEV_T::set_entry(_current_entry_id,
r->physical_page.address(), r->virtual_page.address(),
r->virtual_page.protection_id(),
Paging::size_log2_by_physical_page_size[r->physical_page.size()],
r->physical_page.permissions() == Paging::Physical_page::RW ||
r->physical_page.permissions() == Paging::Physical_page::RWX,
r->physical_page.permissions() == Paging::Physical_page::RX ||
r->physical_page.permissions() == Paging::Physical_page::RWX))
{
PERR("Writing to TLB failed");
}
_next_entry_id();
}
/**
* Add fixed resolution to the tlb (persistent till overwritten by
* fixed resolution)
*/
void add_fixed(Resolution* r1, Resolution* r2)
{
if(DEV_T::set_entry(fixed_entry_id_1,
r1->physical_page.address(), r1->virtual_page.address(),
r1->virtual_page.protection_id(),
Paging::size_log2_by_physical_page_size[r1->physical_page.size()],
r1->physical_page.permissions() == Paging::Physical_page::RW ||
r1->physical_page.permissions() == Paging::Physical_page::RWX,
r1->physical_page.permissions() == Paging::Physical_page::RX ||
r1->physical_page.permissions() == Paging::Physical_page::RWX))
{
PERR("Writing to TLB failed");
}
if(DEV_T::set_entry(fixed_entry_id_2,
r2->physical_page.address(), r2->virtual_page.address(),
r2->virtual_page.protection_id(),
Paging::size_log2_by_physical_page_size[r2->physical_page.size()],
r2->physical_page.permissions() == Paging::Physical_page::RW ||
r2->physical_page.permissions() == Paging::Physical_page::RWX,
r2->physical_page.permissions() == Paging::Physical_page::RX ||
r2->physical_page.permissions() == Paging::Physical_page::RWX))
{
PERR("Writing to TLB failed");
}
}
bool fixed(Entry_id i) {
return (i == fixed_entry_id_1) || (i == fixed_entry_id_2);
}
void flush(Virtual_page *base, unsigned size);
};
typedef Tlb_tpl<Xilinx::Microblaze::Mmu> Tlb;
/**
* Pointer to kernels static translation lookaside buffer
*/
Tlb * tlb();
}
template <typename DEV_T>
void Kernel::Tlb_tpl<DEV_T>::flush(Virtual_page *base, unsigned size)
{
addr_t area_base = base->address();
addr_t area_top = area_base + size;
for (Entry_id i=0; i <= DEV_T::MAX_ENTRY_ID; i++) {
if (fixed(i)) { continue; }
Cpu::addr_t page;
Protection_id pid;
unsigned size_log2;
if(DEV_T::get_entry(i, page, pid, size_log2)) {
PERR("Reading TLB entry failed");
}
if (base->protection_id() != pid) { continue; }
if(page < area_top && (page + (1<<size_log2)) > area_base) {
DEV_T::clear_entry(i);
}
}
}
#endif /* _KERNEL__INCLUDE__GENERIC__TLB_H_ */

View File

@ -1,107 +0,0 @@
/*
* \brief Macros for errors, warnings, debugging
* \author Martin stein
* \date 2010-06-22
*/
/*
* Copyright (C) 2010-2013 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 _KERNEL__INCLUDE__VERBOSE_H_
#define _KERNEL__INCLUDE__VERBOSE_H_
/* kernel includes */
#include <kernel/types.h>
/* OS includes */
#include <base/printf.h>
#include <cpu/prints.h>
using Genode::printf;
namespace Kernel {
using namespace Cpu;
/**
* Halt all executions (uninteruptable endless loop)
*/
void halt();
unsigned word_width();
/**
* Implementing verbose helper methods
*/
namespace Verbose {
enum {
TRACE_KERNEL_PASSES = 0,
TRACE_ALL_THREAD_IDS = 1,
TRACE_ALL_PROTECTION_IDS = 1,
TRACE_ALL_SYSCALL_IDS = 1,
TRACE_ALL_EXCEPTION_IDS = 1,
TRACE_ALL_IRQ_IDS = 1
};
Kernel::Thread_id const trace_these_thread_ids[]= { 0 };
Kernel::Protection_id const trace_these_protection_ids[] = {
Roottask::PROTECTION_ID, Kernel::INVALID_PROTECTION_ID };
Kernel::Syscall_id const trace_these_syscall_ids[] = { INVALID_SYSCALL_ID };
// TLB_LOAD ,
// TLB_FLUSH ,
// THREAD_CREATE,
// THREAD_KILL ,
// THREAD_SLEEP ,
// THREAD_WAKE ,
// THREAD_YIELD ,
// THREAD_PAGER ,
// IPC_REQUEST ,
// IPC_SERVE ,
// PRINT_CHAR ,
// PRINT_INFO ,
Kernel::Exception_id const trace_these_exception_ids[] = { INVALID_EXCEPTION_ID };
// FAST_SIMPLEX_LINK ,
// UNALIGNED ,
// ILLEGAL_OPCODE ,
// INSTRUCTION_BUS ,
// DATA_BUS ,
// DIV_BY_ZERO_EXCEPTON ,
// FPU ,
// PRIVILEGED_INSTRUCTION,
// INTERRUPT ,
// EXTERNAL_NON_MASKABLE_BREAK,
// EXTERNAL_MASKABLE_BREAK ,
// DATA_STORAGE ,
// INSTRUCTION_STORAGE ,
// DATA_TLB_MISS ,
// INSTRUCTION_TLB_MISS,
/*
* Tracing for specific kernel-entry causes can be configured in
* 'platform.cc'.
*/
bool trace_current_kernel_pass();
void begin__trace_current_kernel_pass();
void inline indent(unsigned int const &i);
}
}
void Kernel::Verbose::indent(unsigned int const &indent)
{
for (unsigned int i = 0; i < indent; i++)
_prints_chr1(' ');
}
#endif /* _KERNEL__INCLUDE__VERBOSE_H_ */

View File

@ -1,729 +0,0 @@
/*
* \brief Implementations for kernels platform class
* \author Martin Stein
* \date 2010-10-01
*/
/*
* Copyright (C) 2010-2013 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__PETALOGIX_S3ADSP1800_MMU__PLATFORM__PLATFORM_H_
#define _INCLUDE__PETALOGIX_S3ADSP1800_MMU__PLATFORM__PLATFORM_H_
/* Device includes */
#include <xilinx/xps_intc.h>
#include <xilinx/xps_timer.h>
#include <xilinx/microblaze.h>
/* Kernel includes */
#include <kernel/types.h>
#include <generic/timer.h>
#include <generic/verbose.h>
#include <generic/blocking.h>
/*
* Asm labels where to enter an irq/exception/syscall from userland, and vice
* versa the userland from inside the kernel
*/
extern Kernel::word_t _syscall_entry;
extern Kernel::word_t _exception_entry;
extern Kernel::word_t _interrupt_entry;
extern Kernel::word_t _userland_entry;
extern Kernel::word_t _atomic_ops_begin;
extern Kernel::word_t _atomic_ops_end;
extern Kernel::addr_t _call_after_kernel;
namespace Kernel {
enum {
PLATFORM__TRACE = 1,
PLATFORM__VERBOSE = 0,
PLATFORM__VERBOSE__THREAD_TRACING = 1,
PLATFORM_THREAD__ERROR = 1,
PLATFORM_THREAD__WARNING = 1,
PLATFORM_THREAD__VERBOSE = 0,
PLATFORM_IRQ__VERBOSE = 0,
PLATFORM_EXCEPTION__VERBOSE = 0,
PLATFORM_SYSCALL__VERBOSE = 0,
WORD_WIDTH_LOG2 = 5,
BYTE_WIDTH_LOG2 = 3
};
class Platform_thread;
class Platform;
/**
* Get kernel's static platform representation
*/
Platform* platform();
/**
* Platform specific execution context
*/
struct Exec_context
{
typedef Kernel::Protection_id Protection_id;
typedef Kernel::word_t word_t;
/**
* Type constraints
*/
enum{
WORD_WIDTH_LOG2 = Kernel::WORD_WIDTH_LOG2,
BYTE_WIDTH_LOG2 = Kernel::BYTE_WIDTH_LOG2,
WORD_SIZE = 1 << (WORD_WIDTH_LOG2-BYTE_WIDTH_LOG2) };
/**
* Blocking types
*/
enum{
NO_BLOCKING = 0,
IRQ_BLOCKING = 1,
EXCEPTION_BLOCKING = 2,
SYSCALL_BLOCKING = 3,
BLOCKING_TYPE_RANGE = 4
};
/**
* Register constraints
*/
enum {
/* rmsr */
RMSR_BE_LSHIFT = 0, RMSR_BE_MASK = 1 << RMSR_BE_LSHIFT,
RMSR_IE_LSHIFT = 1, RMSR_IE_MASK = 1 << RMSR_IE_LSHIFT,
RMSR_C_LSHIFT = 2, RMSR_C_MASK = 1 << RMSR_C_LSHIFT,
RMSR_BIP_LSHIFT = 3, RMSR_BIP_MASK = 1 << RMSR_BIP_LSHIFT,
RMSR_FSL_LSHIFT = 4, RMSR_FSL_MASK = 1 << RMSR_FSL_LSHIFT,
RMSR_ICE_LSHIFT = 5, RMSR_ICE_MASK = 1 << RMSR_ICE_LSHIFT,
RMSR_DZ_LSHIFT = 6, RMSR_DZ_MASK = 1 << RMSR_DZ_LSHIFT,
RMSR_DCE_LSHIFT = 7, RMSR_DCE_MASK = 1 << RMSR_DCE_LSHIFT,
RMSR_EE_LSHIFT = 8, RMSR_EE_MASK = 1 << RMSR_EE_LSHIFT,
RMSR_EIP_LSHIFT = 9, RMSR_EIP_MASK = 1 << RMSR_EIP_LSHIFT,
RMSR_PVR_LSHIFT = 10, RMSR_PVR_MASK = 1 << RMSR_PVR_LSHIFT,
RMSR_UM_LSHIFT = 11, RMSR_UM_MASK = 1 << RMSR_UM_LSHIFT,
RMSR_UMS_LSHIFT = 12, RMSR_UMS_MASK = 1 << RMSR_UMS_LSHIFT,
RMSR_VM_LSHIFT = 13, RMSR_VM_MASK = 1 << RMSR_VM_LSHIFT,
RMSR_VMS_LSHIFT = 14, RMSR_VMS_MASK = 1 << RMSR_VMS_LSHIFT,
RMSR_CC_LSHIFT = 31, RMSR_CC_MASK = 1 << RMSR_CC_LSHIFT,
/* resr */
RESR_EC_LSHIFT = 0, RESR_EC_MASK = 0x1F<<RESR_EC_LSHIFT,
RESR_ESS_LSHIFT = 5, RESR_ESS_MASK = 0x7F<<RESR_ESS_LSHIFT,
RESR_DS_LSHIFT = 12, RESR_DS_MASK = 1<<RESR_DS_LSHIFT,
/* resr-ess */
RESR_ESS_DATA_TLB_MISS_S_LSHIFT = 5,
RESR_ESS_DATA_TLB_MISS_S_MASK =
1 << (RESR_ESS_LSHIFT + RESR_ESS_DATA_TLB_MISS_S_LSHIFT)
};
/**
* word_t offsets for execution context
*/
enum {
/* General purpose registers */
R0 = 0, R1 = 1, R2 = 2, R3 = 3, R4 = 4, R5 = 5, R6 = 6, R7 = 7, R8 = 8, R9 = 9,
R10=10, R11=11, R12=12, R13=13, R14=14, R15=15, R16=16, R17=17, R18=18, R19=19,
R20=20, R21=21, R22=22, R23=23, R24=24, R25=25, R26=26, R27=27, R28=28, R29=29,
R30=30, R31=31,
/* Special purpose registers */
RPC = 32, RMSR = 33, REAR = 34, RESR = 35, RPID = 36,
/* special state values */
BLOCKING_TYPE = 37
};
enum{
FIRST_GENERAL_PURPOSE_REGISTER = 0,
LAST_GENERAL_PURPOSE_REGISTER = 31,
CONTEXT_WORD_SIZE = 38
};
/**
* Execution context space read and written by the assembler
* kernel- and userland-entries
* Must be first member instance of Exec_context!
*
* Attention: Any changes in here have to be commited to
* platforms exec_context_macros.s!
*/
word_t
r0, r1, r2, r3, r4, r5, r6, r7, r8, r9,
r10, r11, r12, r13, r14, r15, r16, r17, r18, r19,
r20, r21, r22, r23, r24, r25, r26, r27, r28, r29,
r30, r31,
rpc, rmsr, rear, resr, rpid, blocking_type;
Platform_thread* holder;
word_t word_at_offset(unsigned offset)
{
word_t* w=(word_t*)((uint32_t)this+offset*WORD_SIZE);
return *w;
}
Exec_context(Platform_thread* h) : holder(h)
{
word_t* context = (word_t*)this;
for (unsigned i = 0; i < CONTEXT_WORD_SIZE; i++)
context[i] = 0;
}
void print_general_purpose_registers()
{
unsigned i = FIRST_GENERAL_PURPOSE_REGISTER;
while(i <= LAST_GENERAL_PURPOSE_REGISTER) {
if(!((i ^0) & 3)) {
if(i) { printf("\n"); }
}
printf("r%2d=0x%8X ", i, word_at_offset(i));
i++;
}
}
void print_special_purpose_registers()
{
printf("rpc=0x%8X rmsr=0x%8X rear=0x%8X resr=%8X rpid=%8X",
rpc, rmsr, rear, resr, rpid);
}
void print_content(unsigned indent)
{
print_general_purpose_registers();
printf("\n");
print_special_purpose_registers();
printf(" blocking_type=%i", blocking_type);
}
unsigned int exception_cause() {
return (resr & RESR_EC_MASK) >> RESR_EC_LSHIFT; }
};
}
extern Kernel::Exec_context* _userland_context;
namespace Kernel {
/**
* Platform representation
*/
class Platform : public Kernel_entry::Listener
{
public:
/**
* General configuration
*/
enum {
ATOMIC_OPS_PAGE_SIZE_LOG2 = DEFAULT_PAGE_SIZE_LOG2,
KERNEL_ENTRY_SIZE_LOG2 = DEFAULT_PAGE_SIZE_LOG2
};
/**
* Verbose, errors, warnings
*/
enum {
VERBOSE__CONSTRUCTOR = PLATFORM__VERBOSE,
VERBOSE__ENTER_USERLAND = PLATFORM__VERBOSE
};
/**
* General platform constraints
*/
enum {
WORD_WIDTH_LOG2 = Kernel::WORD_WIDTH_LOG2,
BYTE_WIDTH_LOG2 = Kernel::BYTE_WIDTH_LOG2,
BYTE_WIDTH = 1 << BYTE_WIDTH_LOG2,
WORD_WIDTH = 1 << WORD_WIDTH_LOG2,
WORD_SIZE = 1 << (WORD_WIDTH_LOG2-BYTE_WIDTH_LOG2),
WORD_HALFWIDTH = WORD_WIDTH >> 1,
WORD_LEFTHALF_MASK = ~0 << WORD_HALFWIDTH ,
WORD_RIGHTHALF_MASK = ~WORD_LEFTHALF_MASK
};
typedef uint32_t word_t;
typedef uint32_t Register;
private:
Kernel::Tlb _tlb;
/**
* Processor specific
*/
enum {
ASM_IMM = 0xb0000000,
ASM_BRAI = 0xb8080000,
ASM_RTSD = 0xb6000000,
ASM_NOP = 0x80000000,
SYSCALL_ENTRY = 0x00000008,
INTERRUPT_ENTRY = 0x00000010,
EXCEPTION_ENTRY = 0x00000020
};
void _initial_tlb_entries()
{
using namespace Paging;
Physical_page::size_t atomic_ops_pps, kernel_entry_pps;
if (Physical_page::size_by_size_log2(
atomic_ops_pps, ATOMIC_OPS_PAGE_SIZE_LOG2) ||
Physical_page::size_by_size_log2(
kernel_entry_pps, KERNEL_ENTRY_SIZE_LOG2))
{
printf("Error in Kernel::Platform::_initial_tlb_entries");
return;
};
Physical_page atomic_ops_pp((addr_t)&_atomic_ops_begin,
atomic_ops_pps, Physical_page::RX);
Virtual_page atomic_ops_vp(atomic_ops_pp.address(),
UNIVERSAL_PROTECTION_ID);
Resolution atomic_ops_res(&atomic_ops_vp, &atomic_ops_pp);
Physical_page kernel_entry_pp((addr_t)0, kernel_entry_pps,
Physical_page::RX);
Virtual_page kernel_entry_vp(kernel_entry_pp.address(),
UNIVERSAL_PROTECTION_ID);
Resolution kernel_entry_res(&kernel_entry_vp, &kernel_entry_pp);
tlb()->add_fixed(&atomic_ops_res, &kernel_entry_res);
}
/**
* Initialize the ability to enter userland
*/
inline void _init_userland_entry() {
_call_after_kernel=(addr_t)&_userland_entry; }
/**
* Fill in jump to CPU's 2-word-width exception entry
*/
inline void _init_exception_entry()
{
*(word_t*)EXCEPTION_ENTRY =
ASM_IMM | ((word_t)&_exception_entry & WORD_LEFTHALF_MASK) >> WORD_HALFWIDTH;
*(word_t*)(EXCEPTION_ENTRY + WORD_SIZE) =
ASM_BRAI | ((word_t)&_exception_entry & WORD_RIGHTHALF_MASK);
}
/**
* Fill in jump to CPU's 2-word-width syscall entry
*/
inline void _init_syscall_entry()
{
*(word_t*)SYSCALL_ENTRY =
ASM_IMM | ((word_t)&_syscall_entry & WORD_LEFTHALF_MASK) >> WORD_HALFWIDTH;
*(word_t*)(SYSCALL_ENTRY + WORD_SIZE) =
ASM_BRAI | (word_t) &_syscall_entry & WORD_RIGHTHALF_MASK; }
/**
* Fill in jump to CPU's 2-word-width interrupt entry
*/
inline void _init_interrupt_entry()
{
*((word_t*) INTERRUPT_ENTRY) =
ASM_IMM | ((word_t)&_interrupt_entry & WORD_LEFTHALF_MASK) >> WORD_HALFWIDTH;
*((word_t*)(INTERRUPT_ENTRY + WORD_SIZE)) =
ASM_BRAI | (word_t) &_interrupt_entry & WORD_RIGHTHALF_MASK;
}
public:
/**
* Constructor
*/
Platform();
bool is_atomic_operation(void* ip)
{
enum {
SIZE = (1 << ATOMIC_OPS_PAGE_SIZE_LOG2),
SIZE_WORDS = SIZE/sizeof(word_t)
};
static word_t *const _first_atomic_op = &_atomic_ops_begin;
static word_t *const _last_atomic_op =
_first_atomic_op + (SIZE_WORDS-1);
return ((ip >=_first_atomic_op) & (ip <=_last_atomic_op));
}
/**
* Set execution context loaded at next userland entry
*/
inline int userland_context(Exec_context* c)
{
_userland_context = c;
_userland_context__verbose__set(c);
return 0;
}
/**
* Lock the platforms execution ability to one execution context
*/
inline void lock(Exec_context *c){ userland_context(c); }
/**
* Set return address register
*
* It is essential that this function is always inline!
*/
inline int return_address(addr_t a)
{
asm volatile("add r15, %0, r0"::"r"((Register)a):);
return 0;
}
/**
* Halt whole system
*/
inline void halt() { asm volatile ("bri 0"); };
/**
* Get the platforms general IRQ-controller
*/
inline Irq_controller * const irq_controller();
/**
* Get the timer that is reserved for kernels schedulinge
*/
inline Scheduling_timer * const timer();
Tlb *tlb() { return &_tlb; };
protected:
void _on_kernel_entry__trace__thread_interrupts();
void _on_kernel_entry__verbose__called()
{
if (PLATFORM__VERBOSE)
printf("Kernel::Platform::_on_kernel_entry\n");
}
void _on_kernel_entry();
void _userland_context__verbose__set(Exec_context* c)
{
if (!PLATFORM__VERBOSE) return;
if (_userland_context) {
printf("Kernel::Platform::_userland_context, new userland context c=0x%8X, printing contents", (uint32_t)_userland_context);
c->print_content(2);
} else
printf("Kernel::Platform::_userland_context, no userland context");
printf("\n");
}
};
class Platform_blocking
{
protected:
typedef Kernel::Exec_context Context;
typedef Kernel::Platform_thread Owner;
Owner* _owner;
Context* _context;
public:
/**
* Constructor
*/
Platform_blocking(Owner* o, Context* c)
: _owner(o), _context(c) {}
};
/**
* Platform-specific IRQ
*/
class Platform_irq : public Platform_blocking, public Irq
{
public:
/**
* Constructor
*/
Platform_irq(Owner* o, Context* c) : Platform_blocking(o,c) {}
void block();
protected:
void _block__verbose__success()
{
if (PLATFORM_IRQ__VERBOSE)
printf("Platform_irq::block(), _id=%i\n", _id);
}
};
class Platform_exception : public Platform_blocking, public Exception
{
protected:
Protection_id protection_id();
addr_t address();
bool attempted_write_access();
public:
/**
* Constructor
*/
Platform_exception(Owner* o, Context* c) : Platform_blocking(o, c) { }
void block(Exec_context * c);
};
class Platform_syscall : public Platform_blocking, public Syscall
{
public:
/**
* Constructor
*/
Platform_syscall(Owner *o, Context *c, Source *s) :
Platform_blocking(o,c),
Syscall(&c->r30, &c->r29, &c->r28,
&c->r27, &c->r26, &c->r25,
&c->r24, &c->r30, s)
{ }
void block();
protected:
void _block__verbose__success()
{
if (PLATFORM_IRQ__VERBOSE)
printf("Platform_syscall::block(), _id=%i\n", _id);
}
};
/**
* Platform-specific thread implementations
*/
class Platform_thread
{
typedef Kernel::Blocking Blocking;
enum {
INITIAL_RMSR = 1 << Exec_context::RMSR_PVR_LSHIFT
| 1 << Exec_context::RMSR_UMS_LSHIFT
| 1 << Exec_context::RMSR_VMS_LSHIFT,
INITIAL_BLOCKING_TYPE = Exec_context::NO_BLOCKING
};
Platform_irq _irq;
Platform_exception _exception;
Platform_syscall _syscall;
Exec_context _exec_context;
/* if not zero, this thread is blocked */
Blocking* _blocking;
public:
bool timer_interrupted()
{
return false;
}
void yield_after_atomic_operation() { _exec_context.r31 = 1; }
void unblock() { _blocking = 0; }
typedef Kernel::Protection_id Protection_id;
Platform_thread() :
_irq(this, &_exec_context),
_exception(this, &_exec_context),
_syscall(this, &_exec_context, 0),
_exec_context(this),
_blocking(0)
{ }
Platform_thread(addr_t ip,
addr_t sp,
Protection_id pid,
Syscall::Source *sc)
:
_irq(this, &_exec_context),
_exception(this, &_exec_context),
_syscall(this, &_exec_context, sc),
_exec_context(this),
_blocking(0)
{
_exec_context.rpc = ip;
_exec_context.r1 = sp;
_exec_context.rpid = pid;
_exec_context.blocking_type= INITIAL_BLOCKING_TYPE;
_exec_context.rmsr = INITIAL_RMSR; }
enum { BLOCK__ERROR = 1,
BLOCK__WARNING = 1};
/**
* Get thread blocked if there is a blocking at execution context
*/
void on_kernel_entry()
{
using Kernel::Exec_context;
switch (_exec_context.blocking_type) {
case Exec_context::NO_BLOCKING:
_blocking = 0;
break;
case Exec_context::IRQ_BLOCKING:
_irq.block();
_blocking = &_irq;
break;
case Exec_context::EXCEPTION_BLOCKING:
_exception.block(&_exec_context);
_blocking = &_exception;
break;
case Exec_context::SYSCALL_BLOCKING:
_syscall.block();
_blocking = &_syscall;
break;
default:
_block__error__unknown_blocking_type();
}
_block__verbose__success();
}
Protection_id protection_id() {
return (Protection_id)_exec_context.rpid; }
addr_t instruction_pointer() {
return (addr_t)_exec_context.rpc; }
Exec_context* exec_context() {
return &_exec_context; }
Exec_context* unblocked_exec_context()
{
Exec_context* result=&_exec_context;
if (_blocking) {
if (!_blocking->unblock())
result = 0;
else
_blocking = 0;
}
return result;
}
void call_argument_0(word_t value){
_exec_context.r5=value;}
void bootstrap_argument_0(word_t value){
_exec_context.r31=value;}
void print_state() {
_exec_context.print_content(2);
printf("\n");
};
Exception *exception() { return &_exception; }
Syscall *syscall() { return &_syscall; }
Irq *irq() { return &_irq; }
protected:
void _block__error__unknown_blocking_type()
{
if (!PLATFORM_THREAD__ERROR)
return;
printf("Error in Kernel::Platform_thread::block: "
"unknown blocking_type=%i, printing state\n",
_exec_context.blocking_type);
_exec_context.print_content(2);
printf("halt\n");
halt();
}
void _block__warning__no_blocking()
{
if (!PLATFORM_THREAD__WARNING)
return;
printf("Warning Kernel::Platform_thread::_no_blocking called\n");
halt();
}
void _block__verbose__success()
{
if (!PLATFORM_THREAD__VERBOSE)
return;
printf("Kernel::Platform_thread::block, blocked "
"this=0x%p, blocking_type=%i\n",
this, _exec_context.blocking_type);
}
};
}
Kernel::Irq_controller * const Kernel::Platform::irq_controller()
{
using namespace Xilinx;
static Irq_controller _ic = Irq_controller(Xps_intc::Constr_arg(Cpu::XPS_INTC_BASE));
return &_ic;
}
Kernel::Scheduling_timer * const Kernel::Platform::timer()
{
using namespace Xilinx;
static Scheduling_timer _st = Scheduling_timer(SCHEDULING_TIMER_IRQ,
(addr_t)SCHEDULING_TIMER_BASE);
return &_st;
}
#endif /* _INCLUDE__PETALOGIX_S3ADSP1800_MMU__PLATFORM__PLATFORM_H_ */

Some files were not shown because too many files have changed in this diff Show More