mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-30 16:14:13 +00:00
hw: implement EPT page table
Implement a nested page table to use with x86 virtualization. Fixes #5218
This commit is contained in:
parent
4fc94deccb
commit
221d0c6c48
@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <cpu/vcpu_state_virtualization.h>
|
#include <cpu/vcpu_state_virtualization.h>
|
||||||
#include <hw/spec/x86_64/page_table.h>
|
|
||||||
#include <hw/spec/x86_64/x86_64.h>
|
#include <hw/spec/x86_64/x86_64.h>
|
||||||
|
#include <spec/x86_64/virtualization/ept.h>
|
||||||
#include <spec/x86_64/virtualization/svm.h>
|
#include <spec/x86_64/virtualization/svm.h>
|
||||||
#include <spec/x86_64/virtualization/vmx.h>
|
#include <spec/x86_64/virtualization/vmx.h>
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ using Genode::uint64_t;
|
|||||||
|
|
||||||
namespace Board {
|
namespace Board {
|
||||||
|
|
||||||
using Vm_page_table = Hw::Page_table;
|
using Vm_page_table = Hw::Ept;
|
||||||
using Vm_page_table_array =
|
using Vm_page_table_array =
|
||||||
Vm_page_table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
|
Vm_page_table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
|
||||||
struct Vcpu_context;
|
struct Vcpu_context;
|
||||||
|
199
repos/base-hw/src/core/spec/x86_64/virtualization/ept.h
Normal file
199
repos/base-hw/src/core/spec/x86_64/virtualization/ept.h
Normal file
@ -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 <cpu/page_table_allocator.h>
|
||||||
|
#include <page_table/page_table_base.h>
|
||||||
|
#include <util/register.h>
|
||||||
|
|
||||||
|
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 <unsigned _PAGE_SIZE_LOG2, unsigned _SIZE_LOG2>
|
||||||
|
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 <unsigned _PAGE_SIZE_LOG2>
|
||||||
|
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 <unsigned _PAGE_SIZE_LOG2>
|
||||||
|
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<Ept_page_table_entry_descriptor<SIZE_LOG2_4KB>>
|
||||||
|
{ } __attribute__((aligned(1 << ALIGNM_LOG2)));
|
||||||
|
|
||||||
|
struct Ept_pd
|
||||||
|
:
|
||||||
|
Genode::Page_directory<Ept_page_table,
|
||||||
|
Ept_page_directory_descriptor<SIZE_LOG2_2MB>>
|
||||||
|
{ } __attribute__((aligned(1 << ALIGNM_LOG2)));
|
||||||
|
|
||||||
|
struct Ept_pdpt
|
||||||
|
:
|
||||||
|
Genode::Page_directory<Ept_pd,
|
||||||
|
Ept_page_directory_descriptor<SIZE_LOG2_1GB>>
|
||||||
|
{ } __attribute__((aligned(1 << ALIGNM_LOG2)));
|
||||||
|
|
||||||
|
struct Pml4e_table
|
||||||
|
:
|
||||||
|
Genode::Pml4_table<Ept_pdpt,
|
||||||
|
Pml4e_table_descriptor<SIZE_LOG2_512GB, SIZE_LOG2_256TB>>
|
||||||
|
{ } __attribute__((aligned(1 << ALIGNM_LOG2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <unsigned _PAGE_SIZE_LOG2>
|
||||||
|
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 <unsigned _PAGE_SIZE_LOG2>
|
||||||
|
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<PAGE_SIZE_LOG2,
|
||||||
|
48 - PAGE_SIZE_LOG2> { };
|
||||||
|
|
||||||
|
|
||||||
|
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_ */
|
Loading…
x
Reference in New Issue
Block a user