mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
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:
parent
ce67b73dca
commit
ebc73f66df
18
README
18
README
@ -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
|
||||
|
@ -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
|
@ -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'.
|
||||
|
@ -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.
|
@ -1 +0,0 @@
|
||||
SPECS ?= genode mb-s3a_starter_kit
|
@ -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
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
||||
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
||||
|
@ -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_ */
|
@ -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_ */
|
@ -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
|
@ -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
|
@ -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)
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -1,4 +0,0 @@
|
||||
SRC_CC = pager.cc
|
||||
INC_DIR += $(REP_DIR)/include/codezero/dummies
|
||||
|
||||
vpath pager.cc $(REP_DIR)/src/base/pager
|
@ -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)
|
@ -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)
|
@ -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
|
@ -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))
|
@ -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
|
@ -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
|
@ -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
|
@ -1,7 +0,0 @@
|
||||
SPECS += 32bit mb_timer
|
||||
|
||||
STARTUP_LIB ?= startup
|
||||
|
||||
PRG_LIBS += $(STARTUP_LIB)
|
||||
|
||||
include $(call select_from_repositories,mk/spec-32bit.mk)
|
@ -1,7 +0,0 @@
|
||||
SPECS += 32bit mb_timer
|
||||
|
||||
STARTUP_LIB ?= startup
|
||||
|
||||
PRG_LIBS += $(STARTUP_LIB)
|
||||
|
||||
include $(call select_from_repositories,mk/spec-32bit.mk)
|
@ -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
|
Binary file not shown.
@ -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
|
@ -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
|
@ -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
|
@ -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
|
211
base-mb/run/env
211
base-mb/run/env
@ -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
|
||||
}
|
||||
}
|
@ -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
|
@ -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
|
@ -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 µblaze_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);
|
||||
}
|
@ -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; }
|
@ -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)
|
||||
{ }
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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(); }
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
};
|
||||
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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 */
|
||||
|
||||
|
||||
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
||||
|
@ -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_*/
|
||||
|
||||
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
||||
|
@ -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;
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) { }
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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());
|
||||
}
|
@ -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);
|
||||
}
|
@ -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)
|
@ -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
|
@ -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"); }
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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_ */
|
@ -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_*/
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
@ -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_ */
|
@ -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_ */
|
@ -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
Loading…
Reference in New Issue
Block a user