From 4dd5e6b266fbb8a312af5db97a82a6a6491882c6 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Tue, 17 Oct 2017 11:36:10 +0200 Subject: [PATCH] hw: enable nx bit handling for arm --- repos/base-hw/src/core/spec/arm/cpu_support.h | 15 +++++++++++++-- repos/base-hw/src/core/spec/arm/kernel/thread.cc | 15 +++++++++++---- repos/base-hw/src/core/spec/cortex_a15/cpu.h | 14 ++++++++++++-- repos/base-hw/src/lib/hw/spec/arm/lpae.h | 5 ++++- repos/base/run/rm_fault.run | 1 + 5 files changed, 41 insertions(+), 9 deletions(-) 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 85c8ca4a0..fe0c05f13 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 95c495d1e..65da23493 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 3688a4b64..b52b7c22a 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 82082ccf6..6a9465fea 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 4f21376c7..932a2d0b0 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 }