From 221d0c6c48ee937b795ae858021e26a6e399dff8 Mon Sep 17 00:00:00 2001 From: Benjamin Lamowski Date: Wed, 15 May 2024 15:19:54 +0200 Subject: [PATCH] hw: implement EPT page table Implement a nested page table to use with x86 virtualization. Fixes #5218 --- .../core/spec/x86_64/virtualization/board.h | 4 +- .../src/core/spec/x86_64/virtualization/ept.h | 199 ++++++++++++++++++ 2 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 repos/base-hw/src/core/spec/x86_64/virtualization/ept.h diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/board.h b/repos/base-hw/src/core/spec/x86_64/virtualization/board.h index dadb7d8c60..bf23e46279 100644 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/board.h +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/board.h @@ -20,8 +20,8 @@ #include #include -#include #include +#include #include #include @@ -30,7 +30,7 @@ using Genode::uint64_t; namespace Board { - using Vm_page_table = Hw::Page_table; + using Vm_page_table = Hw::Ept; using Vm_page_table_array = Vm_page_table::Allocator::Array; struct Vcpu_context; diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/ept.h b/repos/base-hw/src/core/spec/x86_64/virtualization/ept.h new file mode 100644 index 0000000000..cb54126afe --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/ept.h @@ -0,0 +1,199 @@ +/* + * \brief EPT page table definitions + * \author Benjamin Lamowski + * \date 2024-04-23 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__PC__VIRTUALIZATION__EPT_H_ +#define _CORE__SPEC__PC__VIRTUALIZATION__EPT_H_ + +#include +#include +#include + +namespace Hw { + class Ept; + using namespace Genode; + + /* + * Common EPT Permissions + * + * For further details see Intel SDM Vol. 3C + * Table 29-2. Format of an EPT PML4 Entry (PML4E) that References an + * EPT Page-Directory-Pointer Table + */ + struct Ept_common_descriptor : Genode::Register<64> + { + struct R : Bitfield< 0,1> { }; /* Read */ + struct W : Bitfield< 1,1> { }; /* Write */ + struct X : Bitfield< 2,1> { }; /* Execute */ + struct A : Bitfield< 8,1> { }; /* Accessed */ + struct D : Bitfield< 9,1> { }; /* Dirty (ignored in tables) */ + struct UX : Bitfield<10,1> { }; /* User-mode execute access */ + + static bool present(access_t const v) { return R::get(v); } + + static access_t create(Page_flags const &flags) + { + return R::bits(1) + | W::bits(flags.writeable) + | UX::bits(!flags.privileged) + | X::bits(flags.executable); + } + + /** + * Return descriptor value with cleared accessed and dirty flags. These + * flags can be set by the MMU. + */ + static access_t clear_mmu_flags(access_t value) + { + A::clear(value); + D::clear(value); + return value; + } + }; + + + + template + struct Pml4e_table_descriptor : Ept_common_descriptor + { + static constexpr size_t PAGE_SIZE_LOG2 = _PAGE_SIZE_LOG2; + static constexpr size_t SIZE_LOG2 = _SIZE_LOG2; + + struct Pa : Bitfield<12, SIZE_LOG2> { }; /* Physical address */ + + static access_t create(addr_t const pa) + { + /* XXX: Set memory type depending on active PAT */ + static Page_flags flags { RW, EXEC, USER, NO_GLOBAL, + RAM, Genode::CACHED }; + return Ept_common_descriptor::create(flags) | Pa::masked(pa); + } + }; + + struct Ept_page_directory_base_descriptor : Ept_common_descriptor + { + using Common = Ept_common_descriptor; + + struct Ps : Common::template Bitfield<7, 1> { }; /* Page size */ + + static bool maps_page(access_t const v) { return Ps::get(v); } + }; + + + template + struct Ept_page_directory_descriptor : Ept_page_directory_base_descriptor + { + static constexpr size_t PAGE_SIZE_LOG2 = _PAGE_SIZE_LOG2; + + struct Page; + struct Table; + }; + + + /* Table 29-7. Format of an EPT Page-Table Entry that Maps a 4-KByte Page */ + template + struct Ept_page_table_entry_descriptor : Ept_common_descriptor + { + using Common = Ept_common_descriptor; + + static constexpr size_t PAGE_SIZE_LOG2 = _PAGE_SIZE_LOG2; + + struct Type : Bitfield< 3, 3> { }; /* Ept memory type, see Section 29.3.7 */ + struct Pat : Bitfield< 6, 1> { }; /* Ignore PAT memory type, see 29.3.7 */ + struct Pa : Bitfield<12,36> { }; /* Physical address */ + + static access_t create(Page_flags const &flags, addr_t const pa) + { + return Common::create(flags) | Pa::masked(pa) | Type::bits(6) | Pat::bits(1); + } + }; + + struct Ept_page_table + : + Genode::Final_table> + { } __attribute__((aligned(1 << ALIGNM_LOG2))); + + struct Ept_pd + : + Genode::Page_directory> + { } __attribute__((aligned(1 << ALIGNM_LOG2))); + + struct Ept_pdpt + : + Genode::Page_directory> + { } __attribute__((aligned(1 << ALIGNM_LOG2))); + + struct Pml4e_table + : + Genode::Pml4_table> + { } __attribute__((aligned(1 << ALIGNM_LOG2))); +} + + +template +struct Hw::Ept_page_directory_descriptor<_PAGE_SIZE_LOG2>::Table + : Ept_page_directory_base_descriptor +{ + using Base = Ept_page_directory_base_descriptor; + + /** + * Physical address + */ + struct Pa : Base::template Bitfield<12, 36> { }; + + static typename Base::access_t create(addr_t const pa) + { + static Page_flags flags { RW, EXEC, USER, NO_GLOBAL, + RAM, Genode::CACHED }; + return Base::create(flags) | Pa::masked(pa); + } +}; + + +template +struct Hw::Ept_page_directory_descriptor<_PAGE_SIZE_LOG2>::Page + : Ept_page_directory_base_descriptor +{ + using Base = Ept_page_directory_base_descriptor; + + struct Type : Bitfield< 3,3> { }; /* Ept memory type, see Section 29.3.7 */ + struct Pat : Bitfield< 6,1> { }; /* Ignore PAT memory type, see 29.3.7 */ + /** + * Physical address + */ + struct Pa : Base::template Bitfield { }; + + + static typename Base::access_t create(Page_flags const &flags, + addr_t const pa) + { + return Base::create(flags) + | Base::Ps::bits(1) + | Pa::masked(pa) + | Type::bits(6) + | Pat::bits(1); + + } +}; + +class Hw::Ept : public Pml4e_table +{ + public: + using Allocator = Genode::Page_table_allocator<1UL << SIZE_LOG2_4KB>; + using Pml4e_table::Pml4e_table; +}; + +#endif /* _CORE__SPEC__PC__VIRTUALIZATION__EPT_H_ */