diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc
index ea62c83405..20ef5781c5 100644
--- a/repos/base-hw/src/core/kernel/thread.cc
+++ b/repos/base-hw/src/core/kernel/thread.cc
@@ -38,6 +38,20 @@ extern "C" void _core_start(void);
using namespace Kernel;
+void Thread_fault::print(Genode::Output &out) const
+{
+ Genode::print(out, "ip=", Genode::Hex(ip));
+ Genode::print(out, " fault-addr=", Genode::Hex(addr));
+ Genode::print(out, " type=");
+ switch (type) {
+ case WRITE: Genode::print(out, "write-fault"); return;
+ case EXEC: Genode::print(out, "exec-fault"); return;
+ case PAGE_MISSING: Genode::print(out, "no-page"); return;
+ case UNKNOWN: Genode::print(out, "unknown"); return;
+ };
+}
+
+
void Thread::_signal_context_kill_pending()
{
assert(_state == ACTIVE);
@@ -619,11 +633,29 @@ void Thread::_call()
}
+void Thread::_mmu_exception()
+{
+ _become_inactive(AWAITS_RESTART);
+ Cpu::mmu_fault(*regs, _fault);
+ _fault.ip = regs->ip;
+
+ if (_fault.type == Thread_fault::UNKNOWN) {
+ Genode::error(*this, " raised unhandled MMU fault ", _fault);
+ return;
+ }
+
+ if (_core)
+ Genode::error(*this, " raised a fault, which should never happen ",
+ _fault);
+
+ if (_pager) _pager->submit(1);
+}
+
+
Thread::Thread(unsigned const priority, unsigned const quota,
char const * const label, bool core)
:
- Cpu_job(priority, quota), _fault_pd(0), _fault_addr(0),
- _fault_writes(0), _state(AWAITS_START),
+ Cpu_job(priority, quota), _state(AWAITS_START),
_signal_receiver(0), _label(label), _core(core), regs(core) { }
diff --git a/repos/base-hw/src/core/kernel/thread.h b/repos/base-hw/src/core/kernel/thread.h
index 39d75e6b5b..d7534949a0 100644
--- a/repos/base-hw/src/core/kernel/thread.h
+++ b/repos/base-hw/src/core/kernel/thread.h
@@ -24,10 +24,24 @@
namespace Kernel
{
+ struct Thread_fault;
class Thread;
class Core_thread;
}
+
+struct Kernel::Thread_fault
+{
+ enum Type { WRITE, EXEC, PAGE_MISSING, UNKNOWN };
+
+ addr_t ip = 0;
+ addr_t addr = 0;
+ Type type = UNKNOWN;
+
+ void print(Genode::Output &out) const;
+};
+
+
/**
* Kernel back-end for userland execution-contexts
*/
@@ -53,9 +67,7 @@ class Kernel::Thread
};
Signal_context * _pager = nullptr;
- addr_t _fault_pd;
- addr_t _fault_addr;
- addr_t _fault_writes;
+ Thread_fault _fault;
State _state;
Signal_receiver * _signal_receiver;
char const * const _label;
@@ -63,7 +75,6 @@ class Kernel::Thread
bool _paused = false;
bool _cancel_next_await_signal = false;
bool const _core = false;
- bool _fault_exec = false;
/**
* Notice that another thread yielded the CPU to this thread
@@ -322,11 +333,8 @@ class Kernel::Thread
** Accessors **
***************/
- char const * label() const { return _label; }
- addr_t fault_pd() const { return _fault_pd; }
- addr_t fault_addr() const { return _fault_addr; }
- addr_t fault_writes() const { return _fault_writes; }
- bool fault_exec() const { return _fault_exec; }
+ char const * label() const { return _label; }
+ Thread_fault fault() const { return _fault; }
};
diff --git a/repos/base-hw/src/core/pager.cc b/repos/base-hw/src/core/pager.cc
index 4522435566..1a8ab38aa3 100644
--- a/repos/base-hw/src/core/pager.cc
+++ b/repos/base-hw/src/core/pager.cc
@@ -34,9 +34,11 @@ addr_t Ipc_pager::fault_ip() const { return _fault.ip; }
addr_t Ipc_pager::fault_addr() const { return _fault.addr; }
-bool Ipc_pager::write_fault() const { return _fault.writes; }
+bool Ipc_pager::write_fault() const {
+ return _fault.type == Kernel::Thread_fault::WRITE; }
-bool Ipc_pager::exec_fault() const { return _fault.exec; }
+bool Ipc_pager::exec_fault() const {
+ return _fault.type == Kernel::Thread_fault::EXEC; }
void Ipc_pager::set_reply_mapping(Mapping m) { _mapping = m; }
@@ -67,9 +69,7 @@ void Pager_object::unresolved_page_fault_occurred()
Platform_thread * const pt = (Platform_thread *)badge();
if (pt && pt->pd())
warning("page fault, pager_object: pd='", pt->pd()->label(),
- "' thread='", pt->label(),
- "' ip=", Hex(pt->kernel_object()->regs->ip),
- " pf-addr=", Hex(pt->kernel_object()->fault_addr()));
+ "' thread='", pt->label(), " ", pt->kernel_object()->fault());
}
void Pager_object::print(Output &out) const
diff --git a/repos/base-hw/src/core/pager.h b/repos/base-hw/src/core/pager.h
index 4e8c78563d..d25c38aca0 100644
--- a/repos/base-hw/src/core/pager.h
+++ b/repos/base-hw/src/core/pager.h
@@ -80,19 +80,8 @@ class Genode::Ipc_pager
{
protected:
- /**
- * Page-fault data that is read from the faulters thread registers
- */
- struct Fault_thread_regs
- {
- addr_t ip;
- addr_t addr;
- addr_t writes;
- addr_t exec;
- addr_t signal;
- } _fault;
-
- Mapping _mapping;
+ Kernel::Thread_fault _fault;
+ Mapping _mapping;
public:
diff --git a/repos/base-hw/src/core/region_map_support.cc b/repos/base-hw/src/core/region_map_support.cc
index d416fe21ad..aa840e127e 100644
--- a/repos/base-hw/src/core/region_map_support.cc
+++ b/repos/base-hw/src/core/region_map_support.cc
@@ -50,10 +50,7 @@ void Pager_entrypoint::entry()
continue;
}
- _fault.ip = pt->kernel_object()->regs->ip;
- _fault.addr = pt->kernel_object()->fault_addr();
- _fault.writes = pt->kernel_object()->fault_writes();
- _fault.exec = pt->kernel_object()->fault_exec();
+ _fault = pt->kernel_object()->fault();
/* try to resolve fault directly via local region managers */
if (po->pager(*this)) continue;
diff --git a/repos/base-hw/src/core/spec/arm/cpu.cc b/repos/base-hw/src/core/spec/arm/cpu.cc
index 5c5e854bb1..27184097be 100644
--- a/repos/base-hw/src/core/spec/arm/cpu.cc
+++ b/repos/base-hw/src/core/spec/arm/cpu.cc
@@ -15,9 +15,12 @@
#include
#include
+#include
#include
-Genode::Arm_cpu::Context::Context(bool privileged)
+using namespace Genode;
+
+Arm_cpu::Context::Context(bool privileged)
{
using Psr = Arm_cpu::Psr;
@@ -31,14 +34,14 @@ Genode::Arm_cpu::Context::Context(bool privileged)
}
-using Asid_allocator = Genode::Bit_allocator<256>;
+using Asid_allocator = Bit_allocator<256>;
static Asid_allocator &alloc() {
return *unmanaged_singleton(); }
-Genode::Arm_cpu::Mmu_context::Mmu_context(addr_t table)
-: cidr((Genode::uint8_t)alloc().alloc()), ttbr0(Ttbr0::init(table)) { }
+Arm_cpu::Mmu_context::Mmu_context(addr_t table)
+: cidr((uint8_t)alloc().alloc()), ttbr0(Ttbr0::init(table)) { }
Genode::Arm_cpu::Mmu_context::~Mmu_context()
@@ -47,3 +50,36 @@ Genode::Arm_cpu::Mmu_context::~Mmu_context()
Cpu::Tlbiasid::write(id());
alloc().free(id());
}
+
+
+using Thread_fault = Kernel::Thread_fault;
+
+void Arm_cpu::mmu_fault(Context & c, Thread_fault & fault)
+{
+ bool prefetch = c.cpu_exception == Context::PREFETCH_ABORT;
+ fault.addr = prefetch ? Ifar::read() : Dfar::read();
+ Fsr::access_t fsr = prefetch ? Ifsr::read() : Dfsr::read();
+
+ if (!prefetch && Dfsr::Wnr::get(fsr)) {
+ fault.type = Thread_fault::WRITE;
+ return;
+ }
+
+ Cpu::mmu_fault_status(Fsr::Fs::get(fsr), fault);
+}
+
+
+void Arm_cpu::mmu_fault_status(Fsr::access_t fsr, Thread_fault & fault)
+{
+ enum {
+ FAULT_MASK = 0b11101,
+ TRANSLATION = 0b00101,
+ PERMISSION = 0b01101,
+ };
+
+ switch(fsr & FAULT_MASK) {
+ case TRANSLATION: fault.type = Thread_fault::PAGE_MISSING; return;
+ case PERMISSION: fault.type = Thread_fault::EXEC; return;
+ default: fault.type = Thread_fault::UNKNOWN;
+ };
+}
diff --git a/repos/base-hw/src/core/spec/arm/cpu_support.h b/repos/base-hw/src/core/spec/arm/cpu_support.h
index 2fa009f271..fa5061d171 100644
--- a/repos/base-hw/src/core/spec/arm/cpu_support.h
+++ b/repos/base-hw/src/core/spec/arm/cpu_support.h
@@ -28,6 +28,8 @@
#include
#include
+namespace Kernel { struct Thread_fault; }
+
namespace Genode {
using sizet_arithm_t = Genode::uint64_t;
struct Arm_cpu;
@@ -137,48 +139,10 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu
}
}
- static bool in_fault(Context & c, addr_t & va, addr_t & w, bool & p)
- {
- /* translation fault on section */
- static constexpr Fsr::access_t section = 5;
- /* translation fault on page */
- static constexpr Fsr::access_t page = 7;
- /* permission fault on page */
- static constexpr Fsr::access_t permission = 0xf;
+ static void mmu_fault(Context & c, Kernel::Thread_fault & fault);
+ static void mmu_fault_status(Fsr::access_t fsr,
+ Kernel::Thread_fault & fault);
- if (c.cpu_exception == Context::PREFETCH_ABORT) {
- /* check if fault was caused by a translation miss */
- Ifsr::access_t const fs = Fsr::Fs::get(Ifsr::read());
-
- if (fs == permission) {
- w = 0;
- va = Ifar::read();
- p = true;
- return true;
- }
-
- if (fs != section && fs != page)
- return false;
-
- /* fetch fault data */
- w = 0;
- va = Ifar::read();
- p = false;
- return true;
- } else {
- /* check if fault is of known type */
- Dfsr::access_t const fs = Fsr::Fs::get(Dfsr::read());
- if (fs != permission && fs != section && fs != page)
- return false;
-
- /* fetch fault data */
- Dfsr::access_t const dfsr = Dfsr::read();
- w = Dfsr::Wnr::get(dfsr);
- va = Dfar::read();
- p = false;
- return true;
- }
- }
/*************
** Dummies **
diff --git a/repos/base-hw/src/core/spec/arm/kernel/thread.cc b/repos/base-hw/src/core/spec/arm/kernel/thread.cc
index 0f7707bc15..722c0f0fca 100644
--- a/repos/base-hw/src/core/spec/arm/kernel/thread.cc
+++ b/repos/base-hw/src/core/spec/arm/kernel/thread.cc
@@ -50,41 +50,6 @@ void Thread::exception(Cpu & cpu)
}
-void Thread::_mmu_exception()
-{
- _become_inactive(AWAITS_RESTART);
- if (Cpu::in_fault(*regs, _fault_addr, _fault_writes, _fault_exec)) {
- _fault_pd = (addr_t)_pd->platform_pd();
-
- /*
- * Core should never raise a page-fault. If this happens, print out an
- * error message with debug information.
- */
- if (_core)
- Genode::error("page fault in core thread (", label(), "): "
- "ip=", Genode::Hex(regs->ip), " fault=", Genode::Hex(_fault_addr));
-
- if (_pager) _pager->submit(1);
- return;
- }
-
- char const *abort_type = "unknown";
- if (regs->cpu_exception == Cpu::Context::DATA_ABORT)
- abort_type = "data";
- if (regs->cpu_exception == Cpu::Context::PREFETCH_ABORT)
- abort_type = "prefetch";
-
- Genode::error(*this, ": raised unhandled ",
- abort_type, " abort ",
- "DFSR=", Genode::Hex(Cpu::Dfsr::read()), " "
- "ISFR=", Genode::Hex(Cpu::Ifsr::read()), " "
- "DFAR=", Genode::Hex(Cpu::Dfar::read()), " "
- "ip=", Genode::Hex(regs->ip), " "
- "sp=", Genode::Hex(regs->sp), " "
- "exception=", Genode::Hex(regs->cpu_exception));
-}
-
-
void Kernel::Thread::_call_update_data_region()
{
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
diff --git a/repos/base-hw/src/core/spec/cortex_a15/cpu.cc b/repos/base-hw/src/core/spec/cortex_a15/cpu.cc
index 422f394293..406bad71c9 100644
--- a/repos/base-hw/src/core/spec/cortex_a15/cpu.cc
+++ b/repos/base-hw/src/core/spec/cortex_a15/cpu.cc
@@ -14,6 +14,7 @@
#include
#include
+#include
#include
using Asid_allocator = Genode::Bit_allocator<256>;
@@ -33,3 +34,22 @@ Genode::Cpu::Mmu_context::~Mmu_context()
Cpu::Tlbiasid::write(id());
alloc().free(id());
}
+
+
+void Genode::Cpu::mmu_fault_status(Genode::Cpu::Fsr::access_t fsr,
+ Kernel::Thread_fault & fault)
+{
+ enum {
+ FAULT_MASK = 0b111100,
+ TRANSLATION = 0b000100,
+ PERMISSION = 0b001100,
+ };
+
+ using Fault = Kernel::Thread_fault;
+
+ switch(fsr & FAULT_MASK) {
+ case TRANSLATION: fault.type = Fault::PAGE_MISSING; return;
+ case PERMISSION: fault.type = Fault::EXEC; return;
+ default: fault.type = Fault::UNKNOWN;
+ };
+};
diff --git a/repos/base-hw/src/core/spec/cortex_a15/cpu.h b/repos/base-hw/src/core/spec/cortex_a15/cpu.h
index 87605156ef..0d725f4b98 100644
--- a/repos/base-hw/src/core/spec/cortex_a15/cpu.h
+++ b/repos/base-hw/src/core/spec/cortex_a15/cpu.h
@@ -105,61 +105,8 @@ class Genode::Cpu : public Arm_v7_cpu
Genode::uint8_t id() const { return Ttbr_64bit::Asid::get(ttbr0); }
};
-
- /**
- * Return if the context is in a page fault due to 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
- * \param p holds whether it's a permission fault if call returns 1
- */
- static bool in_fault(Context & c, addr_t & va, addr_t & w, bool & p)
- {
- /* permission fault on page, 2nd level */
- static constexpr Fsr::access_t permission = 0b1111;
-
- switch (c.cpu_exception) {
-
- case Context::PREFETCH_ABORT:
- {
- /* check if fault was caused by a translation miss */
- Fsr::access_t const fs = Fsr::Fs::get(Ifsr::read());
- if (fs == permission) {
- w = 0;
- va = Ifar::read();
- p = true;
- return true;
- }
-
- if ((fs & 0b11100) != 0b100) return false;
-
- /* fetch fault data */
- w = 0;
- va = Ifar::read();
- p = false;
- return true;
- }
-
- case Context::DATA_ABORT:
- {
- /* check if fault was caused by translation miss */
- Fsr::access_t const fs = Fsr::Fs::get(Dfsr::read());
- if ((fs != permission) && (fs & 0b11100) != 0b100)
- return false;
-
- /* fetch fault data */
- Dfsr::access_t const dfsr = Dfsr::read();
- w = Dfsr::Wnr::get(dfsr);
- va = Dfar::read();
- p = false;
- return true;
- }
-
- default:
- return false;
- };
- };
-
+ static void mmu_fault_status(Fsr::access_t fsr,
+ Kernel::Thread_fault & fault);
/**
* Return kernel name of the executing CPU
diff --git a/repos/base-hw/src/core/spec/riscv/cpu.cc b/repos/base-hw/src/core/spec/riscv/cpu.cc
index dcde9c77b4..394d749913 100644
--- a/repos/base-hw/src/core/spec/riscv/cpu.cc
+++ b/repos/base-hw/src/core/spec/riscv/cpu.cc
@@ -67,3 +67,10 @@ void Genode::Cpu::switch_to(Mmu_context & context)
if (user /*&& sptbr != context.sptbr*/)
Sptbr::write(context.sptbr);
}
+
+
+void Genode::Cpu::mmu_fault(Context & c, Kernel::Thread_fault & f)
+{
+ f.addr = Genode::Cpu::Sbadaddr::read();
+ f.type = Kernel::Thread_fault::PAGE_MISSING;
+}
diff --git a/repos/base-hw/src/core/spec/riscv/cpu.h b/repos/base-hw/src/core/spec/riscv/cpu.h
index 301bf570e9..40667c5fcc 100644
--- a/repos/base-hw/src/core/spec/riscv/cpu.h
+++ b/repos/base-hw/src/core/spec/riscv/cpu.h
@@ -24,6 +24,8 @@
#include
#include
+namespace Kernel { struct Thread_fault; }
+
namespace Genode
{
/**
@@ -76,6 +78,7 @@ class Genode::Cpu : public Hw::Riscv_cpu
static void invalidate_tlb_by_pid(unsigned const pid) { sfence(); }
void switch_to(Mmu_context & context);
+ static void mmu_fault(Context & c, Kernel::Thread_fault & f);
static unsigned executing_id() { return 0; }
static unsigned primary_id() { return 0; }
diff --git a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc
index 239166db2e..774581edfe 100644
--- a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc
+++ b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc
@@ -45,16 +45,6 @@ void Thread::exception(Cpu&)
}
-void Thread::_mmu_exception()
-{
- _become_inactive(AWAITS_RESTART);
- _fault_pd = (addr_t)_pd->platform_pd();
- _fault_addr = Genode::Cpu::Sbadaddr::read();
-
- if (_pager) _pager->submit(1);
-}
-
-
void Thread::_call_update_pd()
{
Genode::Cpu::sfence();
diff --git a/repos/base-hw/src/core/spec/x86_64/cpu.cc b/repos/base-hw/src/core/spec/x86_64/cpu.cc
index 62b6acfeea..d31e440830 100644
--- a/repos/base-hw/src/core/spec/x86_64/cpu.cc
+++ b/repos/base-hw/src/core/spec/x86_64/cpu.cc
@@ -13,6 +13,7 @@
/* core includes */
#include
+#include
#include
extern int __tss;
@@ -56,3 +57,31 @@ void Genode::Cpu::Gdt::init()
uint64_t const base = start;
asm volatile ("lgdt %0" :: "m" (Pseudo_descriptor(limit, base)));
}
+
+
+void Genode::Cpu::mmu_fault(Context & regs, Kernel::Thread_fault & fault)
+{
+ using Fault = Kernel::Thread_fault::Type;
+
+ /*
+ * Intel manual: 6.15 EXCEPTION AND INTERRUPT REFERENCE
+ * Interrupt 14—Page-Fault Exception (#PF)
+ */
+ enum {
+ ERR_I = 1UL << 4,
+ ERR_R = 1UL << 3,
+ ERR_U = 1UL << 2,
+ ERR_W = 1UL << 1,
+ ERR_P = 1UL << 0,
+ };
+
+ auto fault_lambda = [] (addr_t err) {
+ if ((err & ERR_P) && (err & ERR_W)) return Fault::WRITE;
+ if ((err & ERR_P) && (err & ERR_I)) return Fault::EXEC;
+ if (err & ERR_P) return Fault::UNKNOWN;
+ else return Fault::PAGE_MISSING;
+ };
+
+ fault.addr = Genode::Cpu::Cr2::read();
+ fault.type = fault_lambda(regs.errcode);
+}
diff --git a/repos/base-hw/src/core/spec/x86_64/cpu.h b/repos/base-hw/src/core/spec/x86_64/cpu.h
index b9bce5b927..961374f1c3 100644
--- a/repos/base-hw/src/core/spec/x86_64/cpu.h
+++ b/repos/base-hw/src/core/spec/x86_64/cpu.h
@@ -29,6 +29,8 @@
/* core includes */
#include
+namespace Kernel { struct Thread_fault; }
+
namespace Genode {
class Cpu;
using sizet_arithm_t = __uint128_t;
@@ -124,6 +126,8 @@ class Genode::Cpu
* \param context next CPU context
*/
inline void switch_to(Context & context, Mmu_context &);
+
+ static void mmu_fault(Context & regs, Kernel::Thread_fault & fault);
};
diff --git a/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc b/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc
index 01fbeb626d..e7cff13d66 100644
--- a/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc
+++ b/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc
@@ -25,40 +25,6 @@ void Kernel::Thread::_call_update_data_region() { }
void Kernel::Thread::_call_update_instr_region() { }
-/*
- * Intel manual: 6.15 EXCEPTION AND INTERRUPT REFERENCE
- * Interrupt 14—Page-Fault Exception (#PF)
- */
-enum {
- ERR_I = 1UL << 4,
- ERR_R = 1UL << 3,
- ERR_U = 1UL << 2,
- ERR_W = 1UL << 1,
- ERR_P = 1UL << 0,
-};
-
-
-void Kernel::Thread::_mmu_exception()
-{
- _become_inactive(AWAITS_RESTART);
- _fault_pd = (addr_t)_pd->platform_pd();
- _fault_addr = Genode::Cpu::Cr2::read();
- _fault_writes = (regs->errcode & ERR_P) && (regs->errcode & ERR_W);
- _fault_exec = (regs->errcode & ERR_P) && (regs->errcode & ERR_I);
-
- /*
- * Core should never raise a page-fault. If this happens, print out an
- * error message with debug information.
- */
- if (_pd == Kernel::core_pd())
- Genode::error("page fault in core thread (", label(), "): "
- "ip=", Genode::Hex(regs->ip), " fault=", Genode::Hex(_fault_addr));
-
- if (_pager) _pager->submit(1);
- return;
-}
-
-
void Kernel::Thread::_call_update_pd() { }