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 85c8ca4a06..fe0c05f139 100644 --- a/repos/base-hw/src/core/spec/arm/cpu_support.h +++ b/repos/base-hw/src/core/spec/arm/cpu_support.h @@ -139,9 +139,10 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu * 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 w holds whether it's a write fault if call returns 1 + * \param p holds whether it's a permission fault if call returns 1 */ - bool in_fault(addr_t & va, addr_t & w) const + bool in_fault(addr_t & va, addr_t & w, bool & p) const { /* translation fault on section */ static constexpr Fsr::access_t section = 5; @@ -156,12 +157,21 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu { /* 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 = regs->ip; + p = true; + return true; + } + if (fs != section && fs != page) return false; /* fetch fault data */ w = 0; va = regs->ip; + p = false; return true; } case Context::DATA_ABORT: @@ -175,6 +185,7 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu Dfsr::access_t const dfsr = Dfsr::read(); w = Dfsr::Wnr::get(dfsr); va = Dfar::read(); + p = false; return true; } 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 95c495d1e2..65da234938 100644 --- a/repos/base-hw/src/core/spec/arm/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/arm/kernel/thread.cc @@ -59,7 +59,7 @@ void Thread::exception(unsigned const cpu) void Thread::_mmu_exception() { _become_inactive(AWAITS_RESTART); - if (in_fault(_fault_addr, _fault_writes)) { + if (in_fault(_fault_addr, _fault_writes, _fault_exec)) { _fault_pd = (addr_t)_pd->platform_pd(); /* @@ -73,14 +73,21 @@ void Thread::_mmu_exception() if (_pager) _pager->submit(1); return; } - bool da = regs->cpu_exception == Cpu::Context::DATA_ABORT; + + 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 ", - da ? "data abort" : "prefetch abort", " " + 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)); + "sp=", Genode::Hex(regs->sp), " " + "exception=", Genode::Hex(regs->cpu_exception)); } 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 3688a4b644..b52b7c22a0 100644 --- a/repos/base-hw/src/core/spec/cortex_a15/cpu.h +++ b/repos/base-hw/src/core/spec/cortex_a15/cpu.h @@ -195,9 +195,10 @@ class Genode::Cpu : public Arm_v7_cpu * 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 w holds whether it's a write fault if call returns 1 + * \param p holds whether it's a permission fault if call returns 1 */ - bool in_fault(addr_t & va, addr_t & w) const + bool in_fault(addr_t & va, addr_t & w, bool &p) const { /* permission fault on page, 2nd level */ static constexpr Fsr::access_t permission = 0b1111; @@ -208,11 +209,19 @@ class Genode::Cpu : public Arm_v7_cpu { /* 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 = regs->ip; + p = true; + return true; + } + if ((fs & 0b11100) != 0b100) return false; /* fetch fault data */ w = 0; va = regs->ip; + p = false; return true; } @@ -227,6 +236,7 @@ class Genode::Cpu : public Arm_v7_cpu Dfsr::access_t const dfsr = Dfsr::read(); w = Dfsr::Wnr::get(dfsr); va = Dfar::read(); + p = false; return true; } diff --git a/repos/base-hw/src/lib/hw/spec/arm/lpae.h b/repos/base-hw/src/lib/hw/spec/arm/lpae.h index 82082ccf60..6a9465fea1 100644 --- a/repos/base-hw/src/lib/hw/spec/arm/lpae.h +++ b/repos/base-hw/src/lib/hw/spec/arm/lpae.h @@ -240,6 +240,8 @@ class Hw::Long_translation_table struct Privileged_execute_never : Base::template Bitfield<53,1> { }; + struct Execute_never : Base::template Bitfield<54,1> { }; + static typename Descriptor::access_t create(Page_flags const &f, addr_t const pa) { @@ -250,7 +252,8 @@ class Hw::Long_translation_table Base::Shareability::OUTER_SHAREABLE) | Base::Output_address::masked(pa) | Base::Access_flag::bits(1) - | Descriptor::Valid::bits(1); + | Descriptor::Valid::bits(1) + | Execute_never::bits(!f.executable); } }; diff --git a/repos/base/run/rm_fault.run b/repos/base/run/rm_fault.run index 4f21376c78..932a2d0b00 100644 --- a/repos/base/run/rm_fault.run +++ b/repos/base/run/rm_fault.run @@ -8,6 +8,7 @@ if {[have_spec linux]} { proc non_executable_supported { } { if {[have_spec hw] && [have_spec x86_64]} { return true } + if {[have_spec hw] && [have_spec arm]} { return true } if {[have_spec nova] && [have_spec x86_64]} { return true } if {[have_spec foc] && [have_spec x86_64]} { return true } if {[have_spec foc] && [have_spec arm]} { return true }