hw: do not change x86 paging attributes on fly

Instead of changing the attributes (e.g., Xd bit) of the top-level page-tables,
set them to allow everything. Only leafs of the paging hierarchy are set
according to the paging attributes given by core. Otherwise, top-level page-
table attributes are changed during lifetime, which requires a TLB flush
operation (not intended in the semantic of the kernel/core).
This led to problems when using the non-executable features introduced by
issue #1723 in the recent past.
This commit is contained in:
Stefan Kalkowski 2017-11-08 15:17:15 +01:00 committed by Christian Helmuth
parent c365918b82
commit d164cbac8c
5 changed files with 15 additions and 38 deletions

View File

@ -20,8 +20,6 @@
#include <hw/spec/x86_64/cpu.h> #include <hw/spec/x86_64/cpu.h>
#include <hw/spec/x86_64/x86_64.h> #include <hw/spec/x86_64/x86_64.h>
void Hw::Pml4_table::_invalidate_range(addr_t vo, size_t size) {}
namespace Bootstrap { namespace Bootstrap {
struct Pic {}; struct Pic {};
using Cpu = Hw::X86_64_cpu; using Cpu = Hw::X86_64_cpu;

View File

@ -76,10 +76,10 @@ void Genode::Cpu::mmu_fault(Context & regs, Kernel::Thread_fault & fault)
}; };
auto fault_lambda = [] (addr_t err) { auto fault_lambda = [] (addr_t err) {
if ((err & ERR_P) && (err & ERR_W)) return Fault::WRITE; if (!(err & ERR_P)) return Fault::PAGE_MISSING;
if ((err & ERR_P) && (err & ERR_I)) return Fault::EXEC; if (err & ERR_W) return Fault::WRITE;
if (err & ERR_P) return Fault::UNKNOWN; if (err & ERR_I) return Fault::EXEC;
else return Fault::PAGE_MISSING; else return Fault::UNKNOWN;
}; };
fault.addr = Genode::Cpu::Cr2::read(); fault.addr = Genode::Cpu::Cr2::read();

View File

@ -25,7 +25,9 @@ void Kernel::Thread::_call_update_data_region() { }
void Kernel::Thread::_call_update_instr_region() { } void Kernel::Thread::_call_update_instr_region() { }
void Kernel::Thread::_call_update_pd() { } void Kernel::Thread::_call_update_pd() {
Genode::Cpu::Cr3::write(Genode::Cpu::Cr3::read());
}
extern void * __tss_client_context_ptr; extern void * __tss_client_context_ptr;

View File

@ -15,13 +15,5 @@
#define _CORE__SPEC__X86_64__TRANSLATION_TABLE_H_ #define _CORE__SPEC__X86_64__TRANSLATION_TABLE_H_
#include <hw/spec/x86_64/page_table.h> #include <hw/spec/x86_64/page_table.h>
#include <cpu.h>
void Hw::Pml4_table::_invalidate_range(addr_t vo, size_t size)
{
/* FIXME: do not necessarily flush the whole TLB */
Genode::Cpu::Cr3::write(Genode::Cpu::Cr3::read());
}
#endif /* _CORE__SPEC__X86_64__TRANSLATION_TABLE_H_ */ #endif /* _CORE__SPEC__X86_64__TRANSLATION_TABLE_H_ */

View File

@ -100,17 +100,6 @@ namespace Hw
D::clear(value); D::clear(value);
return value; return value;
} }
/**
* Merge access rights of descriptor with given flags.
*/
static void merge_access_rights(access_t &desc,
Page_flags const &flags)
{
Rw::set(desc, Rw::get(desc) | flags.writeable);
Us::set(desc, Us::get(desc) | !flags.privileged);
Xd::set(desc, Xd::get(desc) & !flags.executable);
}
}; };
} }
@ -341,10 +330,11 @@ class Hw::Page_directory
struct Mt : Base::template Bitset_2<Base::Pwt, struct Mt : Base::template Bitset_2<Base::Pwt,
Base::Pcd> { }; Base::Pcd> { };
static typename Base::access_t create(Page_flags const &flags, static typename Base::access_t create(addr_t const pa)
addr_t const pa)
{ {
/* XXX: Set memory type depending on active PAT */ /* XXX: Set memory type depending on active PAT */
static Page_flags flags { RW, EXEC, USER, NO_GLOBAL,
RAM, Genode::CACHED };
return Base::create(flags) | Pa::masked(pa); return Base::create(flags) | Pa::masked(pa);
} }
}; };
@ -388,12 +378,10 @@ class Hw::Page_directory
/* create and link next level table */ /* create and link next level table */
ENTRY & table = alloc.construct<ENTRY>(); ENTRY & table = alloc.construct<ENTRY>();
desc = (access_t) Td::create(flags, alloc.phys_addr(table)); desc = (access_t) Td::create(alloc.phys_addr(table));
} else if (Descriptor::maps_page(desc)) { } else if (Descriptor::maps_page(desc)) {
throw Double_insertion(); throw Double_insertion();
} else {
Descriptor::merge_access_rights(desc, flags);
} }
/* insert translation */ /* insert translation */
@ -528,9 +516,11 @@ class Hw::Pml4_table
struct Pa : Bitfield<12, SIZE_LOG2> { }; /* physical address */ struct Pa : Bitfield<12, SIZE_LOG2> { }; /* physical address */
struct Mt : Genode::Bitset_2<Pwt, Pcd> { }; /* memory type */ struct Mt : Genode::Bitset_2<Pwt, Pcd> { }; /* memory type */
static access_t create(Page_flags const &flags, addr_t const pa) static access_t create(addr_t const pa)
{ {
/* XXX: Set memory type depending on active PAT */ /* XXX: Set memory type depending on active PAT */
static Page_flags flags { RW, EXEC, USER, NO_GLOBAL,
RAM, Genode::CACHED };
return Common_descriptor::create(flags) | Pa::masked(pa); return Common_descriptor::create(flags) | Pa::masked(pa);
} }
}; };
@ -556,9 +546,7 @@ class Hw::Pml4_table
if (!Descriptor::present(desc)) { if (!Descriptor::present(desc)) {
/* create and link next level table */ /* create and link next level table */
ENTRY & table = alloc.construct<ENTRY>(); ENTRY & table = alloc.construct<ENTRY>();
desc = Descriptor::create(flags, alloc.phys_addr(table)); desc = Descriptor::create(alloc.phys_addr(table));
} else {
Descriptor::merge_access_rights(desc, flags);
} }
/* insert translation */ /* insert translation */
@ -622,8 +610,6 @@ class Hw::Pml4_table
/ (1UL << alignment); / (1UL << alignment);
} }
inline void _invalidate_range(addr_t vo, size_t size);
public: public:
static constexpr size_t MIN_PAGE_SIZE_LOG2 = SIZE_LOG2_4KB; static constexpr size_t MIN_PAGE_SIZE_LOG2 = SIZE_LOG2_4KB;
@ -680,7 +666,6 @@ class Hw::Pml4_table
void remove_translation(addr_t vo, size_t size, Allocator & alloc) void remove_translation(addr_t vo, size_t size, Allocator & alloc)
{ {
_range_op(vo, 0, size, Remove_func(alloc)); _range_op(vo, 0, size, Remove_func(alloc));
_invalidate_range(vo, size);
} }
} __attribute__((aligned(1 << ALIGNM_LOG2))); } __attribute__((aligned(1 << ALIGNM_LOG2)));