Files
Xenia-Canary/src/xenia/kernel/kernel_module.cc
2017-02-06 00:40:06 -06:00

154 lines
5.1 KiB
C++

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/kernel/kernel_module.h"
#include "xenia/base/logging.h"
#include "xenia/base/mutex.h"
#include "xenia/cpu/processor.h"
#include "xenia/cpu/raw_module.h"
#include "xenia/emulator.h"
#include "xenia/kernel/xthread.h"
namespace xe {
namespace kernel {
KernelModule::KernelModule(KernelState* kernel_state, const char* path)
: XModule(kernel_state, ModuleType::kKernelModule) {
emulator_ = kernel_state->emulator();
memory_ = emulator_->memory();
export_resolver_ = kernel_state->emulator()->export_resolver();
path_ = path;
name_ = NameFromPath(path);
// Persist this object through reloads.
host_object_ = true;
// 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();
}
KernelModule::~KernelModule() {}
uint32_t KernelModule::GenerateTrampoline(
std::string name, cpu::GuestFunction::ExternHandler handler,
cpu::Export* export_data) {
// 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::GenerateTrampoline 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_") + name);
static_cast<cpu::GuestFunction*>(function)->SetupExtern(handler, export_data);
function->set_status(cpu::Symbol::Status::kDeclared);
return guest_addr;
}
uint32_t KernelModule::GetProcAddressByOrdinal(uint16_t ordinal) {
auto export_entry =
export_resolver_->GetExportByOrdinal(name().c_str(), ordinal);
if (!export_entry) {
// Export (or its parent library) not found.
return 0;
}
if (export_entry->type == cpu::Export::Type::kVariable) {
if (export_entry->variable_ptr) {
return export_entry->variable_ptr;
} else {
XELOGW(
"ERROR: var export referenced GetProcAddressByOrdinal(%.4X(%s)) is "
"not implemented",
ordinal, export_entry->name);
return 0;
}
} else {
if (export_entry->function_data.trampoline ||
export_entry->function_data.shim) {
global_critical_region_.Acquire();
// 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;
}
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;
}
uint32_t guest_addr =
GenerateTrampoline(export_entry->name, handler, export_entry);
XELOGD("GetProcAddressByOrdinal(\"%s\", \"%s\") = %.8X", name().c_str(),
export_entry->name, guest_addr);
// Register the function in our map.
guest_trampoline_map_[ordinal] = guest_addr;
return guest_addr;
} else {
// Not implemented.
XELOGW(
"ERROR: fn export referenced GetProcAddressByOrdinal(%.4X(%s)) is "
"not implemented",
ordinal, export_entry->name);
return 0;
}
}
}
uint32_t KernelModule::GetProcAddressByName(const char* name) {
// TODO: Does this even work for kernel modules?
XELOGE("KernelModule::GetProcAddressByName not implemented");
return 0;
}
} // namespace kernel
} // namespace xe