[Memory] Add HostToGuestVirtual and use it in a couple of places

This commit is contained in:
Triang3l
2019-08-13 23:49:49 +03:00
parent f1b9e1afce
commit 741b5ae2ec
7 changed files with 80 additions and 40 deletions

View File

@@ -25,6 +25,8 @@ MMIOHandler* MMIOHandler::global_handler_ = nullptr;
std::unique_ptr<MMIOHandler> MMIOHandler::Install(
uint8_t* virtual_membase, uint8_t* physical_membase, uint8_t* membase_end,
HostToGuestVirtual host_to_guest_virtual,
const void* host_to_guest_virtual_context,
AccessViolationCallback access_violation_callback,
void* access_violation_callback_context) {
// There can be only one handler at a time.
@@ -34,7 +36,8 @@ std::unique_ptr<MMIOHandler> MMIOHandler::Install(
}
auto handler = std::unique_ptr<MMIOHandler>(new MMIOHandler(
virtual_membase, physical_membase, membase_end, access_violation_callback,
virtual_membase, physical_membase, membase_end, host_to_guest_virtual,
host_to_guest_virtual_context, access_violation_callback,
access_violation_callback_context));
// Install the exception handler directed at the MMIOHandler.
@@ -46,11 +49,15 @@ std::unique_ptr<MMIOHandler> MMIOHandler::Install(
MMIOHandler::MMIOHandler(uint8_t* virtual_membase, uint8_t* physical_membase,
uint8_t* membase_end,
HostToGuestVirtual host_to_guest_virtual,
const void* host_to_guest_virtual_context,
AccessViolationCallback access_violation_callback,
void* access_violation_callback_context)
: virtual_membase_(virtual_membase),
physical_membase_(physical_membase),
memory_end_(membase_end),
host_to_guest_virtual_(host_to_guest_virtual),
host_to_guest_virtual_context_(host_to_guest_virtual_context),
access_violation_callback_(access_violation_callback),
access_violation_callback_context_(access_violation_callback_context) {}
@@ -279,14 +286,16 @@ bool MMIOHandler::ExceptionCallback(Exception* ex) {
// Quick kill anything outside our mapping.
return false;
}
void* fault_host_address = reinterpret_cast<void*>(ex->fault_address());
// Access violations are pretty rare, so we can do a linear search here.
// Only check if in the virtual range, as we only support virtual ranges.
const MMIORange* range = nullptr;
if (ex->fault_address() < uint64_t(physical_membase_)) {
uint32_t fault_virtual_address = host_to_guest_virtual_(
host_to_guest_virtual_context_, fault_host_address);
for (const auto& test_range : mapped_ranges_) {
if ((static_cast<uint32_t>(ex->fault_address()) & test_range.mask) ==
test_range.address) {
if ((fault_virtual_address & test_range.mask) == test_range.address) {
// Address is within the range of this mapping.
range = &test_range;
break;
@@ -300,8 +309,7 @@ bool MMIOHandler::ExceptionCallback(Exception* ex) {
auto lock = global_critical_region_.Acquire();
memory::PageAccess cur_access;
size_t page_length = memory::page_size();
memory::QueryProtect(reinterpret_cast<void*>(ex->fault_address()),
page_length, cur_access);
memory::QueryProtect(fault_host_address, page_length, cur_access);
if (cur_access != memory::PageAccess::kReadOnly &&
cur_access != memory::PageAccess::kNoAccess) {
// Another thread has cleared this write watch. Abort.
@@ -314,10 +322,10 @@ bool MMIOHandler::ExceptionCallback(Exception* ex) {
switch (ex->access_violation_operation()) {
case Exception::AccessViolationOperation::kRead:
return access_violation_callback_(access_violation_callback_context_,
size_t(ex->fault_address()), false);
fault_host_address, false);
case Exception::AccessViolationOperation::kWrite:
return access_violation_callback_(access_violation_callback_context_,
size_t(ex->fault_address()), true);
fault_host_address, true);
default:
// Data Execution Prevention or something else uninteresting.
break;

View File

@@ -27,8 +27,6 @@ typedef uint32_t (*MMIOReadCallback)(void* ppc_context, void* callback_context,
uint32_t addr);
typedef void (*MMIOWriteCallback)(void* ppc_context, void* callback_context,
uint32_t addr, uint32_t value);
typedef void (*AccessWatchCallback)(void* context_ptr, void* data_ptr,
uint32_t address);
struct MMIORange {
uint32_t address;
@@ -44,7 +42,9 @@ class MMIOHandler {
public:
virtual ~MMIOHandler();
typedef bool (*AccessViolationCallback)(void* context, size_t host_address,
typedef uint32_t (*HostToGuestVirtual)(const void* context,
const void* host_address);
typedef bool (*AccessViolationCallback)(void* context, void* host_address,
bool is_write);
// access_violation_callback is called in global_critical_region, so if
@@ -52,6 +52,8 @@ class MMIOHandler {
// will be called only once.
static std::unique_ptr<MMIOHandler> Install(
uint8_t* virtual_membase, uint8_t* physical_membase, uint8_t* membase_end,
HostToGuestVirtual host_to_guest_virtual,
const void* host_to_guest_virtual_context,
AccessViolationCallback access_violation_callback,
void* access_violation_callback_context);
static MMIOHandler* global_handler() { return global_handler_; }
@@ -66,7 +68,8 @@ class MMIOHandler {
protected:
MMIOHandler(uint8_t* virtual_membase, uint8_t* physical_membase,
uint8_t* membase_end,
uint8_t* membase_end, HostToGuestVirtual host_to_guest_virtual,
const void* host_to_guest_virtual_context,
AccessViolationCallback access_violation_callback,
void* access_violation_callback_context);
@@ -79,6 +82,9 @@ class MMIOHandler {
std::vector<MMIORange> mapped_ranges_;
HostToGuestVirtual host_to_guest_virtual_;
const void* host_to_guest_virtual_context_;
AccessViolationCallback access_violation_callback_;
void* access_violation_callback_context_;