[Memory, D3D12] Various refactoring from data provider development

This commit is contained in:
Triang3l
2020-02-15 21:35:24 +03:00
parent b59ae30ec3
commit 8ec813de82
17 changed files with 490 additions and 362 deletions

View File

@@ -11,6 +11,7 @@
#include <algorithm>
#include <cstring>
#include <utility>
#include "xenia/base/assert.h"
#include "xenia/base/byte_order.h"
@@ -281,6 +282,14 @@ bool MMIOHandler::ExceptionCallback(Exception* ex) {
if (ex->code() != Exception::Code::kAccessViolation) {
return false;
}
Exception::AccessViolationOperation operation =
ex->access_violation_operation();
if (operation != Exception::AccessViolationOperation::kRead &&
operation != Exception::AccessViolationOperation::kWrite) {
// Data Execution Prevention or something else uninteresting.
return false;
}
bool is_write = operation == Exception::AccessViolationOperation::kWrite;
if (ex->fault_address() < uint64_t(virtual_membase_) ||
ex->fault_address() > uint64_t(memory_end_)) {
// Quick kill anything outside our mapping.
@@ -304,32 +313,23 @@ bool MMIOHandler::ExceptionCallback(Exception* ex) {
}
if (!range) {
// Recheck if the pages are still protected (race condition - another thread
// clears the writewatch we just hit).
// clears the watch we just hit).
// Do this under the lock so we don't introduce another race condition.
auto lock = global_critical_region_.Acquire();
memory::PageAccess cur_access;
size_t page_length = memory::page_size();
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.
if (cur_access != memory::PageAccess::kNoAccess &&
(!is_write || cur_access != memory::PageAccess::kReadOnly)) {
// Another thread has cleared this watch. Abort.
return true;
}
// The address is not found within any range, so either a write watch or an
// actual access violation.
if (access_violation_callback_) {
switch (ex->access_violation_operation()) {
case Exception::AccessViolationOperation::kRead:
return access_violation_callback_(access_violation_callback_context_,
fault_host_address, false);
case Exception::AccessViolationOperation::kWrite:
return access_violation_callback_(access_violation_callback_context_,
fault_host_address, true);
default:
// Data Execution Prevention or something else uninteresting.
break;
}
return access_violation_callback_(std::move(lock),
access_violation_callback_context_,
fault_host_address, is_write);
}
return false;
}

View File

@@ -11,6 +11,7 @@
#define XENIA_CPU_MMIO_HANDLER_H_
#include <memory>
#include <mutex>
#include <vector>
#include "xenia/base/mutex.h"
@@ -44,12 +45,13 @@ class MMIOHandler {
typedef uint32_t (*HostToGuestVirtual)(const void* context,
const void* host_address);
typedef bool (*AccessViolationCallback)(void* context, void* host_address,
bool is_write);
typedef bool (*AccessViolationCallback)(
std::unique_lock<std::recursive_mutex> global_lock_locked_once,
void* context, void* host_address, bool is_write);
// access_violation_callback is called in global_critical_region, so if
// multiple threads trigger an access violation in the same page, the callback
// will be called only once.
// access_violation_callback is called with global_critical_region locked once
// on the thread, so if multiple threads trigger an access violation in the
// same page, the callback 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,