mirror of
https://github.com/wbenny/hvpp
synced 2026-08-17 04:26:04 -04:00
memory manager refactoring
* make ia32::byte_offset return uint64_t instead of uint32_t * move ia32::mapping_t to mm::memory_mapper * move ia32::physical_memory_descriptor to mm::physical_memory_descriptor * move ia32::mtrr to mm::mtrr_descriptor * remove useless pa_from_va (with cr3) function; the reason is that physical address for each active CR3 is actually always same
This commit is contained in:
parent
188479c084
commit
9608bc71c4
17 changed files with 541 additions and 492 deletions
|
|
@ -104,6 +104,9 @@
|
|||
<ClCompile Include="hvpp\hvpp.cpp" />
|
||||
<ClCompile Include="hvpp\hypervisor.cpp" />
|
||||
<ClCompile Include="hvpp\ia32\memory.cpp" />
|
||||
<ClCompile Include="hvpp\lib\mm\memory_mapper.cpp" />
|
||||
<ClCompile Include="hvpp\lib\mm\win32\memory_mapper.cpp" />
|
||||
<ClCompile Include="hvpp\lib\mm\win32\physical_memory_descriptor.cpp" />
|
||||
<ClCompile Include="hvpp\vcpu.cpp" />
|
||||
<ClCompile Include="hvpp\vmexit.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)/$(RelativeDir)/%(Filename)%(Extension).obj</ObjectFileName>
|
||||
|
|
@ -139,6 +142,9 @@
|
|||
<ClInclude Include="hvpp\config.h" />
|
||||
<ClInclude Include="hvpp\ept.h" />
|
||||
<ClInclude Include="hvpp\hypervisor.h" />
|
||||
<ClInclude Include="hvpp\lib\mm\memory_mapper.h" />
|
||||
<ClInclude Include="hvpp\lib\mm\mtrr_descriptor.h" />
|
||||
<ClInclude Include="hvpp\lib\mm\physical_memory_descriptor.h" />
|
||||
<ClInclude Include="hvpp\vcpu.h" />
|
||||
<ClInclude Include="hvpp\vmexit.h" />
|
||||
<ClInclude Include="hvpp\vmexit\vmexit_c_wrapper.h" />
|
||||
|
|
@ -160,7 +166,6 @@
|
|||
<ClInclude Include="hvpp\ia32\msr\arch.h" />
|
||||
<ClInclude Include="hvpp\ia32\msr\mtrr.h" />
|
||||
<ClInclude Include="hvpp\ia32\msr\vmx.h" />
|
||||
<ClInclude Include="hvpp\ia32\mtrr.h" />
|
||||
<ClInclude Include="hvpp\ia32\paging.h" />
|
||||
<ClInclude Include="hvpp\ia32\vmx.h" />
|
||||
<ClInclude Include="hvpp\ia32\vmx\exception_bitmap.h" />
|
||||
|
|
|
|||
|
|
@ -67,6 +67,15 @@
|
|||
<Filter Include="Header Files\hvpp\lib\vmware">
|
||||
<UniqueIdentifier>{b199f4fb-0f50-4a62-b44d-f80541e9b91a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\hvpp\lib\mm">
|
||||
<UniqueIdentifier>{8e3b0296-08e1-46b7-83f6-555347ca5fe9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\hvpp\lib\mm">
|
||||
<UniqueIdentifier>{48924d45-28d4-4be4-96bc-ef93b3095d01}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\hvpp\lib\mm\win32">
|
||||
<UniqueIdentifier>{c53a048f-d7da-48c6-88a5-fa1ed9bfc1ed}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="hvpp\lib\mm.cpp">
|
||||
|
|
@ -138,6 +147,15 @@
|
|||
<ClCompile Include="hvpp\ia32\memory.cpp">
|
||||
<Filter>Source Files\hvpp\ia32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hvpp\lib\mm\memory_mapper.cpp">
|
||||
<Filter>Source Files\hvpp\lib\mm</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hvpp\lib\mm\win32\memory_mapper.cpp">
|
||||
<Filter>Source Files\hvpp\lib\mm\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hvpp\lib\mm\win32\physical_memory_descriptor.cpp">
|
||||
<Filter>Source Files\hvpp\lib\mm\win32</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="hvpp\lib\bitmap.h">
|
||||
|
|
@ -158,9 +176,6 @@
|
|||
<ClInclude Include="hvpp\ia32\msr.h">
|
||||
<Filter>Header Files\hvpp\ia32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hvpp\ia32\mtrr.h">
|
||||
<Filter>Header Files\hvpp\ia32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hvpp\ia32\vmx.h">
|
||||
<Filter>Header Files\hvpp\ia32</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -302,6 +317,15 @@
|
|||
<ClInclude Include="hvpp\interrupt.h">
|
||||
<Filter>Header Files\hvpp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hvpp\lib\mm\memory_mapper.h">
|
||||
<Filter>Header Files\hvpp\lib\mm</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hvpp\lib\mm\mtrr_descriptor.h">
|
||||
<Filter>Header Files\hvpp\lib\mm</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hvpp\lib\mm\physical_memory_descriptor.h">
|
||||
<Filter>Header Files\hvpp\lib\mm</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="hvpp\ia32\context.asm">
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ ept_t::ept_t() noexcept
|
|||
// Initialize EPT pointer.
|
||||
// It's not really JUST pointer, but Intel Manual calls it this way.
|
||||
//
|
||||
eptptr_.memory_type = static_cast<uint64_t>(mm::mtrr().type(empl4_pa));
|
||||
eptptr_.memory_type = static_cast<uint64_t>(mm::mtrr_descriptor().type(empl4_pa));
|
||||
eptptr_.page_walk_length = ept_ptr_t::page_walk_length_4;
|
||||
eptptr_.page_frame_number = empl4_pa.pfn();
|
||||
}
|
||||
|
|
@ -399,7 +399,7 @@ epte_t* ept_t::map_pdpt(pa_t guest_pa, pa_t host_pa, epte_t* pdpt,
|
|||
|
||||
if (level == pml::pdpt)
|
||||
{
|
||||
pdpte->update(host_pa, mm::mtrr().type(guest_pa), true, access);
|
||||
pdpte->update(host_pa, mm::mtrr_descriptor().type(guest_pa), true, access);
|
||||
return pdpte;
|
||||
}
|
||||
|
||||
|
|
@ -414,7 +414,7 @@ epte_t* ept_t::map_pd(pa_t guest_pa, pa_t host_pa, epte_t* pd,
|
|||
|
||||
if (level == pml::pd)
|
||||
{
|
||||
pde->update(host_pa, mm::mtrr().type(guest_pa), true, access);
|
||||
pde->update(host_pa, mm::mtrr_descriptor().type(guest_pa), true, access);
|
||||
return pde;
|
||||
}
|
||||
|
||||
|
|
@ -430,7 +430,7 @@ epte_t* ept_t::map_pt(pa_t guest_pa, pa_t host_pa, epte_t* pt,
|
|||
(void)(level);
|
||||
hvpp_assert(level == pml::pt);
|
||||
{
|
||||
pte->update(host_pa, mm::mtrr().type(guest_pa), access);
|
||||
pte->update(host_pa, mm::mtrr_descriptor().type(guest_pa), access);
|
||||
return pte;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,28 +2,14 @@
|
|||
|
||||
namespace ia32 {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// namespace detail
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail
|
||||
{
|
||||
uint64_t pa_from_va(const void* va, cr3_t cr3) noexcept
|
||||
{
|
||||
return pa_t::from_pfn(
|
||||
va_t(va).pt_entry(cr3)->page_frame_number
|
||||
).value() + byte_offset(va);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// va_t
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pe_t* va_t::pt_entry(cr3_t cr3 /*= read<cr3_t>()*/, pml level /*= pml::pt*/) const noexcept
|
||||
pe_t* va_t::pt_entry(pml level /*= pml::pt*/) const noexcept
|
||||
{
|
||||
const auto pml4e = &reinterpret_cast<pe_t*>(
|
||||
pa_t::from_pfn(cr3.page_frame_number).va()
|
||||
pa_t::from_pfn(read<cr3_t>().page_frame_number).va()
|
||||
)[index(pml::pml4)];
|
||||
|
||||
if (!pml4e->present || level == pml::pml4)
|
||||
|
|
@ -56,107 +42,4 @@ pe_t* va_t::pt_entry(cr3_t cr3 /*= read<cr3_t>()*/, pml level /*= pml::pt*/) con
|
|||
return pt;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// mapping_t
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
mapping_t::mapping_t() noexcept
|
||||
{
|
||||
//
|
||||
// Reserve 1 page of the virtual address space.
|
||||
// Note that the memory is NOT allocated, just reserved.
|
||||
//
|
||||
va_ = detail::mapping_allocate(page_size);
|
||||
|
||||
//
|
||||
// Get page-table entry for the virtual address.
|
||||
//
|
||||
pte_ = va_t(va_).pt_entry();
|
||||
}
|
||||
|
||||
mapping_t::~mapping_t() noexcept
|
||||
{
|
||||
//
|
||||
// Release the virtual address space.
|
||||
//
|
||||
detail::mapping_free(va_);
|
||||
}
|
||||
|
||||
void* mapping_t::map(pa_t pa) noexcept
|
||||
{
|
||||
//
|
||||
// Make this entry present & writable.
|
||||
//
|
||||
pte_->present = true;
|
||||
pte_->write = true;
|
||||
|
||||
//
|
||||
// Do not flush this page from the TLB on CR3 switch.
|
||||
//
|
||||
pte_->global = true;
|
||||
|
||||
//
|
||||
// Set the PFN of this PTE to the PFN of the
|
||||
// provided physical address.
|
||||
//
|
||||
pte_->page_frame_number = pa.pfn();
|
||||
|
||||
//
|
||||
// Finally, invalidate the cache for the virtual address.
|
||||
//
|
||||
ia32_asm_inv_page(va_);
|
||||
|
||||
return reinterpret_cast<uint8_t*>(va_) + byte_offset(pa.value());
|
||||
}
|
||||
|
||||
void mapping_t::unmap() noexcept
|
||||
{
|
||||
pte_->flags = 0;
|
||||
}
|
||||
|
||||
void mapping_t::read(pa_t pa, void* buffer, size_t size) noexcept
|
||||
{
|
||||
read_write(pa, buffer, size, false);
|
||||
}
|
||||
|
||||
void mapping_t::write(pa_t pa, const void* buffer, size_t size) noexcept
|
||||
{
|
||||
read_write(pa, const_cast<void*>(buffer), size, true);
|
||||
}
|
||||
|
||||
void mapping_t::read_write(pa_t pa, void* buffer, size_t size, bool write) noexcept
|
||||
{
|
||||
uint8_t* byte_buffer = reinterpret_cast<uint8_t*>(buffer);
|
||||
|
||||
//
|
||||
// Map each page of the physical memory to the reserved
|
||||
// virtual address and then copy.
|
||||
//
|
||||
while (size != 0)
|
||||
{
|
||||
void* va = map(pa);
|
||||
size_t bytes_to_copy = page_size - byte_offset(va);
|
||||
|
||||
if (bytes_to_copy > size)
|
||||
{
|
||||
bytes_to_copy = size;
|
||||
}
|
||||
|
||||
if (write)
|
||||
{
|
||||
memcpy(va, byte_buffer, bytes_to_copy);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(byte_buffer, va, bytes_to_copy);
|
||||
}
|
||||
|
||||
byte_buffer += bytes_to_copy;
|
||||
pa += bytes_to_copy;
|
||||
size -= bytes_to_copy;
|
||||
|
||||
unmap();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#pragma once
|
||||
#include "hvpp/lib/log.h"
|
||||
#include "paging.h"
|
||||
#include "arch.h"
|
||||
|
||||
#include <cstddef> // std::byte
|
||||
#include <cstdint>
|
||||
#include <cinttypes>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
|
||||
|
|
@ -26,18 +26,13 @@ static constexpr auto page_mask = page_size - 1;
|
|||
|
||||
class pa_t;
|
||||
class va_t;
|
||||
class mapping_t;
|
||||
class memory_range;
|
||||
class physical_memory_range;
|
||||
class physical_memory_descriptor;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
uint64_t pa_from_va(const void* va) noexcept;
|
||||
uint64_t pa_from_va(const void* va, cr3_t cr3) noexcept;
|
||||
void* va_from_pa(uint64_t pa) noexcept;
|
||||
void* mapping_allocate(size_t size) noexcept;
|
||||
void mapping_free(void* va) noexcept;
|
||||
void check_physical_memory(physical_memory_range* range_list, int range_list_size, int& count) noexcept;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -53,8 +48,6 @@ class pa_t
|
|||
|
||||
static pa_t from_pfn(uint64_t pfn) noexcept { return pa_t(pfn << page_shift); }
|
||||
static pa_t from_va(const void* va) noexcept { return pa_t(detail::pa_from_va(va)); }
|
||||
static pa_t from_va(const void* va,
|
||||
cr3_t cr3) noexcept { return pa_t(detail::pa_from_va(va, cr3)); }
|
||||
|
||||
//
|
||||
// ctor/operators
|
||||
|
|
@ -161,40 +154,12 @@ class va_t
|
|||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
pe_t* pt_entry(cr3_t cr3 = read<cr3_t>(), pml level = pml::pt) const noexcept;
|
||||
pe_t* pt_entry(pml level = pml::pt) const noexcept;
|
||||
|
||||
private:
|
||||
uint64_t value_;
|
||||
};
|
||||
|
||||
//
|
||||
// Mapping
|
||||
//
|
||||
|
||||
class mapping_t
|
||||
{
|
||||
public:
|
||||
mapping_t() noexcept;
|
||||
~mapping_t() noexcept;
|
||||
|
||||
mapping_t(const mapping_t& other) noexcept = delete;
|
||||
mapping_t(mapping_t&& other) noexcept = delete;
|
||||
mapping_t& operator=(const mapping_t& other) noexcept = delete;
|
||||
mapping_t& operator=(mapping_t&& other) noexcept = delete;
|
||||
|
||||
void* map(pa_t pa) noexcept;
|
||||
void unmap() noexcept;
|
||||
|
||||
void read(pa_t pa, void* buffer, size_t size) noexcept;
|
||||
void write(pa_t pa, const void* buffer, size_t size) noexcept;
|
||||
|
||||
private:
|
||||
void read_write(pa_t pa, void* buffer, size_t size, bool write) noexcept;
|
||||
|
||||
void* va_;
|
||||
pe_t* pte_;
|
||||
};
|
||||
|
||||
//
|
||||
// Memory range
|
||||
//
|
||||
|
|
@ -303,55 +268,6 @@ class physical_memory_range
|
|||
pa_t end_;
|
||||
};
|
||||
|
||||
//
|
||||
// Class for receiving physical memory ranges which are backed up
|
||||
// by actual physical memory.
|
||||
//
|
||||
|
||||
class physical_memory_descriptor
|
||||
{
|
||||
public:
|
||||
static constexpr int max_range_count = 32;
|
||||
|
||||
physical_memory_descriptor() noexcept { check_physical_memory(); }
|
||||
physical_memory_descriptor(const physical_memory_descriptor& other) noexcept = delete;
|
||||
physical_memory_descriptor(physical_memory_descriptor&& other) noexcept = delete;
|
||||
physical_memory_descriptor& operator=(const physical_memory_descriptor& other) noexcept = delete;
|
||||
physical_memory_descriptor& operator=(physical_memory_descriptor&& other) noexcept = delete;
|
||||
|
||||
auto begin() const noexcept { return const_cast<const physical_memory_range*>(&range_[0]); }
|
||||
auto end() const noexcept { return const_cast<const physical_memory_range*>(&range_[count_]); }
|
||||
auto size() const noexcept { return static_cast<size_t>(count_); }
|
||||
|
||||
auto total_physical_memory_size() const noexcept
|
||||
{
|
||||
return std::accumulate(begin(), end(), size_t(0), [](auto sum, auto next) {
|
||||
return sum + next.size();
|
||||
});
|
||||
}
|
||||
|
||||
void dump() const noexcept
|
||||
{
|
||||
hvpp_info("Physical memory ranges (%i)", count_);
|
||||
|
||||
for (int i = 0; i < count_; ++i)
|
||||
{
|
||||
hvpp_info(
|
||||
" %3i) [%p - %p] (%8u kb)", i,
|
||||
range_[i].begin().value(),
|
||||
range_[i].end().value(),
|
||||
range_[i].size() / 1024);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void check_physical_memory() noexcept
|
||||
{ detail::check_physical_memory(range_, max_range_count, count_); }
|
||||
|
||||
physical_memory_range range_[max_range_count];
|
||||
int count_ = 0;
|
||||
};
|
||||
|
||||
constexpr inline const char* memory_type_to_string(memory_type type) noexcept
|
||||
{
|
||||
switch (type)
|
||||
|
|
|
|||
|
|
@ -1,209 +0,0 @@
|
|||
#pragma once
|
||||
#include "memory.h"
|
||||
#include "msr.h"
|
||||
#include "msr/mtrr.h"
|
||||
#include "../lib/typelist.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cinttypes>
|
||||
|
||||
namespace ia32 {
|
||||
|
||||
struct mtrr_range
|
||||
{
|
||||
physical_memory_range range;
|
||||
memory_type type;
|
||||
};
|
||||
|
||||
class mtrr
|
||||
{
|
||||
public:
|
||||
static constexpr int fixed_count = (1 + 2 + 8) * 8;
|
||||
static constexpr int max_variable_count = 255;
|
||||
|
||||
mtrr() noexcept { check_fixed(); check_variable(); }
|
||||
mtrr(const mtrr& other) noexcept = delete;
|
||||
mtrr(mtrr&& other) noexcept = delete;
|
||||
mtrr& operator=(const mtrr& other) noexcept = delete;
|
||||
mtrr& operator=(mtrr&& other) noexcept = delete;
|
||||
|
||||
const mtrr_range* begin() const noexcept { return &mtrr_[0]; }
|
||||
const mtrr_range* end() const noexcept { return &mtrr_[size()]; }
|
||||
size_t size() const noexcept { return fixed_count + variable_count_; }
|
||||
|
||||
memory_type type(pa_t pa) const noexcept
|
||||
{
|
||||
//
|
||||
// If the MTRRs are not enabled (by setting the E flag in the
|
||||
// IA32_MTRR_DEF_TYPE MSR), then all memory accesses are of the
|
||||
// UC memory type. If the MTRRs are enabled, then the memory
|
||||
// type used for a memory access is determined as follows:
|
||||
//
|
||||
// 1. If the physical address falls within the first 1 MByte of
|
||||
// physical memory and fixed MTRRs are enabled, the processor
|
||||
// uses the memory type stored for the appropriate fixed-range
|
||||
// MTRR.
|
||||
//
|
||||
// 2. Otherwise, the processor attempts to match the physical
|
||||
// address with a memory type set by the variable-range MTRRs:
|
||||
// - If one variable memory range matches, the processor uses
|
||||
// the memory type stored in the IA32_MTRR_PHYSBASEn register
|
||||
// for that range.
|
||||
//
|
||||
// - If two or more variable memory ranges match and the memory
|
||||
// types are identical, then that memory type is used.
|
||||
//
|
||||
// - If two or more variable memory ranges match and one of the
|
||||
// memory types is UC, the UC memory type is used.
|
||||
//
|
||||
// - If two or more variable memory ranges match and the memory
|
||||
// types are WT and WB, the WT memory type is used.
|
||||
//
|
||||
// - For overlaps not defined by the above rules, processor
|
||||
// behavior is undefined.
|
||||
//
|
||||
// 3. If no fixed or variable memory range matches, the processor uses
|
||||
// the default memory type.
|
||||
//
|
||||
// (ref: Vol3A[11.11.4.1(MTRR Precedences)]
|
||||
//
|
||||
memory_type result = memory_type::invalid;
|
||||
|
||||
for (auto mtrr_item : *this)
|
||||
{
|
||||
if (mtrr_item.range.contains(pa))
|
||||
{
|
||||
if (is_fixed(mtrr_item) || mtrr_item.type == memory_type::uncacheable)
|
||||
{
|
||||
result = mtrr_item.type;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( result == memory_type::write_back &&
|
||||
(result == memory_type::write_through ||
|
||||
mtrr_item.type == memory_type::write_through))
|
||||
{
|
||||
result = memory_type::write_through;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result == memory_type::invalid)
|
||||
{
|
||||
result = default_memory_type_;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void dump() const noexcept
|
||||
{
|
||||
auto dump_range = [](int i, const mtrr_range& mtrr) noexcept
|
||||
{
|
||||
hvpp_info(
|
||||
" %3i) %s [%016" PRIx64 " - %016" PRIx64 "] (%8u kb)", i,
|
||||
memory_type_to_string(mtrr.type),
|
||||
mtrr.range.begin().value(),
|
||||
mtrr.range.end().value(),
|
||||
mtrr.range.size() / 1024);
|
||||
};
|
||||
|
||||
hvpp_info("Fixed MTRR ranges (%i)", fixed_count);
|
||||
for (int i = 0; i < fixed_count; ++i)
|
||||
{
|
||||
dump_range(i, fixed_[i]);
|
||||
}
|
||||
|
||||
hvpp_info("Variable MTRR ranges (%i)", variable_count_);
|
||||
for (int i = 0; i < variable_count_; ++i)
|
||||
{
|
||||
dump_range(i, variable_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void check_fixed() noexcept
|
||||
{
|
||||
auto mtrr_default = msr::read<msr::mtrr_def_type_t>();
|
||||
auto mtrr_capabilities = msr::read<msr::mtrr_capabilities_t>();
|
||||
|
||||
default_memory_type_ = static_cast<memory_type>(mtrr_default.default_memory_type);
|
||||
|
||||
if (mtrr_capabilities.fixed_range_supported && mtrr_default.fixed_range_mtrr_enable)
|
||||
{
|
||||
using mtrr_fix_64k_list_t = type_list<msr::mtrr_fix_64k_00000_t>;
|
||||
using mtrr_fix_16k_list_t = type_list<msr::mtrr_fix_16k_80000_t, msr::mtrr_fix_16k_a0000_t>;
|
||||
using mtrr_fix_4k_list_t = type_list<msr::mtrr_fix_4k_c0000_t, msr::mtrr_fix_4k_c8000_t,
|
||||
msr::mtrr_fix_4k_d0000_t, msr::mtrr_fix_4k_d8000_t,
|
||||
msr::mtrr_fix_4k_e0000_t, msr::mtrr_fix_4k_e8000_t,
|
||||
msr::mtrr_fix_4k_f0000_t, msr::mtrr_fix_4k_f8000_t>;
|
||||
using mtrr_fix_list_t = type_list<mtrr_fix_64k_list_t, mtrr_fix_16k_list_t, mtrr_fix_4k_list_t>;
|
||||
|
||||
for_each_type(mtrr_fix_list_t{}, [this](auto mtrr_fixed, int i) {
|
||||
using ia32_mtrr_t = decltype(mtrr_fixed);
|
||||
mtrr_fixed = msr::read<ia32_mtrr_t>();
|
||||
|
||||
pa_t range = ia32_mtrr_t::mtrr_base;
|
||||
i *= 8;
|
||||
|
||||
for (auto type : mtrr_fixed.type)
|
||||
{
|
||||
fixed_[i].range = physical_memory_range(range, range + ia32_mtrr_t::mtrr_size);
|
||||
fixed_[i].type = static_cast<memory_type>(type);
|
||||
|
||||
range += ia32_mtrr_t::mtrr_size;
|
||||
i += 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void check_variable() noexcept
|
||||
{
|
||||
auto mtrr_capabilities = msr::read<msr::mtrr_capabilities_t>();
|
||||
variable_count_ = mtrr_capabilities.variable_range_count;
|
||||
|
||||
for (int i = 0; i < variable_count_; ++i)
|
||||
{
|
||||
auto mtrr_base = msr::read<msr::mtrr_physbase_t>(msr::mtrr_physbase_t::msr_id + i * 2);
|
||||
auto mtrr_mask = msr::read<msr::mtrr_physmask_t>(msr::mtrr_physmask_t::msr_id + i * 2);
|
||||
|
||||
if (mtrr_mask.valid)
|
||||
{
|
||||
uint64_t size = 1ull << ia32_asm_bsf(mtrr_mask.page_frame_number);
|
||||
|
||||
variable_[i].range = physical_memory_range(
|
||||
pa_t::from_pfn(mtrr_base.page_frame_number),
|
||||
pa_t::from_pfn(mtrr_base.page_frame_number + size));
|
||||
variable_[i].type = static_cast<memory_type>(mtrr_base.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_fixed(const mtrr_range& range) const noexcept
|
||||
{
|
||||
return (const mtrr_range*)&range < (const mtrr_range*)variable_;
|
||||
}
|
||||
|
||||
bool is_variable(const mtrr_range& range) const noexcept
|
||||
{
|
||||
return (const mtrr_range*)&range >= (const mtrr_range*)variable_;
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
mtrr_range fixed_[fixed_count];
|
||||
mtrr_range variable_[max_variable_count];
|
||||
};
|
||||
|
||||
mtrr_range mtrr_[fixed_count + max_variable_count];
|
||||
};
|
||||
|
||||
memory_type default_memory_type_ = memory_type::uncacheable;
|
||||
int variable_count_ = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -378,8 +378,8 @@ template <
|
|||
)
|
||||
>
|
||||
>
|
||||
constexpr inline uint32_t byte_offset(T va, PAGE_DESCRIPTOR) noexcept
|
||||
{ return (uint32_t)(uintptr_t(va) & ~PAGE_DESCRIPTOR::mask); }
|
||||
constexpr inline uint64_t byte_offset(T va, PAGE_DESCRIPTOR) noexcept
|
||||
{ return (uint64_t)(uintptr_t(va) & ~PAGE_DESCRIPTOR::mask); }
|
||||
|
||||
//
|
||||
// Return how many pages are needed to cover specified size.
|
||||
|
|
@ -422,7 +422,7 @@ constexpr inline T page_align_up(T va) noexcept
|
|||
{ return page_align_up(va, pt_t{}); }
|
||||
|
||||
template <typename T>
|
||||
constexpr inline uint32_t byte_offset(T va) noexcept
|
||||
constexpr inline uint64_t byte_offset(T va) noexcept
|
||||
{ return byte_offset(va, pt_t{}); }
|
||||
|
||||
template <typename T>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
#include <ntddk.h>
|
||||
|
||||
#define HVPP_MAPPING_TAG 'mpvh'
|
||||
|
||||
namespace ia32::detail
|
||||
{
|
||||
uint64_t pa_from_va(const void* va) noexcept
|
||||
|
|
@ -18,36 +16,4 @@ namespace ia32::detail
|
|||
|
||||
return MmGetVirtualForPhysical(win_pa);
|
||||
}
|
||||
|
||||
void* mapping_allocate(size_t size) noexcept
|
||||
{
|
||||
return MmAllocateMappingAddress(size, HVPP_MAPPING_TAG);
|
||||
}
|
||||
|
||||
void mapping_free(void* va) noexcept
|
||||
{
|
||||
MmFreeMappingAddress(va, HVPP_MAPPING_TAG);
|
||||
}
|
||||
|
||||
void check_physical_memory(physical_memory_range* range_list, int range_list_size, int& count) noexcept
|
||||
{
|
||||
auto physical_memory_ranges = MmGetPhysicalMemoryRanges();
|
||||
|
||||
count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
pa_t address = physical_memory_ranges[count].BaseAddress.QuadPart;
|
||||
size_t size = physical_memory_ranges[count].NumberOfBytes.QuadPart;
|
||||
|
||||
if (!address && !size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
range_list[count] = physical_memory_range(address, address + size);
|
||||
} while (++count < range_list_size);
|
||||
|
||||
ExFreePool(physical_memory_ranges);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ namespace driver::common
|
|||
//
|
||||
// Print memory information to the debugger.
|
||||
//
|
||||
mm::mtrr().dump();
|
||||
mm::mtrr_descriptor().dump();
|
||||
mm::physical_memory_descriptor().dump();
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -66,8 +66,9 @@ namespace mm
|
|||
|
||||
allocator_t allocator[HVPP_MAX_CPU];
|
||||
|
||||
object_t<ia32::physical_memory_descriptor> memory_descriptor;
|
||||
object_t<ia32::mtrr> memory_type_range_registers;
|
||||
object_t<physical_memory_descriptor_t> physical_memory_descriptor;
|
||||
object_t<mtrr_descriptor_t> mtrr_descriptor;
|
||||
|
||||
object_t<spinlock> lock;
|
||||
};
|
||||
|
||||
|
|
@ -98,8 +99,8 @@ namespace mm
|
|||
//
|
||||
// Initialize physical memory descriptor and MTRRs.
|
||||
//
|
||||
global.memory_descriptor.initialize();
|
||||
global.memory_type_range_registers.initialize();
|
||||
global.physical_memory_descriptor.initialize();
|
||||
global.mtrr_descriptor.initialize();
|
||||
|
||||
//
|
||||
// Initialize lock.
|
||||
|
|
@ -124,8 +125,8 @@ namespace mm
|
|||
// Note that this method doesn't acquire the lock and
|
||||
// assumes all allocations has been already freed.
|
||||
//
|
||||
global.memory_type_range_registers.destroy();
|
||||
global.memory_descriptor.destroy();
|
||||
global.mtrr_descriptor.destroy();
|
||||
global.physical_memory_descriptor.destroy();
|
||||
global.lock.destroy();
|
||||
|
||||
//
|
||||
|
|
@ -179,7 +180,7 @@ namespace mm
|
|||
|
||||
auto assign(void* address, size_t size) noexcept -> error_code_t
|
||||
{
|
||||
if (size < ia32::page_size * 3)
|
||||
if (size < page_size * 3)
|
||||
{
|
||||
//
|
||||
// We need at least 3 pages (see explanation below).
|
||||
|
|
@ -192,11 +193,11 @@ namespace mm
|
|||
// If the provided address is not page aligned, align it
|
||||
// to the next page.
|
||||
//
|
||||
if (ia32::byte_offset(address) != 0)
|
||||
if (byte_offset(address) != 0)
|
||||
{
|
||||
const auto lost_bytes = ia32::byte_offset(address);
|
||||
const auto lost_bytes = byte_offset(address);
|
||||
|
||||
address = reinterpret_cast<uint8_t*>(ia32::page_align(address)) + ia32::page_size;
|
||||
address = reinterpret_cast<uint8_t*>(page_align(address)) + page_size;
|
||||
|
||||
//
|
||||
// Subtract amount of "lost" bytes due to alignment.
|
||||
|
|
@ -207,12 +208,12 @@ namespace mm
|
|||
//
|
||||
// Align size to the page boundary.
|
||||
//
|
||||
size = ia32::page_align(size);
|
||||
size = page_align(size);
|
||||
|
||||
//
|
||||
// Check again.
|
||||
//
|
||||
if (size < ia32::page_size * 3)
|
||||
if (size < page_size * 3)
|
||||
{
|
||||
hvpp_assert(0);
|
||||
return make_error_code_t(std::errc::invalid_argument);
|
||||
|
|
@ -245,17 +246,17 @@ namespace mm
|
|||
// Construct the page bitmap.
|
||||
//
|
||||
uint8_t* page_bitmap_buffer = reinterpret_cast<uint8_t*>(address);
|
||||
global.page_bitmap_buffer_size = static_cast<int>(ia32::round_to_pages(size / ia32::page_size / 8));
|
||||
global.page_bitmap_buffer_size = static_cast<int>(round_to_pages(size / page_size / 8));
|
||||
memset(page_bitmap_buffer, 0, global.page_bitmap_buffer_size);
|
||||
|
||||
int page_bitmap_size_in_bits = static_cast<int>(size / ia32::page_size);
|
||||
int page_bitmap_size_in_bits = static_cast<int>(size / page_size);
|
||||
global.page_bitmap.initialize(page_bitmap_buffer, page_bitmap_size_in_bits);
|
||||
|
||||
//
|
||||
// Construct the page allocation map.
|
||||
//
|
||||
global.page_allocation_map = reinterpret_cast<pgmap_t*>(page_bitmap_buffer + global.page_bitmap_buffer_size);
|
||||
global.page_allocation_map_size = static_cast<int>(ia32::round_to_pages(size / ia32::page_size) * sizeof(pgmap_t));
|
||||
global.page_allocation_map_size = static_cast<int>(round_to_pages(size / page_size) * sizeof(pgmap_t));
|
||||
memset(global.page_allocation_map, 0, global.page_allocation_map_size);
|
||||
|
||||
//
|
||||
|
|
@ -308,7 +309,7 @@ namespace mm
|
|||
size = 1;
|
||||
}
|
||||
|
||||
int page_count = static_cast<int>(ia32::bytes_to_pages(size));
|
||||
int page_count = static_cast<int>(bytes_to_pages(size));
|
||||
|
||||
//
|
||||
// Check if the desired number of pages can fit into the
|
||||
|
|
@ -348,8 +349,8 @@ namespace mm
|
|||
previous_page_offset = global.last_page_offset;
|
||||
global.last_page_offset += page_count;
|
||||
|
||||
global.allocated_bytes += page_count * ia32::page_size;
|
||||
global.free_bytes -= page_count * ia32::page_size;
|
||||
global.allocated_bytes += page_count * page_size;
|
||||
global.free_bytes -= page_count * page_size;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -358,7 +359,7 @@ namespace mm
|
|||
// everything neccessary has been done (bitmap + page allocation map
|
||||
// manipulation).
|
||||
//
|
||||
return global.base_address + previous_page_offset * ia32::page_size;
|
||||
return global.base_address + previous_page_offset * page_size;
|
||||
}
|
||||
|
||||
void free(void* address) noexcept
|
||||
|
|
@ -366,9 +367,9 @@ namespace mm
|
|||
//
|
||||
// Our allocator always provides page-aligned memory.
|
||||
//
|
||||
hvpp_assert(ia32::byte_offset(address) == 0);
|
||||
hvpp_assert(byte_offset(address) == 0);
|
||||
|
||||
const auto offset = static_cast<int>(ia32::bytes_to_pages(reinterpret_cast<uint8_t*>(address) - global.base_address));
|
||||
const auto offset = static_cast<int>(bytes_to_pages(reinterpret_cast<uint8_t*>(address) - global.base_address));
|
||||
|
||||
if (address == nullptr)
|
||||
{
|
||||
|
|
@ -379,7 +380,7 @@ namespace mm
|
|||
return;
|
||||
}
|
||||
|
||||
if (size_t(offset) * ia32::page_size > global.available_size)
|
||||
if (size_t(offset) * page_size > global.available_size)
|
||||
{
|
||||
//
|
||||
// We don't own this memory.
|
||||
|
|
@ -410,8 +411,8 @@ namespace mm
|
|||
//
|
||||
global.page_bitmap->clear(offset, page_count);
|
||||
|
||||
global.allocated_bytes -= page_count * ia32::page_size;
|
||||
global.free_bytes += page_count * ia32::page_size;
|
||||
global.allocated_bytes -= page_count * page_size;
|
||||
global.free_bytes += page_count * page_size;
|
||||
}
|
||||
|
||||
auto system_allocate(size_t size) noexcept -> void*
|
||||
|
|
@ -444,14 +445,14 @@ namespace mm
|
|||
global.allocator[mp::cpu_index()] = new_allocator;
|
||||
}
|
||||
|
||||
auto physical_memory_descriptor() noexcept -> const ia32::physical_memory_descriptor&
|
||||
auto physical_memory_descriptor() noexcept -> const physical_memory_descriptor_t&
|
||||
{
|
||||
return *global.memory_descriptor;
|
||||
return *global.physical_memory_descriptor;
|
||||
}
|
||||
|
||||
auto mtrr() noexcept -> const ia32::mtrr&
|
||||
auto mtrr_descriptor() noexcept -> const mtrr_descriptor_t&
|
||||
{
|
||||
return *global.memory_type_range_registers;
|
||||
return *global.mtrr_descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#pragma once
|
||||
#include "hvpp/ia32/memory.h"
|
||||
#include "hvpp/ia32/mtrr.h"
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#include "mm/physical_memory_descriptor.h"
|
||||
#include "mm/mtrr_descriptor.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace mm
|
||||
|
|
@ -59,6 +60,6 @@ namespace mm
|
|||
auto allocator() noexcept -> const allocator_t&;
|
||||
void allocator(const allocator_t& new_allocator) noexcept;
|
||||
|
||||
auto physical_memory_descriptor() noexcept -> const ia32::physical_memory_descriptor&;
|
||||
auto mtrr() noexcept -> const ia32::mtrr&;
|
||||
auto physical_memory_descriptor() noexcept -> const physical_memory_descriptor_t&;
|
||||
auto mtrr_descriptor() noexcept -> const mtrr_descriptor_t&;
|
||||
}
|
||||
|
|
|
|||
103
src/hvpp/hvpp/lib/mm/memory_mapper.cpp
Normal file
103
src/hvpp/hvpp/lib/mm/memory_mapper.cpp
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#include "memory_mapper.h"
|
||||
|
||||
namespace mm
|
||||
{
|
||||
memory_mapper::memory_mapper() noexcept
|
||||
{
|
||||
//
|
||||
// Reserve 1 page of the virtual address space.
|
||||
// Note that the memory is NOT allocated, just reserved.
|
||||
//
|
||||
va_ = detail::mapper_allocate(page_size);
|
||||
|
||||
//
|
||||
// Get page-table entry for the virtual address.
|
||||
//
|
||||
pte_ = va_t(va_).pt_entry();
|
||||
}
|
||||
|
||||
memory_mapper::~memory_mapper() noexcept
|
||||
{
|
||||
//
|
||||
// Release the virtual address space.
|
||||
//
|
||||
detail::mapper_free(va_);
|
||||
}
|
||||
|
||||
void* memory_mapper::map(pa_t pa) noexcept
|
||||
{
|
||||
//
|
||||
// Make this entry present & writable.
|
||||
//
|
||||
pte_->present = true;
|
||||
pte_->write = true;
|
||||
|
||||
//
|
||||
// Do not flush this page from the TLB on CR3 switch.
|
||||
//
|
||||
pte_->global = true;
|
||||
|
||||
//
|
||||
// Set the PFN of this PTE to the PFN of the
|
||||
// provided physical address.
|
||||
//
|
||||
pte_->page_frame_number = pa.pfn();
|
||||
|
||||
//
|
||||
// Finally, invalidate the cache for the virtual address.
|
||||
//
|
||||
ia32_asm_inv_page(va_);
|
||||
|
||||
return reinterpret_cast<uint8_t*>(va_) + byte_offset(pa.value());
|
||||
}
|
||||
|
||||
void memory_mapper::unmap() noexcept
|
||||
{
|
||||
pte_->flags = 0;
|
||||
}
|
||||
|
||||
void memory_mapper::read(pa_t pa, void* buffer, size_t size) noexcept
|
||||
{
|
||||
read_write(pa, buffer, size, false);
|
||||
}
|
||||
|
||||
void memory_mapper::write(pa_t pa, const void* buffer, size_t size) noexcept
|
||||
{
|
||||
read_write(pa, const_cast<void*>(buffer), size, true);
|
||||
}
|
||||
|
||||
void memory_mapper::read_write(pa_t pa, void* buffer, size_t size, bool write) noexcept
|
||||
{
|
||||
auto byte_buffer = reinterpret_cast<uint8_t*>(buffer);
|
||||
|
||||
//
|
||||
// Map each page of the physical memory to the reserved
|
||||
// system virtual address and then copy.
|
||||
//
|
||||
while (size != 0)
|
||||
{
|
||||
auto va = map(pa);
|
||||
auto bytes_to_copy = page_size - byte_offset(va);
|
||||
|
||||
if (bytes_to_copy > size)
|
||||
{
|
||||
bytes_to_copy = size;
|
||||
}
|
||||
|
||||
if (write)
|
||||
{
|
||||
memcpy(va, byte_buffer, bytes_to_copy);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(byte_buffer, va, bytes_to_copy);
|
||||
}
|
||||
|
||||
byte_buffer += bytes_to_copy;
|
||||
pa += bytes_to_copy;
|
||||
size -= bytes_to_copy;
|
||||
|
||||
unmap();
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/hvpp/hvpp/lib/mm/memory_mapper.h
Normal file
41
src/hvpp/hvpp/lib/mm/memory_mapper.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
#include "hvpp/ia32/memory.h"
|
||||
|
||||
namespace mm
|
||||
{
|
||||
using namespace ia32;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
void* mapper_allocate(size_t size) noexcept;
|
||||
void mapper_free(void* va) noexcept;
|
||||
}
|
||||
|
||||
//
|
||||
// Class for reading/writing physical memory.
|
||||
//
|
||||
|
||||
class memory_mapper
|
||||
{
|
||||
public:
|
||||
memory_mapper() noexcept;
|
||||
~memory_mapper() noexcept;
|
||||
|
||||
memory_mapper(const memory_mapper& other) noexcept = delete;
|
||||
memory_mapper(memory_mapper&& other) noexcept = delete;
|
||||
memory_mapper& operator=(const memory_mapper& other) noexcept = delete;
|
||||
memory_mapper& operator=(memory_mapper&& other) noexcept = delete;
|
||||
|
||||
void* map(pa_t pa) noexcept;
|
||||
void unmap() noexcept;
|
||||
|
||||
void read(pa_t pa, void* buffer, size_t size) noexcept;
|
||||
void write(pa_t pa, const void* buffer, size_t size) noexcept;
|
||||
|
||||
private:
|
||||
void read_write(pa_t pa, void* buffer, size_t size, bool write) noexcept;
|
||||
|
||||
void* va_;
|
||||
pe_t* pte_;
|
||||
};
|
||||
}
|
||||
210
src/hvpp/hvpp/lib/mm/mtrr_descriptor.h
Normal file
210
src/hvpp/hvpp/lib/mm/mtrr_descriptor.h
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
#pragma once
|
||||
#include "hvpp/ia32/memory.h"
|
||||
#include "hvpp/ia32/msr.h"
|
||||
#include "hvpp/ia32/msr/mtrr.h"
|
||||
#include "../typelist.h"
|
||||
#include "../log.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cinttypes>
|
||||
|
||||
namespace mm
|
||||
{
|
||||
using namespace ia32;
|
||||
|
||||
struct mtrr_range
|
||||
{
|
||||
physical_memory_range range;
|
||||
memory_type type;
|
||||
};
|
||||
|
||||
class mtrr_descriptor_t
|
||||
{
|
||||
public:
|
||||
static constexpr auto fixed_count = (1 + 2 + 8) * 8;
|
||||
static constexpr auto max_variable_count = 255;
|
||||
|
||||
mtrr_descriptor_t() noexcept { check_fixed(); check_variable(); }
|
||||
mtrr_descriptor_t(const mtrr_descriptor_t& other) noexcept = delete;
|
||||
mtrr_descriptor_t(mtrr_descriptor_t&& other) noexcept = delete;
|
||||
mtrr_descriptor_t& operator=(const mtrr_descriptor_t& other) noexcept = delete;
|
||||
mtrr_descriptor_t& operator=(mtrr_descriptor_t&& other) noexcept = delete;
|
||||
|
||||
const mtrr_range* begin() const noexcept { return &mtrr_[0]; }
|
||||
const mtrr_range* end() const noexcept { return &mtrr_[size()]; }
|
||||
size_t size() const noexcept { return fixed_count + variable_count_; }
|
||||
|
||||
memory_type type(pa_t pa) const noexcept
|
||||
{
|
||||
//
|
||||
// If the MTRRs are not enabled (by setting the E flag in the
|
||||
// IA32_MTRR_DEF_TYPE MSR), then all memory accesses are of the
|
||||
// UC memory type. If the MTRRs are enabled, then the memory
|
||||
// type used for a memory access is determined as follows:
|
||||
//
|
||||
// 1. If the physical address falls within the first 1 MByte of
|
||||
// physical memory and fixed MTRRs are enabled, the processor
|
||||
// uses the memory type stored for the appropriate fixed-range
|
||||
// MTRR.
|
||||
//
|
||||
// 2. Otherwise, the processor attempts to match the physical
|
||||
// address with a memory type set by the variable-range MTRRs:
|
||||
// - If one variable memory range matches, the processor uses
|
||||
// the memory type stored in the IA32_MTRR_PHYSBASEn register
|
||||
// for that range.
|
||||
//
|
||||
// - If two or more variable memory ranges match and the memory
|
||||
// types are identical, then that memory type is used.
|
||||
//
|
||||
// - If two or more variable memory ranges match and one of the
|
||||
// memory types is UC, the UC memory type is used.
|
||||
//
|
||||
// - If two or more variable memory ranges match and the memory
|
||||
// types are WT and WB, the WT memory type is used.
|
||||
//
|
||||
// - For overlaps not defined by the above rules, processor
|
||||
// behavior is undefined.
|
||||
//
|
||||
// 3. If no fixed or variable memory range matches, the processor uses
|
||||
// the default memory type.
|
||||
//
|
||||
// (ref: Vol3A[11.11.4.1(MTRR Precedences)]
|
||||
//
|
||||
memory_type result = memory_type::invalid;
|
||||
|
||||
for (auto mtrr_item : *this)
|
||||
{
|
||||
if (mtrr_item.range.contains(pa))
|
||||
{
|
||||
if (is_fixed(mtrr_item) || mtrr_item.type == memory_type::uncacheable)
|
||||
{
|
||||
result = mtrr_item.type;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( result == memory_type::write_back &&
|
||||
(result == memory_type::write_through ||
|
||||
mtrr_item.type == memory_type::write_through))
|
||||
{
|
||||
result = memory_type::write_through;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result == memory_type::invalid)
|
||||
{
|
||||
result = default_memory_type_;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void dump() const noexcept
|
||||
{
|
||||
auto dump_range = [](int i, const mtrr_range& mtrr) noexcept
|
||||
{
|
||||
hvpp_info(
|
||||
" %3i) %s [%016" PRIx64 " - %016" PRIx64 "] (%8u kb)", i,
|
||||
memory_type_to_string(mtrr.type),
|
||||
mtrr.range.begin().value(),
|
||||
mtrr.range.end().value(),
|
||||
mtrr.range.size() / 1024);
|
||||
};
|
||||
|
||||
hvpp_info("Fixed MTRR ranges (%i)", fixed_count);
|
||||
for (int i = 0; i < fixed_count; ++i)
|
||||
{
|
||||
dump_range(i, fixed_[i]);
|
||||
}
|
||||
|
||||
hvpp_info("Variable MTRR ranges (%i)", variable_count_);
|
||||
for (int i = 0; i < variable_count_; ++i)
|
||||
{
|
||||
dump_range(i, variable_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void check_fixed() noexcept
|
||||
{
|
||||
auto mtrr_default = msr::read<msr::mtrr_def_type_t>();
|
||||
auto mtrr_capabilities = msr::read<msr::mtrr_capabilities_t>();
|
||||
|
||||
default_memory_type_ = static_cast<memory_type>(mtrr_default.default_memory_type);
|
||||
|
||||
if (mtrr_capabilities.fixed_range_supported && mtrr_default.fixed_range_mtrr_enable)
|
||||
{
|
||||
using mtrr_fix_64k_list_t = type_list<msr::mtrr_fix_64k_00000_t>;
|
||||
using mtrr_fix_16k_list_t = type_list<msr::mtrr_fix_16k_80000_t, msr::mtrr_fix_16k_a0000_t>;
|
||||
using mtrr_fix_4k_list_t = type_list<msr::mtrr_fix_4k_c0000_t, msr::mtrr_fix_4k_c8000_t,
|
||||
msr::mtrr_fix_4k_d0000_t, msr::mtrr_fix_4k_d8000_t,
|
||||
msr::mtrr_fix_4k_e0000_t, msr::mtrr_fix_4k_e8000_t,
|
||||
msr::mtrr_fix_4k_f0000_t, msr::mtrr_fix_4k_f8000_t>;
|
||||
using mtrr_fix_list_t = type_list<mtrr_fix_64k_list_t, mtrr_fix_16k_list_t, mtrr_fix_4k_list_t>;
|
||||
|
||||
for_each_type(mtrr_fix_list_t{}, [this](auto mtrr_fixed, int i) {
|
||||
using ia32_mtrr_t = decltype(mtrr_fixed);
|
||||
mtrr_fixed = msr::read<ia32_mtrr_t>();
|
||||
|
||||
pa_t range = ia32_mtrr_t::mtrr_base;
|
||||
i *= 8;
|
||||
|
||||
for (auto type : mtrr_fixed.type)
|
||||
{
|
||||
fixed_[i].range = physical_memory_range{ range, range + ia32_mtrr_t::mtrr_size };
|
||||
fixed_[i].type = static_cast<memory_type>(type);
|
||||
|
||||
range += ia32_mtrr_t::mtrr_size;
|
||||
i += 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void check_variable() noexcept
|
||||
{
|
||||
auto mtrr_capabilities = msr::read<msr::mtrr_capabilities_t>();
|
||||
variable_count_ = mtrr_capabilities.variable_range_count;
|
||||
|
||||
for (int i = 0; i < variable_count_; ++i)
|
||||
{
|
||||
auto mtrr_base = msr::read<msr::mtrr_physbase_t>(msr::mtrr_physbase_t::msr_id + i * 2);
|
||||
auto mtrr_mask = msr::read<msr::mtrr_physmask_t>(msr::mtrr_physmask_t::msr_id + i * 2);
|
||||
|
||||
if (mtrr_mask.valid)
|
||||
{
|
||||
uint64_t size = 1ull << ia32_asm_bsf(mtrr_mask.page_frame_number);
|
||||
|
||||
variable_[i].range = physical_memory_range(
|
||||
pa_t::from_pfn(mtrr_base.page_frame_number),
|
||||
pa_t::from_pfn(mtrr_base.page_frame_number + size));
|
||||
variable_[i].type = static_cast<memory_type>(mtrr_base.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_fixed(const mtrr_range& range) const noexcept
|
||||
{
|
||||
return (const mtrr_range*)&range < (const mtrr_range*)variable_;
|
||||
}
|
||||
|
||||
bool is_variable(const mtrr_range& range) const noexcept
|
||||
{
|
||||
return (const mtrr_range*)&range >= (const mtrr_range*)variable_;
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
mtrr_range fixed_[fixed_count];
|
||||
mtrr_range variable_[max_variable_count];
|
||||
};
|
||||
|
||||
mtrr_range mtrr_[fixed_count + max_variable_count];
|
||||
};
|
||||
|
||||
memory_type default_memory_type_ = memory_type::uncacheable;
|
||||
int variable_count_ = 0;
|
||||
};
|
||||
}
|
||||
62
src/hvpp/hvpp/lib/mm/physical_memory_descriptor.h
Normal file
62
src/hvpp/hvpp/lib/mm/physical_memory_descriptor.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#pragma once
|
||||
#include "hvpp/ia32/memory.h"
|
||||
#include "../log.h"
|
||||
|
||||
namespace mm
|
||||
{
|
||||
using namespace ia32;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
void check_physical_memory(physical_memory_range* range_list, int range_list_size, int& count) noexcept;
|
||||
}
|
||||
|
||||
//
|
||||
// Class for receiving physical memory ranges which are backed up
|
||||
// by actual physical memory.
|
||||
//
|
||||
|
||||
class physical_memory_descriptor_t
|
||||
{
|
||||
public:
|
||||
static constexpr auto max_range_count = 32;
|
||||
|
||||
physical_memory_descriptor_t() noexcept { check_physical_memory(); }
|
||||
physical_memory_descriptor_t(const physical_memory_descriptor_t& other) noexcept = delete;
|
||||
physical_memory_descriptor_t(physical_memory_descriptor_t&& other) noexcept = delete;
|
||||
physical_memory_descriptor_t& operator=(const physical_memory_descriptor_t& other) noexcept = delete;
|
||||
physical_memory_descriptor_t& operator=(physical_memory_descriptor_t&& other) noexcept = delete;
|
||||
|
||||
auto begin() const noexcept { return const_cast<const physical_memory_range*>(&range_[0]); }
|
||||
auto end() const noexcept { return const_cast<const physical_memory_range*>(&range_[count_]); }
|
||||
auto size() const noexcept { return static_cast<size_t>(count_); }
|
||||
|
||||
auto total_physical_memory_size() const noexcept
|
||||
{
|
||||
return std::accumulate(begin(), end(), size_t{}, [](auto sum, auto next) {
|
||||
return sum + next.size();
|
||||
});
|
||||
}
|
||||
|
||||
void dump() const noexcept
|
||||
{
|
||||
hvpp_info("Physical memory ranges (%i)", count_);
|
||||
|
||||
for (int i = 0; i < count_; ++i)
|
||||
{
|
||||
hvpp_info(
|
||||
" %3i) [%016" PRIx64 " - %016" PRIx64 "] (%8u kb)", i,
|
||||
range_[i].begin().value(),
|
||||
range_[i].end().value(),
|
||||
range_[i].size() / 1024);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void check_physical_memory() noexcept
|
||||
{ detail::check_physical_memory(range_, max_range_count, count_); }
|
||||
|
||||
physical_memory_range range_[max_range_count];
|
||||
int count_ = 0;
|
||||
};
|
||||
}
|
||||
16
src/hvpp/hvpp/lib/mm/win32/memory_mapper.cpp
Normal file
16
src/hvpp/hvpp/lib/mm/win32/memory_mapper.cpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include <ntddk.h>
|
||||
|
||||
#define HVPP_MAPPING_TAG 'mpvh'
|
||||
|
||||
namespace mm::detail
|
||||
{
|
||||
void* mapper_allocate(size_t size) noexcept
|
||||
{
|
||||
return MmAllocateMappingAddress(size, HVPP_MAPPING_TAG);
|
||||
}
|
||||
|
||||
void mapper_free(void* va) noexcept
|
||||
{
|
||||
MmFreeMappingAddress(va, HVPP_MAPPING_TAG);
|
||||
}
|
||||
}
|
||||
30
src/hvpp/hvpp/lib/mm/win32/physical_memory_descriptor.cpp
Normal file
30
src/hvpp/hvpp/lib/mm/win32/physical_memory_descriptor.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include "hvpp/ia32/memory.h"
|
||||
|
||||
#include <ntddk.h>
|
||||
|
||||
using namespace ia32;
|
||||
|
||||
namespace mm::detail
|
||||
{
|
||||
void check_physical_memory(physical_memory_range* range_list, int range_list_size, int& count) noexcept
|
||||
{
|
||||
auto physical_memory_ranges = MmGetPhysicalMemoryRanges();
|
||||
|
||||
count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
pa_t address = physical_memory_ranges[count].BaseAddress.QuadPart;
|
||||
size_t size = physical_memory_ranges[count].NumberOfBytes.QuadPart;
|
||||
|
||||
if (!address && !size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
range_list[count] = physical_memory_range(address, address + size);
|
||||
} while (++count < range_list_size);
|
||||
|
||||
ExFreePool(physical_memory_ranges);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue