hw: communicate page faults via signals

Enable routing of thread events to signal contexts via
Kernel::route_thread_event.

Replace Kernel::set_pager by Kernel::route_thread_event.

In base-hw a pager object is a signal context and a pager activation
is a signal receiver. If a thread wants to start communicating its page
faults via a pager object, the thread calls Kernel::route_thread_event with
its thread ID, event ID "FAULT", and the signal context ID of the pager object.
If a pager activation wants to start handling page faults of a pager object,
the pager activation assigns the corresponding signal context to its signal
receiver. If a pager activation wants to stop handling page faults of a pager
object, the pager activation dissolves the corresponding signal context from
its signal receiver. If a thread wants to start communicating its page faults
via a pager object, the thread calls Kernel::route_thread_event with its
thread ID, event ID "FAULT", and the invalid signal context ID.

Remove Kernel::resume_faulter.

Move all page fault related code from generic kernel sources to CPU
specific cpu_support.h and cpu_support.cc.

fix #935
This commit is contained in:
Martin Stein 2013-11-14 13:29:47 +01:00 committed by Norman Feske
parent ba52529bd6
commit 909ab8dcd0
27 changed files with 981 additions and 559 deletions

View File

@ -23,17 +23,43 @@ namespace Kernel
typedef Genode::uint32_t Syscall_ret;
/**
* Thread registers that can be accessed via Access_thread_regs
* Registers that are provided by a kernel thread-object for user access
*/
struct Access_thread_regs_id
struct Thread_reg_id
{
enum {
R0, R1, R2, R3, R4,
R5, R6, R7, R8, R9,
R10, R11, R12, SP, LR,
IP, CPSR, CPU_EXCEPTION
R0 = 0,
R1 = 1,
R2 = 2,
R3 = 3,
R4 = 4,
R5 = 5,
R6 = 6,
R7 = 7,
R8 = 8,
R9 = 9,
R10 = 10,
R11 = 11,
R12 = 12,
SP = 13,
LR = 14,
IP = 15,
CPSR = 16,
CPU_EXCEPTION = 17,
FAULT_TLB = 18,
FAULT_ADDR = 19,
FAULT_WRITES = 20,
FAULT_SIGNAL = 21,
};
};
/**
* Events that are provided by a kernel thread-object for user handling
*/
struct Thread_event_id
{
enum { FAULT = 0 };
};
}
#endif /* _INCLUDE__ARM__BASE__SYSCALL_H_ */

View File

@ -1,185 +0,0 @@
/*
* \brief IPC backend for a Genode pager
* \author Martin Stein
* \date 2012-03-28
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _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;
bool io_mem;
unsigned size_log2;
bool writable;
/**
* Construct valid mapping
*/
Mapping(addr_t const va, addr_t const pa, bool const wc,
bool io, unsigned const sl2 = MIN_MAPPING_SIZE_LOG2,
bool const w = 1)
:
virt_address(va), phys_address(pa), write_combined(wc),
io_mem(io), 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;
};
/**
* Paging-server backend
*/
class Ipc_pager : public Native_capability
{
private:
Pagefault_msg _pagefault_msg;
Mapping _mapping;
/**
* Backend for wait_for_fault and wait_for_first_fault
*/
void _wait_for_fault();
/**
* Get global name of pager thread
*/
static unsigned _thread_id()
{
return Genode::thread_get_my_native_id();
}
public:
/**
* Constructor
*/
Ipc_pager() : Native_capability(_thread_id(), 0) { }
/**
* Wait for the first pagefault request
*/
void wait_for_first_fault();
/**
* Wait for the next pagefault request
*/
void wait_for_fault();
/**
* Resolve current pagefault and wait for a new one
*
* \retval 0 succeeded
* \retval !=0 failed
*/
int resolve_and_wait_for_fault();
/**
* Request instruction pointer of current page fault
*/
addr_t fault_ip() { return _pagefault_msg.virt_ip; }
/**
* Request fault address of current page fault
*/
addr_t fault_addr() { return _pagefault_msg.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_msg.thread_id; }
/**
* Return badge for faulting thread
*/
unsigned badge() const { return _pagefault_msg.thread_id; }
/**
* Return true if last fault was a write fault
*/
bool is_write_fault() const { return _pagefault_msg.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

@ -11,8 +11,8 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__BASE__NATIVE_TYPES_H_
#define _INCLUDE__BASE__NATIVE_TYPES_H_
#ifndef _BASE__NATIVE_TYPES_H_
#define _BASE__NATIVE_TYPES_H_
/* Genode includes */
#include <kernel/syscalls.h>
@ -61,7 +61,6 @@ namespace Genode
enum Id {
INVALID = 0,
IPC = 1,
PAGEFAULT = 2,
};
};
@ -69,33 +68,6 @@ namespace Genode
uint8_t data[];
};
/**
* Message that reports a pagefault
*/
struct Pagefault_msg : Msg
{
unsigned thread_id;
Tlb * tlb;
addr_t virt_ip;
addr_t virt_address;
bool write;
static void init(void * const p, unsigned const tid, Tlb * const tlb,
addr_t const vip, addr_t const va, bool const w)
{
Pagefault_msg * msg = (Pagefault_msg *)p;
msg->Msg::type = Msg::Type::PAGEFAULT;
msg->thread_id = tid;
msg->tlb = tlb;
msg->virt_ip = vip;
msg->virt_address = va;
msg->write = w;
}
void * base() { return this; }
size_t size() { return sizeof(Pagefault_msg); }
};
/**
* Message that is communicated between user threads
*/
@ -114,7 +86,6 @@ namespace Genode
uint8_t data[1 << MIN_MAPPING_SIZE_LOG2];
Msg msg;
Ipc_msg ipc_msg;
Pagefault_msg pagefault_msg;
};
void syscall_wait_for_request(void * & buf_base, size_t & buf_size)
@ -199,5 +170,5 @@ namespace Genode
struct Native_pd_args { };
}
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */
#endif /* _BASE__NATIVE_TYPES_H_ */

View File

@ -0,0 +1,303 @@
/*
* \brief Paging framework
* \author Martin Stein
* \date 2013-11-07
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _BASE__PAGER_H_
#define _BASE__PAGER_H_
/* Genode includes */
#include <base/thread.h>
#include <base/object_pool.h>
#include <base/signal.h>
#include <pager/capability.h>
namespace Genode
{
class Cap_session;
/**
* Translation of a virtual page frame
*/
struct Mapping;
/**
* Interface between the generic paging system and the base-hw backend
*/
class Ipc_pager;
/**
* Represents a faulter and its paging context
*/
class Pager_object;
/**
* Paging entry point that manages a pool of pager objects
*/
class Pager_entrypoint;
/**
* A thread that processes one page fault of a pager object at a time
*/
class Pager_activation_base;
/**
* Pager-activation base with custom stack size
*/
template <unsigned STACK_SIZE> class Pager_activation;
}
struct Genode::Mapping
{
addr_t virt_address;
addr_t phys_address;
bool write_combined;
bool io_mem;
unsigned size_log2;
bool writable;
/**
* Constructor for invalid mappings
*/
Mapping();
/**
* Constructor for valid mappings
*/
Mapping(addr_t const va, addr_t const pa, bool const wc,
bool const io, unsigned const sl2, bool const w);
/**
* Prepare for the application of the mapping
*/
void prepare_map_operation();
};
class Genode::Ipc_pager
{
protected:
/**
* Page-fault data that is read from the faulters thread registers
*/
struct Fault_thread_regs
{
addr_t tlb;
addr_t ip;
addr_t addr;
addr_t writes;
addr_t signal;
};
Fault_thread_regs _fault;
Mapping _mapping;
public:
/**
* Instruction pointer of current page fault
*/
addr_t fault_ip() const;
/**
* Faulter-local fault address of current page fault
*/
addr_t fault_addr() const;
/**
* Access direction of current page fault
*/
bool is_write_fault() const;
/**
* Input mapping data as reply to current page fault
*/
void set_reply_mapping(Mapping m);
};
class Genode::Pager_object : public Object_pool<Pager_object>::Entry,
public Signal_context
{
friend class Pager_entrypoint;
private:
Signal_context_capability _signal_context_cap;
Thread_capability _thread_cap;
char _signal_buf[sizeof(Signal)];
unsigned const _thread_id;
/***************
** Accessors **
***************/
Signal * _signal() const;
public:
/**
* Constructor
*
* \param thread_id kernel name of faulter thread
*/
Pager_object(unsigned const thread_id, Affinity::Location);
/**
* Destructor
*/
virtual ~Pager_object() { }
/**
* The faulter has caused a fault and awaits paging
*
* \param s signal that communicated the fault
*/
void fault_occured(Signal const & s);
/**
* Current fault has been resolved so resume faulter
*/
void fault_resolved();
/**
* User identification of pager object
*/
unsigned badge() const;
/**
* Resume faulter
*/
void wake_up();
/**
* Unnecessary as base-hw doesn't use exception handlers
*/
void exception_handler(Signal_context_capability);
/******************
** Pure virtual **
******************/
/**
* Request a mapping that resolves a fault directly
*
* \param p offers the fault data and receives mapping data
*
* \retval 0 succeeded
* \retval !=0 fault can't be received directly
*/
virtual int pager(Ipc_pager & p) = 0;
/***************
** Accessors **
***************/
Thread_capability thread_cap() const;
void thread_cap(Thread_capability const & c);
void cap(Native_capability const & c);
unsigned signal_context_id() const;
};
class Genode::Pager_activation_base : public Thread_base,
public Signal_receiver,
public Ipc_pager
{
private:
Native_capability _cap;
Lock _cap_valid;
Pager_entrypoint * _ep;
public:
/**
* Constructor
*
* \param name name of the new thread
* \param stack_size stack size of the new thread
*/
Pager_activation_base(char const * const name,
size_t const stack_size);
/**
* Bring current mapping data into effect
*
* \retval 0 succeeded
* \retval -1 failed
*/
int apply_mapping();
/**********************
** Thread interface **
**********************/
void entry();
/***************
** Accessors **
***************/
Native_capability cap();
void ep(Pager_entrypoint * const ep);
};
class Genode::Pager_entrypoint : public Object_pool<Pager_object>
{
private:
Pager_activation_base * const _activation;
public:
/**
* Constructor
*
* \param a activation that shall handle the objects of the entrypoint
*/
Pager_entrypoint(Cap_session *, Pager_activation_base * const a);
/**
* Associate pager object 'obj' with entry point
*/
Pager_capability manage(Pager_object * const obj);
/**
* Dissolve pager object 'obj' from entry point
*/
void dissolve(Pager_object * const obj);
};
template <unsigned STACK_SIZE>
class Genode::Pager_activation : public Pager_activation_base
{
public:
/**
* Constructor
*/
Pager_activation()
:
Pager_activation_base("pager_activation", STACK_SIZE)
{
start();
}
};
#endif /* _BASE__PAGER_H_ */

View File

@ -33,55 +33,44 @@ namespace Kernel
typedef Genode::Platform_pd Platform_pd;
/**
* Unique opcodes of all syscalls supported by the kernel
* Kernel names of all kernel calls
*/
enum Syscall_type
struct Call_id
{
INVALID_SYSCALL = 0,
/* execution control */
NEW_THREAD = 1,
DELETE_THREAD = 26,
START_THREAD = 2,
PAUSE_THREAD = 3,
RESUME_THREAD = 4,
RESUME_FAULTER = 28,
GET_THREAD = 5,
CURRENT_THREAD_ID = 6,
YIELD_THREAD = 7,
ACCESS_THREAD_REGS = 37,
/* interprocess communication */
REQUEST_AND_WAIT = 8,
REPLY = 9,
WAIT_FOR_REQUEST = 10,
/* management of protection domains */
SET_PAGER = 11,
UPDATE_PD = 12,
UPDATE_REGION = 32,
NEW_PD = 13,
KILL_PD = 34,
/* debugging */
PRINT_CHAR = 17,
/* asynchronous signalling */
NEW_SIGNAL_RECEIVER = 20,
KILL_SIGNAL_RECEIVER = 33,
NEW_SIGNAL_CONTEXT = 21,
KILL_SIGNAL_CONTEXT = 30,
AWAIT_SIGNAL = 22,
SUBMIT_SIGNAL = 23,
SIGNAL_PENDING = 27,
ACK_SIGNAL = 29,
/* vm specific */
NEW_VM = 24,
RUN_VM = 25,
PAUSE_VM = 31,
enum {
NEW_THREAD = 0,
DELETE_THREAD = 1,
START_THREAD = 2,
PAUSE_THREAD = 3,
RESUME_THREAD = 4,
GET_THREAD = 5,
CURRENT_THREAD_ID = 6,
YIELD_THREAD = 7,
ACCESS_THREAD_REGS = 8,
ROUTE_THREAD_EVENT = 9,
UPDATE_PD = 10,
UPDATE_REGION = 11,
NEW_PD = 12,
KILL_PD = 13,
REQUEST_AND_WAIT = 14,
REPLY = 15,
WAIT_FOR_REQUEST = 16,
NEW_SIGNAL_RECEIVER = 17,
NEW_SIGNAL_CONTEXT = 18,
KILL_SIGNAL_CONTEXT = 19,
KILL_SIGNAL_RECEIVER = 20,
SUBMIT_SIGNAL = 21,
AWAIT_SIGNAL = 22,
SIGNAL_PENDING = 23,
ACK_SIGNAL = 24,
NEW_VM = 25,
RUN_VM = 26,
PAUSE_VM = 27,
PRINT_CHAR = 28,
};
};
/*****************************************************************
** Syscall with 1 to 6 arguments **
** **
@ -152,9 +141,10 @@ namespace Kernel
*/
inline unsigned new_pd(void * const dst, Platform_pd * const pd)
{
return syscall(NEW_PD, (Syscall_arg)dst, (Syscall_arg)pd);
return syscall(Call_id::NEW_PD, (Syscall_arg)dst, (Syscall_arg)pd);
}
/**
* Destruct a protection domain
*
@ -165,9 +155,10 @@ namespace Kernel
*/
inline int kill_pd(unsigned const pd)
{
return syscall(KILL_PD, pd);
return syscall(Call_id::KILL_PD, pd);
}
/**
* Propagate changes in PD configuration
*
@ -183,8 +174,11 @@ namespace Kernel
*
* Restricted to core threads.
*/
inline void update_pd(unsigned const pd_id) {
syscall(UPDATE_PD, (Syscall_arg)pd_id); }
inline void update_pd(unsigned const pd_id)
{
syscall(Call_id::UPDATE_PD, (Syscall_arg)pd_id);
}
/**
* Propagate memory-updates within a given virtual region
@ -198,8 +192,11 @@ namespace Kernel
*
* Restricted to core threads.
*/
inline void update_region(addr_t base, size_t size) {
syscall(UPDATE_REGION, (Syscall_arg)base, (Syscall_arg)size); }
inline void update_region(addr_t base, size_t size)
{
syscall(Call_id::UPDATE_REGION, (Syscall_arg)base, (Syscall_arg)size);
}
/**
* Create a new thread that is stopped initially
@ -214,9 +211,11 @@ namespace Kernel
* Restricted to core threads. Regaining of the supplied memory can be done
* through 'delete_thread'.
*/
inline int
new_thread(void * const dst, Platform_thread * const pt) {
return syscall(NEW_THREAD, (Syscall_arg)dst, (Syscall_arg)pt); }
inline int new_thread(void * const dst, Platform_thread * const pt)
{
return syscall(Call_id::NEW_THREAD, (Syscall_arg)dst, (Syscall_arg)pt);
}
/**
* Delete an existing thread
@ -227,8 +226,11 @@ namespace Kernel
* granted beforehand by 'new_thread' to kernel for managing this thread
* is freed again.
*/
inline void delete_thread(unsigned thread_id) {
syscall(DELETE_THREAD, (Syscall_arg)thread_id); }
inline void delete_thread(unsigned thread_id)
{
syscall(Call_id::DELETE_THREAD, (Syscall_arg)thread_id);
}
/**
* Start thread with a given context and let it participate in CPU scheduling
@ -246,9 +248,8 @@ namespace Kernel
inline Tlb * start_thread(Platform_thread * const phys_pt, void * ip,
void * sp, unsigned cpu_no)
{
return (Tlb *)syscall(START_THREAD, (Syscall_arg)phys_pt,
(Syscall_arg)ip, (Syscall_arg)sp,
(Syscall_arg)cpu_no);
return (Tlb *)syscall(Call_id::START_THREAD, (Syscall_arg)phys_pt,
(Syscall_arg)ip, (Syscall_arg)sp, cpu_no);
}
@ -264,8 +265,10 @@ namespace Kernel
*
* If the caller doesn't target itself, this is restricted to core threads.
*/
inline int pause_thread(unsigned const id = 0) {
return syscall(PAUSE_THREAD, id); }
inline int pause_thread(unsigned const id = 0)
{
return syscall(Call_id::PAUSE_THREAD, id);
}
/**
@ -281,17 +284,10 @@ namespace Kernel
* If the targeted thread blocks for any event except a 'start_thread'
* call this call cancels the blocking.
*/
inline int resume_thread(unsigned const id = 0) {
return syscall(RESUME_THREAD, id); }
/**
* Continue thread after a pagefault that could be resolved
*
* \param id ID of the targeted thread
*/
inline void resume_faulter(unsigned const id = 0) {
syscall(RESUME_FAULTER, id); }
inline int resume_thread(unsigned const id = 0)
{
return syscall(Call_id::RESUME_THREAD, id);
}
/**
@ -300,14 +296,19 @@ namespace Kernel
* \param id if this thread ID is set and valid this will resume the
* targeted thread additionally
*/
inline void yield_thread(unsigned const id = 0) {
syscall(YIELD_THREAD, id); }
inline void yield_thread(unsigned const id = 0)
{
syscall(Call_id::YIELD_THREAD, id);
}
/**
* Get the thread ID of the current thread
*/
inline int current_thread_id() { return syscall(CURRENT_THREAD_ID); }
inline int current_thread_id()
{
return syscall(Call_id::CURRENT_THREAD_ID);
}
/**
@ -322,7 +323,25 @@ namespace Kernel
*/
inline Platform_thread * get_thread(unsigned const id)
{
return (Platform_thread *)syscall(GET_THREAD, id);
return (Platform_thread *)syscall(Call_id::GET_THREAD, id);
}
/**
* Set or unset the handler of an event a kernel thread-object triggers
*
* \param thread_id kernel name of the targeted thread
* \param event_id kernel name of the targeted thread event
* \param signal_context_id kernel name of the handlers signal context
*
* Restricted to core threads.
*/
inline int route_thread_event(unsigned const thread_id,
unsigned const event_id,
unsigned const signal_context_id)
{
return syscall(Call_id::ROUTE_THREAD_EVENT, thread_id,
event_id, signal_context_id);
}
@ -335,7 +354,7 @@ namespace Kernel
*/
inline void request_and_wait(unsigned const id)
{
syscall(REQUEST_AND_WAIT, id);
syscall(Call_id::REQUEST_AND_WAIT, id);
}
@ -348,7 +367,7 @@ namespace Kernel
*/
inline void wait_for_request()
{
syscall(WAIT_FOR_REQUEST);
syscall(Call_id::WAIT_FOR_REQUEST);
}
@ -362,21 +381,7 @@ namespace Kernel
*/
inline void reply(bool const await_message)
{
syscall(REPLY, await_message);
}
/**
* Set or unset an IPC destination for pagefaults reports of a thread
*
* \param pager_id kernel name of the pager thread or 0 for "unset"
* \param faulter_id kernel name of the thread that throws the pagefaults
*
* Restricted to core threads.
*/
inline void set_pager(unsigned const pager_id, unsigned const faulter_id)
{
syscall(SET_PAGER, pager_id, faulter_id);
syscall(Call_id::REPLY, await_message);
}
@ -384,7 +389,9 @@ namespace Kernel
* Print a char 'c' to the kernels serial ouput
*/
inline void print_char(char const c)
{ syscall(PRINT_CHAR, (Syscall_arg)c); }
{
syscall(Call_id::PRINT_CHAR, (Syscall_arg)c);
}
/**
@ -426,15 +433,15 @@ namespace Kernel
addr_t * const read_values,
addr_t * const write_values)
{
return syscall(ACCESS_THREAD_REGS, thread_id, reads, writes,
return syscall(Call_id::ACCESS_THREAD_REGS, thread_id, reads, writes,
(Syscall_arg)read_values, (Syscall_arg)write_values);
}
/**
* Create a kernel object that acts as receiver for asynchronous signals
* Create a kernel object that acts as a signal receiver
*
* \param p appropriate memory donation for the kernel object
* \param p memory donation for the kernel signal-receiver object
*
* \retval >0 kernel name of the new signal receiver
* \retval 0 failed
@ -443,16 +450,16 @@ namespace Kernel
*/
inline unsigned new_signal_receiver(addr_t const p)
{
return syscall(NEW_SIGNAL_RECEIVER, p);
return syscall(Call_id::NEW_SIGNAL_RECEIVER, p);
}
/**
* Create a kernel object that acts as a signal context at a receiver
* Create kernel object that acts as a signal context and assign it
*
* \param p appropriate memory donation for the kernel object
* \param p memory donation for the kernel signal-context object
* \param receiver kernel name of targeted signal receiver
* \param imprint userland name of the new signal context
* \param imprint user label of the signal context
*
* \retval >0 kernel name of the new signal context
* \retval 0 failed
@ -463,7 +470,7 @@ namespace Kernel
unsigned const receiver,
unsigned const imprint)
{
return syscall(NEW_SIGNAL_CONTEXT, p, receiver, imprint);
return syscall(Call_id::NEW_SIGNAL_CONTEXT, p, receiver, imprint);
}
@ -490,7 +497,7 @@ namespace Kernel
inline int await_signal(unsigned const receiver_id,
unsigned const context_id)
{
return syscall(AWAIT_SIGNAL, receiver_id, context_id);
return syscall(Call_id::AWAIT_SIGNAL, receiver_id, context_id);
}
@ -504,7 +511,7 @@ namespace Kernel
*/
inline bool signal_pending(unsigned const receiver)
{
return syscall(SIGNAL_PENDING, receiver);
return syscall(Call_id::SIGNAL_PENDING, receiver);
}
@ -519,9 +526,10 @@ namespace Kernel
*/
inline int submit_signal(unsigned const context, unsigned const num)
{
return syscall(SUBMIT_SIGNAL, context, num);
return syscall(Call_id::SUBMIT_SIGNAL, context, num);
}
/**
* Acknowledge the processing of the last delivery of a signal context
*
@ -529,9 +537,10 @@ namespace Kernel
*/
inline void ack_signal(unsigned const context)
{
syscall(ACK_SIGNAL, context);
syscall(Call_id::ACK_SIGNAL, context);
}
/**
* Destruct a signal context
*
@ -544,9 +553,10 @@ namespace Kernel
*/
inline int kill_signal_context(unsigned const context)
{
return syscall(KILL_SIGNAL_CONTEXT, context);
return syscall(Call_id::KILL_SIGNAL_CONTEXT, context);
}
/**
* Destruct a signal receiver
*
@ -559,9 +569,10 @@ namespace Kernel
*/
inline int kill_signal_receiver(unsigned const receiver)
{
return syscall(KILL_SIGNAL_RECEIVER, receiver);
return syscall(Call_id::KILL_SIGNAL_RECEIVER, receiver);
}
/**
* Create a new virtual-machine that is stopped initially
*
@ -579,7 +590,7 @@ namespace Kernel
inline int new_vm(void * const dst, void * const state,
unsigned context_id)
{
return syscall(NEW_VM, (Syscall_arg)dst, (Syscall_arg)state,
return syscall(Call_id::NEW_VM, (Syscall_arg)dst, (Syscall_arg)state,
(Syscall_arg)context_id);
}
@ -591,8 +602,10 @@ namespace Kernel
*
* Restricted to core threads.
*/
inline void run_vm(unsigned const id) {
syscall(RUN_VM, (Syscall_arg)id); }
inline void run_vm(unsigned const id)
{
syscall(Call_id::RUN_VM, (Syscall_arg)id);
}
/**
@ -602,8 +615,10 @@ namespace Kernel
*
* Restricted to core threads.
*/
inline void pause_vm(unsigned const id) {
syscall(PAUSE_VM, (Syscall_arg)id); }
inline void pause_vm(unsigned const id)
{
syscall(Call_id::PAUSE_VM, (Syscall_arg)id);
}
}
#endif /* _INCLUDE__KERNEL__SYSCALLS_H_ */

View File

@ -20,7 +20,6 @@ SRC_CC += lock/lock.cc
SRC_CC += signal/signal.cc signal/common.cc
SRC_CC += server/server.cc server/common.cc
SRC_CC += thread/thread_bootstrap.cc thread/trace.cc
SRC_CC += pager/common.cc
INC_DIR += $(REP_DIR)/src/base/lock
INC_DIR += $(BASE_DIR)/src/base/lock

View File

@ -166,12 +166,13 @@ Syscall_ret Kernel::syscall(Syscall_arg arg_0,
** CPU-state utilities **
*************************/
typedef Access_thread_regs_id Id;
typedef Thread_reg_id Reg_id;
static addr_t const _cpu_state_regs[] = {
Id::R0, Id::R1, Id::R2, Id::R3, Id::R4, Id::R5, Id::R6, Id::R7,
Id::R8, Id::R9, Id::R10, Id::R11, Id::R12, Id::SP, Id::LR, Id::IP,
Id::CPSR, Id::CPU_EXCEPTION };
Reg_id::R0, Reg_id::R1, Reg_id::R2, Reg_id::R3, Reg_id::R4,
Reg_id::R5, Reg_id::R6, Reg_id::R7, Reg_id::R8, Reg_id::R9,
Reg_id::R10, Reg_id::R11, Reg_id::R12, Reg_id::SP, Reg_id::LR,
Reg_id::IP, Reg_id::CPSR, Reg_id::CPU_EXCEPTION };
addr_t const * cpu_state_regs() { return _cpu_state_regs; }

View File

@ -15,47 +15,108 @@
#include <base/pager.h>
#include <base/printf.h>
/* base-hw includes */
#include <placement_new.h>
using namespace Genode;
/*************
** Mapping **
*************/
Mapping::Mapping(addr_t const va, addr_t const pa, bool const wc,
bool const io, unsigned const sl2, bool const w)
:
virt_address(va), phys_address(pa), write_combined(wc),
io_mem(io), size_log2(sl2), writable(w)
{ }
Mapping::Mapping()
:
virt_address(0), phys_address(0), write_combined(0),
io_mem(0), size_log2(0), writable(0)
{ }
void Mapping::prepare_map_operation() { }
/***************
** Ipc_pager **
***************/
addr_t Ipc_pager::fault_ip() const { return _fault.ip; }
addr_t Ipc_pager::fault_addr() const { return _fault.addr; }
bool Ipc_pager::is_write_fault() const { return _fault.writes; }
void Ipc_pager::set_reply_mapping(Mapping m) { _mapping = m; }
/******************
** Pager_object **
******************/
Thread_capability Pager_object::thread_cap() const { return _thread_cap; }
void Pager_object::thread_cap(Thread_capability const & c) { _thread_cap = c; }
Signal * Pager_object::_signal() const { return (Signal *)_signal_buf; }
void Pager_object::wake_up() { fault_resolved(); }
void Pager_object::exception_handler(Signal_context_capability) { }
void Pager_object::fault_resolved() { _signal()->~Signal(); }
unsigned Pager_object::badge() const { return _thread_id; }
void Pager_object::fault_occured(Signal const & s)
{
new (_signal()) Signal(s);
}
void Pager_object::cap(Native_capability const & c)
{
Object_pool<Pager_object>::Entry::cap(c);
}
Pager_object::Pager_object(unsigned const thread_id, Affinity::Location)
:
_thread_id(thread_id)
{ }
unsigned Pager_object::signal_context_id() const
{
return _signal_context_cap.dst();
}
/***************************
** Pager_activation_base **
***************************/
void Pager_activation_base::entry()
void Pager_activation_base::ep(Pager_entrypoint * const ep) { _ep = ep; }
Pager_activation_base::Pager_activation_base(char const * const name,
size_t const stack_size)
:
Thread_base(name, stack_size), _cap_valid(Lock::LOCKED), _ep(0)
{ }
Native_capability Pager_activation_base::cap()
{
/* acknowledge that we're ready to work */
Ipc_pager pager;
_cap = pager;
_cap_valid.unlock();
/* receive and handle faults */
bool mapping_pending = 0;
pager.wait_for_first_fault();
while (1)
{
/* protect bottom half of loop against pager-object guard */
{
/* lookup pager object for current faulter */
Object_pool<Pager_object>::Guard
o(_ep ? _ep->lookup_and_lock(pager.badge()) : 0);
if (!o) {
PERR("invalid pager object");
mapping_pending = 0;
} else {
/* try to find an appropriate mapping */
mapping_pending = !o->pager(pager);
}
}
if (mapping_pending) {
/* apply mapping and await next fault */
if (pager.resolve_and_wait_for_fault()) {
PERR("failed to resolve page fault");
pager.wait_for_fault();
}
} else { pager.wait_for_fault(); }
}
if (!_cap.valid()) { _cap_valid.lock(); }
return _cap;
}
@ -63,84 +124,25 @@ void Pager_activation_base::entry()
** 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_locked(o); }
Pager_entrypoint::Pager_entrypoint(Cap_session *,
Pager_activation_base * const activation)
:
_activation(activation)
{
_activation->ep(this);
}
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->_signal_context_cap = _activation->Signal_receiver::manage(o);
unsigned const dst = _activation->cap().dst();
Native_capability c = Native_capability(dst, o->badge());
o->cap(c);
insert(o);
/* return pager-object cap */
return reinterpret_cap_cast<Pager_object>(c);
}
/***************
** Ipc_pager **
***************/
void Ipc_pager::wait_for_first_fault()
{
Kernel::wait_for_request();
_wait_for_fault();
}
void Ipc_pager::wait_for_fault()
{
Native_utcb * const utcb = Thread_base::myself()->utcb();
utcb->ipc_msg.size = 0;
Kernel::reply(1);
_wait_for_fault();
}
void Ipc_pager::_wait_for_fault()
{
Native_utcb * const utcb = Thread_base::myself()->utcb();
while (1)
{
switch (utcb->msg.type) {
case Msg::Type::PAGEFAULT: {
/* receive pagefault report */
_pagefault_msg = utcb->pagefault_msg;
return; }
case Msg::Type::IPC: {
/* receive release request from region manager */
Native_utcb * const utcb = Thread_base::myself()->utcb();
void * const msg_base = utcb->ipc_msg.data;
Pagefault_resolved * const msg = (Pagefault_resolved *)msg_base;
/* resume faulter */
Kernel::resume_thread(msg->pager_object->badge());
utcb->ipc_msg.size = 0;
/* send ack to region manager and get next message */
Kernel::reply(1);
continue; }
default: {
PERR("unknown message type");
continue; }
}
}
}

View File

@ -125,12 +125,12 @@ void Signal_receiver::_unsynchronized_dissolve(Signal_context * const c)
Signal_context_capability Signal_receiver::manage(Signal_context * const c)
{
/* check if the context is already managed */
/* ensure that the context isn't managed already */
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 */
/* create a context kernel-object at the receiver kernel-object */
bool session_upgraded = 0;
Signal_connection * const s = signal_connection();
while (1) {
@ -146,7 +146,7 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
PERR("failed to alloc signal context");
return Signal_context_capability();
}
PINF("upgrading quota donation for SIGNAL session");
PINF("upgrading quota donation for signal session");
env()->parent()->upgrade(s->cap(), "ram_quota=4K");
session_upgraded = 1;
}

View File

@ -13,35 +13,77 @@
/* core includes */
#include <kernel/thread.h>
#include <kernel/pd.h>
using namespace Kernel;
/********************************
** Kernel::Thread_cpu_support **
********************************/
Thread_cpu_support::Thread_cpu_support(Thread * const t)
:
_fault(t),
_fault_tlb(0),
_fault_addr(0),
_fault_writes(0),
_fault_signal(0)
{ }
/********************
** Kernel::Thread **
********************/
addr_t * Kernel::Thread::_reg(addr_t const id) const
addr_t Thread::* Thread::_reg(addr_t const id) const
{
static addr_t * const _regs[] = {
(addr_t *)&r0,
(addr_t *)&r1,
(addr_t *)&r2,
(addr_t *)&r3,
(addr_t *)&r4,
(addr_t *)&r5,
(addr_t *)&r6,
(addr_t *)&r7,
(addr_t *)&r8,
(addr_t *)&r9,
(addr_t *)&r10,
(addr_t *)&r11,
(addr_t *)&r12,
(addr_t *)&sp,
(addr_t *)&lr,
(addr_t *)&ip,
(addr_t *)&cpsr,
(addr_t *)&cpu_exception
static addr_t Thread::* const _regs[] = {
/* [0] */ (addr_t Thread::*)&Thread::r0,
/* [1] */ (addr_t Thread::*)&Thread::r1,
/* [2] */ (addr_t Thread::*)&Thread::r2,
/* [3] */ (addr_t Thread::*)&Thread::r3,
/* [4] */ (addr_t Thread::*)&Thread::r4,
/* [5] */ (addr_t Thread::*)&Thread::r5,
/* [6] */ (addr_t Thread::*)&Thread::r6,
/* [7] */ (addr_t Thread::*)&Thread::r7,
/* [8] */ (addr_t Thread::*)&Thread::r8,
/* [9] */ (addr_t Thread::*)&Thread::r9,
/* [10] */ (addr_t Thread::*)&Thread::r10,
/* [11] */ (addr_t Thread::*)&Thread::r11,
/* [12] */ (addr_t Thread::*)&Thread::r12,
/* [13] */ (addr_t Thread::*)&Thread::sp,
/* [14] */ (addr_t Thread::*)&Thread::lr,
/* [15] */ (addr_t Thread::*)&Thread::ip,
/* [16] */ (addr_t Thread::*)&Thread::cpsr,
/* [17] */ (addr_t Thread::*)&Thread::cpu_exception,
/* [18] */ (addr_t Thread::*)&Thread::_fault_tlb,
/* [19] */ (addr_t Thread::*)&Thread::_fault_addr,
/* [20] */ (addr_t Thread::*)&Thread::_fault_writes,
/* [21] */ (addr_t Thread::*)&Thread::_fault_signal
};
return id < sizeof(_regs)/sizeof(_regs[0]) ? _regs[id] : 0;
}
Thread_event Thread::* Thread::_event(unsigned const id) const
{
static Thread_event Thread::* _events[] = {
/* [0] */ &Thread::_fault
};
return id < sizeof(_events)/sizeof(_events[0]) ? _events[id] : 0;
}
void Thread::_mmu_exception()
{
cpu_scheduler()->remove(this);
_state = AWAITS_RESUME;
if (in_fault(_fault_addr, _fault_writes)) {
_fault_tlb = (addr_t)_pd->tlb();
_fault_signal = _fault.signal_context_id();
_fault.submit();
return;
}
PERR("unknown MMU exception");
}

View File

@ -0,0 +1,41 @@
/*
* \brief CPU specific support for base-hw
* \author Martin Stein
* \date 2013-11-13
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/thread_event.h>
namespace Kernel
{
/**
* CPU specific parts of a kernel thread-object
*/
class Thread_cpu_support;
}
class Kernel::Thread_cpu_support
{
protected:
Thread_event _fault;
addr_t _fault_tlb;
addr_t _fault_addr;
addr_t _fault_writes;
addr_t _fault_signal;
/**
* Constructor
*
* \param t generic part of kernel thread-object
*/
Thread_cpu_support(Thread * const t);
};

View File

@ -10,6 +10,7 @@ REQUIRES += platform_arndale
# add include paths
INC_DIR += $(REP_DIR)/src/core/arndale
INC_DIR += $(REP_DIR)/src/core/arm
# add C++ sources
SRC_CC += platform_services.cc \

View File

@ -573,12 +573,12 @@ namespace Arm
}
/**
* Return if the context is in a pagefault due to a translation miss
* Return if the context is in a page fault due to a translation miss
*
* \param va holds the virtual fault-address if call returns 1
* \param w holds wether it's a write fault if call returns 1
*/
bool pagefault(addr_t & va, bool & w) const
bool in_fault(addr_t & va, addr_t & w) const
{
/* determine fault type */
switch (cpu_exception) {

View File

@ -9,6 +9,7 @@ REQUIRES = platform_imx31
# add include paths
INC_DIR += $(REP_DIR)/src/core/imx31
INC_DIR += $(REP_DIR)/src/core/arm
# add C++ sources
SRC_CC += platform_services.cc \

View File

@ -10,6 +10,7 @@ REQUIRES = platform_imx53
# add include paths
INC_DIR += $(REP_DIR)/src/core/imx53
INC_DIR += $(REP_DIR)/src/core/arm
# add C++ sources
SRC_CC += platform_services.cc \

View File

@ -44,7 +44,8 @@ class Kernel::Irq
:
public Object_pool<Irq>::Item,
public Signal_receiver,
public Signal_context
public Signal_context,
public Signal_ack_handler
{
friend class Genode::Irq;
@ -120,11 +121,11 @@ class Kernel::Irq
~Irq() { PERR("method not implemented"); }
/********************
** Signal_context **
********************/
/************************
** Signal_ack_handler **
************************/
void _signal_context_acknowledged() { _enable(); }
void _signal_acknowledged() { _enable(); }
public:
@ -138,6 +139,7 @@ class Kernel::Irq
Pool::Item(irq_id),
Signal_context(this, 0)
{
Signal_context::ack_handler(this);
_pool()->insert(this);
_disable();
}

View File

@ -17,28 +17,53 @@
using namespace Kernel;
/************************
** Signal_ack_handler **
************************/
Signal_ack_handler::~Signal_ack_handler()
{
if (_signal_context) { _signal_context->ack_handler(0); }
}
/********************
** Signal_handler **
********************/
void Signal_handler::_cancel_waiting()
{
if (_receiver) { _receiver->_handler_cancelled(this); }
}
/***************************
** Signal_context_killer **
***************************/
void Signal_context_killer::_cancel_waiting()
{
if (_context) { _context->_killer_cancelled(); }
}
/****************************
** Signal_receiver_killer **
****************************/
void Signal_receiver_killer::_cancel_waiting()
{
if (_receiver) { _receiver->_killer_cancelled(); }
}
/********************
** Signal_context **
********************/
void Signal_context::_deliverable()
{
if (!_submits) return;
_receiver->_add_deliverable(this);
if (_submits) { _receiver->_add_deliverable(this); }
}
@ -48,7 +73,8 @@ Signal_context::~Signal_context() { _receiver->_context_killed(this); }
Signal_context::Signal_context(Signal_receiver * const r, unsigned const imprint)
:
_deliver_fe(this), _contexts_fe(this), _receiver(r),
_imprint(imprint), _submits(0), _ack(1), _kill(0), _killer(0)
_imprint(imprint), _submits(0), _ack(1), _kill(0), _killer(0),
_ack_handler(&_default_ack_handler)
{
if (r->_add_context(this)) { throw Assign_to_receiver_failed(); }
}

View File

@ -25,10 +25,15 @@
namespace Kernel
{
/**
* Ability to receive from signal receivers
* Ability to receive signals from signal receivers
*/
class Signal_handler;
/**
* Ability to get informed about signal acks
*/
class Signal_ack_handler;
/**
* Ability to destruct signal contexts
*/
@ -60,6 +65,30 @@ namespace Kernel
Signal_receiver_pool * signal_receiver_pool();
}
class Kernel::Signal_ack_handler
{
friend class Signal_context;
Signal_context * _signal_context;
protected:
/**
* Provide custom handler for acks at a signal context
*/
virtual void _signal_acknowledged() = 0;
/**
* Constructor
*/
Signal_ack_handler() : _signal_context(0) { }
/**
* Destructor
*/
virtual ~Signal_ack_handler();
};
class Kernel::Signal_handler
{
friend class Signal_receiver;
@ -203,6 +232,20 @@ class Kernel::Signal_context
typedef Genode::Fifo_element<Signal_context> Fifo_element;
/**
* Dummy handler that is used every time no other handler is available
*/
class Default_ack_handler : public Signal_ack_handler
{
private:
/************************
** Signal_ack_handler **
************************/
void _signal_acknowledged() { }
};
Fifo_element _deliver_fe;
Fifo_element _contexts_fe;
Signal_receiver * const _receiver;
@ -211,6 +254,8 @@ class Kernel::Signal_context
bool _ack;
bool _kill;
Signal_context_killer * _killer;
Default_ack_handler _default_ack_handler;
Signal_ack_handler * _ack_handler;
/**
* Tell receiver about the submits of the context if any
@ -231,11 +276,6 @@ class Kernel::Signal_context
*/
void _killer_cancelled() { _killer = 0; }
/**
* Hook to install in-kernel handler for acks at specific signal types
*/
virtual void _signal_context_acknowledged() { };
protected:
/**
@ -260,6 +300,17 @@ class Kernel::Signal_context
*/
Signal_context(Signal_receiver * const r, unsigned const imprint);
/**
* Attach or detach a handler for acknowledgments at this context
*
* \param h handler that shall be attached or 0 to detach handler
*/
void ack_handler(Signal_ack_handler * const h)
{
_ack_handler = h ? h : &_default_ack_handler;
_ack_handler->_signal_context = this;
}
/**
* Submit the signal
*
@ -281,7 +332,7 @@ class Kernel::Signal_context
*/
void ack()
{
_signal_context_acknowledged();
_ack_handler->_signal_acknowledged();
if (_ack) { return; }
if (!_kill) {
_ack = 1;
@ -454,7 +505,7 @@ class Kernel::Signal_receiver
*/
int add_handler(Signal_handler * const h)
{
if (_kill) { return -1; }
if (_kill || h->_receiver) { return -1; }
_handlers.enqueue(&h->_handlers_fe);
h->_receiver = this;
h->_await_signal(this);

View File

@ -19,6 +19,7 @@
#include <kernel/scheduler.h>
#include <kernel/signal_receiver.h>
#include <kernel/ipc_node.h>
#include <cpu_support.h>
#include <cpu.h>
namespace Genode
@ -32,7 +33,6 @@ namespace Kernel
class Pd;
typedef Genode::Cpu Cpu;
typedef Genode::Pagefault_msg Pagefault_msg;
typedef Genode::Native_utcb Native_utcb;
void reset_lap_time();
@ -57,8 +57,11 @@ class Kernel::Thread
public Ipc_node,
public Signal_context_killer,
public Signal_receiver_killer,
public Signal_handler
public Signal_handler,
public Thread_cpu_support
{
friend class Thread_event;
private:
enum { START_VERBOSE = 0 };
@ -69,19 +72,15 @@ class Kernel::Thread
AWAITS_START = 2,
AWAITS_IPC = 3,
AWAITS_RESUME = 4,
AWAITS_PAGER = 5,
AWAITS_PAGER_IPC = 6,
AWAITS_SIGNAL = 8,
AWAITS_SIGNAL_CONTEXT_KILL = 9,
AWAITS_SIGNAL_RECEIVER_KILL = 10,
STOPPED = 11,
AWAITS_SIGNAL = 5,
AWAITS_SIGNAL_CONTEXT_KILL = 6,
AWAITS_SIGNAL_RECEIVER_KILL = 7,
STOPPED = 8,
};
Platform_thread * const _platform_thread;
State _state;
Pagefault_msg _pagefault_msg;
Thread * _pager;
unsigned _pd_id;
Pd * _pd;
Native_utcb * _phys_utcb;
Native_utcb * _virt_utcb;
Signal_receiver * _signal_receiver;
@ -92,9 +91,26 @@ class Kernel::Thread
void _receive_yielded_cpu();
/**
* Return kernel backend of protection domain the thread is in
* Attach or detach the handler of a thread-triggered event
*
* \param event_id kernel name of the thread event
* \param signal_context_id kernel name signal context or 0 to detach
*
* \retval 0 succeeded
* \retval -1 failed
*/
Pd * _pd() const;
int _route_event(unsigned const event_id,
unsigned const signal_context_id);
/**
* Map kernel name of thread event to the corresponding member
*
* \param id kernel name of targeted thread event
*
* \retval 0 failed
* \retval >0 targeted member pointer
*/
Thread_event Thread::* _event(unsigned const id) const;
/**
* Return wether this is a core thread
@ -165,43 +181,42 @@ class Kernel::Thread
* \retval 0 failed
* \retval >0 pointer to register content
*/
addr_t * _reg(addr_t const id) const;
addr_t Thread::* _reg(addr_t const id) const;
/***************************************************
** Syscall backends, for details see 'syscall.h' **
***************************************************/
void _syscall_new_pd();
void _syscall_kill_pd();
void _syscall_new_thread();
void _syscall_delete_thread();
void _syscall_start_thread();
void _syscall_pause_thread();
void _syscall_resume_thread();
void _syscall_resume_faulter();
void _syscall_yield_thread();
void _syscall_current_thread_id();
void _syscall_get_thread();
void _syscall_wait_for_request();
void _syscall_request_and_wait();
void _syscall_reply();
void _syscall_set_pager();
void _syscall_update_pd();
void _syscall_update_region();
void _syscall_print_char();
void _syscall_new_signal_receiver();
void _syscall_new_signal_context();
void _syscall_await_signal();
void _syscall_signal_pending();
void _syscall_submit_signal();
void _syscall_ack_signal();
void _syscall_kill_signal_context();
void _syscall_kill_signal_receiver();
void _syscall_new_vm();
void _syscall_run_vm();
void _syscall_pause_vm();
void _syscall_access_thread_regs();
void _call_new_pd();
void _call_kill_pd();
void _call_new_thread();
void _call_delete_thread();
void _call_start_thread();
void _call_pause_thread();
void _call_resume_thread();
void _call_yield_thread();
void _call_current_thread_id();
void _call_get_thread();
void _call_wait_for_request();
void _call_request_and_wait();
void _call_reply();
void _call_update_pd();
void _call_update_region();
void _call_print_char();
void _call_new_signal_receiver();
void _call_new_signal_context();
void _call_await_signal();
void _call_signal_pending();
void _call_submit_signal();
void _call_ack_signal();
void _call_kill_signal_context();
void _call_kill_signal_receiver();
void _call_new_vm();
void _call_run_vm();
void _call_pause_vm();
void _call_access_thread_regs();
void _call_route_thread_event();
/***************************
@ -277,10 +292,9 @@ class Kernel::Thread
***************/
Platform_thread * platform_thread() const { return _platform_thread; }
void pager(Thread * const p) { _pager = p; }
unsigned id() const { return Object::id(); }
char const * label() const;
unsigned pd_id() const { return _pd_id; }
unsigned pd_id() const;
char const * pd_label() const;
};

View File

@ -0,0 +1,63 @@
/*
* \brief Event that is provided by akernel thread-object for user handling
* \author Martin Stein
* \date 2013-11-13
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
namespace Kernel
{
class Thread;
/**
* Event that is provided by kernel thread-objects for user handling
*/
class Thread_event;
}
class Kernel::Thread_event : public Signal_ack_handler
{
private:
Thread * const _thread;
Signal_context * _signal_context;
/************************
** Signal_ack_handler **
************************/
void _signal_acknowledged();
public:
/**
* Constructor
*
* \param t thread that blocks on the event
*/
Thread_event(Thread * const t);
/**
* Submit to listening handlers just like a signal context
*/
void submit();
/**
* Kernel name of assigned signal context or 0 if not assigned
*/
unsigned signal_context_id() const;
/**
* Override signal context of the event
*
* \param c new signal context or 0 to dissolve current signal context
*/
void signal_context(Signal_context * const c);
};

View File

@ -10,6 +10,7 @@ REQUIRES += platform_panda
# add include paths
INC_DIR += $(REP_DIR)/src/core/panda
INC_DIR += $(REP_DIR)/src/core/arm
# add C++ sources
SRC_CC += platform_services.cc \

View File

@ -10,6 +10,7 @@ REQUIRES += platform_pbxa9
# add include paths
INC_DIR += $(REP_DIR)/src/core/pbxa9
INC_DIR += $(REP_DIR)/src/core/arm
# add C++ sources
SRC_CC += platform_services.cc \

View File

@ -65,7 +65,7 @@ Platform_thread::~Platform_thread()
assert(object);
Rm_session_component * const rm = _rm_client->member_rm_session();
assert(rm);
Pager_capability cap = reinterpret_cap_cast<Pager_object>(object->cap());
Pager_capability cap = reinterpret_cap_cast<Pager_object>(object->Object_pool<Pager_object>::Entry::cap());
rm->remove_client(cap);
}
/* destroy object at the kernel */
@ -197,13 +197,25 @@ int Platform_thread::start(void * ip, void * sp, unsigned int cpu_no)
void Platform_thread::pager(Pager_object * const pager)
{
typedef Kernel::Thread_event_id Event_id;
if (pager) {
Kernel::set_pager(pager->cap().dst(), _id);
_rm_client = dynamic_cast<Rm_client *>(pager);
unsigned const sc_id = pager->signal_context_id();
if (sc_id) {
if (!Kernel::route_thread_event(id(), Event_id::FAULT, sc_id)) {
_rm_client = dynamic_cast<Rm_client *>(pager);
return;
}
}
PERR("failed to attach signal context to fault");
return;
} else {
if (!Kernel::route_thread_event(id(), Event_id::FAULT, 0)) {
_rm_client = 0;
return;
}
PERR("failed to detach signal context from fault");
return;
}
Kernel::set_pager(0, _id);
_rm_client = 0;
return;
}

View File

@ -12,7 +12,7 @@
*/
/* Genode includes */
#include <base/ipc_pager.h>
#include <base/pager.h>
/* core includes */
#include <rm_session_component.h>
@ -48,23 +48,18 @@ void Rm_client::unmap(addr_t, addr_t virt_base, size_t size)
}
/***************
** Ipc_pager **
***************/
/***************************
** Pager_activation_base **
***************************/
int Ipc_pager::resolve_and_wait_for_fault()
int Pager_activation_base::apply_mapping()
{
/* check mapping */
if (!_mapping.valid()) {
PERR("invalid mapping");
return -1;
}
/* prepare mapping */
Tlb * const tlb = _pagefault_msg.tlb;
Tlb * const tlb = (Tlb *)_fault.tlb;
Page_flags::access_t const flags =
Page_flags::resolve_and_wait_for_fault(_mapping.writable,
_mapping.write_combined,
_mapping.io_mem);
Page_flags::apply_mapping(_mapping.writable,
_mapping.write_combined,
_mapping.io_mem);
/* insert mapping into TLB */
unsigned sl2;
@ -90,11 +85,48 @@ int Ipc_pager::resolve_and_wait_for_fault()
return -1;
}
}
/* wake up faulter */
Kernel::resume_faulter(_pagefault_msg.thread_id);
/* wait for next page fault */
wait_for_fault();
return 0;
}
void Pager_activation_base::entry()
{
/* get ready to receive faults */
_cap = Native_capability(thread_get_my_native_id(), 0);
_cap_valid.unlock();
while (1)
{
/* await fault */
Pager_object * o;
while (1) {
Signal s = Signal_receiver::wait_for_signal();
o = dynamic_cast<Pager_object *>(s.context());
if (o) {
o->fault_occured(s);
break;
}
PERR("unknown pager object");
}
/* fetch fault data */
unsigned const thread_id = o->badge();
typedef Kernel::Thread_reg_id Reg_id;
static addr_t const read_regs[] = {
Reg_id::FAULT_TLB, Reg_id::IP, Reg_id::FAULT_ADDR,
Reg_id::FAULT_WRITES, Reg_id::FAULT_SIGNAL };
enum { READS = sizeof(read_regs)/sizeof(read_regs[0]) };
void * const utcb = Thread_base::myself()->utcb()->base();
memcpy(utcb, read_regs, sizeof(read_regs));
addr_t * const read_values = (addr_t *)&_fault;
if (Kernel::access_thread_regs(thread_id, READS, 0, read_values, 0)) {
PERR("failed to read page-fault data");
continue;
}
/* handle fault */
if (o->pager(*this)) { continue; }
if (apply_mapping()) {
PERR("failed to apply mapping");
continue;
}
o->fault_resolved();
}
}

View File

@ -9,6 +9,7 @@ REQUIRES = platform_rpi
# add include paths
INC_DIR += $(REP_DIR)/src/core/rpi
INC_DIR += $(REP_DIR)/src/core/arm
# add C++ sources
SRC_CC += platform_services.cc \

View File

@ -41,9 +41,9 @@ namespace Arm
* Create flag POD for Genode pagers
*/
static access_t
resolve_and_wait_for_fault(bool const writeable,
bool const write_combined,
bool const io_mem) {
apply_mapping(bool const writeable,
bool const write_combined,
bool const io_mem) {
return W::bits(writeable) | X::bits(1) | K::bits(0) | G::bits(0) |
D::bits(io_mem) | C::bits(!write_combined & !io_mem); }

View File

@ -7,6 +7,7 @@
# add include paths
INC_DIR += $(REP_DIR)/src/core/vea9x4
INC_DIR += $(REP_DIR)/src/core/arm
# add C++ sources
SRC_CC += platform_services.cc \