mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-19 03:06:39 +00:00
hw: communicate page faults via signals
Enable routing of thread events to signal contexts via Kernel::route_thread_event. Replace Kernel::set_pager by Kernel::route_thread_event. In base-hw a pager object is a signal context and a pager activation is a signal receiver. If a thread wants to start communicating its page faults via a pager object, the thread calls Kernel::route_thread_event with its thread ID, event ID "FAULT", and the signal context ID of the pager object. If a pager activation wants to start handling page faults of a pager object, the pager activation assigns the corresponding signal context to its signal receiver. If a pager activation wants to stop handling page faults of a pager object, the pager activation dissolves the corresponding signal context from its signal receiver. If a thread wants to start communicating its page faults via a pager object, the thread calls Kernel::route_thread_event with its thread ID, event ID "FAULT", and the invalid signal context ID. Remove Kernel::resume_faulter. Move all page fault related code from generic kernel sources to CPU specific cpu_support.h and cpu_support.cc. fix #935
This commit is contained in:
parent
ba52529bd6
commit
909ab8dcd0
@ -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_ */
|
||||
|
@ -1,185 +0,0 @@
|
||||
/*
|
||||
* \brief IPC backend for a Genode pager
|
||||
* \author Martin Stein
|
||||
* \date 2012-03-28
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__BASE__IPC_PAGER_H_
|
||||
#define _INCLUDE__BASE__IPC_PAGER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/thread.h>
|
||||
#include <base/ipc.h>
|
||||
#include <base/native_types.h>
|
||||
#include <kernel/log.h>
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
class Pager_object;
|
||||
|
||||
/**
|
||||
* Translation of a virtual page frame
|
||||
*/
|
||||
struct Mapping
|
||||
{
|
||||
addr_t virt_address;
|
||||
addr_t phys_address;
|
||||
bool write_combined;
|
||||
bool io_mem;
|
||||
unsigned size_log2;
|
||||
bool writable;
|
||||
|
||||
/**
|
||||
* Construct valid mapping
|
||||
*/
|
||||
Mapping(addr_t const va, addr_t const pa, bool const wc,
|
||||
bool io, unsigned const sl2 = MIN_MAPPING_SIZE_LOG2,
|
||||
bool const w = 1)
|
||||
:
|
||||
virt_address(va), phys_address(pa), write_combined(wc),
|
||||
io_mem(io), size_log2(sl2), writable(w)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Construct invalid mapping
|
||||
*/
|
||||
Mapping() : size_log2(0) { }
|
||||
|
||||
/**
|
||||
* Dummy, all data is available since construction
|
||||
*/
|
||||
void prepare_map_operation() { }
|
||||
|
||||
/**
|
||||
* Validation
|
||||
*/
|
||||
bool valid() { return size_log2 > 0; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Message format for the acknowledgment of a resolved pagefault
|
||||
*/
|
||||
struct Pagefault_resolved
|
||||
{
|
||||
Native_thread_id const reply_dst;
|
||||
Pager_object * const pager_object;
|
||||
};
|
||||
|
||||
/**
|
||||
* Paging-server backend
|
||||
*/
|
||||
class Ipc_pager : public Native_capability
|
||||
{
|
||||
private:
|
||||
|
||||
Pagefault_msg _pagefault_msg;
|
||||
Mapping _mapping;
|
||||
|
||||
/**
|
||||
* Backend for wait_for_fault and wait_for_first_fault
|
||||
*/
|
||||
void _wait_for_fault();
|
||||
|
||||
/**
|
||||
* Get global name of pager thread
|
||||
*/
|
||||
static unsigned _thread_id()
|
||||
{
|
||||
return Genode::thread_get_my_native_id();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Ipc_pager() : Native_capability(_thread_id(), 0) { }
|
||||
|
||||
/**
|
||||
* Wait for the first pagefault request
|
||||
*/
|
||||
void wait_for_first_fault();
|
||||
|
||||
/**
|
||||
* Wait for the next pagefault request
|
||||
*/
|
||||
void wait_for_fault();
|
||||
|
||||
/**
|
||||
* Resolve current pagefault and wait for a new one
|
||||
*
|
||||
* \retval 0 succeeded
|
||||
* \retval !=0 failed
|
||||
*/
|
||||
int resolve_and_wait_for_fault();
|
||||
|
||||
/**
|
||||
* Request instruction pointer of current page fault
|
||||
*/
|
||||
addr_t fault_ip() { return _pagefault_msg.virt_ip; }
|
||||
|
||||
/**
|
||||
* Request fault address of current page fault
|
||||
*/
|
||||
addr_t fault_addr() { return _pagefault_msg.virt_address; }
|
||||
|
||||
/**
|
||||
* Set parameters for next reply
|
||||
*/
|
||||
void set_reply_mapping(Mapping m) { _mapping = m; }
|
||||
|
||||
/**
|
||||
* Set destination for next reply
|
||||
*/
|
||||
void set_reply_dst(Native_capability pager_object) {
|
||||
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
|
||||
while (1) ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer call without sending a flex-page mapping
|
||||
*
|
||||
* This function is used to acknowledge local calls from one of
|
||||
* core's region-manager sessions.
|
||||
*/
|
||||
void acknowledge_wakeup() {
|
||||
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
|
||||
while (1) ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return thread ID of last faulter
|
||||
*/
|
||||
Native_thread_id last() const { return _pagefault_msg.thread_id; }
|
||||
|
||||
/**
|
||||
* Return badge for faulting thread
|
||||
*/
|
||||
unsigned badge() const { return _pagefault_msg.thread_id; }
|
||||
|
||||
/**
|
||||
* Return true if last fault was a write fault
|
||||
*/
|
||||
bool is_write_fault() const { return _pagefault_msg.write; }
|
||||
|
||||
/**
|
||||
* Return true if last fault was an exception
|
||||
*/
|
||||
bool is_exception() const
|
||||
{
|
||||
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
|
||||
while (1) ;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__BASE__IPC_PAGER_H_ */
|
||||
|
@ -11,8 +11,8 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__BASE__NATIVE_TYPES_H_
|
||||
#define _INCLUDE__BASE__NATIVE_TYPES_H_
|
||||
#ifndef _BASE__NATIVE_TYPES_H_
|
||||
#define _BASE__NATIVE_TYPES_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <kernel/syscalls.h>
|
||||
@ -61,7 +61,6 @@ namespace Genode
|
||||
enum Id {
|
||||
INVALID = 0,
|
||||
IPC = 1,
|
||||
PAGEFAULT = 2,
|
||||
};
|
||||
};
|
||||
|
||||
@ -69,33 +68,6 @@ namespace Genode
|
||||
uint8_t data[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Message that reports a pagefault
|
||||
*/
|
||||
struct Pagefault_msg : Msg
|
||||
{
|
||||
unsigned thread_id;
|
||||
Tlb * tlb;
|
||||
addr_t virt_ip;
|
||||
addr_t virt_address;
|
||||
bool write;
|
||||
|
||||
static void init(void * const p, unsigned const tid, Tlb * const tlb,
|
||||
addr_t const vip, addr_t const va, bool const w)
|
||||
{
|
||||
Pagefault_msg * msg = (Pagefault_msg *)p;
|
||||
msg->Msg::type = Msg::Type::PAGEFAULT;
|
||||
msg->thread_id = tid;
|
||||
msg->tlb = tlb;
|
||||
msg->virt_ip = vip;
|
||||
msg->virt_address = va;
|
||||
msg->write = w;
|
||||
}
|
||||
|
||||
void * base() { return this; }
|
||||
size_t size() { return sizeof(Pagefault_msg); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Message that is communicated between user threads
|
||||
*/
|
||||
@ -114,7 +86,6 @@ namespace Genode
|
||||
uint8_t data[1 << MIN_MAPPING_SIZE_LOG2];
|
||||
Msg msg;
|
||||
Ipc_msg ipc_msg;
|
||||
Pagefault_msg pagefault_msg;
|
||||
};
|
||||
|
||||
void syscall_wait_for_request(void * & buf_base, size_t & buf_size)
|
||||
@ -199,5 +170,5 @@ namespace Genode
|
||||
struct Native_pd_args { };
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__BASE__NATIVE_TYPES_H_ */
|
||||
#endif /* _BASE__NATIVE_TYPES_H_ */
|
||||
|
||||
|
303
base-hw/include/base/pager.h
Normal file
303
base-hw/include/base/pager.h
Normal file
@ -0,0 +1,303 @@
|
||||
/*
|
||||
* \brief Paging framework
|
||||
* \author Martin Stein
|
||||
* \date 2013-11-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _BASE__PAGER_H_
|
||||
#define _BASE__PAGER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/thread.h>
|
||||
#include <base/object_pool.h>
|
||||
#include <base/signal.h>
|
||||
#include <pager/capability.h>
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
class Cap_session;
|
||||
|
||||
/**
|
||||
* Translation of a virtual page frame
|
||||
*/
|
||||
struct Mapping;
|
||||
|
||||
/**
|
||||
* Interface between the generic paging system and the base-hw backend
|
||||
*/
|
||||
class Ipc_pager;
|
||||
|
||||
/**
|
||||
* Represents a faulter and its paging context
|
||||
*/
|
||||
class Pager_object;
|
||||
|
||||
/**
|
||||
* Paging entry point that manages a pool of pager objects
|
||||
*/
|
||||
class Pager_entrypoint;
|
||||
|
||||
/**
|
||||
* A thread that processes one page fault of a pager object at a time
|
||||
*/
|
||||
class Pager_activation_base;
|
||||
|
||||
/**
|
||||
* Pager-activation base with custom stack size
|
||||
*/
|
||||
template <unsigned STACK_SIZE> class Pager_activation;
|
||||
}
|
||||
|
||||
struct Genode::Mapping
|
||||
{
|
||||
addr_t virt_address;
|
||||
addr_t phys_address;
|
||||
bool write_combined;
|
||||
bool io_mem;
|
||||
unsigned size_log2;
|
||||
bool writable;
|
||||
|
||||
/**
|
||||
* Constructor for invalid mappings
|
||||
*/
|
||||
Mapping();
|
||||
|
||||
/**
|
||||
* Constructor for valid mappings
|
||||
*/
|
||||
Mapping(addr_t const va, addr_t const pa, bool const wc,
|
||||
bool const io, unsigned const sl2, bool const w);
|
||||
|
||||
/**
|
||||
* Prepare for the application of the mapping
|
||||
*/
|
||||
void prepare_map_operation();
|
||||
};
|
||||
|
||||
class Genode::Ipc_pager
|
||||
{
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Page-fault data that is read from the faulters thread registers
|
||||
*/
|
||||
struct Fault_thread_regs
|
||||
{
|
||||
addr_t tlb;
|
||||
addr_t ip;
|
||||
addr_t addr;
|
||||
addr_t writes;
|
||||
addr_t signal;
|
||||
};
|
||||
|
||||
Fault_thread_regs _fault;
|
||||
Mapping _mapping;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Instruction pointer of current page fault
|
||||
*/
|
||||
addr_t fault_ip() const;
|
||||
|
||||
/**
|
||||
* Faulter-local fault address of current page fault
|
||||
*/
|
||||
addr_t fault_addr() const;
|
||||
|
||||
/**
|
||||
* Access direction of current page fault
|
||||
*/
|
||||
bool is_write_fault() const;
|
||||
|
||||
/**
|
||||
* Input mapping data as reply to current page fault
|
||||
*/
|
||||
void set_reply_mapping(Mapping m);
|
||||
};
|
||||
|
||||
class Genode::Pager_object : public Object_pool<Pager_object>::Entry,
|
||||
public Signal_context
|
||||
{
|
||||
friend class Pager_entrypoint;
|
||||
|
||||
private:
|
||||
|
||||
Signal_context_capability _signal_context_cap;
|
||||
Thread_capability _thread_cap;
|
||||
char _signal_buf[sizeof(Signal)];
|
||||
unsigned const _thread_id;
|
||||
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
|
||||
Signal * _signal() const;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param thread_id kernel name of faulter thread
|
||||
*/
|
||||
Pager_object(unsigned const thread_id, Affinity::Location);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Pager_object() { }
|
||||
|
||||
/**
|
||||
* The faulter has caused a fault and awaits paging
|
||||
*
|
||||
* \param s signal that communicated the fault
|
||||
*/
|
||||
void fault_occured(Signal const & s);
|
||||
|
||||
/**
|
||||
* Current fault has been resolved so resume faulter
|
||||
*/
|
||||
void fault_resolved();
|
||||
|
||||
/**
|
||||
* User identification of pager object
|
||||
*/
|
||||
unsigned badge() const;
|
||||
|
||||
/**
|
||||
* Resume faulter
|
||||
*/
|
||||
void wake_up();
|
||||
|
||||
/**
|
||||
* Unnecessary as base-hw doesn't use exception handlers
|
||||
*/
|
||||
void exception_handler(Signal_context_capability);
|
||||
|
||||
|
||||
/******************
|
||||
** Pure virtual **
|
||||
******************/
|
||||
|
||||
/**
|
||||
* Request a mapping that resolves a fault directly
|
||||
*
|
||||
* \param p offers the fault data and receives mapping data
|
||||
*
|
||||
* \retval 0 succeeded
|
||||
* \retval !=0 fault can't be received directly
|
||||
*/
|
||||
virtual int pager(Ipc_pager & p) = 0;
|
||||
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
|
||||
Thread_capability thread_cap() const;
|
||||
|
||||
void thread_cap(Thread_capability const & c);
|
||||
|
||||
void cap(Native_capability const & c);
|
||||
|
||||
unsigned signal_context_id() const;
|
||||
};
|
||||
|
||||
class Genode::Pager_activation_base : public Thread_base,
|
||||
public Signal_receiver,
|
||||
public Ipc_pager
|
||||
{
|
||||
private:
|
||||
|
||||
Native_capability _cap;
|
||||
Lock _cap_valid;
|
||||
Pager_entrypoint * _ep;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param name name of the new thread
|
||||
* \param stack_size stack size of the new thread
|
||||
*/
|
||||
Pager_activation_base(char const * const name,
|
||||
size_t const stack_size);
|
||||
|
||||
/**
|
||||
* Bring current mapping data into effect
|
||||
*
|
||||
* \retval 0 succeeded
|
||||
* \retval -1 failed
|
||||
*/
|
||||
int apply_mapping();
|
||||
|
||||
|
||||
/**********************
|
||||
** Thread interface **
|
||||
**********************/
|
||||
|
||||
void entry();
|
||||
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
|
||||
Native_capability cap();
|
||||
|
||||
void ep(Pager_entrypoint * const ep);
|
||||
};
|
||||
|
||||
class Genode::Pager_entrypoint : public Object_pool<Pager_object>
|
||||
{
|
||||
private:
|
||||
|
||||
Pager_activation_base * const _activation;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param a activation that shall handle the objects of the entrypoint
|
||||
*/
|
||||
Pager_entrypoint(Cap_session *, Pager_activation_base * const a);
|
||||
|
||||
/**
|
||||
* Associate pager object 'obj' with entry point
|
||||
*/
|
||||
Pager_capability manage(Pager_object * const obj);
|
||||
|
||||
/**
|
||||
* Dissolve pager object 'obj' from entry point
|
||||
*/
|
||||
void dissolve(Pager_object * const obj);
|
||||
};
|
||||
|
||||
template <unsigned STACK_SIZE>
|
||||
class Genode::Pager_activation : public Pager_activation_base
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Pager_activation()
|
||||
:
|
||||
Pager_activation_base("pager_activation", STACK_SIZE)
|
||||
{
|
||||
start();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _BASE__PAGER_H_ */
|
@ -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_ */
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -15,47 +15,108 @@
|
||||
#include <base/pager.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
/* base-hw includes */
|
||||
#include <placement_new.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
/*************
|
||||
** Mapping **
|
||||
*************/
|
||||
|
||||
Mapping::Mapping(addr_t const va, addr_t const pa, bool const wc,
|
||||
bool const io, unsigned const sl2, bool const w)
|
||||
:
|
||||
virt_address(va), phys_address(pa), write_combined(wc),
|
||||
io_mem(io), size_log2(sl2), writable(w)
|
||||
{ }
|
||||
|
||||
|
||||
Mapping::Mapping()
|
||||
:
|
||||
virt_address(0), phys_address(0), write_combined(0),
|
||||
io_mem(0), size_log2(0), writable(0)
|
||||
{ }
|
||||
|
||||
|
||||
void Mapping::prepare_map_operation() { }
|
||||
|
||||
|
||||
/***************
|
||||
** Ipc_pager **
|
||||
***************/
|
||||
|
||||
addr_t Ipc_pager::fault_ip() const { return _fault.ip; }
|
||||
|
||||
addr_t Ipc_pager::fault_addr() const { return _fault.addr; }
|
||||
|
||||
bool Ipc_pager::is_write_fault() const { return _fault.writes; }
|
||||
|
||||
void Ipc_pager::set_reply_mapping(Mapping m) { _mapping = m; }
|
||||
|
||||
|
||||
/******************
|
||||
** Pager_object **
|
||||
******************/
|
||||
|
||||
Thread_capability Pager_object::thread_cap() const { return _thread_cap; }
|
||||
|
||||
void Pager_object::thread_cap(Thread_capability const & c) { _thread_cap = c; }
|
||||
|
||||
Signal * Pager_object::_signal() const { return (Signal *)_signal_buf; }
|
||||
|
||||
void Pager_object::wake_up() { fault_resolved(); }
|
||||
|
||||
void Pager_object::exception_handler(Signal_context_capability) { }
|
||||
|
||||
void Pager_object::fault_resolved() { _signal()->~Signal(); }
|
||||
|
||||
unsigned Pager_object::badge() const { return _thread_id; }
|
||||
|
||||
|
||||
void Pager_object::fault_occured(Signal const & s)
|
||||
{
|
||||
new (_signal()) Signal(s);
|
||||
}
|
||||
|
||||
|
||||
void Pager_object::cap(Native_capability const & c)
|
||||
{
|
||||
Object_pool<Pager_object>::Entry::cap(c);
|
||||
}
|
||||
|
||||
|
||||
Pager_object::Pager_object(unsigned const thread_id, Affinity::Location)
|
||||
:
|
||||
_thread_id(thread_id)
|
||||
{ }
|
||||
|
||||
|
||||
unsigned Pager_object::signal_context_id() const
|
||||
{
|
||||
return _signal_context_cap.dst();
|
||||
}
|
||||
|
||||
|
||||
/***************************
|
||||
** Pager_activation_base **
|
||||
***************************/
|
||||
|
||||
void Pager_activation_base::entry()
|
||||
void Pager_activation_base::ep(Pager_entrypoint * const ep) { _ep = ep; }
|
||||
|
||||
|
||||
Pager_activation_base::Pager_activation_base(char const * const name,
|
||||
size_t const stack_size)
|
||||
:
|
||||
Thread_base(name, stack_size), _cap_valid(Lock::LOCKED), _ep(0)
|
||||
{ }
|
||||
|
||||
|
||||
Native_capability Pager_activation_base::cap()
|
||||
{
|
||||
/* acknowledge that we're ready to work */
|
||||
Ipc_pager pager;
|
||||
_cap = pager;
|
||||
_cap_valid.unlock();
|
||||
|
||||
/* receive and handle faults */
|
||||
bool mapping_pending = 0;
|
||||
pager.wait_for_first_fault();
|
||||
while (1)
|
||||
{
|
||||
/* protect bottom half of loop against pager-object guard */
|
||||
{
|
||||
/* lookup pager object for current faulter */
|
||||
Object_pool<Pager_object>::Guard
|
||||
o(_ep ? _ep->lookup_and_lock(pager.badge()) : 0);
|
||||
|
||||
if (!o) {
|
||||
PERR("invalid pager object");
|
||||
mapping_pending = 0;
|
||||
} else {
|
||||
/* try to find an appropriate mapping */
|
||||
mapping_pending = !o->pager(pager);
|
||||
}
|
||||
}
|
||||
if (mapping_pending) {
|
||||
/* apply mapping and await next fault */
|
||||
if (pager.resolve_and_wait_for_fault()) {
|
||||
PERR("failed to resolve page fault");
|
||||
pager.wait_for_fault();
|
||||
}
|
||||
} else { pager.wait_for_fault(); }
|
||||
}
|
||||
if (!_cap.valid()) { _cap_valid.lock(); }
|
||||
return _cap;
|
||||
}
|
||||
|
||||
|
||||
@ -63,84 +124,25 @@ void Pager_activation_base::entry()
|
||||
** Pager_entrypoint **
|
||||
**********************/
|
||||
|
||||
Pager_entrypoint::
|
||||
Pager_entrypoint(Cap_session *, Pager_activation_base * const a)
|
||||
: _activation(a) { _activation->ep(this); }
|
||||
|
||||
|
||||
void Pager_entrypoint::dissolve(Pager_object * const o) { remove_locked(o); }
|
||||
|
||||
|
||||
Pager_entrypoint::Pager_entrypoint(Cap_session *,
|
||||
Pager_activation_base * const activation)
|
||||
:
|
||||
_activation(activation)
|
||||
{
|
||||
_activation->ep(this);
|
||||
}
|
||||
|
||||
|
||||
Pager_capability Pager_entrypoint::manage(Pager_object * const o)
|
||||
{
|
||||
/* do we have an activation */
|
||||
if (!_activation) return Pager_capability();
|
||||
|
||||
/* create cap with the object badge as local name */
|
||||
Native_capability c;
|
||||
c = Native_capability(_activation->cap().dst(), o->badge());
|
||||
|
||||
/* let activation provide the pager object */
|
||||
o->_signal_context_cap = _activation->Signal_receiver::manage(o);
|
||||
unsigned const dst = _activation->cap().dst();
|
||||
Native_capability c = Native_capability(dst, o->badge());
|
||||
o->cap(c);
|
||||
insert(o);
|
||||
|
||||
/* return pager-object cap */
|
||||
return reinterpret_cap_cast<Pager_object>(c);
|
||||
}
|
||||
|
||||
|
||||
/***************
|
||||
** Ipc_pager **
|
||||
***************/
|
||||
|
||||
void Ipc_pager::wait_for_first_fault()
|
||||
{
|
||||
Kernel::wait_for_request();
|
||||
_wait_for_fault();
|
||||
}
|
||||
|
||||
|
||||
void Ipc_pager::wait_for_fault()
|
||||
{
|
||||
Native_utcb * const utcb = Thread_base::myself()->utcb();
|
||||
utcb->ipc_msg.size = 0;
|
||||
Kernel::reply(1);
|
||||
_wait_for_fault();
|
||||
}
|
||||
|
||||
|
||||
void Ipc_pager::_wait_for_fault()
|
||||
{
|
||||
Native_utcb * const utcb = Thread_base::myself()->utcb();
|
||||
while (1)
|
||||
{
|
||||
switch (utcb->msg.type) {
|
||||
|
||||
case Msg::Type::PAGEFAULT: {
|
||||
|
||||
/* receive pagefault report */
|
||||
_pagefault_msg = utcb->pagefault_msg;
|
||||
return; }
|
||||
|
||||
case Msg::Type::IPC: {
|
||||
|
||||
/* receive release request from region manager */
|
||||
Native_utcb * const utcb = Thread_base::myself()->utcb();
|
||||
void * const msg_base = utcb->ipc_msg.data;
|
||||
Pagefault_resolved * const msg = (Pagefault_resolved *)msg_base;
|
||||
|
||||
/* resume faulter */
|
||||
Kernel::resume_thread(msg->pager_object->badge());
|
||||
utcb->ipc_msg.size = 0;
|
||||
|
||||
/* send ack to region manager and get next message */
|
||||
Kernel::reply(1);
|
||||
continue; }
|
||||
|
||||
default: {
|
||||
|
||||
PERR("unknown message type");
|
||||
continue; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -13,35 +13,77 @@
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/thread.h>
|
||||
#include <kernel/pd.h>
|
||||
|
||||
using namespace Kernel;
|
||||
|
||||
|
||||
/********************************
|
||||
** Kernel::Thread_cpu_support **
|
||||
********************************/
|
||||
|
||||
Thread_cpu_support::Thread_cpu_support(Thread * const t)
|
||||
:
|
||||
_fault(t),
|
||||
_fault_tlb(0),
|
||||
_fault_addr(0),
|
||||
_fault_writes(0),
|
||||
_fault_signal(0)
|
||||
{ }
|
||||
|
||||
|
||||
/********************
|
||||
** Kernel::Thread **
|
||||
********************/
|
||||
|
||||
addr_t * Kernel::Thread::_reg(addr_t const id) const
|
||||
addr_t Thread::* Thread::_reg(addr_t const id) const
|
||||
{
|
||||
static addr_t * const _regs[] = {
|
||||
(addr_t *)&r0,
|
||||
(addr_t *)&r1,
|
||||
(addr_t *)&r2,
|
||||
(addr_t *)&r3,
|
||||
(addr_t *)&r4,
|
||||
(addr_t *)&r5,
|
||||
(addr_t *)&r6,
|
||||
(addr_t *)&r7,
|
||||
(addr_t *)&r8,
|
||||
(addr_t *)&r9,
|
||||
(addr_t *)&r10,
|
||||
(addr_t *)&r11,
|
||||
(addr_t *)&r12,
|
||||
(addr_t *)&sp,
|
||||
(addr_t *)&lr,
|
||||
(addr_t *)&ip,
|
||||
(addr_t *)&cpsr,
|
||||
(addr_t *)&cpu_exception
|
||||
static addr_t Thread::* const _regs[] = {
|
||||
/* [0] */ (addr_t Thread::*)&Thread::r0,
|
||||
/* [1] */ (addr_t Thread::*)&Thread::r1,
|
||||
/* [2] */ (addr_t Thread::*)&Thread::r2,
|
||||
/* [3] */ (addr_t Thread::*)&Thread::r3,
|
||||
/* [4] */ (addr_t Thread::*)&Thread::r4,
|
||||
/* [5] */ (addr_t Thread::*)&Thread::r5,
|
||||
/* [6] */ (addr_t Thread::*)&Thread::r6,
|
||||
/* [7] */ (addr_t Thread::*)&Thread::r7,
|
||||
/* [8] */ (addr_t Thread::*)&Thread::r8,
|
||||
/* [9] */ (addr_t Thread::*)&Thread::r9,
|
||||
/* [10] */ (addr_t Thread::*)&Thread::r10,
|
||||
/* [11] */ (addr_t Thread::*)&Thread::r11,
|
||||
/* [12] */ (addr_t Thread::*)&Thread::r12,
|
||||
/* [13] */ (addr_t Thread::*)&Thread::sp,
|
||||
/* [14] */ (addr_t Thread::*)&Thread::lr,
|
||||
/* [15] */ (addr_t Thread::*)&Thread::ip,
|
||||
/* [16] */ (addr_t Thread::*)&Thread::cpsr,
|
||||
/* [17] */ (addr_t Thread::*)&Thread::cpu_exception,
|
||||
/* [18] */ (addr_t Thread::*)&Thread::_fault_tlb,
|
||||
/* [19] */ (addr_t Thread::*)&Thread::_fault_addr,
|
||||
/* [20] */ (addr_t Thread::*)&Thread::_fault_writes,
|
||||
/* [21] */ (addr_t Thread::*)&Thread::_fault_signal
|
||||
};
|
||||
return id < sizeof(_regs)/sizeof(_regs[0]) ? _regs[id] : 0;
|
||||
}
|
||||
|
||||
|
||||
Thread_event Thread::* Thread::_event(unsigned const id) const
|
||||
{
|
||||
static Thread_event Thread::* _events[] = {
|
||||
/* [0] */ &Thread::_fault
|
||||
};
|
||||
return id < sizeof(_events)/sizeof(_events[0]) ? _events[id] : 0;
|
||||
}
|
||||
|
||||
|
||||
void Thread::_mmu_exception()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAITS_RESUME;
|
||||
if (in_fault(_fault_addr, _fault_writes)) {
|
||||
_fault_tlb = (addr_t)_pd->tlb();
|
||||
_fault_signal = _fault.signal_context_id();
|
||||
_fault.submit();
|
||||
return;
|
||||
}
|
||||
PERR("unknown MMU exception");
|
||||
}
|
||||
|
41
base-hw/src/core/arm/cpu_support.h
Normal file
41
base-hw/src/core/arm/cpu_support.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* \brief CPU specific support for base-hw
|
||||
* \author Martin Stein
|
||||
* \date 2013-11-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/thread_event.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
/**
|
||||
* CPU specific parts of a kernel thread-object
|
||||
*/
|
||||
class Thread_cpu_support;
|
||||
}
|
||||
|
||||
class Kernel::Thread_cpu_support
|
||||
{
|
||||
protected:
|
||||
|
||||
Thread_event _fault;
|
||||
addr_t _fault_tlb;
|
||||
addr_t _fault_addr;
|
||||
addr_t _fault_writes;
|
||||
addr_t _fault_signal;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param t generic part of kernel thread-object
|
||||
*/
|
||||
Thread_cpu_support(Thread * const t);
|
||||
};
|
@ -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 \
|
||||
|
@ -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) {
|
||||
|
@ -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 \
|
||||
|
@ -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 \
|
||||
|
@ -44,7 +44,8 @@ class Kernel::Irq
|
||||
:
|
||||
public Object_pool<Irq>::Item,
|
||||
public Signal_receiver,
|
||||
public Signal_context
|
||||
public Signal_context,
|
||||
public Signal_ack_handler
|
||||
{
|
||||
friend class Genode::Irq;
|
||||
|
||||
@ -120,11 +121,11 @@ class Kernel::Irq
|
||||
~Irq() { PERR("method not implemented"); }
|
||||
|
||||
|
||||
/********************
|
||||
** Signal_context **
|
||||
********************/
|
||||
/************************
|
||||
** Signal_ack_handler **
|
||||
************************/
|
||||
|
||||
void _signal_context_acknowledged() { _enable(); }
|
||||
void _signal_acknowledged() { _enable(); }
|
||||
|
||||
public:
|
||||
|
||||
@ -138,6 +139,7 @@ class Kernel::Irq
|
||||
Pool::Item(irq_id),
|
||||
Signal_context(this, 0)
|
||||
{
|
||||
Signal_context::ack_handler(this);
|
||||
_pool()->insert(this);
|
||||
_disable();
|
||||
}
|
||||
|
@ -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(); }
|
||||
}
|
||||
|
@ -25,10 +25,15 @@
|
||||
namespace Kernel
|
||||
{
|
||||
/**
|
||||
* Ability to receive from signal receivers
|
||||
* Ability to receive signals from signal receivers
|
||||
*/
|
||||
class Signal_handler;
|
||||
|
||||
/**
|
||||
* Ability to get informed about signal acks
|
||||
*/
|
||||
class Signal_ack_handler;
|
||||
|
||||
/**
|
||||
* Ability to destruct signal contexts
|
||||
*/
|
||||
@ -60,6 +65,30 @@ namespace Kernel
|
||||
Signal_receiver_pool * signal_receiver_pool();
|
||||
}
|
||||
|
||||
class Kernel::Signal_ack_handler
|
||||
{
|
||||
friend class Signal_context;
|
||||
|
||||
Signal_context * _signal_context;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Provide custom handler for acks at a signal context
|
||||
*/
|
||||
virtual void _signal_acknowledged() = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Signal_ack_handler() : _signal_context(0) { }
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Signal_ack_handler();
|
||||
};
|
||||
|
||||
class Kernel::Signal_handler
|
||||
{
|
||||
friend class Signal_receiver;
|
||||
@ -203,6 +232,20 @@ class Kernel::Signal_context
|
||||
|
||||
typedef Genode::Fifo_element<Signal_context> Fifo_element;
|
||||
|
||||
/**
|
||||
* Dummy handler that is used every time no other handler is available
|
||||
*/
|
||||
class Default_ack_handler : public Signal_ack_handler
|
||||
{
|
||||
private:
|
||||
|
||||
/************************
|
||||
** Signal_ack_handler **
|
||||
************************/
|
||||
|
||||
void _signal_acknowledged() { }
|
||||
};
|
||||
|
||||
Fifo_element _deliver_fe;
|
||||
Fifo_element _contexts_fe;
|
||||
Signal_receiver * const _receiver;
|
||||
@ -211,6 +254,8 @@ class Kernel::Signal_context
|
||||
bool _ack;
|
||||
bool _kill;
|
||||
Signal_context_killer * _killer;
|
||||
Default_ack_handler _default_ack_handler;
|
||||
Signal_ack_handler * _ack_handler;
|
||||
|
||||
/**
|
||||
* Tell receiver about the submits of the context if any
|
||||
@ -231,11 +276,6 @@ class Kernel::Signal_context
|
||||
*/
|
||||
void _killer_cancelled() { _killer = 0; }
|
||||
|
||||
/**
|
||||
* Hook to install in-kernel handler for acks at specific signal types
|
||||
*/
|
||||
virtual void _signal_context_acknowledged() { };
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
@ -260,6 +300,17 @@ class Kernel::Signal_context
|
||||
*/
|
||||
Signal_context(Signal_receiver * const r, unsigned const imprint);
|
||||
|
||||
/**
|
||||
* Attach or detach a handler for acknowledgments at this context
|
||||
*
|
||||
* \param h handler that shall be attached or 0 to detach handler
|
||||
*/
|
||||
void ack_handler(Signal_ack_handler * const h)
|
||||
{
|
||||
_ack_handler = h ? h : &_default_ack_handler;
|
||||
_ack_handler->_signal_context = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit the signal
|
||||
*
|
||||
@ -281,7 +332,7 @@ class Kernel::Signal_context
|
||||
*/
|
||||
void ack()
|
||||
{
|
||||
_signal_context_acknowledged();
|
||||
_ack_handler->_signal_acknowledged();
|
||||
if (_ack) { return; }
|
||||
if (!_kill) {
|
||||
_ack = 1;
|
||||
@ -454,7 +505,7 @@ class Kernel::Signal_receiver
|
||||
*/
|
||||
int add_handler(Signal_handler * const h)
|
||||
{
|
||||
if (_kill) { return -1; }
|
||||
if (_kill || h->_receiver) { return -1; }
|
||||
_handlers.enqueue(&h->_handlers_fe);
|
||||
h->_receiver = this;
|
||||
h->_await_signal(this);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <kernel/scheduler.h>
|
||||
#include <kernel/signal_receiver.h>
|
||||
#include <kernel/ipc_node.h>
|
||||
#include <cpu_support.h>
|
||||
#include <cpu.h>
|
||||
|
||||
namespace Genode
|
||||
@ -32,7 +33,6 @@ namespace Kernel
|
||||
class Pd;
|
||||
|
||||
typedef Genode::Cpu Cpu;
|
||||
typedef Genode::Pagefault_msg Pagefault_msg;
|
||||
typedef Genode::Native_utcb Native_utcb;
|
||||
|
||||
void reset_lap_time();
|
||||
@ -57,8 +57,11 @@ class Kernel::Thread
|
||||
public Ipc_node,
|
||||
public Signal_context_killer,
|
||||
public Signal_receiver_killer,
|
||||
public Signal_handler
|
||||
public Signal_handler,
|
||||
public Thread_cpu_support
|
||||
{
|
||||
friend class Thread_event;
|
||||
|
||||
private:
|
||||
|
||||
enum { START_VERBOSE = 0 };
|
||||
@ -69,19 +72,15 @@ class Kernel::Thread
|
||||
AWAITS_START = 2,
|
||||
AWAITS_IPC = 3,
|
||||
AWAITS_RESUME = 4,
|
||||
AWAITS_PAGER = 5,
|
||||
AWAITS_PAGER_IPC = 6,
|
||||
AWAITS_SIGNAL = 8,
|
||||
AWAITS_SIGNAL_CONTEXT_KILL = 9,
|
||||
AWAITS_SIGNAL_RECEIVER_KILL = 10,
|
||||
STOPPED = 11,
|
||||
AWAITS_SIGNAL = 5,
|
||||
AWAITS_SIGNAL_CONTEXT_KILL = 6,
|
||||
AWAITS_SIGNAL_RECEIVER_KILL = 7,
|
||||
STOPPED = 8,
|
||||
};
|
||||
|
||||
Platform_thread * const _platform_thread;
|
||||
State _state;
|
||||
Pagefault_msg _pagefault_msg;
|
||||
Thread * _pager;
|
||||
unsigned _pd_id;
|
||||
Pd * _pd;
|
||||
Native_utcb * _phys_utcb;
|
||||
Native_utcb * _virt_utcb;
|
||||
Signal_receiver * _signal_receiver;
|
||||
@ -92,9 +91,26 @@ class Kernel::Thread
|
||||
void _receive_yielded_cpu();
|
||||
|
||||
/**
|
||||
* Return kernel backend of protection domain the thread is in
|
||||
* Attach or detach the handler of a thread-triggered event
|
||||
*
|
||||
* \param event_id kernel name of the thread event
|
||||
* \param signal_context_id kernel name signal context or 0 to detach
|
||||
*
|
||||
* \retval 0 succeeded
|
||||
* \retval -1 failed
|
||||
*/
|
||||
Pd * _pd() const;
|
||||
int _route_event(unsigned const event_id,
|
||||
unsigned const signal_context_id);
|
||||
|
||||
/**
|
||||
* Map kernel name of thread event to the corresponding member
|
||||
*
|
||||
* \param id kernel name of targeted thread event
|
||||
*
|
||||
* \retval 0 failed
|
||||
* \retval >0 targeted member pointer
|
||||
*/
|
||||
Thread_event Thread::* _event(unsigned const id) const;
|
||||
|
||||
/**
|
||||
* Return wether this is a core thread
|
||||
@ -165,43 +181,42 @@ class Kernel::Thread
|
||||
* \retval 0 failed
|
||||
* \retval >0 pointer to register content
|
||||
*/
|
||||
addr_t * _reg(addr_t const id) const;
|
||||
addr_t Thread::* _reg(addr_t const id) const;
|
||||
|
||||
|
||||
/***************************************************
|
||||
** Syscall backends, for details see 'syscall.h' **
|
||||
***************************************************/
|
||||
|
||||
void _syscall_new_pd();
|
||||
void _syscall_kill_pd();
|
||||
void _syscall_new_thread();
|
||||
void _syscall_delete_thread();
|
||||
void _syscall_start_thread();
|
||||
void _syscall_pause_thread();
|
||||
void _syscall_resume_thread();
|
||||
void _syscall_resume_faulter();
|
||||
void _syscall_yield_thread();
|
||||
void _syscall_current_thread_id();
|
||||
void _syscall_get_thread();
|
||||
void _syscall_wait_for_request();
|
||||
void _syscall_request_and_wait();
|
||||
void _syscall_reply();
|
||||
void _syscall_set_pager();
|
||||
void _syscall_update_pd();
|
||||
void _syscall_update_region();
|
||||
void _syscall_print_char();
|
||||
void _syscall_new_signal_receiver();
|
||||
void _syscall_new_signal_context();
|
||||
void _syscall_await_signal();
|
||||
void _syscall_signal_pending();
|
||||
void _syscall_submit_signal();
|
||||
void _syscall_ack_signal();
|
||||
void _syscall_kill_signal_context();
|
||||
void _syscall_kill_signal_receiver();
|
||||
void _syscall_new_vm();
|
||||
void _syscall_run_vm();
|
||||
void _syscall_pause_vm();
|
||||
void _syscall_access_thread_regs();
|
||||
void _call_new_pd();
|
||||
void _call_kill_pd();
|
||||
void _call_new_thread();
|
||||
void _call_delete_thread();
|
||||
void _call_start_thread();
|
||||
void _call_pause_thread();
|
||||
void _call_resume_thread();
|
||||
void _call_yield_thread();
|
||||
void _call_current_thread_id();
|
||||
void _call_get_thread();
|
||||
void _call_wait_for_request();
|
||||
void _call_request_and_wait();
|
||||
void _call_reply();
|
||||
void _call_update_pd();
|
||||
void _call_update_region();
|
||||
void _call_print_char();
|
||||
void _call_new_signal_receiver();
|
||||
void _call_new_signal_context();
|
||||
void _call_await_signal();
|
||||
void _call_signal_pending();
|
||||
void _call_submit_signal();
|
||||
void _call_ack_signal();
|
||||
void _call_kill_signal_context();
|
||||
void _call_kill_signal_receiver();
|
||||
void _call_new_vm();
|
||||
void _call_run_vm();
|
||||
void _call_pause_vm();
|
||||
void _call_access_thread_regs();
|
||||
void _call_route_thread_event();
|
||||
|
||||
|
||||
/***************************
|
||||
@ -277,10 +292,9 @@ class Kernel::Thread
|
||||
***************/
|
||||
|
||||
Platform_thread * platform_thread() const { return _platform_thread; }
|
||||
void pager(Thread * const p) { _pager = p; }
|
||||
unsigned id() const { return Object::id(); }
|
||||
char const * label() const;
|
||||
unsigned pd_id() const { return _pd_id; }
|
||||
unsigned pd_id() const;
|
||||
char const * pd_label() const;
|
||||
};
|
||||
|
||||
|
63
base-hw/src/core/kernel/thread_event.h
Normal file
63
base-hw/src/core/kernel/thread_event.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* \brief Event that is provided by akernel thread-object for user handling
|
||||
* \author Martin Stein
|
||||
* \date 2013-11-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
class Thread;
|
||||
|
||||
/**
|
||||
* Event that is provided by kernel thread-objects for user handling
|
||||
*/
|
||||
class Thread_event;
|
||||
}
|
||||
|
||||
class Kernel::Thread_event : public Signal_ack_handler
|
||||
{
|
||||
private:
|
||||
|
||||
Thread * const _thread;
|
||||
Signal_context * _signal_context;
|
||||
|
||||
|
||||
/************************
|
||||
** Signal_ack_handler **
|
||||
************************/
|
||||
|
||||
void _signal_acknowledged();
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param t thread that blocks on the event
|
||||
*/
|
||||
Thread_event(Thread * const t);
|
||||
|
||||
/**
|
||||
* Submit to listening handlers just like a signal context
|
||||
*/
|
||||
void submit();
|
||||
|
||||
/**
|
||||
* Kernel name of assigned signal context or 0 if not assigned
|
||||
*/
|
||||
unsigned signal_context_id() const;
|
||||
|
||||
/**
|
||||
* Override signal context of the event
|
||||
*
|
||||
* \param c new signal context or 0 to dissolve current signal context
|
||||
*/
|
||||
void signal_context(Signal_context * const c);
|
||||
};
|
@ -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 \
|
||||
|
@ -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 \
|
||||
|
@ -65,7 +65,7 @@ Platform_thread::~Platform_thread()
|
||||
assert(object);
|
||||
Rm_session_component * const rm = _rm_client->member_rm_session();
|
||||
assert(rm);
|
||||
Pager_capability cap = reinterpret_cap_cast<Pager_object>(object->cap());
|
||||
Pager_capability cap = reinterpret_cap_cast<Pager_object>(object->Object_pool<Pager_object>::Entry::cap());
|
||||
rm->remove_client(cap);
|
||||
}
|
||||
/* destroy object at the kernel */
|
||||
@ -197,13 +197,25 @@ int Platform_thread::start(void * ip, void * sp, unsigned int cpu_no)
|
||||
|
||||
void Platform_thread::pager(Pager_object * const pager)
|
||||
{
|
||||
typedef Kernel::Thread_event_id Event_id;
|
||||
if (pager) {
|
||||
Kernel::set_pager(pager->cap().dst(), _id);
|
||||
_rm_client = dynamic_cast<Rm_client *>(pager);
|
||||
unsigned const sc_id = pager->signal_context_id();
|
||||
if (sc_id) {
|
||||
if (!Kernel::route_thread_event(id(), Event_id::FAULT, sc_id)) {
|
||||
_rm_client = dynamic_cast<Rm_client *>(pager);
|
||||
return;
|
||||
}
|
||||
}
|
||||
PERR("failed to attach signal context to fault");
|
||||
return;
|
||||
} else {
|
||||
if (!Kernel::route_thread_event(id(), Event_id::FAULT, 0)) {
|
||||
_rm_client = 0;
|
||||
return;
|
||||
}
|
||||
PERR("failed to detach signal context from fault");
|
||||
return;
|
||||
}
|
||||
Kernel::set_pager(0, _id);
|
||||
_rm_client = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/ipc_pager.h>
|
||||
#include <base/pager.h>
|
||||
|
||||
/* core includes */
|
||||
#include <rm_session_component.h>
|
||||
@ -48,23 +48,18 @@ void Rm_client::unmap(addr_t, addr_t virt_base, size_t size)
|
||||
}
|
||||
|
||||
|
||||
/***************
|
||||
** Ipc_pager **
|
||||
***************/
|
||||
/***************************
|
||||
** Pager_activation_base **
|
||||
***************************/
|
||||
|
||||
int Ipc_pager::resolve_and_wait_for_fault()
|
||||
int Pager_activation_base::apply_mapping()
|
||||
{
|
||||
/* check mapping */
|
||||
if (!_mapping.valid()) {
|
||||
PERR("invalid mapping");
|
||||
return -1;
|
||||
}
|
||||
/* prepare mapping */
|
||||
Tlb * const tlb = _pagefault_msg.tlb;
|
||||
Tlb * const tlb = (Tlb *)_fault.tlb;
|
||||
Page_flags::access_t const flags =
|
||||
Page_flags::resolve_and_wait_for_fault(_mapping.writable,
|
||||
_mapping.write_combined,
|
||||
_mapping.io_mem);
|
||||
Page_flags::apply_mapping(_mapping.writable,
|
||||
_mapping.write_combined,
|
||||
_mapping.io_mem);
|
||||
|
||||
/* insert mapping into TLB */
|
||||
unsigned sl2;
|
||||
@ -90,11 +85,48 @@ int Ipc_pager::resolve_and_wait_for_fault()
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* wake up faulter */
|
||||
Kernel::resume_faulter(_pagefault_msg.thread_id);
|
||||
|
||||
/* wait for next page fault */
|
||||
wait_for_fault();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Pager_activation_base::entry()
|
||||
{
|
||||
/* get ready to receive faults */
|
||||
_cap = Native_capability(thread_get_my_native_id(), 0);
|
||||
_cap_valid.unlock();
|
||||
while (1)
|
||||
{
|
||||
/* await fault */
|
||||
Pager_object * o;
|
||||
while (1) {
|
||||
Signal s = Signal_receiver::wait_for_signal();
|
||||
o = dynamic_cast<Pager_object *>(s.context());
|
||||
if (o) {
|
||||
o->fault_occured(s);
|
||||
break;
|
||||
}
|
||||
PERR("unknown pager object");
|
||||
}
|
||||
/* fetch fault data */
|
||||
unsigned const thread_id = o->badge();
|
||||
typedef Kernel::Thread_reg_id Reg_id;
|
||||
static addr_t const read_regs[] = {
|
||||
Reg_id::FAULT_TLB, Reg_id::IP, Reg_id::FAULT_ADDR,
|
||||
Reg_id::FAULT_WRITES, Reg_id::FAULT_SIGNAL };
|
||||
enum { READS = sizeof(read_regs)/sizeof(read_regs[0]) };
|
||||
void * const utcb = Thread_base::myself()->utcb()->base();
|
||||
memcpy(utcb, read_regs, sizeof(read_regs));
|
||||
addr_t * const read_values = (addr_t *)&_fault;
|
||||
if (Kernel::access_thread_regs(thread_id, READS, 0, read_values, 0)) {
|
||||
PERR("failed to read page-fault data");
|
||||
continue;
|
||||
}
|
||||
/* handle fault */
|
||||
if (o->pager(*this)) { continue; }
|
||||
if (apply_mapping()) {
|
||||
PERR("failed to apply mapping");
|
||||
continue;
|
||||
}
|
||||
o->fault_resolved();
|
||||
}
|
||||
}
|
||||
|
@ -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 \
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user