Merge pull request #445 from DrChat/kernel_trampolines
Generate trampoline functions for GetProcAddress on kernel modules
This commit is contained in:
commit
e0b3d24a50
|
@ -61,6 +61,12 @@ bool RawModule::LoadFile(uint32_t base_address, const std::wstring& path) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RawModule::SetAddressRange(uint32_t base_address, uint32_t size) {
|
||||||
|
base_address_ = base_address;
|
||||||
|
low_address_ = base_address;
|
||||||
|
high_address_ = base_address + size;
|
||||||
|
}
|
||||||
|
|
||||||
bool RawModule::ContainsAddress(uint32_t address) {
|
bool RawModule::ContainsAddress(uint32_t address) {
|
||||||
return address >= low_address_ && address < high_address_;
|
return address >= low_address_ && address < high_address_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,12 @@ class RawModule : public Module {
|
||||||
|
|
||||||
bool LoadFile(uint32_t base_address, const std::wstring& path);
|
bool LoadFile(uint32_t base_address, const std::wstring& path);
|
||||||
|
|
||||||
|
// Set address range if you've already allocated memory and placed code
|
||||||
|
// in it.
|
||||||
|
void SetAddressRange(uint32_t base_address, uint32_t size);
|
||||||
|
|
||||||
const std::string& name() const override { return name_; }
|
const std::string& name() const override { return name_; }
|
||||||
|
void set_name(const std::string& name) { name_ = name; }
|
||||||
|
|
||||||
bool ContainsAddress(uint32_t address) override;
|
bool ContainsAddress(uint32_t address) override;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include "xenia/kernel/kernel_module.h"
|
#include "xenia/kernel/kernel_module.h"
|
||||||
|
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/mutex.h"
|
||||||
|
#include "xenia/cpu/raw_module.h"
|
||||||
#include "xenia/emulator.h"
|
#include "xenia/emulator.h"
|
||||||
#include "xenia/kernel/xthread.h"
|
#include "xenia/kernel/xthread.h"
|
||||||
|
|
||||||
|
@ -22,6 +24,26 @@ KernelModule::KernelModule(KernelState* kernel_state, const char* path)
|
||||||
memory_ = emulator_->memory();
|
memory_ = emulator_->memory();
|
||||||
export_resolver_ = kernel_state->emulator()->export_resolver();
|
export_resolver_ = kernel_state->emulator()->export_resolver();
|
||||||
|
|
||||||
|
// HACK: Allocates memory where xboxkrnl.exe would be!
|
||||||
|
// TODO: Need to free this memory when necessary.
|
||||||
|
auto heap = memory()->LookupHeap(0x80040000);
|
||||||
|
if (heap->AllocRange(0x80040000, 0x801C0000, kTrampolineSize, 16,
|
||||||
|
kMemoryAllocationCommit,
|
||||||
|
kMemoryProtectRead | kMemoryProtectWrite, false,
|
||||||
|
&guest_trampoline_)) {
|
||||||
|
guest_trampoline_size_ = kTrampolineSize;
|
||||||
|
|
||||||
|
auto module = std::make_unique<cpu::RawModule>(emulator_->processor());
|
||||||
|
guest_trampoline_module_ = module.get();
|
||||||
|
|
||||||
|
module->set_name(name_ + "_trampoline");
|
||||||
|
module->SetAddressRange(guest_trampoline_, guest_trampoline_size_);
|
||||||
|
emulator_->processor()->AddModule(std::move(module));
|
||||||
|
} else {
|
||||||
|
XELOGW("KernelModule %s could not allocate trampoline for GetProcAddress!",
|
||||||
|
path);
|
||||||
|
}
|
||||||
|
|
||||||
OnLoad();
|
OnLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,10 +67,51 @@ uint32_t KernelModule::GetProcAddressByOrdinal(uint16_t ordinal) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (export_entry->function_data.shim) {
|
if (export_entry->function_data.trampoline ||
|
||||||
// Implemented. Dynamically generate trampoline.
|
export_entry->function_data.shim) {
|
||||||
XELOGE("GetProcAddressByOrdinal not implemented");
|
global_critical_region_.Acquire();
|
||||||
return 0;
|
|
||||||
|
// See if the function has been generated already.
|
||||||
|
if (guest_trampoline_map_.find(ordinal) != guest_trampoline_map_.end()) {
|
||||||
|
auto entry = guest_trampoline_map_.find(ordinal);
|
||||||
|
return entry->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the function.
|
||||||
|
assert_true(guest_trampoline_next_ * 8 < guest_trampoline_size_);
|
||||||
|
if (guest_trampoline_next_ * 8 >= guest_trampoline_size_) {
|
||||||
|
assert_always(); // If you hit this, increase kTrampolineSize
|
||||||
|
XELOGE("KernelModule::GetProcAddressByOrdinal trampoline exhausted");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t guest_addr = guest_trampoline_ + (guest_trampoline_next_++ * 8);
|
||||||
|
|
||||||
|
auto mem = memory()->TranslateVirtual(guest_addr);
|
||||||
|
xe::store_and_swap<uint32_t>(mem + 0x0, 0x44000002); // sc
|
||||||
|
xe::store_and_swap<uint32_t>(mem + 0x4, 0x4E800020); // blr
|
||||||
|
|
||||||
|
// Declare/define the extern function.
|
||||||
|
cpu::Function* function;
|
||||||
|
guest_trampoline_module_->DeclareFunction(guest_addr, &function);
|
||||||
|
function->set_end_address(guest_addr + 8);
|
||||||
|
function->set_name(std::string("__T_") + export_entry->name);
|
||||||
|
|
||||||
|
cpu::GuestFunction::ExternHandler handler = nullptr;
|
||||||
|
if (export_entry->function_data.trampoline) {
|
||||||
|
handler = (cpu::GuestFunction::ExternHandler)
|
||||||
|
export_entry->function_data.trampoline;
|
||||||
|
} else {
|
||||||
|
handler =
|
||||||
|
(cpu::GuestFunction::ExternHandler)export_entry->function_data.shim;
|
||||||
|
}
|
||||||
|
static_cast<cpu::GuestFunction*>(function)->SetupExtern(handler);
|
||||||
|
|
||||||
|
function->set_status(cpu::Symbol::Status::kDeclared);
|
||||||
|
|
||||||
|
// Register the function in our map.
|
||||||
|
guest_trampoline_map_[ordinal] = guest_addr;
|
||||||
|
return guest_addr;
|
||||||
} else {
|
} else {
|
||||||
// Not implemented.
|
// Not implemented.
|
||||||
XELOGW(
|
XELOGW(
|
||||||
|
@ -61,7 +124,8 @@ uint32_t KernelModule::GetProcAddressByOrdinal(uint16_t ordinal) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t KernelModule::GetProcAddressByName(const char* name) {
|
uint32_t KernelModule::GetProcAddressByName(const char* name) {
|
||||||
XELOGE("GetProcAddressByName not implemented");
|
// TODO: Does this even work for kernel modules?
|
||||||
|
XELOGE("KernelModule::GetProcAddressByName not implemented");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
#include "xenia/kernel/xmodule.h"
|
#include "xenia/kernel/xmodule.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
namespace cpu {
|
||||||
|
class RawModule;
|
||||||
|
} // namespace cpu
|
||||||
|
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
class KernelState;
|
class KernelState;
|
||||||
|
@ -30,6 +34,16 @@ class KernelModule : public XModule {
|
||||||
Emulator* emulator_;
|
Emulator* emulator_;
|
||||||
Memory* memory_;
|
Memory* memory_;
|
||||||
xe::cpu::ExportResolver* export_resolver_;
|
xe::cpu::ExportResolver* export_resolver_;
|
||||||
|
|
||||||
|
// Guest trampoline for GetProcAddress
|
||||||
|
static const uint32_t kTrampolineSize = 400 * 8;
|
||||||
|
uint32_t guest_trampoline_ = 0;
|
||||||
|
uint32_t guest_trampoline_next_ = 0; // Next free entry to be generated.
|
||||||
|
uint32_t guest_trampoline_size_ = 0;
|
||||||
|
cpu::RawModule* guest_trampoline_module_ = nullptr;
|
||||||
|
std::map<uint16_t, uint32_t> guest_trampoline_map_;
|
||||||
|
|
||||||
|
xe::global_critical_region global_critical_region_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
|
|
Loading…
Reference in New Issue