[Memory] BaseHeap::host_address_offset

This commit is contained in:
Triang3l 2019-08-04 23:55:54 +03:00
parent 25675cb8b8
commit cb0e18c7dc
2 changed files with 49 additions and 43 deletions

View File

@ -420,13 +420,18 @@ bool Memory::AccessViolationCallback(size_t host_address, bool is_write) {
uint32_t virtual_address = uint32_t virtual_address =
uint32_t(reinterpret_cast<uint8_t*>(host_address) - virtual_membase_); uint32_t(reinterpret_cast<uint8_t*>(host_address) - virtual_membase_);
// Revert the adjustment made by CPU emulation. // If the 4 KB page offset in 0xE0000000 cannot be applied via memory mapping,
if (virtual_address >= 0xE0000000 && // it will be added by CPU load/store implementations, so the host virtual
system_allocation_granularity_ > 0x1000) { // addresses (relative to virtual_membase_) where access violations occur do
if (virtual_address < 0xE0001000) { // not match guest virtual addresses. Revert what CPU memory accesses are
// doing.
// TODO(Triang3l): Move this to a host->guest address conversion function.
if (virtual_address >= 0xE0000000) {
uint32_t host_address_offset = heaps_.vE0000000.host_address_offset();
if (virtual_address < 0xE0000000 + host_address_offset) {
return false; return false;
} }
virtual_address -= 0x1000; virtual_address -= host_address_offset;
} }
BaseHeap* heap = LookupHeap(virtual_address); BaseHeap* heap = LookupHeap(virtual_address);
@ -603,12 +608,14 @@ BaseHeap::BaseHeap()
BaseHeap::~BaseHeap() = default; BaseHeap::~BaseHeap() = default;
void BaseHeap::Initialize(Memory* memory, uint8_t* membase, uint32_t heap_base, void BaseHeap::Initialize(Memory* memory, uint8_t* membase, uint32_t heap_base,
uint32_t heap_size, uint32_t page_size) { uint32_t heap_size, uint32_t page_size,
uint32_t host_address_offset) {
memory_ = memory; memory_ = memory;
membase_ = membase; membase_ = membase;
heap_base_ = heap_base; heap_base_ = heap_base;
heap_size_ = heap_size - 1; heap_size_ = heap_size - 1;
page_size_ = page_size; page_size_ = page_size;
host_address_offset_ = host_address_offset;
page_table_.resize(heap_size / page_size); page_table_.resize(heap_size / page_size);
} }
@ -630,10 +637,12 @@ void BaseHeap::DumpMap() {
XELOGE("------------------------------------------------------------------"); XELOGE("------------------------------------------------------------------");
XELOGE("Heap: %.8X-%.8X", heap_base_, heap_base_ + heap_size_); XELOGE("Heap: %.8X-%.8X", heap_base_, heap_base_ + heap_size_);
XELOGE("------------------------------------------------------------------"); XELOGE("------------------------------------------------------------------");
XELOGE(" Heap Base: %.8X", heap_base_); XELOGE(" Heap Base: %.8X", heap_base_);
XELOGE(" Heap Size: %d (%.8X)", heap_size_, heap_size_); XELOGE(" Heap Size: %d (%.8X)", heap_size_, heap_size_);
XELOGE(" Page Size: %d (%.8X)", page_size_, page_size_); XELOGE(" Page Size: %d (%.8X)", page_size_, page_size_);
XELOGE(" Page Count: %lld", page_table_.size()); XELOGE(" Page Count: %lld", page_table_.size());
XELOGE(" Host Address Offset: %d (%.8X)", host_address_offset_,
host_address_offset_);
bool is_empty_span = false; bool is_empty_span = false;
uint32_t empty_span_start = 0; uint32_t empty_span_start = 0;
for (uint32_t i = 0; i < uint32_t(page_table_.size()); ++i) { for (uint32_t i = 0; i < uint32_t(page_table_.size()); ++i) {
@ -1288,26 +1297,22 @@ PhysicalHeap::~PhysicalHeap() = default;
void PhysicalHeap::Initialize(Memory* memory, uint8_t* membase, void PhysicalHeap::Initialize(Memory* memory, uint8_t* membase,
uint32_t heap_base, uint32_t heap_size, uint32_t heap_base, uint32_t heap_size,
uint32_t page_size, VirtualHeap* parent_heap) { uint32_t page_size, VirtualHeap* parent_heap) {
BaseHeap::Initialize(memory, membase, heap_base, heap_size, page_size); uint32_t host_address_offset;
if (heap_base_ >= 0xE0000000 &&
xe::memory::allocation_granularity() > 0x1000) {
host_address_offset = 0x1000;
} else {
host_address_offset = 0;
}
BaseHeap::Initialize(memory, membase, heap_base, heap_size, page_size,
host_address_offset);
parent_heap_ = parent_heap; parent_heap_ = parent_heap;
system_page_size_ = uint32_t(xe::memory::page_size()); system_page_size_ = uint32_t(xe::memory::page_size());
// If the 4 KB page offset in 0xE0000000 cannot be applied via memory mapping, system_page_count_ =
// it will be added by CPU load/store implementations, so the host virtual (heap_size_ /* already - 1 */ + host_address_offset + system_page_size_) /
// addresses (relative to virtual_membase_) where access violations will occur system_page_size_;
// will not match guest virtual addresses.
if (heap_base_ >= 0xE0000000 &&
xe::memory::allocation_granularity() > 0x1000) {
system_address_offset_ = 0x1000;
} else {
system_address_offset_ = 0;
}
// Include the 0xE0000000 mapping offset because these bits are for host OS
// pages.
system_page_count_ = (heap_size_ /* already - 1 */ + system_address_offset_ +
system_page_size_) /
system_page_size_;
system_pages_watched_write_.resize((system_page_count_ + 63) / 64); system_pages_watched_write_.resize((system_page_count_ + 63) / 64);
std::memset(system_pages_watched_write_.data(), 0, std::memset(system_pages_watched_write_.data(), 0,
system_pages_watched_write_.size() * sizeof(uint64_t)); system_pages_watched_write_.size() * sizeof(uint64_t));
@ -1499,12 +1504,10 @@ void PhysicalHeap::WatchPhysicalWrite(uint32_t physical_address,
return; return;
} }
// Include the 0xE0000000 mapping offset because watches are placed on OS
// pages.
uint32_t system_page_first = uint32_t system_page_first =
(heap_relative_address + system_address_offset_) / system_page_size_; (heap_relative_address + host_address_offset()) / system_page_size_;
uint32_t system_page_last = uint32_t system_page_last =
(heap_relative_address + length - 1 + system_address_offset_) / (heap_relative_address + length - 1 + host_address_offset()) /
system_page_size_; system_page_size_;
system_page_last = std::min(system_page_last, system_page_count_ - 1); system_page_last = std::min(system_page_last, system_page_count_ - 1);
assert_true(system_page_first <= system_page_last); assert_true(system_page_first <= system_page_last);
@ -1522,7 +1525,7 @@ void PhysicalHeap::WatchPhysicalWrite(uint32_t physical_address,
(system_pages_watched_write_[i >> 6] & page_bit) == 0; (system_pages_watched_write_[i >> 6] & page_bit) == 0;
if (add_page_to_watch) { if (add_page_to_watch) {
uint32_t page_number = uint32_t page_number =
xe::sat_sub(i * system_page_size_, system_address_offset_) / xe::sat_sub(i * system_page_size_, host_address_offset()) /
page_size_; page_size_;
if (ToPageAccess(page_table_[page_number].current_protect) != if (ToPageAccess(page_table_[page_number].current_protect) !=
xe::memory::PageAccess::kReadWrite) { xe::memory::PageAccess::kReadWrite) {
@ -1577,12 +1580,10 @@ bool PhysicalHeap::TriggerWatches(uint32_t virtual_address, uint32_t length,
return false; return false;
} }
// Include the 0xE0000000 mapping offset because watches are placed on OS
// pages.
uint32_t system_page_first = uint32_t system_page_first =
(heap_relative_address + system_address_offset_) / system_page_size_; (heap_relative_address + host_address_offset()) / system_page_size_;
uint32_t system_page_last = uint32_t system_page_last =
(heap_relative_address + length - 1 + system_address_offset_) / (heap_relative_address + length - 1 + host_address_offset()) /
system_page_size_; system_page_size_;
system_page_last = std::min(system_page_last, system_page_count_ - 1); system_page_last = std::min(system_page_last, system_page_count_ - 1);
assert_true(system_page_first <= system_page_last); assert_true(system_page_first <= system_page_last);
@ -1619,11 +1620,11 @@ bool PhysicalHeap::TriggerWatches(uint32_t virtual_address, uint32_t length,
uint32_t physical_address_offset = GetPhysicalAddress(heap_base_); uint32_t physical_address_offset = GetPhysicalAddress(heap_base_);
uint32_t physical_address_start = uint32_t physical_address_start =
xe::sat_sub(system_page_first * system_page_size_, xe::sat_sub(system_page_first * system_page_size_,
system_address_offset_) + host_address_offset()) +
physical_address_offset; physical_address_offset;
uint32_t physical_length = std::min( uint32_t physical_length = std::min(
xe::sat_sub(system_page_last * system_page_size_ + system_page_size_, xe::sat_sub(system_page_last * system_page_size_ + system_page_size_,
system_address_offset_) + host_address_offset()) +
physical_address_offset - physical_address_start, physical_address_offset - physical_address_start,
heap_size_ + 1 - (physical_address_start - physical_address_offset)); heap_size_ + 1 - (physical_address_start - physical_address_offset));
uint32_t unwatch_first = 0; uint32_t unwatch_first = 0;
@ -1662,8 +1663,8 @@ bool PhysicalHeap::TriggerWatches(uint32_t virtual_address, uint32_t length,
unwatch_first = std::min(unwatch_first, heap_size_); unwatch_first = std::min(unwatch_first, heap_size_);
unwatch_last = std::min(unwatch_last, heap_size_); unwatch_last = std::min(unwatch_last, heap_size_);
// Convert to system pages and update the range. // Convert to system pages and update the range.
unwatch_first += system_address_offset_; unwatch_first += host_address_offset();
unwatch_last += system_address_offset_; unwatch_last += host_address_offset();
assert_true(unwatch_first <= unwatch_last); assert_true(unwatch_first <= unwatch_last);
system_page_first = unwatch_first / system_page_size_; system_page_first = unwatch_first / system_page_size_;
system_page_last = unwatch_last / system_page_size_; system_page_last = unwatch_last / system_page_size_;
@ -1681,7 +1682,7 @@ bool PhysicalHeap::TriggerWatches(uint32_t virtual_address, uint32_t length,
(uint64_t(1) << (i & 63))) != 0; (uint64_t(1) << (i & 63))) != 0;
if (unprotect_page) { if (unprotect_page) {
uint32_t page_number = uint32_t page_number =
xe::sat_sub(i * system_page_size_, system_address_offset_) / xe::sat_sub(i * system_page_size_, host_address_offset()) /
page_size_; page_size_;
if (ToPageAccess(page_table_[page_number].current_protect) != if (ToPageAccess(page_table_[page_number].current_protect) !=
xe::memory::PageAccess::kReadWrite) { xe::memory::PageAccess::kReadWrite) {

View File

@ -98,6 +98,10 @@ class BaseHeap {
// Size of each page within the heap range in bytes. // Size of each page within the heap range in bytes.
uint32_t page_size() const { return page_size_; } uint32_t page_size() const { return page_size_; }
// Offset added to the virtual addresses to convert them to host addresses
// (not including membase).
uint32_t host_address_offset() const { return host_address_offset_; }
// Disposes and decommits all memory and clears the page table. // Disposes and decommits all memory and clears the page table.
virtual void Dispose(); virtual void Dispose();
@ -167,13 +171,15 @@ class BaseHeap {
BaseHeap(); BaseHeap();
void Initialize(Memory* memory, uint8_t* membase, uint32_t heap_base, void Initialize(Memory* memory, uint8_t* membase, uint32_t heap_base,
uint32_t heap_size, uint32_t page_size); uint32_t heap_size, uint32_t page_size,
uint32_t host_address_offset = 0);
Memory* memory_; Memory* memory_;
uint8_t* membase_; uint8_t* membase_;
uint32_t heap_base_; uint32_t heap_base_;
uint32_t heap_size_; uint32_t heap_size_;
uint32_t page_size_; uint32_t page_size_;
uint32_t host_address_offset_;
xe::global_critical_region global_critical_region_; xe::global_critical_region global_critical_region_;
std::vector<PageEntry> page_table_; std::vector<PageEntry> page_table_;
}; };
@ -229,7 +235,6 @@ class PhysicalHeap : public BaseHeap {
VirtualHeap* parent_heap_; VirtualHeap* parent_heap_;
uint32_t system_page_size_; uint32_t system_page_size_;
uint32_t system_address_offset_;
uint32_t system_page_count_; uint32_t system_page_count_;
// Protected by global_critical_region. // Protected by global_critical_region.
std::vector<uint64_t> system_pages_watched_write_; std::vector<uint64_t> system_pages_watched_write_;