diff --git a/src/hvpp/hvpp.vcxproj b/src/hvpp/hvpp.vcxproj
index 7fe2f32..bd4ad89 100644
--- a/src/hvpp/hvpp.vcxproj
+++ b/src/hvpp/hvpp.vcxproj
@@ -104,6 +104,9 @@
+
+
+
$(IntDir)/$(RelativeDir)/%(Filename)%(Extension).obj
@@ -139,6 +142,9 @@
+
+
+
@@ -160,7 +166,6 @@
-
diff --git a/src/hvpp/hvpp.vcxproj.filters b/src/hvpp/hvpp.vcxproj.filters
index 0301d3e..e40f8a0 100644
--- a/src/hvpp/hvpp.vcxproj.filters
+++ b/src/hvpp/hvpp.vcxproj.filters
@@ -67,6 +67,15 @@
{b199f4fb-0f50-4a62-b44d-f80541e9b91a}
+
+ {8e3b0296-08e1-46b7-83f6-555347ca5fe9}
+
+
+ {48924d45-28d4-4be4-96bc-ef93b3095d01}
+
+
+ {c53a048f-d7da-48c6-88a5-fa1ed9bfc1ed}
+
@@ -138,6 +147,15 @@
Source Files\hvpp\ia32
+
+ Source Files\hvpp\lib\mm
+
+
+ Source Files\hvpp\lib\mm\win32
+
+
+ Source Files\hvpp\lib\mm\win32
+
@@ -158,9 +176,6 @@
Header Files\hvpp\ia32
-
- Header Files\hvpp\ia32
-
Header Files\hvpp\ia32
@@ -302,6 +317,15 @@
Header Files\hvpp
+
+ Header Files\hvpp\lib\mm
+
+
+ Header Files\hvpp\lib\mm
+
+
+ Header Files\hvpp\lib\mm
+
diff --git a/src/hvpp/hvpp/ept.cpp b/src/hvpp/hvpp/ept.cpp
index 1e182b4..8b0d3a8 100644
--- a/src/hvpp/hvpp/ept.cpp
+++ b/src/hvpp/hvpp/ept.cpp
@@ -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(mm::mtrr().type(empl4_pa));
+ eptptr_.memory_type = static_cast(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;
}
}
diff --git a/src/hvpp/hvpp/ia32/memory.cpp b/src/hvpp/hvpp/ia32/memory.cpp
index 544fcb9..6313ebd 100644
--- a/src/hvpp/hvpp/ia32/memory.cpp
+++ b/src/hvpp/hvpp/ia32/memory.cpp
@@ -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()*/, pml level /*= pml::pt*/) const noexcept
+pe_t* va_t::pt_entry(pml level /*= pml::pt*/) const noexcept
{
const auto pml4e = &reinterpret_cast(
- pa_t::from_pfn(cr3.page_frame_number).va()
+ pa_t::from_pfn(read().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()*/, 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(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(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(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();
- }
-}
-
}
diff --git a/src/hvpp/hvpp/ia32/memory.h b/src/hvpp/hvpp/ia32/memory.h
index e159a96..476e807 100644
--- a/src/hvpp/hvpp/ia32/memory.h
+++ b/src/hvpp/hvpp/ia32/memory.h
@@ -1,10 +1,10 @@
#pragma once
-#include "hvpp/lib/log.h"
#include "paging.h"
#include "arch.h"
#include // std::byte
#include
+#include
#include
#include
@@ -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(result);
}
- pe_t* pt_entry(cr3_t cr3 = read(), 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(&range_[0]); }
- auto end() const noexcept { return const_cast(&range_[count_]); }
- auto size() const noexcept { return static_cast(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)
diff --git a/src/hvpp/hvpp/ia32/mtrr.h b/src/hvpp/hvpp/ia32/mtrr.h
deleted file mode 100644
index 1384d8b..0000000
--- a/src/hvpp/hvpp/ia32/mtrr.h
+++ /dev/null
@@ -1,209 +0,0 @@
-#pragma once
-#include "memory.h"
-#include "msr.h"
-#include "msr/mtrr.h"
-#include "../lib/typelist.h"
-
-#include
-#include
-
-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();
- auto mtrr_capabilities = msr::read();
-
- default_memory_type_ = static_cast(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;
- using mtrr_fix_16k_list_t = type_list;
- using mtrr_fix_4k_list_t = type_list;
- using mtrr_fix_list_t = type_list;
-
- for_each_type(mtrr_fix_list_t{}, [this](auto mtrr_fixed, int i) {
- using ia32_mtrr_t = decltype(mtrr_fixed);
- mtrr_fixed = msr::read();
-
- 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(type);
-
- range += ia32_mtrr_t::mtrr_size;
- i += 1;
- }
- });
- }
- }
-
- void check_variable() noexcept
- {
- auto mtrr_capabilities = msr::read();
- 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_id + i * 2);
- auto mtrr_mask = msr::read(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(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;
-};
-
-}
diff --git a/src/hvpp/hvpp/ia32/paging.h b/src/hvpp/hvpp/ia32/paging.h
index c3f55ae..71f729a 100644
--- a/src/hvpp/hvpp/ia32/paging.h
+++ b/src/hvpp/hvpp/ia32/paging.h
@@ -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
-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
diff --git a/src/hvpp/hvpp/ia32/win32/memory.cpp b/src/hvpp/hvpp/ia32/win32/memory.cpp
index b8e30f5..cc6837c 100644
--- a/src/hvpp/hvpp/ia32/win32/memory.cpp
+++ b/src/hvpp/hvpp/ia32/win32/memory.cpp
@@ -2,8 +2,6 @@
#include
-#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);
- }
}
diff --git a/src/hvpp/hvpp/lib/driver.cpp b/src/hvpp/hvpp/lib/driver.cpp
index 508be2f..604990e 100644
--- a/src/hvpp/hvpp/lib/driver.cpp
+++ b/src/hvpp/hvpp/lib/driver.cpp
@@ -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();
//
diff --git a/src/hvpp/hvpp/lib/mm.cpp b/src/hvpp/hvpp/lib/mm.cpp
index 2e01cad..de4df34 100644
--- a/src/hvpp/hvpp/lib/mm.cpp
+++ b/src/hvpp/hvpp/lib/mm.cpp
@@ -66,8 +66,9 @@ namespace mm
allocator_t allocator[HVPP_MAX_CPU];
- object_t memory_descriptor;
- object_t memory_type_range_registers;
+ object_t physical_memory_descriptor;
+ object_t mtrr_descriptor;
+
object_t 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(ia32::page_align(address)) + ia32::page_size;
+ address = reinterpret_cast(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(address);
- global.page_bitmap_buffer_size = static_cast(ia32::round_to_pages(size / ia32::page_size / 8));
+ global.page_bitmap_buffer_size = static_cast(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(size / ia32::page_size);
+ int page_bitmap_size_in_bits = static_cast(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(page_bitmap_buffer + global.page_bitmap_buffer_size);
- global.page_allocation_map_size = static_cast(ia32::round_to_pages(size / ia32::page_size) * sizeof(pgmap_t));
+ global.page_allocation_map_size = static_cast(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(ia32::bytes_to_pages(size));
+ int page_count = static_cast(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(ia32::bytes_to_pages(reinterpret_cast(address) - global.base_address));
+ const auto offset = static_cast(bytes_to_pages(reinterpret_cast(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;
}
}
diff --git a/src/hvpp/hvpp/lib/mm.h b/src/hvpp/hvpp/lib/mm.h
index 4142f24..2b27e37 100644
--- a/src/hvpp/hvpp/lib/mm.h
+++ b/src/hvpp/hvpp/lib/mm.h
@@ -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
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&;
}
diff --git a/src/hvpp/hvpp/lib/mm/memory_mapper.cpp b/src/hvpp/hvpp/lib/mm/memory_mapper.cpp
new file mode 100644
index 0000000..42de093
--- /dev/null
+++ b/src/hvpp/hvpp/lib/mm/memory_mapper.cpp
@@ -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(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(buffer), size, true);
+ }
+
+ void memory_mapper::read_write(pa_t pa, void* buffer, size_t size, bool write) noexcept
+ {
+ auto byte_buffer = reinterpret_cast(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();
+ }
+ }
+}
diff --git a/src/hvpp/hvpp/lib/mm/memory_mapper.h b/src/hvpp/hvpp/lib/mm/memory_mapper.h
new file mode 100644
index 0000000..2e59af7
--- /dev/null
+++ b/src/hvpp/hvpp/lib/mm/memory_mapper.h
@@ -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_;
+ };
+}
diff --git a/src/hvpp/hvpp/lib/mm/mtrr_descriptor.h b/src/hvpp/hvpp/lib/mm/mtrr_descriptor.h
new file mode 100644
index 0000000..485a425
--- /dev/null
+++ b/src/hvpp/hvpp/lib/mm/mtrr_descriptor.h
@@ -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
+#include
+
+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();
+ auto mtrr_capabilities = msr::read();
+
+ default_memory_type_ = static_cast(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;
+ using mtrr_fix_16k_list_t = type_list;
+ using mtrr_fix_4k_list_t = type_list;
+ using mtrr_fix_list_t = type_list;
+
+ for_each_type(mtrr_fix_list_t{}, [this](auto mtrr_fixed, int i) {
+ using ia32_mtrr_t = decltype(mtrr_fixed);
+ mtrr_fixed = msr::read();
+
+ 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(type);
+
+ range += ia32_mtrr_t::mtrr_size;
+ i += 1;
+ }
+ });
+ }
+ }
+
+ void check_variable() noexcept
+ {
+ auto mtrr_capabilities = msr::read();
+ 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_id + i * 2);
+ auto mtrr_mask = msr::read(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(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;
+ };
+}
diff --git a/src/hvpp/hvpp/lib/mm/physical_memory_descriptor.h b/src/hvpp/hvpp/lib/mm/physical_memory_descriptor.h
new file mode 100644
index 0000000..6ec6b21
--- /dev/null
+++ b/src/hvpp/hvpp/lib/mm/physical_memory_descriptor.h
@@ -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(&range_[0]); }
+ auto end() const noexcept { return const_cast(&range_[count_]); }
+ auto size() const noexcept { return static_cast(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;
+ };
+}
diff --git a/src/hvpp/hvpp/lib/mm/win32/memory_mapper.cpp b/src/hvpp/hvpp/lib/mm/win32/memory_mapper.cpp
new file mode 100644
index 0000000..1d5519f
--- /dev/null
+++ b/src/hvpp/hvpp/lib/mm/win32/memory_mapper.cpp
@@ -0,0 +1,16 @@
+#include
+
+#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);
+ }
+}
diff --git a/src/hvpp/hvpp/lib/mm/win32/physical_memory_descriptor.cpp b/src/hvpp/hvpp/lib/mm/win32/physical_memory_descriptor.cpp
new file mode 100644
index 0000000..4218b35
--- /dev/null
+++ b/src/hvpp/hvpp/lib/mm/win32/physical_memory_descriptor.cpp
@@ -0,0 +1,30 @@
+#include "hvpp/ia32/memory.h"
+
+#include
+
+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);
+ }
+}