Run Genode directly on hardware with 'base-hw'.

This commit is contained in:
Martin Stein 2012-05-30 20:13:09 +02:00 committed by Norman Feske
parent 8220ea272c
commit ff65f6f021
81 changed files with 7800 additions and 1 deletions

67
base-hw/doc/hw.txt Normal file
View File

@ -0,0 +1,67 @@
======================================
How to use Genode directly on hardware
======================================
Martin Stein
The 'base-hw' repository provides an implementation of Genodes core that runs
directly on hardware, without an intermediate third-party kernel. Currently it
runs on the ARM platforms Realview PBXA9, Versatile Express A9X4 and
PandaBoard A2.
This document provides brief instructions about building and booting Genode
directly on hardware.
Prerequisites
#############
To build Genode you need to download and install the tool-chain used by Genode.
Have a look at this page:
:[http://genode.org/download/tool-chain]:
Genode tool-chain
If you want to use the so called run-scripts in Genode, a mechanism that
automates building, integration and testing of components, you have to install
the following, additional package:
! apt-get install expect
If you want to examine the examples that are given in this document, you will
need Qemu for ARM emulations to run them on your machine:
! apt-get install qemu-kvm-extras
Building Genode to run directly on hardware
###########################################
The current version of the Genode source code is available at this page:
:http://genode.org/download/repository:
Donwloading the Genode source code
Now, go to a directory where you want the Genode build directory to
remain. Use the helper script in the 'tool' directory of the Genode
source tree to create the initial build environment. You need to state the
build directory you want to create, and the hardware system to run
Genode on. Choose 'hw_pbxa9', 'hw_vea9x4', or 'hw_panda_a2' depending on the
hardware system you aim at.
! <genode-dir>/tool/create_builddir hw_pbxa9 BUILD_DIR=<build-dir>
Now, go to the newly created build directory make a test:
! cd <build-dir>
! make run/nested_init
This will build the Genode components that are needed to run a simple test
with 3 nested init programs, and than execute it via Qemu.
For further informations according to the specific hardware systems, have
look into the other documentations:
! base-hw/doc/<system>.txt

95
base-hw/doc/panda_a2.txt Normal file
View File

@ -0,0 +1,95 @@
======================================================
Getting started with 'genode/base-hw' on PandaBoard A2
======================================================
Martin Stein
Abstract
########
This is a short tutorial that depicts a handy way to get a Genode ELF image,
build with 'base-hw', started on the PandaBoard A2. It is dedicated to common
Linux systems, but all examples originate from a Ubuntu 10.10.
Tutorial
########
Connect the PandaBoard to your local Ethernet through its RJ45 connector.
Additionally connect the PandaBoard to your machine through its COM port.
Ensure that you have installed the genode tool chain that is available at:
[http://genode.org/download/tool-chain - Get the genode tool chain]
Ensure that '<GENODE_GCC_DIR>/bin/' is in your 'PATH' variable.
Get the linaro U-Boot repository and compile U-Boot for PandaBoard:
! git clone git://git.linaro.org/boot/u-boot-linaro-stable.git
! cd <UBOOT_DIR>
! make CROSS_COMPILE=genode-arm- omap4_panda_config
! make CROSS_COMPILE=genode-arm-
During the compilation i had some errors. The first was in assembly code,
it seemed to originate from a slip with the typo and was easy to fix.
The second kind of errors occured because the GCC version had no support for
direct array initialization, thus i avoided them by simply initialize
the array elements separately.
Now install the following packages to communicate with the PandaBoard:
! sudo apt-get install tftp-hpa minicom
Open '/etc/default/tftpd-hpa' with a text editor and ensure that it has
the following content:
! # /etc/default/tftpd-hpa
! TFTP_USERNAME="tftp"
! TFTP_DIRECTORY="/var/lib/tftpboot"
! TFTP_ADDRESS="0.0.0.0:69"
! TFTP_OPTIONS="-l"
Tell U-Boot wich image to load on boot command:
! cd /var/lib/tftpboot/
! ln -s <GENODE_BOOT_ELF> image.elf
Start TFTP to enable the upload of the image:
! sudo service tftp-hpa restart
Start Minicom in configuration mode:
! minicom -s
Go to 'Serial port setting' and ensure that the device is set the
TTY of the COM port you've conntected PandaBoard with, in my case it was
'/dev/ttyS0'. Configure the other settings for a baud rate of '115200',
8 bit char length, no parity and 1 stop bit. Quit Minicom and start
it once more:
! minicom
Mount your SD-card and copy the U-Boot files to its boot partition:
! cd <UBOOT_DIR>; cp MLO /media/boot/; cp u-boot.bin /media/boot/
Unmount the SD card and insert it into the appropriate PandaBoard slot.
Plug in the power connector or push the 'S1' button if the PandaBoard is
already powered.
Minicom should now show the following message:
! Hit any key to stop autoboot:
We have to stop autoboot and type in this line to load and boot the genode
image via ethernet:
! usb start; dhcp; bootelf 0x82000000
Now the ELF image should start correctly and offer some debug output in
minicom. You can now boot further images by redirecting the link
'/var/lib/tftpboot/image.elf' accordingly, restarting your pandaboard
and instructing 'uboot' again as described above.

View File

@ -0,0 +1,62 @@
/*
* \brief Syscall declarations specific for ARM V7A systems
* \author Martin Stein
* \date 2011-11-30
*/
/*
* Copyright (C) 2011-2012 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__ARM_V7A__BASE__SYSCALL_H_
#define _INCLUDE__ARM_V7A__BASE__SYSCALL_H_
/* Genode includes */
#include <base/stdint.h>
namespace Kernel
{
typedef Genode::uint32_t Syscall_arg;
typedef Genode::uint32_t Syscall_ret;
/*****************************************************************
** Syscall with 1 to 6 arguments **
** **
** These functions must not be inline to ensure that objects, **
** wich are referenced by arguments, are tagged as "used" even **
** though only the pointer gets handled in here. **
*****************************************************************/
Syscall_ret syscall(Syscall_arg arg_0);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4,
Syscall_arg arg_5);
}
#endif /* _INCLUDE__ARM_V7A__BASE__SYSCALL_H_ */

View File

@ -0,0 +1,71 @@
/*
* \brief IPC message buffers
* \author Martin Stein
* \date 2012-01-03
*/
/*
* Copyright (C) 2012 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; /* buffer size in bytes */
public:
char buf[]; /* begin of actual message buffer */
/*************************************************
** 'buf' must be the last member of this class **
*************************************************/
/**
* Return size of message buffer
*/
inline size_t size() const { return _size; }
/**
* Return address of message buffer
*/
inline void *addr() { return &buf[0]; }
};
/**
* Instance of IPC message buffer with specified buffer size
*
* 'Msgbuf_base' must be the last class this class inherits from.
*/
template <unsigned BUF_SIZE>
class Msgbuf : public Msgbuf_base
{
public:
/**************************************************
** 'buf' must be the first member of this class **
**************************************************/
char buf[BUF_SIZE];
/**
* Constructor
*/
Msgbuf() { _size = BUF_SIZE; }
};
}
#endif /* _INCLUDE__BASE__IPC_MSGBUF_H_ */

View File

@ -0,0 +1,172 @@
/*
* \brief IPC backend for a Genode pager
* \author Martin Stein
* \date 2012-03-28
*/
/*
* Copyright (C) 2012 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/thread.h>
#include <base/ipc.h>
#include <base/native_types.h>
#include <kernel/log.h>
namespace Genode
{
class Pager_object;
/**
* Translation of a virtual page frame
*/
struct Mapping
{
addr_t virt_address;
addr_t phys_address;
bool write_combined;
unsigned size_log2;
bool writable;
/**
* Construct valid mapping
*/
Mapping(addr_t const va, addr_t const pa, bool const wc,
unsigned const sl2 = MIN_MAPPING_SIZE_LOG2, bool w = 1)
:
virt_address(va), phys_address(pa), write_combined(wc),
size_log2(sl2), writable(w)
{ }
/**
* Construct invalid mapping
*/
Mapping() : size_log2(0) { }
/**
* Dummy, all data is available since construction
*/
void prepare_map_operation() { }
/**
* Validation
*/
bool valid() { return size_log2 > 0; }
};
/**
* Message format for the acknowledgment of a resolved pagefault
*/
struct Pagefault_resolved
{
Native_thread_id const reply_dst;
Pager_object * const pager_object;
};
/**
* Special paging server class
*/
class Ipc_pager : public Native_capability
{
enum { VERBOSE = 1 };
Pagefault _pagefault; /* data of lastly received pagefault */
Mapping _mapping; /* mapping to resolve last pagefault */
public:
/**
* Constructor
*/
Ipc_pager() :
Native_capability(Genode::thread_get_my_native_id(), 0)
{
/* check if we can distinguish all message types */
if (sizeof(Pagefault) == sizeof(Pagefault_resolved))
{
kernel_log() << __PRETTY_FUNCTION__
<< ": Message types indiscernible\n";
while (1) ;
}
}
/**
* Wait for the next pagefault request
*/
void wait_for_fault();
/**
* Resolve current pagefault and wait for a new one
*/
void resolve_and_wait_for_fault();
/**
* Request instruction pointer of current page fault
*/
addr_t fault_ip() { return _pagefault.virt_ip; }
/**
* Request fault address of current page fault
*/
addr_t fault_addr() { return _pagefault.virt_address; }
/**
* Set parameters for next reply
*/
void set_reply_mapping(Mapping m) { _mapping = m; }
/**
* Set destination for next reply
*/
void set_reply_dst(Native_capability pager_object) {
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
}
/**
* Answer call without sending a flex-page mapping
*
* This function is used to acknowledge local calls from one of
* core's region-manager sessions.
*/
void acknowledge_wakeup() {
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
}
/**
* Return thread ID of last faulter
*/
Native_thread_id last() const { return _pagefault.thread_id; }
/**
* Return badge for faulting thread
*/
unsigned long badge() const { return _pagefault.thread_id; }
/**
* Return true if last fault was a write fault
*/
bool is_write_fault() const { return _pagefault.write; }
/**
* Return true if last fault was an exception
*/
bool is_exception() const
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
return false;
}
};
}
#endif /* _INCLUDE__BASE__IPC_PAGER_H_ */

View File

@ -0,0 +1,142 @@
/*
* \brief Platform specific basic Genode types
* \author Martin Stein
* \date 2012-01-02
*/
/*
* Copyright (C) 2012 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_
/* Genode includes */
#include <kernel/syscalls.h>
#include <base/native_capability.h>
namespace Genode
{
class Platform_thread;
typedef int volatile Native_lock;
typedef Platform_thread * Native_thread;
typedef unsigned long Native_thread_id;
typedef int Native_connection_state;
/* FIXME needs to be MMU dependent */
enum { MIN_MAPPING_SIZE_LOG2 = 12 };
/**
* Get kernel-object identifier of the current thread
*/
inline Native_thread_id thread_get_my_native_id()
{ return Kernel::current_thread_id(); }
/**
* Get the thread ID, wich is handled as invalid by the kernel
*/
inline Native_thread_id thread_invalid_id() { return 0; }
/**
* Describes a pagefault
*/
struct Pagefault
{
unsigned long thread_id; /* thread ID of the faulter */
Software_tlb * software_tlb; /* TLB to wich the faulter is assigned */
addr_t virt_ip; /* the faulters virtual instruction pointer */
addr_t virt_address; /* virtual fault address */
bool write; /* write access attempted at fault? */
/**
* Placement new operator
*/
void * operator new (size_t, void * p) { return p; }
/**
* Construct invalid pagefault
*/
Pagefault() : thread_id(0) { }
/**
* Construct valid pagefault
*/
Pagefault(unsigned const tid, Software_tlb * const sw_tlb,
addr_t const vip, addr_t const va, bool const w)
:
thread_id(tid), software_tlb(sw_tlb), virt_ip(vip),
virt_address(va), write(w)
{ }
/**
* Validation
*/
bool valid() const { return thread_id != 0; }
};
/**
* Describes a userland-thread-context region
*/
struct Native_utcb
{
/* UTCB payload */
union {
char bytes[1<<MIN_MAPPING_SIZE_LOG2];
umword_t words[sizeof(bytes)/sizeof(umword_t)];
};
/**
* Get pointer to a specific word within the UTCB
*/
umword_t * word(unsigned long const index) { return &words[index]; }
/**
* Get the base of the UTCB
*/
void * base() { return (void *)bytes; }
/**
* Get the UTCB size
*/
unsigned long size() { return sizeof(bytes); }
};
struct Cap_dst_policy
{
typedef Native_thread_id Dst;
/**
* Validate capability destination
*/
static bool valid(Dst pt) { return pt != 0; }
/**
* Get invalid capability destination
*/
static Dst invalid() { return 0; }
/**
* Copy capability 'src' to a given memory destination 'dst'
*/
static void
copy(void * dst, Native_capability_tpl<Cap_dst_policy> * src);
};
typedef Native_capability_tpl<Cap_dst_policy> Native_capability;
/**
* A coherent address region
*/
struct Native_region
{
addr_t base;
size_t size;
};
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */

View File

@ -0,0 +1,172 @@
/*
* \brief Delivery and reception of asynchronous notifications on HW-core
* \author Martin Stein
* \date 2012-05-05
*/
/*
* Copyright (C) 2012 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__SIGNAL_H__
#define _INCLUDE__BASE__SIGNAL_H__
/* Genode includes */
#include <signal_session/signal_session.h>
#include <base/lock.h>
#include <util/list.h>
namespace Genode
{
/**
* A bunch of asynchronuosly triggered events that target the same context
*
* Because a signal can trigger asynchronously at a context,
* the kernel accumulates them and provides them as such a bunch,
* once the receiver indicates that he is ready to receive.
*/
class Signal
{
unsigned long _imprint; /* receiver-local signal-context pointer */
int _num; /* how often this signal has been triggered */
public:
/**
* Construct valid signal
*/
Signal(unsigned long const imprint, int const num)
: _imprint(imprint), _num(num) { }
/***************
** Accessors **
***************/
Signal_context * context() { return (Signal_context *)_imprint; }
int num() { return _num; }
};
typedef List<Signal_context> Context_list;
/**
* A specific signal type that a transmitter can target when it submits
*
* One receiver might handle multiple signal contexts,
* but a signal context is owned by exactly one signal receiver.
*/
class Signal_context : public Context_list::Element
{
friend class Signal_receiver;
Signal_receiver * _receiver; /* receiver that manages us */
Lock _lock; /* serialize object access */
Signal_context_capability _cap; /* holds the name of our context
* kernel-object as 'dst' */
public:
/**
* Construct context that is not yet managed by a receiver
*/
Signal_context() : _receiver(0), _lock(Lock::UNLOCKED) { }
/**
* Destructor
*/
virtual ~Signal_context() { }
/* solely needed to enable one to type a capability with us */
GENODE_RPC_INTERFACE();
};
/**
* To submit signals to one specific context
*
* Multiple transmitters can submit to the same context.
*/
class Signal_transmitter
{
/* names the targeted context kernel-object with its 'dst' field */
Signal_context_capability _context;
public:
/**
* Constructor
*/
Signal_transmitter(Signal_context_capability const c =
Signal_context_capability())
: _context(c) { }
/**
* Trigger a signal 'num' times at the context we target
*/
void submit(int const num = 1)
{ Kernel::submit_signal(_context.dst(), num); }
/***************
** Accessors **
***************/
void context(Signal_context_capability const c) { _context = c; }
};
/**
* Manage multiple signal contexts and receive signals targeted to them
*/
class Signal_receiver
{
Context_list _contexts; /* contexts that we manage */
Lock _contexts_lock; /* serialize access to
* 'contexts' */
Signal_receiver_capability _cap; /* holds name of our receiver
* kernel-object as 'dst' */
/**
* Let a context 'c' no longer be managed by us
*
* Doesn't serialize any member access.
*/
void _unsync_dissolve(Signal_context * const c);
public:
class Context_already_in_use : public Exception { };
class Context_not_associated : public Exception { };
/**
* Constructor
*/
Signal_receiver();
/**
* Destructor
*/
~Signal_receiver();
/**
* Let a context 'c' be managed by us
*
* \return Capability wich names the context kernel-object in its
* 'dst' field . Can be used as target for transmitters.
*/
Signal_context_capability manage(Signal_context * const c);
/**
* Let a context 'c' no longer be managed by us
*/
void dissolve(Signal_context * const c);
/**
* Block on any signal that is triggered at one of our contexts
*/
Signal wait_for_signal();
};
}
#endif /* _INCLUDE__BASE__SIGNAL_H__ */

View File

@ -0,0 +1,109 @@
/*
* \brief Print to kernel log output
* \author Martin stein
* \date 2012-04-05
*/
/*
* Copyright (C) 2012 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__LOG_H_
#define _INCLUDE__KERNEL__LOG_H_
/* Genode includes */
#include <kernel/syscalls.h>
namespace Genode
{
/**
* Prints incoming streams to the kernel log output
*/
class Kernel_log
{
/**
* Print an unsigned 4 bit integer as hexadecimal value
*/
void _print_4bit_hex(unsigned char x) const
{
/* decode to ASCII char */
x &= 0x0f;
if (x > 9) x += 39;
x += 48;
/* print ASCII char */
Kernel::print_char(x);
}
public:
/**
* Print zero-terminated string
*/
Kernel_log & operator << (char const * s)
{
while (*s) Kernel::print_char(*s++);
return *this;
}
/**
* Print an unsigned integer as hexadecimal value
*/
Kernel_log & operator << (unsigned int const & x)
{
enum {
BYTE_WIDTH = 8,
CW = sizeof(unsigned char)*BYTE_WIDTH,
IW = sizeof(unsigned int)*BYTE_WIDTH
};
/*
* Walk from most significant to least significant bit and
* process 2 hex digits per step.
*/
bool leading = true;
for (int i = IW - CW; i >= 0; i = i - CW)
{
/* fetch the 2 current digits */
unsigned char c = (char)((x >> i) & 0xff);
/* has the payload part of the value already begun? */
if (leading)
{
/* ignore leading zeros ... */
if (!c)
{
/* ... expect they are the only digits */
if (i == 0) _print_4bit_hex(c);
continue;
}
/* transit from leading to payload part */
leading = false;
if (c < 0x10) {
_print_4bit_hex(c);
continue;
}
}
/* print both digits */
_print_4bit_hex(c >> 4);
_print_4bit_hex(c);
}
return *this;
}
};
/**
* Give static 'Kernel_log' reference as target for common log output
*/
inline Kernel_log & kernel_log()
{
static Kernel_log _log;
return _log;
}
}
#endif /* _INCLUDE__KERNEL__LOG_H_ */

View File

@ -0,0 +1,427 @@
/*
* \brief Kernels syscall frontend
* \author Martin stein
* \date 2011-11-30
*/
/*
* Copyright (C) 2011-2012 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__SYSCALLS_H_
#define _INCLUDE__KERNEL__SYSCALLS_H_
/* Genode includes */
#include <base/syscall.h>
class Software_tlb;
namespace Genode
{
class Platform_thread;
}
namespace Kernel
{
/**
* Unique opcodes of all syscalls supported by the kernel
*/
enum Syscall_type
{
INVALID_SYSCALL = 0,
/* execution control */
NEW_THREAD = 1,
START_THREAD = 2,
PAUSE_THREAD = 3,
RESUME_THREAD = 4,
GET_THREAD = 5,
CURRENT_THREAD_ID = 6,
YIELD_THREAD = 7,
READ_REGISTER = 18,
WRITE_REGISTER = 19,
/* interprocess communication */
REQUEST_AND_WAIT = 8,
REPLY_AND_WAIT = 9,
WAIT_FOR_REQUEST = 10,
/* management of resource protection-domains */
SET_PAGER = 11,
UPDATE_PD = 12,
NEW_PD = 13,
/* interrupt handling */
ALLOCATE_IRQ = 14,
AWAIT_IRQ = 15,
FREE_IRQ = 16,
/* debugging */
PRINT_CHAR = 17,
/* asynchronous signalling */
NEW_SIGNAL_RECEIVER = 20,
NEW_SIGNAL_CONTEXT = 21,
AWAIT_SIGNAL = 22,
SUBMIT_SIGNAL = 23,
};
/**
* Virtual range of the mode transition region in every PD
*/
Genode::addr_t mode_transition_virt_base();
Genode::size_t mode_transition_size();
/**
* Get sizes of the kernel objects
*/
Genode::size_t thread_size();
Genode::size_t pd_size();
Genode::size_t signal_context_size();
Genode::size_t signal_receiver_size();
/**
* Get alignment constraints of the kernel objects
*/
unsigned kernel_pd_alignm_log2();
/**
* Create a new PD
*
* \param dst physical base of an appropriate portion of memory
* that is thereupon allocated to the kernel
*
* \retval >0 ID of the new PD
* \retval 0 if no new PD was created
*
* Restricted to core threads. Regaining of the supplied memory is not
* supported by now.
*/
inline int new_pd(void * const dst)
{ return syscall(NEW_PD, (Syscall_arg)dst); }
/**
* Propagate changes in PD configuration
*
* \param pd_id ID of the PD that has been configured
*
* It might be, that the kernel and/or the hardware caches parts of PD
* configurations such as virtual address translations. This syscall
* ensures that the current configuration of the targeted PD gets fully
* applied from the moment it returns to the userland. This syscall is
* inappropriate in case that a PD wants to change its own configuration.
* There's no need for this syscall after a configuration change that
* can't affect the kernel and/or hardware caches.
*
* Restricted to core threads.
*/
inline void update_pd(unsigned long const pd_id)
{ syscall(UPDATE_PD, (Syscall_arg)pd_id); }
/**
* Create a new thread that is stopped initially
*
* \param dst physical base of an appropriate portion of memory
* that is thereupon allocated to the kernel
* \param pt assigned platform thread
*
* \retval >0 ID of the new thread
* \retval 0 if no new thread was created
*
* Restricted to core threads. Regaining of the supplied memory is not
* supported by now.
*/
inline int new_thread(void * const dst, Genode::Platform_thread * const pt)
{ return syscall(NEW_THREAD, (Syscall_arg)dst, (Syscall_arg)pt); }
/**
* Start thread with a given context and let it participate in CPU scheduling
*
* \param id ID of targeted thread
* \param ip initial instruction pointer
* \param sp initial stack pointer
*
* \retval >0 success, return value is the software TLB of the thread
* \retval 0 the targeted thread wasn't started or was already started
* when this gets called (in both cases it remains untouched)
*
* Restricted to core threads.
*/
inline Software_tlb *
start_thread(Genode::Platform_thread * const phys_pt, void * ip, void * sp,
unsigned int cpu_no)
{
return (Software_tlb *)syscall(START_THREAD,
(Syscall_arg)phys_pt,
(Syscall_arg)ip,
(Syscall_arg)sp,
(Syscall_arg)cpu_no);
}
/**
* Prevent thread from participating in CPU scheduling
*
* \param id ID of the targeted thread. If not set
* this will target the current thread.
*
* \retval 0 syscall was successful
* \retval <0 if the targeted thread does not exist or still participates
* in CPU scheduling after
*
* If the caller doesn't target itself, this is restricted to core threads.
*/
inline int pause_thread(unsigned long const id = 0)
{ return syscall(PAUSE_THREAD, id); }
/**
* Let an already started thread participate in CPU scheduling
*
* \param id ID of the targeted thread
*
* \retval 0 if syscall was successful and thread were paused beforehand
* \retval >0 if syscall was successful and thread were already active
* \retval <0 if targeted thread doesn't participate in CPU
* scheduling after
*/
inline int resume_thread(unsigned long const id = 0)
{ return syscall(RESUME_THREAD, id); }
/**
* Let the current thread give up its remaining timeslice
*
* \param id if this thread ID is set and valid this will resume the
* targeted thread additionally
*/
inline void yield_thread(unsigned long const id = 0)
{ syscall(YIELD_THREAD, id); }
/**
* Get the thread ID of the current thread
*/
inline int current_thread_id() { return syscall(CURRENT_THREAD_ID); }
/**
* Get platform thread by ID or 0 if target is "core main" or "idle"
*
* \param id ID of the targeted thread or 0 if caller targets itself
*
* Restricted to core threads.
*/
inline Genode::Platform_thread * get_thread(unsigned long const id = 0)
{ return (Genode::Platform_thread *)syscall(GET_THREAD, id); }
/**
* Send IPC request and wait for reply
*
* \param id ID of the receiver thread
* \param size request size (beginning with the callers UTCB base)
*
* \return size of received reply (beginning with the callers UTCB base)
*
* If the receiver exists, this blocks execution until a dedicated reply
* message has been send by the receiver. The receiver may never do so.
*/
inline unsigned long request_and_wait(unsigned long const id,
unsigned long const size)
{ return (unsigned long)syscall(REQUEST_AND_WAIT, id, size); }
/**
* Wait for next IPC request, discard current request
*
* \return size of received request (beginning with the callers UTCB base)
*/
inline unsigned long wait_for_request()
{ return (unsigned long)syscall(WAIT_FOR_REQUEST); }
/**
* Send reply of the last received request and wait for next request
*
* \param size reply-message size (beginning with the callers UTCB base)
*
* \return size of received request (beginning with the callers UTCB base)
*/
inline unsigned long reply_and_wait(unsigned long const size)
{ return (unsigned long)syscall(REPLY_AND_WAIT, size); }
/**
* Set a thread that gets informed about pagefaults of another thread
*
* \param pager_id ID of the thread that shall get informed.
* Subsequently this thread gets an IPC message,
* wich contains an according 'Pagefault' object for
* every pagefault the faulter throws.
* \param faulter_id ID of the thread that throws the pagefaults
* wich shall be notified. After every pagefault this
* thread remains paused to be reactivated by
* 'resume_thread'.
*
* Restricted to core threads.
*/
inline void set_pager(unsigned long const pager_id,
unsigned long const faulter_id)
{ syscall(SET_PAGER, pager_id, faulter_id); }
/**
* Print a char 'c' to the kernels serial ouput
*/
inline void print_char(char const c)
{ syscall(PRINT_CHAR, (Syscall_arg)c); }
/**
* Allocate an IRQ to the caller if the IRQ is not allocated already
*
* \param id ID of the targeted IRQ
*
* \return wether the IRQ has been allocated to this thread or not
*
* Restricted to core threads.
*/
inline bool allocate_irq(unsigned long const id)
{ return syscall(ALLOCATE_IRQ, (Syscall_arg)id); }
/**
* Free an IRQ from allocation if it is allocated by the caller
*
* \param id ID of the targeted IRQ
*
* \return wether the IRQ has been freed or not
*
* Restricted to core threads.
*/
inline bool free_irq(unsigned long const id)
{ return syscall(FREE_IRQ, (Syscall_arg)id); }
/**
* Block caller for the occurence of its IRQ
*
* Restricted to core threads. Blocks the caller forever
* if he has not allocated any IRQ.
*/
inline void await_irq() { syscall(AWAIT_IRQ); }
/**
* Get the current value of a register of a specific CPU context
*
* \param thread_id ID of the thread that owns the targeted context
* \param reg_id platform-specific ID of the targeted register
*
* Restricted to core threads. One can also read from its own context,
* or any thread that is active in the meantime. In these cases
* be aware of the fact, that the result reflects the context
* state that were backed at the last kernel entry of the thread.
*/
inline unsigned long read_register(unsigned long const thread_id,
unsigned long const reg_id)
{
return syscall(READ_REGISTER, (Syscall_arg)thread_id,
(Syscall_arg)reg_id);
}
/**
* Write a value to a register of a specific CPU context
*
* \param thread_id ID of the thread that owns the targeted context
* \param reg_id platform-specific ID of the targeted register
* \param value value that shall be written to the register
*
* Restricted to core threads. One can also write to its own context, or
* to that of a thread that is active in the meantime.
*/
inline void write_register(unsigned long const thread_id,
unsigned long const reg_id,
unsigned long const value)
{
syscall(WRITE_REGISTER, (Syscall_arg)thread_id, (Syscall_arg)reg_id,
(Syscall_arg)value);
}
/**
* Create a kernel object that acts as receiver for asynchronous signals
*
* \param dst physical base of an appropriate portion of memory
* that is thereupon allocated to the kernel
*
* \return ID of the new kernel object
*
* Restricted to core threads. Regaining of the supplied memory is not
* supported by now.
*/
inline unsigned long new_signal_receiver(void * dst)
{ return syscall(NEW_SIGNAL_RECEIVER, (Syscall_arg)dst); }
/**
* Create a kernel object that acts as a distinct signal type at a receiver
*
* \param dst physical base of an appropriate portion of memory
* that is thereupon allocated to the kernel
* \param receiver_id ID of the receiver kernel-object that shall
* provide the new signal context
* \param imprint Every signal, one receives at the new context,
* will hold this imprint. This enables the receiver
* to interrelate signals with the context.
*
* \return ID of the new kernel object
*
* Core-only syscall. Regaining of the supplied memory is not
* supported by now.
*/
inline unsigned long new_signal_context(void * dst,
unsigned long receiver_id,
unsigned long imprint)
{
return syscall(NEW_SIGNAL_CONTEXT, (Syscall_arg)dst,
(Syscall_arg)receiver_id, (Syscall_arg)imprint);
}
/**
* Wait for occurence of at least one signal at any context of a receiver
*
* \param receiver_id ID of the targeted receiver kernel-object
*
* When this call returns, an instance of 'Signal' is located at the base
* of the callers UTCB. It holds information about wich context was
* triggered how often. It is granted that every occurence of a signal is
* provided through this function, exactly till it gets delivered through
* this function. If multiple threads listen at the same receiver and/or
* multiple contexts trigger simultanously there is no assertion about
* wich thread receives the 'Signal' instance of wich context.
*/
inline void await_signal(unsigned long receiver_id)
{ syscall(AWAIT_SIGNAL, (Syscall_arg)receiver_id); }
/**
* Trigger a specific signal context
*
* \param context_id ID of the targeted context kernel-object
* \param num how often the context shall be triggered by this call
*/
inline void submit_signal(unsigned long context_id, int num)
{ syscall(SUBMIT_SIGNAL, (Syscall_arg)context_id, (Syscall_arg)num); }
}
#endif /* _INCLUDE__KERNEL__SYSCALLS_H_ */

View File

@ -0,0 +1,43 @@
/*
* \brief Serial output driver specific for the ARM PL011
* \author Martin Stein
* \date 2012-04-23
*/
/*
* Copyright (C) 2012 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__PL011__DRIVERS__SERIAL_LOG_H_
#define _INCLUDE__PL011__DRIVERS__SERIAL_LOG_H_
/* Genode includes */
#include <drivers/board.h>
#include <drivers/uart/pl011_base.h>
namespace Genode
{
/**
* Serial output driver specific for the ARM PL011
*/
class Serial_log : public Pl011_base
{
public:
/**
* Constructor
*
* \param baud_rate targeted transfer baud-rate
*/
Serial_log(unsigned const baud_rate) :
Pl011_base(Board::LOG_PL011_MMIO_BASE,
Board::LOG_PL011_CLOCK, baud_rate)
{ }
};
}
#endif /* _INCLUDE__PL011__DRIVERS__SERIAL_LOG_H_ */

View File

@ -0,0 +1,37 @@
/**
* \brief Motherboard driver specific for the PandaBoard A2
* \author Martin Stein
* \date 2012-03-08
*/
/*
* Copyright (C) 2012 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__PLATFORM__PANDA_A2__DRIVERS__BOARD_H_
#define _INCLUDE__PLATFORM__PANDA_A2__DRIVERS__BOARD_H_
/* Genode includes */
#include <drivers/board/panda_a2.h>
namespace Genode
{
/**
* Provide specific board driver
*/
class Board : public Panda_a2
{
public:
enum {
LOG_TL16C750_MMIO_BASE = TL16C750_3_MMIO_BASE,
LOG_TL16C750_CLOCK = TL16C750_3_CLOCK,
};
};
}
#endif /* _INCLUDE__PLATFORM__PANDA_A2__DRIVERS__BOARD_H_ */

View File

@ -0,0 +1,38 @@
/**
* \brief Motherboard driver specific for the Realview PBXA9
* \author Martin Stein
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-2012 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__PLATFORM__PBXA9__DRIVERS__BOARD_H_
#define _INCLUDE__PLATFORM__PBXA9__DRIVERS__BOARD_H_
/* Genode includes */
#include <drivers/board/pbxa9.h>
#include <base/native_types.h>
namespace Genode
{
/**
* Provide specific board driver
*/
class Board : public Pbxa9
{
public:
enum {
LOG_PL011_MMIO_BASE = PL011_0_MMIO_BASE,
LOG_PL011_CLOCK = PL011_0_CLOCK,
};
};
}
#endif /* _INCLUDE__PLATFORM__PBXA9__DRIVERS__BOARD_H_ */

View File

@ -0,0 +1,37 @@
/**
* \brief Provide specific board driver
* \author Martin Stein
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-2012 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__PLATFORM__VEA9X4__DRIVERS__BOARD_H_
#define _INCLUDE__PLATFORM__VEA9X4__DRIVERS__BOARD_H_
/* Genode inlcudes */
#include <drivers/board/vea9x4.h>
namespace Genode
{
/**
* Provide specific board driver
*/
class Board : public Vea9x4
{
public:
enum {
LOG_PL011_MMIO_BASE = PL011_0_MMIO_BASE,
LOG_PL011_CLOCK = PL011_0_CLOCK,
};
};
}
#endif /* _INCLUDE__PLATFORM__VEA9X4__DRIVERS__BOARD_H_ */

View File

@ -0,0 +1,51 @@
/*
* \brief Client-side implementation of the signal session interface
* \author Martin Stein
* \date 2012-05-05
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__SIGNAL_SESSION__CLIENT_H_
#define _INCLUDE__SIGNAL_SESSION__CLIENT_H_
/* Genode includes */
#include <signal_session/capability.h>
#include <signal_session/signal_session.h>
#include <base/rpc_client.h>
namespace Genode
{
/**
* Client-side implementation of the signal session interface
*/
struct Signal_session_client : Rpc_client<Signal_session>
{
/**
* Constructor
*
* \param s targeted signal session
*/
explicit Signal_session_client(Signal_session_capability const s)
: Rpc_client<Signal_session>(s) { }
/******************************
** Signal_session interface **
******************************/
Signal_receiver_capability alloc_receiver()
{ return call<Rpc_alloc_receiver>(); }
Signal_context_capability
alloc_context(Signal_receiver_capability const r,
unsigned long const imprint)
{ return call<Rpc_alloc_context>(r, imprint); }
};
}
#endif /* _INCLUDE__SIGNAL_SESSION__CLIENT_H_ */

View File

@ -0,0 +1,96 @@
/*
* \brief Signal session interface
* \author Martin Stein
* \date 2012-05-05
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__SIGNAL_SESSION__SIGNAL_SESSION_H_
#define _INCLUDE__SIGNAL_SESSION__SIGNAL_SESSION_H_
/* Genode includes */
#include <base/capability.h>
#include <base/exception.h>
#include <session/session.h>
namespace Genode
{
class Signal_receiver;
class Signal_context;
/*
* The 'dst' of this cap is used to communicate the ID of the
* corresponding signal-receiver kernel-object or 0 if the cap is invalid.
*/
typedef Capability<Signal_receiver> Signal_receiver_capability;
/*
* The 'dst' of this cap is used to communicate the ID of the
* corresponding signal-context kernel-object or 0 if the cap is invalid.
*/
typedef Capability<Signal_context> Signal_context_capability;
/**
* Signal session interface
*/
struct Signal_session : Session
{
class Out_of_metadata : public Exception { };
/**
* String that can be used to refer to this service
*/
static const char * service_name() { return "SIGNAL"; }
/**
* Destructor
*/
virtual ~Signal_session() { }
/**
* Create a new signal-receiver kernel-object
*
* \return a cap that acts as reference to the created object
*
* \throw Out_of_metadata
*/
virtual Signal_receiver_capability alloc_receiver() = 0;
/**
* Create a new signal-context kernel-object
*
* \param r names the signal receiver that shall provide
* the new context
* \param imprint every signal that occures on the new context gets
* signed with this value
*
* \return a cap that acts as reference to the created object
*
* \throw Out_of_metadata
*/
virtual Signal_context_capability
alloc_context(Signal_receiver_capability const r,
unsigned long const imprint) = 0;
/*********************
** RPC declaration **
*********************/
GENODE_RPC_THROW(Rpc_alloc_receiver, Signal_receiver_capability,
alloc_receiver, GENODE_TYPE_LIST(Out_of_metadata));
GENODE_RPC_THROW(Rpc_alloc_context, Signal_context_capability,
alloc_context, GENODE_TYPE_LIST(Out_of_metadata),
Signal_receiver_capability, unsigned long);
GENODE_RPC_INTERFACE(Rpc_alloc_receiver, Rpc_alloc_context);
};
}
#endif /* _INCLUDE__SIGNAL_SESSION__SIGNAL_SESSION_H_ */

View File

@ -0,0 +1,43 @@
/*
* \brief Serial output driver specific for the Texas Instruments TL16C750
* \author Martin Stein
* \date 2012-04-23
*/
/*
* Copyright (C) 2012 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__TL16C750__DRIVERS__SERIAL_LOG_H_
#define _INCLUDE__TL16C750__DRIVERS__SERIAL_LOG_H_
/* Genode includes */
#include <drivers/board.h>
#include <drivers/uart/tl16c750_base.h>
namespace Genode
{
/**
* Serial output driver specific for the Texas Instruments TL16C750
*/
class Serial_log : public Tl16c750_base
{
public:
/**
* Constructor
*
* \param baud_rate targeted transfer baud-rate
*/
Serial_log(unsigned const baud_rate) :
Tl16c750_base(Board::LOG_TL16C750_MMIO_BASE,
Board::LOG_TL16C750_CLOCK, baud_rate)
{ }
};
}
#endif /* _INCLUDE__TL16C750__DRIVERS__SERIAL_LOG_H_ */

View File

@ -0,0 +1,22 @@
#
# \brief Essential platform specific sources for common programs
# \author Martin Stein
# \date 2012-04-16
#
# add libraries
LIBS += cxx lock
# add C++ sources
SRC_CC += _main.cc
# add assembly sources
SRC_S += crt0.s syscall.cc
# add include paths
INC_DIR += $(REP_DIR)/src/platform $(BASE_DIR)/src/platform
# declare source paths
vpath crt0.s $(REP_DIR)/src/platform
vpath _main.cc $(BASE_DIR)/src/platform
vpath syscall.cc $(REP_DIR)/src/base/arm_v7a

View File

@ -0,0 +1,29 @@
#
# \brief Essential platform specific sources for core
# \author Martin Stein
# \date 2012-04-16
#
# Aad C++ sources
SRC_CC += syscall.cc
# add assembly sources
SRC_S += crt0.s mode_transition.s boot_modules.s
# add inlucde paths
INC_DIR += $(BASE_DIR)/src/core/include/
#
# Check if there are other images wich shall be linked to core.
# If not use a dummy boot-modules file wich includes only the symbols.
#
ifeq ($(wildcard $(BUILD_BASE_DIR)/boot_modules.s),)
vpath boot_modules.s $(REP_DIR)/src/core/arm_v7a
else
INC_DIR += $(BUILD_BASE_DIR)
vpath boot_modules.s $(BUILD_BASE_DIR)
endif
# declare remaining source paths
vpath syscall.cc $(REP_DIR)/src/base/arm_v7a
vpath % $(REP_DIR)/src/core/arm_v7a

View File

@ -0,0 +1,20 @@
#
# \brief Generic parts of the core-support lib
# \author Martin Stein
# \date 2012-04-27
#
# add include paths
INC_DIR += $(BOARD_DIR) $(REP_DIR)/src/core/include $(REP_DIR)/include \
$(BASE_DIR)/src/core/include $(BASE_DIR)/include
# set entry point of core's first thread
CC_OPT += -DCORE_MAIN=_main
# add C++ sources
SRC_CC += platform_support.cc kernel.cc rm_session_support.cc
# declare source paths
vpath platform_support.cc $(BOARD_DIR)
vpath % $(REP_DIR)/src/core

12
base-hw/lib/mk/ipc.mk Normal file
View File

@ -0,0 +1,12 @@
#
# \brief Interprocess communication
# \author Martin Stein
# \date 2012-04-16
#
# add library dependencies
LIBS += thread
# include implied libraries
include $(REP_DIR)/lib/mk/raw_ipc.mk

14
base-hw/lib/mk/lock.mk Normal file
View File

@ -0,0 +1,14 @@
#
# \brief Synchronisation through locks
# \author Martin Stein
# \date 2012-04-16
#
# add C++ sources
SRC_CC += lock.cc
# add include paths
INC_DIR += $(REP_DIR)/src/base/lock
# declare source paths
vpath % $(BASE_DIR)/src/base/lock

11
base-hw/lib/mk/pager.mk Normal file
View File

@ -0,0 +1,11 @@
#
# \brief Genode pager threads
# \author Martin Stein
# \date 2012-04-16
#
# add C++ sources
SRC_CC += pager.cc
# declare source paths
vpath % $(REP_DIR)/src/base

View File

@ -0,0 +1,12 @@
#
# \brief Parts of core that depend on the PandaBoard A2
# \author Martin Stein
# \date 2012-04-27
#
# declare location of core files that are board specific
BOARD_DIR = $(REP_DIR)/src/core/panda_a2
# include generic parts of core support
include $(REP_DIR)/lib/mk/core_support.inc

View File

@ -0,0 +1,16 @@
#
# \brief Platform implementations specific for base-hw and Panda A2
# \author Martin Stein
# \date 2012-05-10
#
# add include paths
INC_DIR += $(REP_DIR)/src/core/include \
$(BASE_DIR)/src/core/include
# add C++ sources
SRC_CC += platform_support.cc
# declare source paths
vpath % $(REP_DIR)/src/core/panda_a2

View File

@ -0,0 +1,12 @@
#
# \brief Parts of core that depend on the Realview PBXA9
# \author Martin Stein
# \date 2012-04-27
#
# declare location of core files that are board specific
BOARD_DIR = $(REP_DIR)/src/core/pbxa9
# include generic part of core support
include $(REP_DIR)/lib/mk/core_support.inc

View File

@ -0,0 +1,12 @@
#
# \brief Parts of core that depend on the Versatile VEA9X4
# \author Martin Stein
# \date 2012-04-27
#
# declare location of core files that are board specific
BOARD_DIR = $(REP_DIR)/src/core/vea9x4
# include generic part of core support
include $(REP_DIR)/lib/mk/core_support.inc

11
base-hw/lib/mk/raw_ipc.mk Normal file
View File

@ -0,0 +1,11 @@
#
# \brief Interprocess communication without thread implementations
# \author Martin Stein
# \date 2012-04-16
#
# add C++ source files
SRC_CC += ipc.cc
# declare source paths
vpath % $(REP_DIR)/src/base

View File

@ -0,0 +1,15 @@
#
# \brief Submit and receive asynchronous events
# \author Martin Stein
# \date 2012-05-07
#
# add C++ sources
SRC_CC += signal.cc
# add library dependencies
LIBS += slab
# declare source paths
vpath % $(REP_DIR)/src/base/signal

9
base-hw/lib/mk/signal.mk Normal file
View File

@ -0,0 +1,9 @@
#
# \brief Shortcut for raw-signal lib to ensure Genode compliance
# \author Martin Stein
# \date 2012-04-16
#
# include implied libraries
include $(REP_DIR)/lib/mk/raw_signal.mk

12
base-hw/lib/mk/thread.mk Normal file
View File

@ -0,0 +1,12 @@
#
# \brief Implementation of the Genode thread-API
# \author Martin Stein
# \date 2012-04-16
#
# add C++ sources
SRC_CC += thread.cc thread_bootstrap.cc thread_support.cc
# declare source paths
vpath thread_support.cc $(REP_DIR)/src/base/
vpath % $(BASE_DIR)/src/base/thread/

12
base-hw/mk/spec-hw.mk Normal file
View File

@ -0,0 +1,12 @@
#
# \brief Offer build configurations that are specific to base-hw
# \author Martin Stein
# \date 2012-04-16
#
#
# Denote library that brings the setup sequence for C++ enviroment.
# Also add an according dependency.
#
STARTUP_LIB ?= startup
PRG_LIBS += $(STARTUP_LIB)

View File

@ -0,0 +1,15 @@
#
# \brief Offer build configurations that are specific to base-hw and Pandaboard A2
# \author Martin Stein
# \date 2011-12-20
#
# denote wich specs are also fullfilled by this spec
SPECS += hw platform_panda_a2
# set address where to link the text segment at
LD_TEXT_ADDR ?= 0x80000000
# include implied specs
include $(call select_from_repositories,mk/spec-hw.mk)
include $(call select_from_repositories,mk/spec-platform_panda_a2.mk)

View File

@ -0,0 +1,15 @@
#
# \brief Offer build configurations that are specific to base-hw and PBXA9
# \author Martin Stein
# \date 2011-12-20
#
# denote wich specs are also fullfilled by this spec
SPECS += hw platform_pbxa9
# set address where to link text segment at
LD_TEXT_ADDR ?= 0x01000000
# include implied specs
include $(call select_from_repositories,mk/spec-hw.mk)
include $(call select_from_repositories,mk/spec-platform_pbxa9.mk)

View File

@ -0,0 +1,15 @@
#
# \brief Offer build configurations that are specific to base-hw and VEA9X4
# \author Martin Stein
# \date 2011-12-20
#
# denote wich specs are also fullfilled by this spec
SPECS += hw platform_vea9x4
# set address where to link text segment at
LD_TEXT_ADDR ?= 0x01000000
# include implied specs
include $(call select_from_repositories,mk/spec-hw.mk)
include $(call select_from_repositories,mk/spec-platform_vea9x4.mk)

229
base-hw/run/env Normal file
View File

@ -0,0 +1,229 @@
#!/usr/bin/expect
#
# \brief Implementation of the interface provided by 'tool/run'
# \author Martin Stein
# \date 2011-12-16
#
######################
## Utility routines ##
######################
#
# Build an assembly file that enables the creation of a single boot image
#
# \param file targeted file
# \parem binaries targeted boot modules, must reside in '[run_dir]/genode/'
#
# This file rawly includes all binaries given in
# 'binaries', minus 'core' if given, plus 'config' if available. It also
# provides a simple file system that enables Genode to access these BLOBs.
#
proc boot_modules_arm_v7a {{file} {binaries}} {
set load_store_alignm 0x3
set min_page_alignm 12
# introduce boot module headers
exec echo -e \
"/**" \
"\n * This file was automatically generated by the procedure" \
"\n * 'boot_modules_arm_v7a' in 'run/env'." \
"\n */" \
"\n" \
"\n.section .data" \
"\n" \
"\n.align ${load_store_alignm}" \
"\n.global _boot_modules_begin" \
"\n_boot_modules_begin:" \
"\n.string \"GROM\"" \
"\n" \
"\n.align ${load_store_alignm}" \
"\n.global _boot_module_headers_begin" \
"\n_boot_module_headers_begin:" > $file
# generate header for each boot module except core
set i 1
foreach binary $binaries {
if {$binary == "core"} { continue }
exec echo -e \
"\n.long mod${i}_name" \
"\n.long mod${i}_start" \
"\n.long mod${i}_end - mod${i}_start" >> $file
incr i
}
# end boot module headers
exec echo -e \
"\n.global _boot_module_headers_end" \
"\n_boot_module_headers_end:" \
"\n" >> $file
# generate name string for each module except core
set i 1
foreach binary $binaries {
if {$binary == "core"} { continue }
exec echo -e \
".align ${load_store_alignm}" \
"\nmod${i}_name:" \
"\n.string \"${binary}\"" \
"\n.byte 0" \
"\n" >> $file
incr i
}
# include raw data of modules consecutively but page aligned
set i 1
foreach binary $binaries {
if {$binary == "core"} { continue }
exec echo -e \
".align ${min_page_alignm}" \
"\nmod${i}_start:" \
"\n.incbin \"[run_dir]/genode/${binary}\"" \
"\nmod${i}_end:" \
"\n" >> $file
incr i
}
# end boot-modules file
exec echo -e \
".global _boot_modules_end" \
"\n_boot_modules_end:" >> $file
}
#
# Ensure that the next Genode build includes no target specific boot modules
#
proc disable_specific_boot_modules { } {
exec rm -rf boot_modules.s
exec rm -rf var/libcache/boot_modules/boot_modules.o
}
#
# Ensure that the next Genode build includes target specific boot modules
#
proc enable_specific_boot_modules {file} {
exec rm -rf boot_modules.s
exec ln -s $file boot_modules.s
exec rm -rf var/libcache/boot_modules/boot_modules.o
}
#
# Apply the boot modules file 'file' to the core image
#
proc apply_boot_modules_to_core {file} {
# recompile 'core', with specific boot modules
puts "Building single boot image"
set timeout 10000
enable_specific_boot_modules $file
set pid [eval "spawn make core"]
expect { eof { } }
if {[lindex [wait $pid] end] != 0} {
puts "Error: Genode build failed"
exit -4
}
# clean up for subsequent builds
disable_specific_boot_modules
puts "Single boot image built"
}
######################################
## Interface supplied by 'tool/run' ##
######################################
proc build {targets} {
# skip targets that shall not be build
if {[get_cmd_switch --skip-build]} return
# handle false remnants of previous builds
disable_specific_boot_modules
#
# Build all remaining targets.
# Core is build with a dummy boot-modules file first.
#
regsub -all {\s\s+} $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 install_config {config} {
set fh [open "bin/config" "WRONLY CREAT TRUNC"]
puts $fh $config
close $fh
}
proc create_boot_directory { } {
exec rm -rf [run_dir]
exec mkdir -p [run_dir]/genode
}
proc build_boot_image {binaries} {
# create additional stripped version of any binary
copy_and_strip_genode_binaries_to_run_dir $binaries
# append init configuration if existent to the binaries
if {[file exists "bin/config"] == 1} {
exec cp bin/config [run_dir]/genode
append binaries " config"
}
# create scenario-specific 'boot_modules.s' of all given binaries
set boot_modules "[run_dir]/boot_modules.s"
if { [have_spec {arm_v7a}] } {
boot_modules_arm_v7a $boot_modules $binaries
}
# preserve stand-alone core for debugging
exec mv core/core core/core.standalone
# apply the new 'boot_modules.s' to 'core' to create single boot image
apply_boot_modules_to_core $boot_modules
exec mv core/core [run_dir]/image.elf
exec [cross_dev_prefix]strip [run_dir]/image.elf
# remove stripped binaries and retrieve stand-alone core
exec mv core/core.standalone core/core
exec rm -r [run_dir]/genode
}
proc run_genode_until {{wait_for_re forever} {timeout_value 0}} {
# get the targeted method of execution, the default is 'qemu'
set image [run_dir]/image.elf
set target [get_cmd_arg --target "qemu"]
# try to execute image according to the targeted method of execution
if { $target == "qemu" } {
spawn_qemu $wait_for_re $timeout_value
} else {
puts stderr "Error: Target '${target}' is not supported"
puts stderr " Supported targets are: 'qemu'"; exit -3
}
}

View File

@ -0,0 +1,75 @@
#
# \brief Test genode basics by starting init instances in a nested manner
# \author Martin Stein
# \date 2012-05-30
#
# build program images
build "core init"
# create directory where the boot files are written to
create_boot_directory
# create XML configuration for init
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>
<default-route><any-service><parent/></any-service></default-route>
<start name="init">
<resource name="RAM" quantum="10M"/>
<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>
<default-route><any-service><parent/></any-service></default-route>
<start name="init">
<resource name="RAM" quantum="5M"/>
<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>
<default-route>
<any-service><parent/></any-service>
</default-route>
</config>
</start>
</config>
</start>
</config>
}
# create single boot image from the compiled program images
build_boot_image "core init"
# configure qemu to use 64 MB RAM and avoid GUI mode
append qemu_args " -m 64 -nographic"
# execute the test in qemu if the targeted platform is supported
if {[have_spec hw_vea9x4] || [have_spec hw_pbxa9]} {
run_genode_until "No children to start.*\n" 10
}

View File

@ -0,0 +1,160 @@
/*
* \brief Syscall-framework implementation for ARM V7A systems
* \author Martin stein
* \date 2011-11-30
*/
/*
* Copyright (C) 2011-2012 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/syscall.h>
using namespace Kernel;
/******************************************************************
** Inline assembly templates for syscalls with 1 to 6 arguments **
******************************************************************/
#define SYSCALL_6_ASM_OPS \
"mov r5, #0 \n" \
"add r5, %[arg_5] \n" \
SYSCALL_5_ASM_OPS
#define SYSCALL_5_ASM_OPS \
"mov r4, #0 \n" \
"add r4, %[arg_4] \n" \
SYSCALL_4_ASM_OPS
#define SYSCALL_4_ASM_OPS \
"mov r3, #0 \n" \
"add r3, %[arg_3] \n" \
SYSCALL_3_ASM_OPS
#define SYSCALL_3_ASM_OPS \
"mov r2, #0 \n" \
"add r2, %[arg_2] \n" \
SYSCALL_2_ASM_OPS
#define SYSCALL_2_ASM_OPS \
"mov r1, #0 \n" \
"add r1, %[arg_1] \n" \
SYSCALL_1_ASM_OPS
#define SYSCALL_1_ASM_OPS \
"mov r0, #0 \n" \
"add r0, %[arg_0] \n" \
"svc 0x0 \n" \
"mov %[result], #0 \n" \
"add %[result], r0 "
/*****************************************************************************
** Inline assembly "writeable" template-args for syscalls with 1 to 6 args **
*****************************************************************************/
#define SYSCALL_6_ASM_WRITE [arg_5] "+r" (arg_5), SYSCALL_5_ASM_WRITE
#define SYSCALL_5_ASM_WRITE [arg_4] "+r" (arg_4), SYSCALL_4_ASM_WRITE
#define SYSCALL_4_ASM_WRITE [arg_3] "+r" (arg_3), SYSCALL_3_ASM_WRITE
#define SYSCALL_3_ASM_WRITE [arg_2] "+r" (arg_2), SYSCALL_2_ASM_WRITE
#define SYSCALL_2_ASM_WRITE [arg_1] "+r" (arg_1), SYSCALL_1_ASM_WRITE
#define SYSCALL_1_ASM_WRITE \
[arg_0] "+r" (arg_0), \
[result] "+r" (result)
/**********************************************************************
** Inline assembly clobber lists for syscalls with 1 to 6 arguments **
**********************************************************************/
#define SYSCALL_6_ASM_CLOBBER "r5", SYSCALL_5_ASM_CLOBBER
#define SYSCALL_5_ASM_CLOBBER "r4", SYSCALL_4_ASM_CLOBBER
#define SYSCALL_4_ASM_CLOBBER "r3", SYSCALL_3_ASM_CLOBBER
#define SYSCALL_3_ASM_CLOBBER "r2", SYSCALL_2_ASM_CLOBBER
#define SYSCALL_2_ASM_CLOBBER "r1", SYSCALL_1_ASM_CLOBBER
#define SYSCALL_1_ASM_CLOBBER "r0"
/************************************
** Syscalls with 1 to 6 arguments **
************************************/
Syscall_ret Kernel::syscall(Syscall_arg arg_0)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_1_ASM_OPS
: SYSCALL_1_ASM_WRITE
:: SYSCALL_1_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_2_ASM_OPS
: SYSCALL_2_ASM_WRITE
:: SYSCALL_2_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_3_ASM_OPS
: SYSCALL_3_ASM_WRITE
:: SYSCALL_3_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_4_ASM_OPS
: SYSCALL_4_ASM_WRITE
:: SYSCALL_4_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_5_ASM_OPS
: SYSCALL_5_ASM_WRITE
:: SYSCALL_5_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(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_ret result = 0;
asm volatile(SYSCALL_6_ASM_OPS
: SYSCALL_6_ASM_WRITE
:: SYSCALL_6_ASM_CLOBBER);
return result;
}

View File

@ -0,0 +1,73 @@
/**
* \brief Genode-console backend
* \author Martin Stein
* \date 2011-10-17
*/
/*
* Copyright (C) 2011-2012 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/console.h>
#include <base/printf.h>
#include <drivers/serial_log.h>
namespace Genode
{
/**
* Platform specific Genode console
*/
class Platform_console : public Console,
public Serial_log
{
enum { BAUD_RATE = 115200 };
protected:
/**
* Print a char to the console
*/
void _out_char(char c) { Serial_log::put_char(c); }
public:
/**
* Constructor
*/
Platform_console() : Serial_log(BAUD_RATE) { }
};
}
using namespace Genode;
/**
* Static object to print log output
*/
static Platform_console * platform_console()
{
static Platform_console static_platform_console;
return &static_platform_console;
}
/****************************
** Genode print functions **
****************************/
void Genode::printf(const char *format, ...)
{
va_list list;
va_start(list, format);
platform_console()->vprintf(format, list);
va_end(list);
}
void Genode::vprintf(const char *format, va_list list)
{ platform_console()->vprintf(format, list); }

220
base-hw/src/base/ipc.cc Normal file
View File

@ -0,0 +1,220 @@
/*
* \brief Implementation of the Genode IPC-framework
* \author Martin Stein
* \date 2012-02-12
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/ipc.h>
#include <base/thread.h>
#include <kernel/syscalls.h>
#include <kernel/log.h>
using namespace Genode;
enum
{
/* size of the callee-local name of a targeted RPC object */
RPC_OBJECT_ID_SIZE = sizeof(umword_t),
/*
* The RPC framework marshalls a return value into reply messages to
* deliver exceptions, wich occured during the RPC call to the caller.
* This defines the size of this value.
*/
RPC_RETURN_VALUE_SIZE = sizeof(umword_t),
};
/***************
** Utilities **
***************/
/**
* Translate byte size 's' to size in words
*/
static unsigned long size_in_words(unsigned long const s)
{ return (s + sizeof(unsigned long) - 1) / sizeof(unsigned long); }
/**
* Copy message payload to message buffer
*/
static void copy_utcb_to_msgbuf(Msgbuf_base * const receive_buffer,
unsigned long const message_size)
{
/* log data that is received via IPC */
enum { VERBOSE = 0 };
/* get pointers and message attributes */
Native_utcb * const utcb = Thread_base::myself()->utcb();
unsigned long * const msgbuf = (unsigned long *)receive_buffer->buf;
unsigned long const message_wsize = size_in_words(message_size);
/* assertions, avoid 'printf' in here, it may lead to infinite recursion */
if (message_wsize > size_in_words(utcb->size()))
{
kernel_log() << __PRETTY_FUNCTION__ << ": Oversized message\n";
while (1) ;
}
/* fill message buffer with message */
for (unsigned i=0; i < message_wsize; i++)
msgbuf[i] = *utcb->word(i);
}
/**
* Copy message payload to the UTCB
*/
static void copy_msgbuf_to_utcb(Msgbuf_base * const send_buffer,
unsigned long const message_size,
unsigned long const local_name)
{
/* log data that is send via IPC */
enum { VERBOSE = 0 };
/* get pointers and message attributes */
Native_utcb * const utcb = Thread_base::myself()->utcb();
unsigned long * const msgbuf = (unsigned long *)send_buffer->buf;
unsigned long const message_wsize = size_in_words(message_size);
/* assertions, avoid 'printf' in here, it may lead to infinite recursion */
if (message_wsize > size_in_words(utcb->size()))
{
kernel_log() << __PRETTY_FUNCTION__ << ": Oversized message\n";
while (1) ;
}
/* address message to an object that the targeted thread knows */
*utcb->word(0) = local_name;
/* write message payload */
for (unsigned long i = 1; i < message_wsize; i++)
*utcb->word(i) = msgbuf[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 = RPC_OBJECT_ID_SIZE;
}
/*****************
** Ipc_istream **
*****************/
void Ipc_istream::_wait()
{
/* FIXME this shall be not supported */
Kernel::pause_thread();
}
Ipc_istream::Ipc_istream(Msgbuf_base *rcv_msg)
:
Ipc_unmarshaller(&rcv_msg->buf[0], rcv_msg->size()),
Native_capability(Genode::thread_get_my_native_id(), 0),
_rcv_msg(rcv_msg), _rcv_cs(-1)
{ _read_offset = RPC_OBJECT_ID_SIZE; }
Ipc_istream::~Ipc_istream() { }
/****************
** Ipc_client **
****************/
void Ipc_client::_call()
{
using namespace Kernel;
/* send request and receive reply */
copy_msgbuf_to_utcb(_snd_msg, _write_offset,
Ipc_ostream::_dst.local_name());
size_t const s = request_and_wait(Ipc_ostream::_dst.dst(), _write_offset);
copy_utcb_to_msgbuf(_rcv_msg, s);
/* reset unmarshaller */
_write_offset = _read_offset = RPC_OBJECT_ID_SIZE;
}
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 **
****************/
Ipc_server::Ipc_server(Msgbuf_base *snd_msg,
Msgbuf_base *rcv_msg) :
Ipc_istream(rcv_msg),
Ipc_ostream(Native_capability(), snd_msg),
_reply_needed(false)
{ }
void Ipc_server::_prepare_next_reply_wait()
{
/* now we have a request to reply */
_reply_needed = true;
/* leave space for RPC method return value */
_write_offset = RPC_OBJECT_ID_SIZE + RPC_RETURN_VALUE_SIZE;
/* reset unmarshaller */
_read_offset = RPC_OBJECT_ID_SIZE;
}
void Ipc_server::_wait()
{
/* receive next request */
copy_utcb_to_msgbuf(_rcv_msg, Kernel::wait_for_request());
/* update server state */
_prepare_next_reply_wait();
}
void Ipc_server::_reply()
{
kernel_log() << __PRETTY_FUNCTION__ << ": Unexpected call\n";
while (1) ;
}
void Ipc_server::_reply_wait()
{
/* if there is no reply simply do wait for request */
/* FIXME this shall be not supported */
if (!_reply_needed) {
_wait();
return;
}
/* send reply and receive next request */
copy_msgbuf_to_utcb(_snd_msg, _write_offset,
Ipc_ostream::_dst.local_name());
copy_utcb_to_msgbuf(_rcv_msg, Kernel::reply_and_wait(_write_offset));
/* update server state */
_prepare_next_reply_wait();
}

View File

@ -0,0 +1,58 @@
/*
* \brief Helper functions for the Lock implementation
* \author Martin Stein
* \date 2011-01-02
*/
/*
* Copyright (C) 2011-2012 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__BASE__LOCK__LOCK_HELPER_H_
#define _SRC__BASE__LOCK__LOCK_HELPER_H_
/* Genode includes */
#include <base/native_types.h>
/**
* Yield CPU to any other thread
*/
static inline void thread_yield()
{ Kernel::yield_thread(); }
/**
* Yield CPU to a specified thread 't'
*/
static inline void
thread_switch_to(Genode::Native_thread_id const t)
{ Kernel::yield_thread(t); }
/**
* Resume another thread 't' and return if it were paused or not
*/
static inline bool
thread_check_stopped_and_restart(Genode::Native_thread_id const t)
{ return Kernel::resume_thread(t) == 0; }
/**
* Validation kernel thread-identifier 'id'
*/
static inline bool thread_id_valid(Genode::Native_thread_id const id)
{ return id != Genode::thread_invalid_id(); }
/**
* Exclude ourselves from CPU scheduling for now
*/
static inline void thread_stop_myself() { Kernel::pause_thread(); }
#endif /* _SRC__BASE__LOCK__LOCK_HELPER_H_ */

127
base-hw/src/base/pager.cc Normal file
View File

@ -0,0 +1,127 @@
/*
* \brief Pager implementations that are specific for the HW-core
* \author Martin Stein
* \date 2012-03-29
*/
/*
* Copyright (C) 2012 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>
#include <base/printf.h>
using namespace Genode;
/***************************
** Pager_activation_base **
***************************/
void Pager_activation_base::entry()
{
/* acknowledge that we're ready to work */
Ipc_pager pager;
_cap = pager;
_cap_valid.unlock();
/* wait for the first pagefault */
pager.wait_for_fault();
while (1)
{
/* lookup pager object for the current faulter */
Pager_object * o = _ep ? _ep->obj_by_id(pager.badge()) : 0;
if (!o) {
PERR("%s:%d: Invalid pager object", __FILE__, __LINE__);
while (1) ;
}
/* let pager handle the pagefault, apply mapping, await pagefault */
if (o->pager(pager)) pager.wait_for_fault();
else pager.resolve_and_wait_for_fault();
}
}
/**********************
** Pager_entrypoint **
**********************/
Pager_entrypoint::Pager_entrypoint(Cap_session *,
Pager_activation_base * const a)
: _activation(a) { _activation->ep(this); }
void Pager_entrypoint::dissolve(Pager_object * const o) { remove(o); }
Pager_capability Pager_entrypoint::manage(Pager_object * const o)
{
/* do we have an activation */
if (!_activation) return Pager_capability();
/* create cap with the object badge as local name */
Native_capability c;
c = Native_capability(_activation->cap().dst(), o->badge());
/* let activation provide the pager object */
o->cap(c);
insert(o);
/* return pager-object cap */
return reinterpret_cap_cast<Pager_object>(c);
}
/***************
** Ipc_pager **
***************/
void Ipc_pager::wait_for_fault()
{
/* receive first message */
size_t s = Kernel::wait_for_request();
while (1) {
switch (s) {
case sizeof(Pagefault): {
/* message is a pagefault */
Native_utcb * const utcb = Thread_base::myself()->utcb();
Pagefault * const pf = (Pagefault *)utcb;
if (pf->valid())
{
/* give our caller the chance to handle the fault */
_pagefault = *pf;
return;
}
/* pagefault is invalid so get the next message */
else {
PERR("%s:%d: Invalid pagefault", __FILE__, __LINE__);
continue;
}
continue; }
case sizeof(Pagefault_resolved): {
/* message is a release request from a RM session */
Native_utcb * const utcb = Thread_base::myself()->utcb();
Pagefault_resolved * const msg = (Pagefault_resolved *)utcb;
/* resume faulter, send ack to RM and get the next message */
Kernel::resume_thread(msg->pager_object->badge());
s = Kernel::reply_and_wait(0);
continue; }
default: {
PERR("%s:%d: Invalid message format", __FILE__, __LINE__);
continue; }
}
}
}

View File

@ -0,0 +1,130 @@
/*
* \brief Implementations of the signaling framework specific for HW-core
* \author Martin Stein
* \date 2012-05-05
*/
/*
* Copyright (C) 2012 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/signal.h>
#include <signal_session/connection.h>
#include <kernel/syscalls.h>
using namespace Genode;
/**
* Provide a static signal connection
*/
static Signal_connection * signal_connection()
{
static Signal_connection _object;
return &_object;
}
/*********************
** Signal_receiver **
*********************/
Signal_receiver::Signal_receiver() :
_cap(signal_connection()->alloc_receiver())
{
if (!_cap.valid()) {
PERR("%s: Failed to create receiver", __PRETTY_FUNCTION__);
while (1) ;
}
}
Signal_receiver::~Signal_receiver()
{
/* dissolve all contexts that are managed by us */
Lock::Guard contexts_guard(_contexts_lock);
while (1) {
Signal_context * const c = _contexts.first();
if (!c) break;
Lock::Guard context_guard(c->_lock);
_unsync_dissolve(c);
}
}
Signal_context_capability Signal_receiver::manage(Signal_context * const c)
{
/* check if the context is already managed */
Lock::Guard contexts_guard(_contexts_lock);
Lock::Guard context_guard(c->_lock);
if (c->_receiver) throw Context_already_in_use();
/* create a kernel object that corresponds to the context */
bool session_upgraded = 0;
Signal_connection * const s = signal_connection();
while (1) {
try {
c->_cap = s->alloc_context(_cap, (unsigned long)c);
break;
} catch (Signal_session::Out_of_metadata)
{
/* upgrade session quota and try again, but only once */
if (session_upgraded) return Signal_context_capability();
env()->parent()->upgrade(s->cap(), "ram_quota=4K");
session_upgraded = 1;
}
}
/* assign the context to us */
c->_receiver = this;
_contexts.insert(c);
return c->_cap;
}
Signal Signal_receiver::wait_for_signal()
{
/* await a signal */
Kernel::await_signal(_cap.dst());
Signal s = *(Signal *)Thread_base::myself()->utcb();
Signal_context * c = s.context();
/* check if the context of the signal is managed by us */
Lock::Guard context_guard(c->_lock);
if (c->_receiver != this) {
PERR("%s: Context not managed by this receiver", __PRETTY_FUNCTION__);
while (1) ;
}
/* check attributes of the signal and return it */
if (s.num() == 0) PWRN("Returning signal with num == 0");
return s;
}
void Signal_receiver::dissolve(Signal_context * const c)
{
/* check if the context is managed by us */
Lock::Guard contexts_guard(_contexts_lock);
Lock::Guard context_guard(c->_lock);
if (c->_receiver != this) throw Context_not_associated();
/* unassign the context */
_unsync_dissolve(c);
}
void Signal_receiver::_unsync_dissolve(Signal_context * const c)
{
/* reset the context */
c->_receiver = 0;
c->_cap = Signal_context_capability();
/* forget the context */
_contexts.remove(c);
}

View File

@ -0,0 +1,91 @@
/**
* \brief Platform specific parts of the thread API
* \author Martin Stein
* \date 2012-02-12
*/
/*
* Copyright (C) 2012 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;
extern Native_utcb * _main_utcb;
namespace Genode { Rm_session *env_context_area_rm_session(); }
/*****************
** Thread_base **
*****************/
Native_utcb * Thread_base::utcb()
{
/* this is a main thread, so CRT0 provides UTCB through '_main_utcb' */
if (!this) return _main_utcb;
/* otherwise we have a valid thread base */
return &_context->utcb;
}
void Thread_base::_thread_start()
{
Thread_base::myself()->_thread_bootstrap();
Thread_base::myself()->entry();
Genode::sleep_forever();
}
void Thread_base::_init_platform_thread() { }
void Thread_base::_deinit_platform_thread()
{ env()->cpu_session()->kill_thread(_thread_cap); }
void Thread_base::start()
{
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
Cpu_session * cpu = env()->cpu_session();
_thread_cap = cpu->create_thread(buf, (addr_t)&_context->utcb);
/* assign thread to protection domain */
env()->pd_session()->bind_thread(_thread_cap);
/* create new pager object and assign it to the new thread */
Pager_capability pager_cap = env()->rm_session()->add_client(_thread_cap);
env()->cpu_session()->set_pager(_thread_cap, pager_cap);
/* attach UTCB */
try {
Ram_dataspace_capability ds = env()->cpu_session()->utcb(_thread_cap);
size_t const size = sizeof(_context->utcb);
addr_t dst = Context_allocator::addr_to_base(_context) +
CONTEXT_VIRTUAL_SIZE - size - CONTEXT_AREA_VIRTUAL_BASE;
env_context_area_rm_session()->attach_at(ds, dst, size);
} catch (...) {
PERR("%s: Failed to attach UTCB", __PRETTY_FUNCTION__);
sleep_forever();
}
/* start thread with its initial IP and aligned SP */
addr_t thread_sp = (addr_t)&_context->stack[-4];
thread_sp &= ~0xf;
env()->cpu_session()->start(_thread_cap, (addr_t)_thread_start, thread_sp);
}
void Thread_base::cancel_blocking()
{ env()->cpu_session()->cancel_blocking(_thread_cap); }

View File

@ -0,0 +1,33 @@
/*
* \brief Dummy version of a boot modules file to enable a 'core' standalone image
* \author Martin Stein
* \date 2011-12-16
*/
/*
* Copyright (C) 2011-2012 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.
*/
.section .data
.align 3
.global _boot_modules_begin
_boot_modules_begin:
.string "GROM"
.align 3
.global _boot_module_headers_begin
_boot_module_headers_begin:
/* no module headers */
.global _boot_module_headers_end
_boot_module_headers_end:
/* no modules */
.global _boot_modules_end
_boot_modules_end:

View File

@ -0,0 +1,72 @@
/*
* \brief Startup code for the Genode Kernel on ARM
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-10-01
*/
/*
* Copyright (C) 2011-2012 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.
*/
.section .text
/* ELF entry symbol */
.global _start
_start:
/* idle a little initially because 'u-boot' likes it this way */
.rept 8
nop
.endr
/* zero-fill BSS segment */
.extern _bss_start
.extern _bss_end
ldr r0, =_bss_start
ldr r1, =_bss_end
mov r2, #0
sub r1, r1, #4
1:
str r2, [r0]
add r0, r0, #4
cmp r0, r1
bne 1b
/* call kernel routine */
.extern kernel
_start_kernel:
ldr sp, =_kernel_stack_high
bl kernel
/* jump to code that kernel has designated for when he has returned */
ldr r1, =_call_after_kernel
ldr r1, [r1]
add pc, r1, #0
/* handle for dynamic symbol objects */
.align 3
.global __dso_handle
__dso_handle: .long 0
.section .bss
/* instruction pointer wich gets loaded when kernel returns */
.align 3
.global _call_after_kernel
_call_after_kernel: .long 0
/* kernel stack */
.align 3
.space 64*1024
.global _kernel_stack_high
_kernel_stack_high:
/* main thread UTCB pointer for the Genode thread API */
.align 3
.global _main_utcb
_main_utcb: .long 0

View File

@ -0,0 +1,205 @@
/*
* \brief Transition between kernel and userland
* \author Martin stein
* \date 2011-11-15
*/
/*
* Copyright (C) 2011-2012 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.
*/
/**
* Invalidate all entries of the branch predictor array
*/
.macro _flush_branch_predictor
mcr p15, 0, sp, c7, c5, 6
isb
.endm
/**
* Switch from an interrupted user context to a kernel context
*
* \param exception_type immediate exception type ID
* \param pc_adjust immediate value that gets subtracted from the
* user PC before it gets saved
*/
.macro _user_to_kernel_pic exception_type, pc_adjust
/*
* We expect that privileged modes are never interrupted by an
* exception. Thus we can assume that we always come from
* user mode at this point.
*/
/************************************************
** We're still in the user protection domain, **
** so we must avoid access to kernel memory **
************************************************/
/* load kernel contextidr */
adr sp, _mt_kernel_context_begin
ldr sp, [sp, #17*4]
mcr p15, 0, sp, c13, c0, 1
_flush_branch_predictor
/* load kernel section table */
adr sp, _mt_kernel_context_begin
ldr sp, [sp, #19*4]
mcr p15, 0, sp, c2, c0, 0
_flush_branch_predictor
/*******************************************
** Now it's save to access kernel memory **
*******************************************/
/* get user context pointer */
ldr sp, _mt_user_context_ptr
/*
* Save user r0 ... r12. We explicitely target user registers
* via '^' because we might be in FIQ exception-mode where
* some of them are banked. Doesn't affect other modes.
*/
stmia sp, {r0-r12}^
/* save user lr and sp */
add r0, sp, #13*4
stmia r0, {sp,lr}^
/* adjust and save user pc */
.if \pc_adjust != 0
sub lr, lr, #\pc_adjust
.endif
str lr, [sp, #15*4]
/* save user psr */
mrs r0, spsr
str r0, [sp, #16*4]
/* save type of exception that interrupted the user */
mov r0, #\exception_type
str r0, [sp, #18*4]
/*
* Switch to supervisor mode
* FIXME This is done due to incorrect behavior when running the kernel
* high-level-code in FIQ-exception mode. Please debug this behavior
* and remove this switch.
*/
cps #19
/* get kernel context pointer */
adr r0, _mt_kernel_context_begin
/* load kernel context */
add r0, r0, #13*4
ldmia r0, {sp, lr, pc}
.endm
.section .text
/*
* The mode transition PIC switches between a kernel context and a user
* context and thereby between their address spaces. Due to the latter
* it must be mapped executable to the same region in every address space.
* To enable such switching, the kernel context must be stored within this
* region, thus one should map it solely accessable for privileged modes.
*/
.align 3
.global _mode_transition_begin
_mode_transition_begin:
/*
* On user exceptions the CPU has to jump to one of the following
* 7 entry vectors to switch to a kernel context.
*/
.align 3
.global _mt_kernel_entry_pic
_mt_kernel_entry_pic:
b _rst_entry /* reset */
b _und_entry /* undefined instruction */
b _svc_entry /* supervisor call */
b _pab_entry /* prefetch abort */
b _dab_entry /* data abort */
nop /* reserved */
b _irq_entry /* interrupt request */
b _fiq_entry /* fast interrupt request */
/* PICs that switch from an user exception to the kernel */
_rst_entry: _user_to_kernel_pic 1, 0
_und_entry: _user_to_kernel_pic 2, 4
_svc_entry: _user_to_kernel_pic 3, 0
_pab_entry: _user_to_kernel_pic 4, 4
_dab_entry: _user_to_kernel_pic 5, 8
_irq_entry: _user_to_kernel_pic 6, 4
_fiq_entry: _user_to_kernel_pic 7, 4
/* kernel must jump to this point to switch to a user context */
.align 3
.global _mt_user_entry_pic
_mt_user_entry_pic:
/* get user context pointer */
ldr lr, _mt_user_context_ptr
/* buffer user pc */
ldr r0, [lr, #15*4]
adr r1, _mt_buffer
str r0, [r1]
/* buffer user psr */
ldr r0, [lr, #16*4]
msr spsr, r0
/* load user r0 ... r12 */
ldmia lr, {r0-r12}
/* load user sp and lr */
add sp, lr, #13*4
ldmia sp, {sp,lr}^
/* get user contextidr and section table */
ldr sp, [lr, #17*4]
ldr lr, [lr, #19*4]
/********************************************************
** From now on, until we leave kernel mode, we must **
** avoid access to memory that is not mapped globally **
********************************************************/
/* apply user contextidr and section table */
mcr p15, 0, sp, c13, c0, 1
mcr p15, 0, lr, c2, c0, 0
_flush_branch_predictor
/* load user pc (implies application of the user psr) */
adr lr, _mt_buffer
ldmia lr, {pc}^
/* leave some space for the kernel context */
.align 3
.global _mt_kernel_context_begin
_mt_kernel_context_begin: .space 32*4
.global _mt_kernel_context_end
_mt_kernel_context_end:
/* pointer to the user context backup space */
.align 3
.global _mt_user_context_ptr
_mt_user_context_ptr: .long 0
/* a local word-sized buffer */
.align 3
.global _mt_buffer
_mt_buffer: .long 0
.align 3
.global _mode_transition_end
_mode_transition_end:

View File

@ -0,0 +1,34 @@
/*
* \brief Platform specific parts of CPU session
* \author Martin Stein
* \date 2012-04-17
*/
/*
* Copyright (C) 2012 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 thread_cap)
{
/* serialize access */
Lock::Guard lock_guard(_thread_list_lock);
/* lookup requested UTCB dataspace */
Cpu_thread_component * t = _lookup_thread(thread_cap);
if (!t) return Ram_dataspace_capability();
return t->platform_thread()->utcb();
}

View File

@ -0,0 +1,36 @@
/*
* \brief Assertion macro
* \author Martin Stein
* \date 2012-04-04
*/
/*
* Copyright (C) 2012 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__ASSERT_H_
#define _CORE__INCLUDE__ASSERT_H_
/* Genode includes */
#include <base/printf.h>
/**
* Assert a condition
*
* \param expression Expression that must be true
*/
#define assert(expression) \
do { \
if (!(expression)) { \
PERR("Assertion failed: "#expression""); \
PERR(" File: %s:%d", __FILE__, __LINE__); \
PERR(" Function: %s", __PRETTY_FUNCTION__); \
while (1) ; \
} \
} while (0) ;
#endif /* _CORE__INCLUDE__ASSERT_H_ */

View File

@ -0,0 +1,54 @@
/*
* \brief Parts of kernel support that are identical for all Cortex A9 systems
* \author Martin Stein
* \date 2012-04-23
*/
/*
* Copyright (C) 2012 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__CORTEX_A9__KERNEL_SUPPORT_H_
#define _CORE__INCLUDE__CORTEX_A9__KERNEL_SUPPORT_H_
/* Genode includes */
#include <drivers/cpu/cortex_a9/core.h>
#include <drivers/pic/pl390_base.h>
/**
* CPU driver
*/
class Cpu : public Genode::Cortex_a9 { };
namespace Kernel
{
/* import Genode types */
typedef Genode::Cortex_a9 Cortex_a9;
typedef Genode::Pl390_base Pl390_base;
/**
* Kernel interrupt-controller
*/
class Pic : public Pl390_base
{
public:
/**
* Constructor
*/
Pic() : Pl390_base(Cortex_a9::PL390_DISTRIBUTOR_MMIO_BASE,
Cortex_a9::PL390_CPU_MMIO_BASE)
{ }
};
/**
* Kernel timer
*/
class Timer : public Cortex_a9::Private_timer { };
}
#endif /* _CORE__INCLUDE__CORTEX_A9__KERNEL_SUPPORT_H_ */

View File

@ -0,0 +1,68 @@
/*
* \brief Platform specific parts of the core CPU session
* \author Martin Stein
* \date 2012-03-21
*/
/*
* Copyright (C) 2012 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__CPU_SESSION_SUPPORT_H_
#define _CORE__INCLUDE__CPU_SESSION_SUPPORT_H_
#include <base/printf.h>
#include <base/allocator.h>
namespace Genode
{
/**
* Thread allocator for cores CPU service
*
* Normally one would use a SLAB for threads because usually they
* are tiny objects, but in 'base-hw' they contain the whole kernel
* object in addition. Thus we use the given allocator directly.
*/
class Cpu_thread_allocator : public Allocator
{
Allocator * const _alloc;
public:
/**
* Constructor
*
* \param alloc allocator backend
*/
Cpu_thread_allocator(Allocator * alloc) : _alloc(alloc) { }
/*************************
** Allocator interface **
*************************/
bool alloc(size_t size, void **out_addr) {
return _alloc->alloc(size, out_addr); }
void free(void *addr, size_t size) {
_alloc->free(addr, size); }
size_t consumed() {
PDBG("Unexprected call");
while (1) ;
return 0;
}
size_t overhead(size_t size) {
PDBG("Unexprected call");
while (1) ;
return 0;
}
bool need_size_for_free() const { return true; }
};
}
#endif /* _CORE__INCLUDE__CPU_SESSION_SUPPORT_H_ */

View File

@ -0,0 +1,111 @@
/*
* \brief Platform interface
* \author Martin Stein
* \date 2011-12-21
*/
/*
* Copyright (C) 2011-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__PLATFORM_H_
#define _CORE__INCLUDE__PLATFORM_H_
/* Genode includes */
#include <base/sync_allocator.h>
#include <base/allocator_avl.h>
#include <kernel/log.h>
#include <kernel/syscalls.h>
/* core includes */
#include <platform_generic.h>
namespace Genode {
/**
* Manages all platform ressources
*/
class Platform : public Platform_generic
{
typedef Synchronized_range_allocator<Allocator_avl> Phys_allocator;
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 */
addr_t _vm_base; /* base of virtual address space */
size_t _vm_size; /* size of virtual address space */
/**
* Get one of the consecutively numbered available resource regions
*
* \return >0 region pointer if region with index 'i' exists
* 0 if region with index 'i' doesn't exist
*
* These functions should provide all ressources that are available
* on the current platform.
*/
static Native_region * _ram_regions(unsigned i);
static Native_region * _mmio_regions(unsigned i);
static Native_region * _irq_regions(unsigned i);
/**
* Get one of the consecutively numbered core regions
*
* \return >0 Region pointer if region with index 'i' exists
* 0 If region with index 'i' doesn't exist
*
* Core regions are address regions that must be permitted to
* core only, such as the core image ROM. These regions are normally
* a subset of the ressource regions provided above.
*/
static Native_region * _core_only_ram_regions(unsigned i);
static Native_region * _core_only_mmio_regions(unsigned i);
static Native_region * _core_only_irq_regions(unsigned i);
public:
/**
* Constructor
*/
Platform();
/********************************
** Platform_generic interface **
********************************/
inline Range_allocator * core_mem_alloc() { return &_core_mem_alloc; }
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 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() { while (1) Kernel::pause_thread(); };
inline Range_allocator * region_alloc()
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
return 0;
}
};
}
#endif /* _CORE__INCLUDE__PLATFORM_H_ */

View File

@ -0,0 +1,105 @@
/*
* \brief Platform specific part of a Genode protection domain
* \author Martin Stein
* \date 2012-02-12
*/
/*
* Copyright (C) 2009-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__PLATFORM_PD_H_
#define _CORE__INCLUDE__PLATFORM_PD_H_
/* Genode includes */
#include <base/printf.h>
/* Core includes */
#include <platform.h>
#include <platform_thread.h>
namespace Kernel
{
Genode::size_t pd_size();
unsigned pd_alignm_log2();
}
namespace Genode
{
class Platform_thread;
/**
* Platform specific part of a Genode protection domain
*/
class Platform_pd
{
unsigned long _id; /* ID of our kernel object */
Native_capability _parent; /* our parent interface */
Native_thread_id _main_thread; /* the first thread that gets
* executed in this PD */
public:
/**
* Constructor
*/
Platform_pd() : _main_thread(0)
{
/* get some aligned space for the kernel object */
void * kernel_pd;
Range_allocator * ram = platform()->ram_alloc();
assert(ram->alloc_aligned(Kernel::pd_size(), &kernel_pd,
Kernel::pd_alignm_log2()));
/* create kernel object */
_id = Kernel::new_pd(kernel_pd);
assert(_id);
}
/**
* Destructor
*/
~Platform_pd();
/**
* Bind thread 't' to protection domain
*
* \return 0 on success or
* -1 if failed
*/
int bind_thread(Platform_thread * t)
{
/* is this the first and therefore main thread in this PD? */
if (!_main_thread)
{
/* annotate that we've got a main thread from now on */
_main_thread = t->id();
return t->join_pd(_id, 1);
}
return t->join_pd(_id, 0);
}
/**
* Unbind thread from protection domain
*
* Free the thread's slot and update thread object.
*/
void unbind_thread(Platform_thread * t);
/**
* Assign parent interface to protection domain
*/
int assign_parent(Native_capability parent)
{
assert(parent.valid());
_parent = parent;
return 0;
}
};
}
#endif /* _CORE__INCLUDE__PLATFORM_PD_H_ */

View File

@ -0,0 +1,184 @@
/*
* \brief Userland interface for the management of kernel thread-objects
* \author Martin Stein
* \date 2012-02-02
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__PLATFORM_THREAD_H_
#define _CORE__INCLUDE__PLATFORM_THREAD_H_
/* Genode includes */
#include <ram_session/ram_session.h>
#include <base/native_types.h>
#include <kernel/syscalls.h>
#include <kernel/log.h>
/* core includes */
#include <assert.h>
namespace Genode {
class Pager_object;
class Thread_state;
class Thread_base;
class Rm_client;
class Platform_thread;
size_t kernel_thread_size();
/**
* Userland interface for the management of kernel thread-objects
*/
class Platform_thread
{
enum { NAME_MAX_LEN = 32 };
Thread_base * _thread_base;
unsigned long _stack_size;
unsigned long _pd_id;
unsigned long _id;
Rm_client * _rm_client;
bool _main_thread;
Native_utcb * _phys_utcb;
Native_utcb * _virt_utcb;
Software_tlb * _software_tlb;
Ram_dataspace_capability _utcb;
char _name[NAME_MAX_LEN];
/**
* Common construction part
*/
void _init();
public:
/**
* Constructor for core threads
*/
Platform_thread(const char * name,
Thread_base * const thread_base,
unsigned long const stack_size,
unsigned long const pd_id);
/**
* Constructor for threads outside of core
*/
Platform_thread(const char * name, unsigned int priority,
addr_t utcb);
/**
* Join PD identified by 'pd_id'
*
* \param pd_id ID of targeted PD
* \param main_thread wether we are the main thread in this PD
*
* \retval 0 on success
* \retval <0 otherwise
*/
int join_pd(unsigned long const pd_id,
bool const main_thread);
/**
* Run this thread
*/
int start(void * ip, void * sp, unsigned int cpu_no = 0);
/**
* Pause this thread
*/
void pause() { Kernel::pause_thread(_id); }
/**
* Resume this thread
*/
void resume() { Kernel::resume_thread(_id); }
/**
* Cancel currently blocking operation
*/
void cancel_blocking()
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
};
/**
* Request our raw thread state
*
* \param state_dst destination state buffer
*
* \retval 0 successful
* \retval -1 thread state not accessible
*/
int state(Genode::Thread_state * state_dst)
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
return -1;
};
/**
* Destructor
*/
~Platform_thread()
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
}
/**
* Return unique identification of this thread as faulter
*/
unsigned long pager_object_badge() { return _id; }
/**
* Set the executing CPU for this thread.
*/
void set_cpu(unsigned int cpu_no)
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
};
/***************
** Accessors **
***************/
inline char const * name() const { return _name; }
void pager(Pager_object * const pager);
Pager_object * pager() const;
unsigned long pd_id() const { return _pd_id; }
Native_thread_id id() const { return _id; }
unsigned long stack_size() const { return _stack_size; }
Thread_base * thread_base()
{
if (!_thread_base) assert(_main_thread);
return _thread_base;
}
Native_utcb * phys_utcb() const { return _phys_utcb; }
Native_utcb * virt_utcb() const { return _virt_utcb; }
Ram_dataspace_capability utcb() const { return _utcb; }
Software_tlb * software_tlb() const { return _software_tlb; }
};
}
#endif /* _CORE__INCLUDE__PLATFORM_THREAD_H_ */

View File

@ -0,0 +1,93 @@
/*
* \brief Signal root interface on HW-core
* \author Martin Stein
* \date 2012-05-06
*/
/*
* Copyright (C) 2012 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__SIGNAL_ROOT_H_
#define _CORE__INCLUDE__SIGNAL_ROOT_H_
/* Genode includes */
#include <root/component.h>
/* core includes */
#include <signal_session_component.h>
namespace Genode
{
/**
* Provide EP to signal root before it initialises root component
*/
class Signal_handler
{
enum { STACK_SIZE = 4096 };
Rpc_entrypoint _entrypoint;
public:
/**
* Constructor
*/
Signal_handler(Cap_session * const c)
: _entrypoint(c, STACK_SIZE, "signal") { }
/***************
** Accessors **
***************/
Rpc_entrypoint * entrypoint() { return &_entrypoint; }
};
/**
* Provides signal service by managing appropriate sessions to the clients
*/
class Signal_root : private Signal_handler,
public Root_component<Signal_session_component>
{
public:
/**
* Constructor
*
* \param md Meta-data allocator to be used by root component
* \param c CAP session to be used by the root entrypoint
*/
Signal_root(Allocator * const md, Cap_session * const c) :
Signal_handler(c),
Root_component<Signal_session_component>(entrypoint(), md)
{ }
protected:
/********************************
** 'Root_component' interface **
********************************/
Signal_session_component * _create_session(const char * args)
{
size_t ram_quota =
Arg_string::find_arg(args, "ram_quota").long_value(0);
return new (md_alloc())
Signal_session_component(md_alloc(), ram_quota);
}
void _upgrade_session(Signal_session_component *s,
const char * args)
{
size_t ram_quota =
Arg_string::find_arg(args, "ram_quota").long_value(0);
s->upgrade_ram_quota(ram_quota);
}
};
}
#endif /* _CORE__INCLUDE__SIGNAL_ROOT_H_ */

View File

@ -0,0 +1,68 @@
/*
* \brief Signal service on the HW-core
* \author Martin stein
* \date 2012-05-05
*/
/*
* Copyright (C) 2012 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__SIGNAL_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__SIGNAL_SESSION_COMPONENT_H_
/* Genode includes */
#include <signal_session/signal_session.h>
#include <base/rpc_server.h>
#include <base/slab.h>
#include <base/allocator_guard.h>
namespace Genode
{
/**
* Provides the signal service
*/
class Signal_session_component : public Rpc_object<Signal_session>
{
Allocator_guard _md_alloc; /* Metadata allocator */
Slab _receivers_slab; /* SLAB to allocate receiver kernel-objects */
Slab _contexts_slab; /* SLAB to allocate context kernel-objects */
public:
/**
* Constructor
*
* \param md Metadata allocator
* \param ram_quota Amount of RAM quota donated to this session
*/
Signal_session_component(Allocator * const md,
size_t const ram_quota);
/**
* Destructor
*/
~Signal_session_component();
/**
* Raise the quota of this session by 'q'
*/
void upgrade_ram_quota(size_t const q) { _md_alloc.upgrade(q); }
/******************************
** Signal_session interface **
******************************/
Signal_receiver_capability alloc_receiver();
Signal_context_capability
alloc_context(Signal_receiver_capability const r,
unsigned long const imprint);
};
}
#endif /* _CORE__INCLUDE__CAP_SESSION_COMPONENT_H_ */

View File

@ -0,0 +1,109 @@
/*
* \brief Core-internal utilities
* \author Martin Stein
* \date 2012-01-02
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__UTIL_H_
#define _CORE__INCLUDE__UTIL_H_
/* Genode includes */
#include <rm_session/rm_session.h>
#include <base/printf.h>
namespace Genode
{
enum { MIN_PAGE_SIZE_LOG2 = 12 };
/**
* Get the the minimal supported page-size log 2
*/
inline size_t get_page_size_log2() { return MIN_PAGE_SIZE_LOG2; }
/**
* Get the the minimal supported page-size
*/
inline size_t get_page_size() { return 1 << get_page_size_log2(); }
/**
* Get the base mask for the minimal supported page-size
*/
inline addr_t get_page_mask() { return ~(get_page_size() - 1); }
/**
* Round down to the minimal page-size alignment
*/
inline addr_t trunc_page(addr_t addr) { return addr & get_page_mask(); }
/**
* Round up to the minimal page-size alignment
*/
inline addr_t round_page(addr_t addr)
{ return trunc_page(addr + get_page_size() - 1); }
/**
* Round down to a specific alignment
*/
inline addr_t trunc(addr_t const addr, unsigned const alignm_log2)
{ return addr & ~((1 << alignm_log2) - 1); }
/**
* Round up to a specific alignment
*/
inline addr_t round(addr_t const addr, unsigned const alignm_log2)
{ return trunc(addr + (1<<alignm_log2) - 1, alignm_log2); }
/**
* Select source used for map operations
*/
inline addr_t map_src_addr(addr_t core_local, addr_t phys) { return phys; }
/**
* Return highest supported flexpage size for the given mapping size
*
* This function is called by the page-fault handler to determine the
* mapping granularity to be used for a page-fault answer. If a kernel
* supports flexible page sizes, this function can just return the
* argument. If a kernel only supports a certain set of map sizes such
* as 4K and 4M, this function should select one of those smaller or
* equal to the argument.
*/
inline size_t constrain_map_size_log2(size_t size_log2)
{
if (size_log2<20) return 12;
return 20;
}
/**
* Debug output on page faults
*/
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)", msg,
pf_type == Rm_session::WRITE_FAULT ? "WRITE" : "READ",
(void *)pf_addr, (void *)pf_ip,
faulter_badge);
}
}
#endif /* _CORE__INCLUDE__UTIL_H_ */

View File

@ -0,0 +1,29 @@
/*
* \brief Implementation of the IO_MEM session interface
* \author Martin Stein
* \date 2012-02-12
*
*/
/*
* Copyright (C) 2012 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 <kernel/log.h>
/* core includes */
#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)
{ return base; }

View File

@ -0,0 +1,85 @@
/*
* \brief Implementation of the IO_PORT session interface
* \author Martin Stein
* \date 2012-02-12
*/
/*
* Copyright (C) 2012 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 <kernel/log.h>
/* core includes */
#include <io_port_session_component.h>
using namespace Genode;
unsigned char Io_port_session_component::inb(unsigned short address)
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
return 0;
}
unsigned short Io_port_session_component::inw(unsigned short address)
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
return 0;
}
unsigned Io_port_session_component::inl(unsigned short address)
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
return 0;
}
void Io_port_session_component::outb(unsigned short address,
unsigned char value)
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
}
void Io_port_session_component::outw(unsigned short address,
unsigned short value)
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
}
void Io_port_session_component::outl(unsigned short address, unsigned value)
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
}
Io_port_session_component::
Io_port_session_component(Range_allocator * io_port_alloc,
const char * args)
: _io_port_alloc(io_port_alloc)
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
}
Io_port_session_component::~Io_port_session_component()
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
}

View File

@ -0,0 +1,69 @@
/*
* \brief Implementation of IRQ session component
* \author Martin Stein
* \date 2012-02-12
*/
/*
* Copyright (C) 2012 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 <kernel/syscalls.h>
/* core includes */
#include <irq_root.h>
using namespace Genode;
bool
Irq_session_component::Irq_control_component::associate_to_irq(unsigned irq)
{ return Kernel::allocate_irq(irq); }
void Irq_session_component::wait_for_irq() { Kernel::await_irq(); }
Irq_session_component::~Irq_session_component()
{
/* free IRQ for other threads */
if (Kernel::free_irq(_irq_number))
PERR("Could not free IRQ %u", _irq_number);
}
Irq_session_component::Irq_session_component(Cap_session * cap_session,
Range_allocator * irq_alloc,
const char * args)
:
_irq_alloc(irq_alloc), _ep(cap_session, STACK_SIZE, "irqctrl"),
_control_cap(_ep.manage(&_control_component)),
_control_client(_control_cap)
{
/* check arguments */
bool shared = Arg_string::find_arg(args, "irq_shared").bool_value(false);
if (shared) {
PERR("IRQ sharing not supported");
throw Root::Invalid_args();
}
/* allocate IRQ */
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (irq_number == -1 || !irq_alloc ||
irq_alloc->alloc_addr(1, irq_number) != Range_allocator::ALLOC_OK) {
PERR("Unavailable IRQ %lu requested", irq_number);
throw Root::Invalid_args();
}
_irq_number = irq_number;
/* configure control client */
if (!_control_client.associate_to_irq(irq_number)) {
PERR("IRQ association failed");
throw Root::Invalid_args();
}
/* create IRQ capability */
_irq_cap = Irq_session_capability(_ep.manage(this));
}

2088
base-hw/src/core/kernel.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
/*
* \brief Kernel support specific for the PandaBoard A2
* \author Martin Stein
* \date 2012-04-23
*/
/*
* Copyright (C) 2012 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__PANDA_A2__KERNEL_SUPPORT_H_
#define _SRC__CORE__PANDA_A2__KERNEL_SUPPORT_H_
/* local includes */
#include <cortex_a9/kernel_support.h>
#endif /* _SRC__CORE__PANDA_A2__KERNEL_SUPPORT_H_ */

View File

@ -0,0 +1,84 @@
/*
* \brief Platform implementations specific for base-hw and Panda A2
* \author Martin Stein
* \date 2012-04-27
*/
/*
* Copyright (C) 2012 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 <drivers/board/panda_a2.h>
#include <drivers/cpu/cortex_a9/core.h>
#include <drivers/pic/pl390_base.h>
/* core includes */
#include <platform.h>
using namespace Genode;
Native_region * Platform::_ram_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ Panda_a2::EMIF1_EMIF2_CS0_SDRAM_BASE,
Panda_a2::EMIF1_EMIF2_CS0_SDRAM_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Pl390_base::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* core timer */
{ Cortex_a9::PRIVATE_TIMER_IRQ, 1 },
/* core UART */
{ Panda_a2::TL16C750_3_IRQ, 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ Panda_a2::L4_PER_BASE, Panda_a2::L4_PER_SIZE },
{ Panda_a2::L4_CFG_BASE, Panda_a2::L4_CFG_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_mmio_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* core timer and PIC */
{ Panda_a2::CORTEX_A9_PRIVATE_MEM_BASE,
Panda_a2::CORTEX_A9_PRIVATE_MEM_SIZE },
/* core UART */
{ Panda_a2::TL16C750_3_MMIO_BASE, Panda_a2::TL16C750_3_MMIO_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}

View File

@ -0,0 +1,26 @@
/*
* \brief Software TLB controls specific for the PandaBoard A2
* \author Martin Stein
* \date 2012-04-23
*/
/*
* Copyright (C) 2012 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__PANDA_A2__SOFTWARE_TLB_H_
#define _SRC__CORE__PANDA_A2__SOFTWARE_TLB_H_
/* Genode includes */
#include <drivers/cpu/cortex_a9/section_table.h>
/**
* Software TLB controls
*/
class Software_tlb : public Genode::Section_table { };
#endif /* _SRC__CORE__PANDA_A2__SOFTWARE_TLB_H_ */

View File

@ -0,0 +1,21 @@
/*
* \brief Kernel support specific for the Realview PBXA9
* \author Martin Stein
* \date 2012-04-23
*/
/*
* Copyright (C) 2012 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__PBXA9__KERNEL_SUPPORT_H_
#define _SRC__CORE__PBXA9__KERNEL_SUPPORT_H_
/* local includes */
#include <cortex_a9/kernel_support.h>
#endif /* _SRC__CORE__PBXA9__KERNEL_SUPPORT_H_ */

View File

@ -0,0 +1,82 @@
/*
* \brief Parts of platform that are specific to PBXA9
* \author Martin Stein
* \date 2012-04-27
*/
/*
* Copyright (C) 2012 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 <drivers/board/pbxa9.h>
#include <drivers/cpu/cortex_a9/core.h>
#include <drivers/pic/pl390_base.h>
/* core includes */
#include <platform.h>
using namespace Genode;
Native_region * Platform::_ram_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ Pbxa9::NORTHBRIDGE_DDR_0_BASE, Pbxa9::NORTHBRIDGE_DDR_0_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Pl390_base::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* core timer */
{ Cortex_a9::PRIVATE_TIMER_IRQ, 1 },
/* core UART */
{ Pbxa9::PL011_0_IRQ, 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ Pbxa9::SOUTHBRIDGE_APB_BASE, Pbxa9::SOUTHBRIDGE_APB_SIZE },
{ Pbxa9::NORTHBRIDGE_AHB_BASE, Pbxa9::NORTHBRIDGE_AHB_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_mmio_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* core timer and PIC */
{ Pbxa9::CORTEX_A9_PRIVATE_MEM_BASE, Pbxa9::CORTEX_A9_PRIVATE_MEM_SIZE },
/* core UART */
{ Pbxa9::PL011_0_MMIO_BASE, Pbxa9::PL011_0_MMIO_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}

View File

@ -0,0 +1,26 @@
/*
* \brief Software TLB controls specific for the Realview PBXA9
* \author Martin Stein
* \date 2012-04-23
*/
/*
* Copyright (C) 2012 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__PBXA9__SOFTWARE_TLB_H_
#define _SRC__CORE__PBXA9__SOFTWARE_TLB_H_
/* Genode includes */
#include <drivers/cpu/cortex_a9/section_table.h>
/**
* Software TLB controls
*/
class Software_tlb : public Genode::Section_table { };
#endif /* _SRC__CORE__PBXA9__SOFTWARE_TLB_H_ */

View File

@ -0,0 +1,162 @@
/*
* \brief Platform implementation specific for hw
* \author Martin Stein
* \date 2011-12-21
*/
/*
* Copyright (C) 2011-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <base/sleep.h>
#include <kernel/log.h>
/* core includes */
#include <core_parent.h>
#include <platform.h>
#include <util.h>
using namespace Genode;
extern int _prog_img_beg;
extern int _prog_img_end;
/**
* Format of a boot-module header
*/
struct Bm_header
{
long name; /* physical address of null-terminated string */
long base; /* physical address of module data */
long size; /* size of module data in bytes */
};
extern int _boot_modules_begin;
extern Bm_header _boot_module_headers_begin;
extern Bm_header _boot_module_headers_end;
extern int _boot_modules_end;
/**
* Functionpointer that provides accessor to a pool of address regions
*/
typedef Native_region * (*Region_pool)(unsigned const);
namespace Kernel
{
addr_t mode_transition_virt_base();
size_t mode_transition_size();
}
/**
* Helper to initialise allocators through include/exclude region lists
*/
static void init_alloc(Range_allocator * const alloc,
Region_pool incl_regions, Region_pool excl_regions,
unsigned const granu_log2 = 0)
{
/* make all include regions available */
Native_region * r = incl_regions(0);
for (unsigned i = 0; r; r = incl_regions(++i)) {
if (granu_log2) {
addr_t const b = trunc(r->base, granu_log2);
addr_t const s = round(r->size, granu_log2);
alloc->add_range(b, s);
}
else alloc->add_range(r->base, r->size);
}
/* preserve all exclude regions */
r = excl_regions(0);
for (unsigned i = 0; r; r = excl_regions(++i)) {
if (granu_log2) {
addr_t const b = trunc(r->base, granu_log2);
addr_t const s = round(r->size, granu_log2);
alloc->remove_range(b, s);
}
else alloc->remove_range(r->base, r->size);
}
}
/**************
** Platform **
**************/
Native_region * Platform::_core_only_ram_regions(unsigned const i)
{
static Native_region _r[] =
{
/* avoid null pointers */
{ 0, 1 },
/* mode transition region */
{ Kernel::mode_transition_virt_base(), Kernel::mode_transition_size() },
/* core image */
{ (addr_t)&_prog_img_beg,
(size_t)((addr_t)&_prog_img_end - (addr_t)&_prog_img_beg) },
/* boot modules */
{ (addr_t)&_boot_modules_begin,
(size_t)((addr_t)&_boot_modules_end - (addr_t)&_boot_modules_begin) }
};
return i < sizeof(_r)/sizeof(_r[0]) ? &_r[i] : 0;
}
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(0xffff0000)
{
/*
* Initialise platform resource allocators.
* Core mem alloc must come first because it is
* used by the other allocators.
*/
enum { VERBOSE = 0 };
unsigned const psl2 = get_page_size_log2();
init_alloc(&_core_mem_alloc, _ram_regions, _core_only_ram_regions, psl2);
init_alloc(&_irq_alloc, _irq_regions, _core_only_irq_regions);
init_alloc(&_io_mem_alloc, _mmio_regions, _core_only_mmio_regions, psl2);
/* add boot modules to ROM FS */
Bm_header * header = &_boot_module_headers_begin;
for (; header < &_boot_module_headers_end; header++) {
Rom_module * rom_module = new (core_mem_alloc())
Rom_module(header->base, header->size, (const char*)header->name);
_rom_fs.insert(rom_module);
}
/* print ressource summary */
if (VERBOSE) {
printf("Core memory allocator\n");
printf("---------------------\n");
_core_mem_alloc.raw()->dump_addr_tree();
printf("\n");
printf("IO memory allocator\n");
printf("-------------------\n");
_io_mem_alloc.raw()->dump_addr_tree();
printf("\n");
printf("ROM filesystem\n");
printf("--------------\n");
_rom_fs.print_fs();
printf("\n");
}
}
/*****************
** Core_parent **
*****************/
void Core_parent::exit(int exit_value)
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
}

View File

@ -0,0 +1,28 @@
/*
* \brief Protection-domain facility
* \author Martin Stein
* \date 2012-02-12
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <platform_pd.h>
using namespace Genode;
/*****************
** Platform PD **
*****************/
void Platform_pd::unbind_thread(Platform_thread *thread) { assert(0); }
Platform_pd::~Platform_pd() { assert(0); }

View File

@ -0,0 +1,145 @@
/*
* \brief Thread facility
* \author Martin Stein
* \date 2012-02-12
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <platform_thread.h>
#include <core_env.h>
#include <rm_session_component.h>
using namespace Genode;
namespace Kernel { unsigned core_id(); }
Platform_thread::Platform_thread(const char * name,
Thread_base * const thread_base,
unsigned long const stack_size,
unsigned long const pd_id)
:
_thread_base(thread_base), _stack_size(stack_size),
_pd_id(pd_id), _rm_client(0), _virt_utcb(0)
{
strncpy(_name, name, NAME_MAX_LEN);
/* create UTCB for a core thread */
Range_allocator * const ram = platform()->ram_alloc();
assert(ram->alloc_aligned(sizeof(Native_utcb), (void **)&_phys_utcb,
MIN_MAPPING_SIZE_LOG2));
_virt_utcb = _phys_utcb;
/* common constructor parts */
_init();
}
Platform_thread::Platform_thread(const char * name, unsigned int priority,
addr_t utcb)
:
_thread_base(0), _stack_size(0), _pd_id(0), _rm_client(0),
_virt_utcb((Native_utcb *)utcb)
{
strncpy(_name, name, NAME_MAX_LEN);
/*
* Allocate UTCB backing store for a thread outside of core. Page alignment
* is done by RAM session by default. It's save to use core env because
* this cannot be its server activation thread.
*/
try {
Ram_session_component * const ram =
dynamic_cast<Ram_session_component *>(core_env()->ram_session());
assert(ram);
_utcb = ram->alloc(sizeof(Native_utcb), 1);
_phys_utcb = (Native_utcb *)ram->phys_addr(_utcb);
}
catch (...) { assert(0); }
/* common constructor parts */
_init();
}
int Platform_thread::join_pd(unsigned long const pd_id,
bool const main_thread)
{
/* check if we're already in another PD */
if (_pd_id && _pd_id != pd_id) return -1;
/* denote configuration for start method */
_pd_id = pd_id;
_main_thread = main_thread;
return 0;
}
void Platform_thread::_init()
{
/* create kernel object */
void * kernel_thread;
Range_allocator * ram = platform()->ram_alloc();
assert(ram->alloc(Kernel::thread_size(), &kernel_thread));
_id = Kernel::new_thread(kernel_thread, this);
assert(_id);
}
int Platform_thread::start(void * ip, void * sp, unsigned int cpu_no)
{
/* check thread attributes */
assert(_pd_id);
/*
* If this is a main thread outside of core it'll not manage its
* virtual context area by itself, as it is done for other threads
* through a sub RM-session. Therefore we attach the UTCB to its
* address space before it gets started.
*/
if (_pd_id != Kernel::core_id() && _main_thread)
{
/*
* Declare page aligned virtual UTCB outside the context area.
* Kernel afterwards offers this as bootstrap argument to the thread.
*/
_virt_utcb = (Native_utcb *)((platform()->vm_start()
+ platform()->vm_size() - sizeof(Native_utcb))
& ~((1<<MIN_MAPPING_SIZE_LOG2)-1));
/* attach UTCB */
assert(_rm_client);
Rm_session_component * const rm = _rm_client->member_rm_session();
try { rm->attach(_utcb, 0, 0, true, _virt_utcb, 0); }
catch (...) { assert(0); }
}
/* let thread participate in CPU scheduling */
_software_tlb = Kernel::start_thread(this, ip, sp, cpu_no);
return _software_tlb ? 0 : -1;
}
void Platform_thread::pager(Pager_object * const pager)
{
/* announce pager thread to kernel */
Kernel::set_pager(pager->cap().dst(), _id);
/* get RM client from pager pointer */
_rm_client = dynamic_cast<Rm_client *>(pager);
assert(_rm_client);
}
Genode::Pager_object * Platform_thread::pager() const
{
assert(_rm_client)
return static_cast<Pager_object *>(_rm_client);
}

View File

@ -0,0 +1,31 @@
/*
* \brief Export RAM dataspace as shared memory object (dummy)
* \author Martin Stein
* \date 2012-02-12
*/
/*
* Copyright (C) 2012 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;
void Ram_session_component::_export_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds) { }
void Ram_session_component::_clear_ds (Dataspace_component * ds)
{ memset((void *)ds->phys_addr(), 0, ds->size()); }

View File

@ -0,0 +1,85 @@
/*
* \brief RM- and pager implementations specific for base-hw and core
* \author Martin Stein
* \date 2012-02-12
*/
/*
* Copyright (C) 2012 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>
/* core includes */
#include <rm_session_component.h>
#include <platform.h>
#include <platform_thread.h>
#include <assert.h>
#include <software_tlb.h>
using namespace Genode;
/***************
** Rm_client **
***************/
void Rm_client::unmap(addr_t core_local_base, addr_t virt_base, size_t size)
{
/* get software TLB of the thread that we serve */
Platform_thread * const pt = Kernel::get_thread(badge());
assert(pt);
Software_tlb * const tlb = pt->software_tlb();
assert(tlb);
/* update all translation caches */
tlb->remove_region(virt_base, size);
Kernel::update_pd(pt->pd_id());
/* try to regain administrative memory that has been freed by unmap */
size_t s;
void * base;
while (tlb->regain_memory(base, s)) platform()->ram_alloc()->free(base, s);
}
/***************
** Ipc_pager **
***************/
void Ipc_pager::resolve_and_wait_for_fault()
{
/* valid mapping? */
assert(_mapping.valid());
/* do we need extra space to resolve pagefault? */
Software_tlb * const tlb = _pagefault.software_tlb;
enum Mapping_attributes { X = 1, K = 0, G = 0 };
unsigned sl2 = tlb->insert_translation(_mapping.virt_address,
_mapping.phys_address, _mapping.size_log2,
_mapping.writable, X, K, G);
if (sl2)
{
/* try to get some natural aligned space */
void * space;
assert(platform()->ram_alloc()->alloc_aligned(1<<sl2, &space, sl2));
/* try to translate again with extra space */
sl2 = tlb->insert_translation(_mapping.virt_address,
_mapping.phys_address,
_mapping.size_log2,
_mapping.writable, X, K, G, space);
assert(!sl2);
}
/* try to wake up faulter */
assert(!Kernel::resume_thread(_pagefault.thread_id));
/* wait for next page fault */
wait_for_fault();
}

View File

@ -0,0 +1,79 @@
/*
* \brief Implementation of the SIGNAL service on the HW-core
* \author Martin Stein
* \date 2012-05-05
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <kernel/syscalls.h>
/* core includes */
#include <signal_session_component.h>
using namespace Genode;
enum {
RECEIVER_SLAB_CHUNK_SIZE = 32,
CONTEXT_SLAB_CHUNK_SIZE = 32,
};
Signal_session_component::Signal_session_component(Allocator * const md,
size_t const ram_quota) :
_md_alloc(md, ram_quota),
_receivers_slab(Kernel::signal_receiver_size(),
RECEIVER_SLAB_CHUNK_SIZE * Kernel::signal_receiver_size(),
0, &_md_alloc),
_contexts_slab(Kernel::signal_context_size(),
CONTEXT_SLAB_CHUNK_SIZE * Kernel::signal_context_size(),
0, &_md_alloc)
{ }
Signal_session_component::~Signal_session_component()
{
PERR("%s: Not implemented", __PRETTY_FUNCTION__);
while (1) ;
}
Signal_receiver_capability Signal_session_component::alloc_receiver()
{
/* create receiver kernel-object */
size_t const s = Kernel::signal_receiver_size();
void * p;
if (!_receivers_slab.alloc(s, &p)) throw Out_of_metadata();
unsigned long const id = Kernel::new_signal_receiver(p);
if (!id) throw Out_of_metadata();
/* return reference to the new kernel-object */
Native_capability c(id, 0);
return reinterpret_cap_cast<Signal_receiver>(c);
}
Signal_context_capability
Signal_session_component::alloc_context(Signal_receiver_capability r,
unsigned long imprint)
{
/* create context kernel-object */
size_t const s = Kernel::signal_context_size();
void * p;
if (!_contexts_slab.alloc(s, &p)) throw Out_of_metadata();
unsigned long const id = Kernel::new_signal_context(p, r.dst(), imprint);
if (!id) throw Out_of_metadata();
/* return reference to the new kernel-object */
Native_capability c(id, 0);
return reinterpret_cap_cast<Signal_context>(c);
}

View File

@ -0,0 +1,49 @@
#
# \brief The core of Genode
# \author Martin Stein
# \date 2011-12-16
#
# set program name
TARGET = core
# use core specific startup library
STARTUP_LIB = startup_core
# add library dependencies
LIBS += cxx raw_ipc heap process pager lock console signal raw_server \
syscall startup_core core_support
# add include paths
GEN_CORE_DIR = $(BASE_DIR)/src/core
INC_DIR += $(REP_DIR)/src/core/include $(REP_DIR)/include \
$(REP_DIR)/src/platform $(GEN_CORE_DIR)/include \
$(BASE_DIR)/src/platform $(BASE_DIR)/src/core/include \
$(BASE_DIR)/include
# add C++ sources
SRC_CC += main.cc _main.cc ram_session_component.cc \
ram_session_support.cc rom_session_component.cc \
pd_session_component.cc io_mem_session_component.cc \
io_mem_session_support.cc thread.cc platform_pd.cc platform.cc \
platform_thread.cc dataspace_component.cc rm_session_component.cc \
io_port_session_component.cc \
irq_session_component.cc signal_session_component.cc \
dump_alloc.cc cpu_session_component.cc \
cpu_session_support.cc console.cc
# declare file locations
vpath _main.cc $(BASE_DIR)/src/platform
vpath main.cc $(GEN_CORE_DIR)
vpath ram_session_component.cc $(GEN_CORE_DIR)
vpath rom_session_component.cc $(GEN_CORE_DIR)
vpath cpu_session_component.cc $(GEN_CORE_DIR)
vpath pd_session_component.cc $(GEN_CORE_DIR)
vpath rm_session_component.cc $(GEN_CORE_DIR)
vpath io_mem_session_component.cc $(GEN_CORE_DIR)
vpath io_mem_session_support.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath console.cc $(REP_DIR)/src/base
vpath % $(REP_DIR)/src/core

View File

@ -0,0 +1,92 @@
/*
* \brief Implementation of Thread API interface for core
* \author Martin Stein
* \date 2012-01-25
*/
/*
* Copyright (C) 2012 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/env.h>
#include <kernel/log.h>
/* core includes */
#include <platform.h>
#include <platform_thread.h>
using namespace Genode;
extern Genode::Native_utcb * _main_utcb;
namespace Kernel { unsigned core_id(); }
Native_utcb * Thread_base::utcb()
{
/* this is the main thread */
if (!this) { return _main_utcb; }
/* this isn't the main thread */
return _tid->phys_utcb();
}
/**
* Returns 0 if this is the main thread or the thread base pointer otherwise
*/
Thread_base * Thread_base::myself()
{
/* get our platform thread wich holds our thread base or 0 */
Platform_thread * const pt = Kernel::get_thread();
if (pt) return pt->thread_base();
/* we are core main, the only thread beside idle with no platform thread */
else return 0;
}
static void thread_entry()
{
/* this is never called by a main thread */
Thread_base::myself()->entry();
}
Thread_base::Thread_base(const char *name, size_t stack_size)
: _list_element(this), _tid(0)
{
_tid = new (platform()->core_mem_alloc())
Platform_thread(name, this, stack_size, Kernel::core_id());
}
Thread_base::~Thread_base()
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
}
void Thread_base::start()
{
size_t const stack_size = _tid->stack_size()/sizeof(unsigned long) + 1;
void * const stack_base = new (platform()->core_mem_alloc())
unsigned long [stack_size];
void * sp = (void *)((addr_t)stack_base + _tid->stack_size());
void * ip = (void *)&thread_entry;
if (_tid->start(ip, sp)) PERR("Couldn't start thread");
}
void Thread_base::cancel_blocking()
{
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
while (1) ;
}

View File

@ -0,0 +1,21 @@
/*
* \brief Kernel support specific for the Versatile VEA9X4
* \author Martin Stein
* \date 2012-04-23
*/
/*
* Copyright (C) 2012 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__VEA9X4__KERNEL_SUPPORT_H_
#define _SRC__CORE__VEA9X4__KERNEL_SUPPORT_H_
/* local includes */
#include <cortex_a9/kernel_support.h>
#endif /* _SRC__CORE__VEA9X4__KERNEL_SUPPORT_H_ */

View File

@ -0,0 +1,83 @@
/*
* \brief Platform implementations specific for base-hw and VEA9X4
* \author Martin Stein
* \date 2012-04-27
*/
/*
* Copyright (C) 2012 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 <drivers/board/vea9x4.h>
#include <drivers/cpu/cortex_a9/core.h>
#include <drivers/pic/pl390_base.h>
/* Core includes */
#include <platform.h>
using namespace Genode;
Native_region * Platform::_ram_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ Vea9x4::LOCAL_DDR2_BASE, Vea9x4::LOCAL_DDR2_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Pl390_base::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* Core timer */
{ Cortex_a9::PRIVATE_TIMER_IRQ, 1 },
/* Core UART */
{ Vea9x4::PL011_0_IRQ, 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ Vea9x4::SMB_CS7_BASE, Vea9x4::SMB_CS7_SIZE },
{ Vea9x4::SMB_CS0_TO_CS6_BASE, Vea9x4::SMB_CS0_TO_CS6_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_mmio_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* Core timer and PIC */
{ Vea9x4::CORTEX_A9_PRIVATE_MEM_BASE,
Vea9x4::CORTEX_A9_PRIVATE_MEM_SIZE },
/* Core UART */
{ Vea9x4::PL011_0_MMIO_BASE, Vea9x4::PL011_0_MMIO_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}

View File

@ -0,0 +1,26 @@
/*
* \brief Software TLB controls specific for the Versatile VEA9X4
* \author Martin Stein
* \date 2012-04-23
*/
/*
* Copyright (C) 2012 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__VEA9X4__SOFTWARE_TLB_H_
#define _SRC__CORE__VEA9X4__SOFTWARE_TLB_H_
/* Genode includes */
#include <drivers/cpu/cortex_a9/section_table.h>
/**
* Software TLB controls
*/
class Software_tlb : public Genode::Section_table { };
#endif /* _SRC__CORE__VEA9X4__SOFTWARE_TLB_H_ */

View File

@ -0,0 +1,20 @@
/*
* \brief Platform-specific helper functions for the _main() function
* \author Martin Stein
* \date 2010-09-13
*/
/*
* Copyright (C) 2010-2012 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__PLATFORM__MAIN_HELPER_H_
#define _SRC__PLATFORM__MAIN_HELPER_H_
static void main_thread_bootstrap() { }
#endif /* _SRC__PLATFORM__MAIN_HELPER_H_ */

View File

@ -0,0 +1,61 @@
/**
* \brief Startup code for Genode programs on Cortex A9
* \author Martin Stein
* \date 2011-10-01
*/
/*
* Copyright (C) 2012 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.
*/
.section .text
/* ELF entry symbol */
.global _start
_start:
/* zero-fill BSS segment but don't pollute thread-entry arguments */
.extern _bss_start
ldr r4, =_bss_start
.extern _bss_end
ldr r3, =_bss_end
mov r2, #0
sub r3, r3, #4
1:
str r2, [r4]
add r4, r4, #4
cmp r4, r3
bne 1b
/* fetch thread-entry arguments to their destinations in BSS */
ldr r1, =_main_utcb
str r0, [r1]
/* call _main routine */
ldr sp, =_main_stack_high
.extern _main
bl _main
1:
b 1b
/* dynamic symbol object handle */
.align 3
.global __dso_handle
__dso_handle: .long 0
.section .bss
/* main-thread stack */
.align 3
.space 64*1024
.global _main_stack_high
_main_stack_high:
/* main-thread UTCB-pointer for the Genode thread-API */
.align 3
.global _main_utcb
_main_utcb: .long 0

View File

@ -0,0 +1,123 @@
/*
* \brief Linker script for Genode programs
* \author Christian Helmuth
* \date 2006-04-12
*/
/*
* Copyright (C) 2006-2012 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.
*/
ENTRY(_start)
PHDRS
{
ro PT_LOAD;
rw PT_LOAD;
}
SECTIONS
{
.text : {
_prog_img_beg = .;
*(.init)
*(.text .text.* .gnu.linkonce.t.*)
*(.fini)
*(.rodata .rodata.* .gnu.linkonce.r.*)
. = ALIGN(0x08);
_ctors_start = .;
KEEP (*(.ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.init_array)) /* list of constructors specific for ARM eabi */
_ctors_end = .;
_dtors_start = .;
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
_dtors_end = .;
} : ro = 0x90909090
/* Linux: exception section for uaccess mechanism */
__ex_table : { *(__ex_table) }
.eh_frame_hdr : { *(.eh_frame_hdr) }
. = ALIGN(0x1000);
_prog_img_data = .;
.data : {
/*
* Leave space for parent capability parameters at start of data
* section. The protection domain creator is reponsible for storing
* sane values here.
*/
_parent_cap = .;
_parent_cap_thread_id = .;
LONG(0xffffffff);
_parent_cap_local_name = .;
LONG(0xffffffff);
/*
* Platform-specific entry for Fiasco.OC.
*
* PIC-code compiled for Fiasco.OC, needs some PIC-compatible
* way to enter the kernel, the fixed address of the kernel
* entry code address needs to be found here.
*/
__l4sys_invoke_indirect = .;
LONG(0xeacff000);
*(.data .data.* .gnu.linkonce.d.*)
} : rw
/* exception frames for C++ */
.eh_frame : {
__eh_frame_start__ = .;
KEEP (*(.eh_frame))
LONG(0)
} : rw
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
}
.gcc_except_table : {
KEEP(*(.gcc_except_table))
KEEP(*(.gcc_except_table.*))
}
.dynamic : { *(.dynamic) }
/* .ARM.exidx is sorted, so has to go in its own output section */
__exidx_start = .;
.ARM.exidx : {
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
}
__exidx_end = .;
.ARM.extab : {
*(.ARM.extab*)
} : rw
.bss : {
_bss_start = .;
*(.bss .bss.* .gnu.linkonce.b.* COMMON)
}
_bss_end = .;
_prog_img_end = .;
/DISCARD/ : {
*(.note)
*(.note.ABI-tag)
*(.comment)
}
}

View File

@ -23,9 +23,11 @@ namespace Genode
{
enum
{
/* buses */
/* interconnect domains */
L4_PER_BASE = 0x48000000,
L4_PER_SIZE = 0x01000000,
L4_CFG_BASE = 0x4a000000,
L4_CFG_SIZE = 0x01000000,
/* clocks */
MPU_DPLL_CLOCK = 200*1000*1000,