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 \