Starting to properly attribute virtual vs. physical memory accesses.
This commit is contained in:
@@ -368,8 +368,7 @@ uint64_t TrapDebugPrint(void* raw_context, uint64_t address) {
|
||||
auto thread_state = *reinterpret_cast<ThreadState**>(raw_context);
|
||||
uint32_t str_ptr = uint32_t(thread_state->context()->r[3]);
|
||||
uint16_t str_len = uint16_t(thread_state->context()->r[4]);
|
||||
const char* str =
|
||||
reinterpret_cast<const char*>(thread_state->memory()->Translate(str_ptr));
|
||||
auto str = thread_state->memory()->TranslateVirtual<const char*>(str_ptr);
|
||||
// TODO(benvanik): truncate to length?
|
||||
PLOGD("(DebugPrint) %s", str);
|
||||
return 0;
|
||||
|
||||
@@ -37,7 +37,7 @@ int X64Function::RemoveBreakpointImpl(Breakpoint* breakpoint) { return 0; }
|
||||
int X64Function::CallImpl(ThreadState* thread_state, uint32_t return_address) {
|
||||
auto backend = (X64Backend*)thread_state->runtime()->backend();
|
||||
auto thunk = backend->host_to_guest_thunk();
|
||||
thunk(machine_code_, thread_state->raw_context(),
|
||||
thunk(machine_code_, thread_state->context(),
|
||||
reinterpret_cast<void*>(uintptr_t(return_address)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ typedef struct alignas(64) PPCContext_s {
|
||||
// TODO(benvanik): find a nice way to describe this to the JIT.
|
||||
ThreadState* thread_state;
|
||||
// TODO(benvanik): this is getting nasty. Must be here.
|
||||
uint8_t* membase;
|
||||
uint8_t* virtual_membase;
|
||||
|
||||
// Most frequently used registers first.
|
||||
uint64_t r[32]; // General purpose registers
|
||||
@@ -210,6 +210,8 @@ typedef struct alignas(64) PPCContext_s {
|
||||
// current runtime and its data.
|
||||
Runtime* runtime;
|
||||
|
||||
uint8_t* physical_membase;
|
||||
|
||||
void SetRegFromString(const char* name, const char* value);
|
||||
bool CompareRegWithString(const char* name, const char* value,
|
||||
char* out_value, size_t out_value_size);
|
||||
|
||||
@@ -46,7 +46,6 @@ int PPCHIRBuilder::Emit(FunctionInfo* symbol_info, uint32_t flags) {
|
||||
SCOPE_profile_cpu_f("cpu");
|
||||
|
||||
Memory* memory = frontend_->memory();
|
||||
const uint8_t* p = memory->membase();
|
||||
|
||||
symbol_info_ = symbol_info;
|
||||
start_address_ = symbol_info->address();
|
||||
@@ -80,7 +79,7 @@ int PPCHIRBuilder::Emit(FunctionInfo* symbol_info, uint32_t flags) {
|
||||
for (uint32_t address = start_address, offset = 0; address <= end_address;
|
||||
address += 4, offset++) {
|
||||
i.address = address;
|
||||
i.code = poly::load_and_swap<uint32_t>(p + address);
|
||||
i.code = poly::load_and_swap<uint32_t>(memory->TranslateVirtual(address));
|
||||
// TODO(benvanik): find a way to avoid using the opcode tables.
|
||||
i.type = GetInstrType(i.code);
|
||||
trace_info_.dest_count = 0;
|
||||
|
||||
@@ -50,7 +50,6 @@ int PPCScanner::FindExtents(FunctionInfo* symbol_info) {
|
||||
// split up and the second half is treated as another function.
|
||||
|
||||
Memory* memory = frontend_->memory();
|
||||
const uint8_t* p = memory->membase();
|
||||
|
||||
LOGPPC("Analyzing function %.8X...", symbol_info->address());
|
||||
|
||||
@@ -64,7 +63,7 @@ int PPCScanner::FindExtents(FunctionInfo* symbol_info) {
|
||||
InstrData i;
|
||||
while (true) {
|
||||
i.address = address;
|
||||
i.code = poly::load_and_swap<uint32_t>(p + address);
|
||||
i.code = poly::load_and_swap<uint32_t>(memory->TranslateVirtual(address));
|
||||
|
||||
// If we fetched 0 assume that we somehow hit one of the awesome
|
||||
// 'no really we meant to end after that bl' functions.
|
||||
@@ -281,7 +280,6 @@ int PPCScanner::FindExtents(FunctionInfo* symbol_info) {
|
||||
|
||||
std::vector<BlockInfo> PPCScanner::FindBlocks(FunctionInfo* symbol_info) {
|
||||
Memory* memory = frontend_->memory();
|
||||
const uint8_t* p = memory->membase();
|
||||
|
||||
std::map<uint32_t, BlockInfo> block_map;
|
||||
|
||||
@@ -292,7 +290,7 @@ std::vector<BlockInfo> PPCScanner::FindBlocks(FunctionInfo* symbol_info) {
|
||||
InstrData i;
|
||||
for (uint32_t address = start_address; address <= end_address; address += 4) {
|
||||
i.address = address;
|
||||
i.code = poly::load_and_swap<uint32_t>(p + address);
|
||||
i.code = poly::load_and_swap<uint32_t>(memory->TranslateVirtual(address));
|
||||
if (!i.code) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -175,7 +175,6 @@ int PPCTranslator::Translate(FunctionInfo* symbol_info,
|
||||
void PPCTranslator::DumpSource(FunctionInfo* symbol_info,
|
||||
poly::StringBuffer* string_buffer) {
|
||||
Memory* memory = frontend_->memory();
|
||||
const uint8_t* p = memory->membase();
|
||||
|
||||
string_buffer->Append("%s fn %.8X-%.8X %s\n",
|
||||
symbol_info->module()->name().c_str(),
|
||||
@@ -184,14 +183,14 @@ void PPCTranslator::DumpSource(FunctionInfo* symbol_info,
|
||||
|
||||
auto blocks = scanner_->FindBlocks(symbol_info);
|
||||
|
||||
uint64_t start_address = symbol_info->address();
|
||||
uint64_t end_address = symbol_info->end_address();
|
||||
uint32_t start_address = symbol_info->address();
|
||||
uint32_t end_address = symbol_info->end_address();
|
||||
InstrData i;
|
||||
auto block_it = blocks.begin();
|
||||
for (uint64_t address = start_address, offset = 0; address <= end_address;
|
||||
for (uint32_t address = start_address, offset = 0; address <= end_address;
|
||||
address += 4, offset++) {
|
||||
i.address = address;
|
||||
i.code = poly::load_and_swap<uint32_t>(p + address);
|
||||
i.code = poly::load_and_swap<uint32_t>(memory->TranslateVirtual(address));
|
||||
// TODO(benvanik): find a way to avoid using the opcode tables.
|
||||
i.type = GetInstrType(i.code);
|
||||
|
||||
|
||||
@@ -241,7 +241,7 @@ class TestRunner {
|
||||
auto address_str = it.second.substr(0, space_pos);
|
||||
auto bytes_str = it.second.substr(space_pos + 1);
|
||||
uint32_t address = std::strtoul(address_str.c_str(), nullptr, 16);
|
||||
auto p = memory->Translate(address);
|
||||
auto p = memory->TranslateVirtual(address);
|
||||
const char* c = bytes_str.c_str();
|
||||
while (*c) {
|
||||
while (*c == ' ') ++c;
|
||||
@@ -283,7 +283,7 @@ class TestRunner {
|
||||
auto address_str = it.second.substr(0, space_pos);
|
||||
auto bytes_str = it.second.substr(space_pos + 1);
|
||||
uint32_t address = std::strtoul(address_str.c_str(), nullptr, 16);
|
||||
auto base_address = memory->Translate(address);
|
||||
auto base_address = memory->TranslateVirtual(address);
|
||||
auto p = base_address;
|
||||
const char* c = bytes_str.c_str();
|
||||
while (*c) {
|
||||
|
||||
@@ -88,7 +88,7 @@ int Function::Call(ThreadState* thread_state, uint32_t return_address) {
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
handler(thread_state->raw_context(), symbol_info_->extern_arg0(),
|
||||
handler(thread_state->context(), symbol_info_->extern_arg0(),
|
||||
symbol_info_->extern_arg1());
|
||||
} else {
|
||||
PLOGW("undefined extern call to %.8llX %s", symbol_info_->address(),
|
||||
|
||||
@@ -163,8 +163,8 @@ uint64_t Processor::ExecuteInterrupt(uint32_t cpu, uint32_t address,
|
||||
std::lock_guard<std::mutex> lock(interrupt_thread_lock_);
|
||||
|
||||
// Set 0x10C(r13) to the current CPU ID.
|
||||
uint8_t* p = memory_->membase();
|
||||
poly::store_and_swap<uint8_t>(p + interrupt_thread_block_ + 0x10C, cpu);
|
||||
poly::store_and_swap<uint8_t>(
|
||||
memory_->TranslateVirtual(interrupt_thread_block_ + 0x10C), cpu);
|
||||
|
||||
// Execute interrupt.
|
||||
uint64_t result = Execute(interrupt_thread_state_, address, args, arg_count);
|
||||
|
||||
@@ -30,8 +30,8 @@ int RawModule::LoadFile(uint32_t base_address, const std::wstring& path) {
|
||||
// Allocate memory.
|
||||
// Since we have no real heap just load it wherever.
|
||||
base_address_ = base_address;
|
||||
uint8_t* p = memory_->Translate(base_address_);
|
||||
memset(p, 0, file_length);
|
||||
uint8_t* p = memory_->TranslateVirtual(base_address_);
|
||||
std::memset(p, 0, file_length);
|
||||
|
||||
// Read into memory.
|
||||
fread(p, file_length, 1, file);
|
||||
|
||||
@@ -29,7 +29,6 @@ ThreadState::ThreadState(Runtime* runtime, uint32_t thread_id,
|
||||
thread_id_(thread_id),
|
||||
name_(""),
|
||||
backend_data_(0),
|
||||
raw_context_(0),
|
||||
stack_size_(stack_size),
|
||||
thread_state_address_(thread_state_address) {
|
||||
if (thread_id_ == UINT_MAX) {
|
||||
@@ -50,13 +49,16 @@ ThreadState::ThreadState(Runtime* runtime, uint32_t thread_id,
|
||||
assert_not_zero(stack_address_);
|
||||
|
||||
// Allocate with 64b alignment.
|
||||
context_ = (PPCContext*)calloc(1, sizeof(PPCContext));
|
||||
assert_true(((uint64_t)context_ & 0xF) == 0);
|
||||
context_ =
|
||||
reinterpret_cast<PPCContext*>(_aligned_malloc(sizeof(PPCContext), 64));
|
||||
assert_true(((uint64_t)context_ & 0x3F) == 0);
|
||||
std::memset(context_, 0, sizeof(PPCContext));
|
||||
|
||||
// Stash pointers to common structures that callbacks may need.
|
||||
context_->reserve_address = memory_->reserve_address();
|
||||
context_->reserve_value = memory_->reserve_value();
|
||||
context_->membase = memory_->membase();
|
||||
context_->virtual_membase = memory_->virtual_membase();
|
||||
context_->physical_membase = memory_->physical_membase();
|
||||
context_->runtime = runtime;
|
||||
context_->thread_state = this;
|
||||
context_->thread_id = thread_id_;
|
||||
@@ -69,8 +71,6 @@ ThreadState::ThreadState(Runtime* runtime, uint32_t thread_id,
|
||||
// 16 to 32b.
|
||||
context_->r[1] -= 64;
|
||||
|
||||
raw_context_ = context_;
|
||||
|
||||
runtime_->debugger()->OnThreadCreated(this);
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ ThreadState::~ThreadState() {
|
||||
thread_state_ = nullptr;
|
||||
}
|
||||
|
||||
free(context_);
|
||||
_aligned_free(context_);
|
||||
if (stack_allocated_) {
|
||||
memory()->SystemHeapFree(stack_address_);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ class ThreadState {
|
||||
const std::string& name() const { return name_; }
|
||||
void set_name(const std::string& value) { name_ = value; }
|
||||
void* backend_data() const { return backend_data_; }
|
||||
void* raw_context() const { return raw_context_; }
|
||||
uint32_t stack_address() const { return stack_address_; }
|
||||
size_t stack_size() const { return stack_size_; }
|
||||
uint32_t thread_state_address() const { return thread_state_address_; }
|
||||
@@ -60,7 +59,6 @@ class ThreadState {
|
||||
uint32_t thread_id_;
|
||||
std::string name_;
|
||||
void* backend_data_;
|
||||
void* raw_context_;
|
||||
uint32_t stack_address_;
|
||||
bool stack_allocated_;
|
||||
uint32_t stack_size_;
|
||||
|
||||
@@ -99,8 +99,6 @@ int XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t* membase = memory_->membase();
|
||||
|
||||
char name[128];
|
||||
for (size_t n = 0; n < import_info_count; n++) {
|
||||
const xe_xex2_import_info_t* info = &import_infos[n];
|
||||
@@ -129,7 +127,7 @@ int XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
||||
|
||||
// Grab, if available.
|
||||
if (kernel_export) {
|
||||
uint32_t* slot = (uint32_t*)(membase + info->value_address);
|
||||
auto slot = memory_->TranslateVirtual<uint32_t*>(info->value_address);
|
||||
if (kernel_export->type == KernelExport::Function) {
|
||||
// Not exactly sure what this should be...
|
||||
if (info->thunk_address) {
|
||||
@@ -176,7 +174,7 @@ int XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
||||
// blr
|
||||
// nop
|
||||
// nop
|
||||
uint8_t* p = memory()->Translate(info->thunk_address);
|
||||
uint8_t* p = memory()->TranslateVirtual(info->thunk_address);
|
||||
poly::store_and_swap<uint32_t>(p + 0x0, 0x44000002);
|
||||
poly::store_and_swap<uint32_t>(p + 0x4, 0x4E800020);
|
||||
poly::store_and_swap<uint32_t>(p + 0x8, 0x60000000);
|
||||
|
||||
Reference in New Issue
Block a user