diff --git a/base-hw/include/arm/base/syscall_support.h b/base-hw/include/arm/base/syscall_support.h
index 237501f1f..3430e66f0 100644
--- a/base-hw/include/arm/base/syscall_support.h
+++ b/base-hw/include/arm/base/syscall_support.h
@@ -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_ */
diff --git a/base-hw/include/base/ipc_pager.h b/base-hw/include/base/ipc_pager.h
deleted file mode 100644
index 729daf4cb..000000000
--- a/base-hw/include/base/ipc_pager.h
+++ /dev/null
@@ -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
-#include
-#include
-#include
-
-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_ */
-
diff --git a/base-hw/include/base/native_types.h b/base-hw/include/base/native_types.h
index cb90c646c..3b4efd521 100644
--- a/base-hw/include/base/native_types.h
+++ b/base-hw/include/base/native_types.h
@@ -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
@@ -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_ */
diff --git a/base-hw/include/base/pager.h b/base-hw/include/base/pager.h
new file mode 100644
index 000000000..7393b94b2
--- /dev/null
+++ b/base-hw/include/base/pager.h
@@ -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
+#include
+#include
+#include
+
+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 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::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
+{
+ 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
+class Genode::Pager_activation : public Pager_activation_base
+{
+ public:
+
+ /**
+ * Constructor
+ */
+ Pager_activation()
+ :
+ Pager_activation_base("pager_activation", STACK_SIZE)
+ {
+ start();
+ }
+};
+
+#endif /* _BASE__PAGER_H_ */
diff --git a/base-hw/include/kernel/syscalls.h b/base-hw/include/kernel/syscalls.h
index b3185001a..c9ecd0f58 100644
--- a/base-hw/include/kernel/syscalls.h
+++ b/base-hw/include/kernel/syscalls.h
@@ -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_ */
diff --git a/base-hw/lib/mk/base-common.mk b/base-hw/lib/mk/base-common.mk
index 024e40059..3acdbc877 100644
--- a/base-hw/lib/mk/base-common.mk
+++ b/base-hw/lib/mk/base-common.mk
@@ -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
diff --git a/base-hw/src/base/arm/syscall.cc b/base-hw/src/base/arm/syscall.cc
index bdbdef237..e67978f3b 100644
--- a/base-hw/src/base/arm/syscall.cc
+++ b/base-hw/src/base/arm/syscall.cc
@@ -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; }
diff --git a/base-hw/src/base/pager.cc b/base-hw/src/base/pager.cc
index d907c8167..a8a8c24e7 100644
--- a/base-hw/src/base/pager.cc
+++ b/base-hw/src/base/pager.cc
@@ -15,47 +15,108 @@
#include
#include
+/* base-hw includes */
+#include
+
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::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::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(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; }
- }
- }
-}
diff --git a/base-hw/src/base/signal/signal.cc b/base-hw/src/base/signal/signal.cc
index 86b599fd1..438c5f6da 100644
--- a/base-hw/src/base/signal/signal.cc
+++ b/base-hw/src/base/signal/signal.cc
@@ -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;
}
diff --git a/base-hw/src/core/arm/cpu_support.cc b/base-hw/src/core/arm/cpu_support.cc
index 895998216..66ac742e0 100644
--- a/base-hw/src/core/arm/cpu_support.cc
+++ b/base-hw/src/core/arm/cpu_support.cc
@@ -13,35 +13,77 @@
/* core includes */
#include
+#include
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");
+}
diff --git a/base-hw/src/core/arm/cpu_support.h b/base-hw/src/core/arm/cpu_support.h
new file mode 100644
index 000000000..13f27e848
--- /dev/null
+++ b/base-hw/src/core/arm/cpu_support.h
@@ -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
+
+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);
+};
diff --git a/base-hw/src/core/arndale/target.mk b/base-hw/src/core/arndale/target.mk
index 6c03e5392..51db8cd1a 100644
--- a/base-hw/src/core/arndale/target.mk
+++ b/base-hw/src/core/arndale/target.mk
@@ -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 \
diff --git a/base-hw/src/core/cpu/arm.h b/base-hw/src/core/cpu/arm.h
index b15d5b078..e3f1bf204 100644
--- a/base-hw/src/core/cpu/arm.h
+++ b/base-hw/src/core/cpu/arm.h
@@ -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) {
diff --git a/base-hw/src/core/imx31/target.mk b/base-hw/src/core/imx31/target.mk
index 5a2997e7a..7a3ac0ae0 100644
--- a/base-hw/src/core/imx31/target.mk
+++ b/base-hw/src/core/imx31/target.mk
@@ -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 \
diff --git a/base-hw/src/core/imx53/target.mk b/base-hw/src/core/imx53/target.mk
index 31f068ebd..8894df656 100644
--- a/base-hw/src/core/imx53/target.mk
+++ b/base-hw/src/core/imx53/target.mk
@@ -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 \
diff --git a/base-hw/src/core/kernel/irq.h b/base-hw/src/core/kernel/irq.h
index b64d22167..ec49f73ac 100644
--- a/base-hw/src/core/kernel/irq.h
+++ b/base-hw/src/core/kernel/irq.h
@@ -44,7 +44,8 @@ class Kernel::Irq
:
public Object_pool::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();
}
diff --git a/base-hw/src/core/kernel/signal_receiver.cc b/base-hw/src/core/kernel/signal_receiver.cc
index 8f5a8f44b..b04010b0e 100644
--- a/base-hw/src/core/kernel/signal_receiver.cc
+++ b/base-hw/src/core/kernel/signal_receiver.cc
@@ -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(); }
}
diff --git a/base-hw/src/core/kernel/signal_receiver.h b/base-hw/src/core/kernel/signal_receiver.h
index b75eec7cf..eb75355e3 100644
--- a/base-hw/src/core/kernel/signal_receiver.h
+++ b/base-hw/src/core/kernel/signal_receiver.h
@@ -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 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);
diff --git a/base-hw/src/core/kernel/thread.h b/base-hw/src/core/kernel/thread.h
index 9ff21b40f..7ec9c7921 100644
--- a/base-hw/src/core/kernel/thread.h
+++ b/base-hw/src/core/kernel/thread.h
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
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;
};
diff --git a/base-hw/src/core/kernel/thread_event.h b/base-hw/src/core/kernel/thread_event.h
new file mode 100644
index 000000000..90d41a0a8
--- /dev/null
+++ b/base-hw/src/core/kernel/thread_event.h
@@ -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);
+};
diff --git a/base-hw/src/core/panda/target.mk b/base-hw/src/core/panda/target.mk
index e68191709..7b637b630 100644
--- a/base-hw/src/core/panda/target.mk
+++ b/base-hw/src/core/panda/target.mk
@@ -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 \
diff --git a/base-hw/src/core/pbxa9/target.mk b/base-hw/src/core/pbxa9/target.mk
index 0b3d953f5..2cbcf5583 100644
--- a/base-hw/src/core/pbxa9/target.mk
+++ b/base-hw/src/core/pbxa9/target.mk
@@ -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 \
diff --git a/base-hw/src/core/platform_thread.cc b/base-hw/src/core/platform_thread.cc
index 155a3db22..123988fb6 100644
--- a/base-hw/src/core/platform_thread.cc
+++ b/base-hw/src/core/platform_thread.cc
@@ -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(object->cap());
+ Pager_capability cap = reinterpret_cap_cast(object->Object_pool::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(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(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;
}
diff --git a/base-hw/src/core/rm_session_support.cc b/base-hw/src/core/rm_session_support.cc
index fbba8515d..4c0baf9ff 100644
--- a/base-hw/src/core/rm_session_support.cc
+++ b/base-hw/src/core/rm_session_support.cc
@@ -12,7 +12,7 @@
*/
/* Genode includes */
-#include
+#include
/* core includes */
#include
@@ -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(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();
+ }
+}
diff --git a/base-hw/src/core/rpi/target.mk b/base-hw/src/core/rpi/target.mk
index c788b6c1f..1d4ea216b 100644
--- a/base-hw/src/core/rpi/target.mk
+++ b/base-hw/src/core/rpi/target.mk
@@ -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 \
diff --git a/base-hw/src/core/tlb/arm.h b/base-hw/src/core/tlb/arm.h
index 011f2298e..2d16f9540 100644
--- a/base-hw/src/core/tlb/arm.h
+++ b/base-hw/src/core/tlb/arm.h
@@ -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); }
diff --git a/base-hw/src/core/vea9x4/target.inc b/base-hw/src/core/vea9x4/target.inc
index 4c9de6f7f..470580131 100644
--- a/base-hw/src/core/vea9x4/target.inc
+++ b/base-hw/src/core/vea9x4/target.inc
@@ -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 \