mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-29 23:54:14 +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/vcpu_state_virtualization.h>
|
||||
#include <hw/spec/x86_64/page_table.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/vmx.h>
|
||||
|
||||
@ -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<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
|
||||
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