From 6c4af5aa70b477b4374fa41cdb206d1eed6fafe1 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Mon, 28 Jan 2013 12:36:39 -0800 Subject: [PATCH] Kernel calls and variables now working and tracing better. --- include/xenia/cpu/codegen/module_generator.h | 5 +- include/xenia/cpu/ppc/state.h | 1 + include/xenia/cpu/thread_state.h | 1 + include/xenia/kernel/export.h | 7 +- src/cpu/codegen/function_generator.cc | 41 ++++--- src/cpu/codegen/module_generator.cc | 48 ++++++-- src/cpu/exec_module.cc | 24 ++-- src/cpu/thread_state.cc | 6 + src/kernel/export.cc | 10 +- src/kernel/modules/xboxkrnl/kernel_state.cc | 33 ++++++ src/kernel/modules/xboxkrnl/kernel_state.h | 44 +++++++ src/kernel/modules/xboxkrnl/sources.gypi | 3 + src/kernel/modules/xboxkrnl/xboxkrnl_hal.cc | 54 +++++++++ src/kernel/modules/xboxkrnl/xboxkrnl_hal.h | 29 +++++ .../modules/xboxkrnl/xboxkrnl_memory.cc | 112 ++++++++++++++++++ src/kernel/modules/xboxkrnl/xboxkrnl_memory.h | 29 +++++ .../modules/xboxkrnl/xboxkrnl_module.cc | 17 ++- src/kernel/modules/xboxkrnl/xboxkrnl_module.h | 6 +- src/kernel/shim_utils.h | 43 +++++++ 19 files changed, 462 insertions(+), 51 deletions(-) create mode 100644 src/kernel/modules/xboxkrnl/kernel_state.cc create mode 100644 src/kernel/modules/xboxkrnl/kernel_state.h create mode 100644 src/kernel/modules/xboxkrnl/xboxkrnl_hal.cc create mode 100644 src/kernel/modules/xboxkrnl/xboxkrnl_hal.h create mode 100644 src/kernel/modules/xboxkrnl/xboxkrnl_memory.cc create mode 100644 src/kernel/modules/xboxkrnl/xboxkrnl_memory.h create mode 100644 src/kernel/shim_utils.h diff --git a/include/xenia/cpu/codegen/module_generator.h b/include/xenia/cpu/codegen/module_generator.h index beea1e266..e0a2541ee 100644 --- a/include/xenia/cpu/codegen/module_generator.h +++ b/include/xenia/cpu/codegen/module_generator.h @@ -23,6 +23,7 @@ namespace llvm { class DIBuilder; + class ExecutionEngine; class Function; class FunctionType; class LLVMContext; @@ -42,7 +43,8 @@ public: xe_memory_ref memory, kernel::ExportResolver* export_resolver, const char* module_name, const char* module_path, sdb::SymbolDatabase* sdb, - llvm::LLVMContext* context, llvm::Module* gen_module); + llvm::LLVMContext* context, llvm::Module* gen_module, + llvm::ExecutionEngine* engine); ~ModuleGenerator(); int Generate(); @@ -76,6 +78,7 @@ private: llvm::LLVMContext* context_; llvm::Module* gen_module_; + llvm::ExecutionEngine* engine_; llvm::DIBuilder* di_builder_; llvm::MDNode* cu_; diff --git a/include/xenia/cpu/ppc/state.h b/include/xenia/cpu/ppc/state.h index 5262e2a9b..e15ec6086 100644 --- a/include/xenia/cpu/ppc/state.h +++ b/include/xenia/cpu/ppc/state.h @@ -143,6 +143,7 @@ typedef struct XECACHEALIGN64 xe_ppc_state { // Runtime-specific data pointer. Used on callbacks to get access to the // current runtime and its data. + uint8_t* membase; void* processor; void* thread_state; void* runtime; diff --git a/include/xenia/cpu/thread_state.h b/include/xenia/cpu/thread_state.h index efe71befe..60ab75edc 100644 --- a/include/xenia/cpu/thread_state.h +++ b/include/xenia/cpu/thread_state.h @@ -33,6 +33,7 @@ public: private: uint32_t stack_address_; uint32_t stack_size_; + xe_memory_ref memory_; xe_ppc_state_t ppc_state_; }; diff --git a/include/xenia/kernel/export.h b/include/xenia/kernel/export.h index e8a3d7473..15a1d2a9b 100644 --- a/include/xenia/kernel/export.h +++ b/include/xenia/kernel/export.h @@ -23,7 +23,7 @@ namespace kernel { typedef void (*xe_kernel_export_impl_fn)(); -typedef void (*xe_kernel_export_shim_fn)(xe_ppc_state_t* state); +typedef void (*xe_kernel_export_shim_fn)(xe_ppc_state_t*, void*); class KernelExport { public: @@ -47,6 +47,9 @@ public: uint32_t variable_ptr; struct { + // Second argument passed to the shim function. + void* shim_data; + // Shimmed implementation. // This is called directly from generated code. // It should parse args, do fixups, and call the impl. @@ -83,7 +86,7 @@ public: void SetVariableMapping(const char* library_name, const uint32_t ordinal, uint32_t value); void SetFunctionMapping(const char* library_name, const uint32_t ordinal, - xe_kernel_export_shim_fn shim, + void* shim_data, xe_kernel_export_shim_fn shim, xe_kernel_export_impl_fn impl); private: diff --git a/src/cpu/codegen/function_generator.cc b/src/cpu/codegen/function_generator.cc index fd28a8b9e..4cadb3d80 100644 --- a/src/cpu/codegen/function_generator.cc +++ b/src/cpu/codegen/function_generator.cc @@ -117,23 +117,26 @@ void FunctionGenerator::PopInsertPoint() { } void FunctionGenerator::GenerateBasicBlocks() { + IRBuilder<>& b = *builder_; + // Always add an entry block. BasicBlock* entry = BasicBlock::Create(*context_, "entry", gen_fn_); - builder_->SetInsertPoint(entry); + b.SetInsertPoint(entry); if (FLAGS_trace_user_calls) { SpillRegisters(); Value* traceUserCall = gen_module_->getFunction("XeTraceUserCall"); - builder_->CreateCall3( + b.CreateCall4( traceUserCall, gen_fn_->arg_begin(), - builder_->getInt64(fn_->start_address), - ++gen_fn_->arg_begin()); + b.getInt64(fn_->start_address), + ++gen_fn_->arg_begin(), + b.getInt64((uint64_t)fn_)); } // If this function is empty, abort! if (!fn_->blocks.size()) { - builder_->CreateRetVoid(); + b.CreateRetVoid(); return; } @@ -214,13 +217,15 @@ void FunctionGenerator::GenerateSharedBlocks() { void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block, BasicBlock* bb) { + IRBuilder<>& b = *builder_; + printf(" bb %.8X-%.8X:\n", block->start_address, block->end_address); fn_block_ = block; bb_ = bb; // Move the builder to this block and setup. - builder_->SetInsertPoint(bb); + b.SetInsertPoint(bb); //i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname))); Value* invalidInstruction = @@ -238,21 +243,21 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block, if (FLAGS_trace_instructions) { SpillRegisters(); - builder_->CreateCall3( + b.CreateCall3( traceInstruction, gen_fn_->arg_begin(), - builder_->getInt32(i.address), - builder_->getInt32(i.code)); + b.getInt32(i.address), + b.getInt32(i.code)); } if (!i.type) { XELOGCPU("Invalid instruction %.8X %.8X", ia, i.code); SpillRegisters(); - builder_->CreateCall3( + b.CreateCall3( invalidInstruction, gen_fn_->arg_begin(), - builder_->getInt32(i.address), - builder_->getInt32(i.code)); + b.getInt32(i.address), + b.getInt32(i.code)); continue; } printf(" %.8X: %.8X %s\n", ia, i.code, i.type->name); @@ -273,11 +278,11 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block, XELOGCPU("Unimplemented instr %.8X %.8X %s", ia, i.code, i.type->name); SpillRegisters(); - builder_->CreateCall3( + b.CreateCall3( invalidInstruction, gen_fn_->arg_begin(), - builder_->getInt32(i.address), - builder_->getInt32(i.code)); + b.getInt32(i.address), + b.getInt32(i.code)); } } @@ -285,13 +290,13 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block, if (block->outgoing_type == FunctionBlock::kTargetNone) { BasicBlock* next_bb = GetNextBasicBlock(); XEASSERTNOTNULL(next_bb); - builder_->CreateBr(next_bb); + b.CreateBr(next_bb); } else if (block->outgoing_type == FunctionBlock::kTargetUnknown) { // Hrm. // TODO(benvanik): assert this doesn't occur - means a bad sdb run! XELOGCPU("SDB function scan error in %.8X: bb %.8X has unknown exit\n", fn_->start_address, block->start_address); - builder_->CreateRetVoid(); + b.CreateRetVoid(); } // TODO(benvanik): finish up BB @@ -348,7 +353,7 @@ int FunctionGenerator::GenerateIndirectionBranch(uint32_t cia, Value* target, // after we are done with all user instructions. if (!external_indirection_block_) { // Setup locals in the entry block. - builder_->SetInsertPoint(&gen_fn_->getEntryBlock()); + b.SetInsertPoint(&gen_fn_->getEntryBlock()); locals_.indirection_target = b.CreateAlloca( b.getInt64Ty(), 0, "indirection_target"); locals_.indirection_cia = b.CreateAlloca( diff --git a/src/cpu/codegen/module_generator.cc b/src/cpu/codegen/module_generator.cc index e5af317a3..c4a698e2a 100644 --- a/src/cpu/codegen/module_generator.cc +++ b/src/cpu/codegen/module_generator.cc @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,7 @@ using namespace xe::kernel; ModuleGenerator::ModuleGenerator( xe_memory_ref memory, ExportResolver* export_resolver, const char* module_name, const char* module_path, SymbolDatabase* sdb, - LLVMContext* context, Module* gen_module) { + LLVMContext* context, Module* gen_module, ExecutionEngine* engine) { memory_ = xe_memory_retain(memory); export_resolver_ = export_resolver; module_name_ = xestrdupa(module_name); @@ -48,6 +49,7 @@ ModuleGenerator::ModuleGenerator( sdb_ = sdb; context_ = context; gen_module_ = gen_module; + engine_ = engine; di_builder_ = NULL; } @@ -196,11 +198,12 @@ void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) { if (FLAGS_trace_kernel_calls) { Value* traceKernelCall = m->getFunction("XeTraceKernelCall"); - b.CreateCall3( + b.CreateCall4( traceKernelCall, f->arg_begin(), b.getInt64(fn->start_address), - ++f->arg_begin()); + ++f->arg_begin(), + b.getInt64((uint64_t)fn->kernel_export)); } b.CreateRetVoid(); @@ -221,18 +224,37 @@ void ModuleGenerator::AddPresentImport(FunctionSymbol* fn) { Module *m = gen_module_; LLVMContext& context = m->getContext(); - // Add the extern. + const DataLayout* dl = engine_->getDataLayout(); + Type* intPtrTy = dl->getIntPtrType(context); + Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context)); + + // Add the externs. + // We have both the shim function pointer and the shim data pointer. char shim_name[256]; xesnprintfa(shim_name, XECOUNT(shim_name), - "__shim__%s", fn->kernel_export->name); + "__shim_%s", fn->kernel_export->name); + char shim_data_name[256]; + xesnprintfa(shim_data_name, XECOUNT(shim_data_name), + "__shim_data_%s", fn->kernel_export->name); std::vector shimArgs; - shimArgs.push_back(PointerType::getUnqual(Type::getInt8Ty(context))); + shimArgs.push_back(int8PtrTy); + shimArgs.push_back(int8PtrTy); FunctionType* shimTy = FunctionType::get( Type::getVoidTy(context), shimArgs, false); Function* shim = Function::Create( shimTy, Function::ExternalLinkage, shim_name, m); - // engine_->addGlobalMapping(shim, - // (void*)fn->kernel_export->function_data.shim); + + GlobalVariable* gv = new GlobalVariable( + *m, int8PtrTy, true, GlobalValue::ExternalLinkage, 0, + shim_data_name); + + // TODO(benvanik): don't initialize on startup - move to exec_module + gv->setInitializer(ConstantExpr::getIntToPtr( + ConstantInt::get(intPtrTy, + (uintptr_t)fn->kernel_export->function_data.shim_data), + int8PtrTy)); + engine_->addGlobalMapping(shim, + (void*)fn->kernel_export->function_data.shim); // Create the function (and setup args/attributes/etc). Function* f = CreateFunctionDefinition(fn->name); @@ -242,16 +264,18 @@ void ModuleGenerator::AddPresentImport(FunctionSymbol* fn) { if (FLAGS_trace_kernel_calls) { Value* traceKernelCall = m->getFunction("XeTraceKernelCall"); - b.CreateCall3( + b.CreateCall4( traceKernelCall, f->arg_begin(), b.getInt64(fn->start_address), - ++f->arg_begin()); + ++f->arg_begin(), + b.getInt64((uint64_t)fn->kernel_export)); } - b.CreateCall( + b.CreateCall2( shim, - f->arg_begin()); + f->arg_begin(), + b.CreateLoad(gv)); b.CreateRetVoid(); diff --git a/src/cpu/exec_module.cc b/src/cpu/exec_module.cc index 719206782..89e1d4651 100644 --- a/src/cpu/exec_module.cc +++ b/src/cpu/exec_module.cc @@ -162,7 +162,8 @@ int ExecModule::Prepare() { // Build the module from the source code. codegen_ = auto_ptr(new ModuleGenerator( memory_, export_resolver_.get(), module_name_, module_path_, - sdb_.get(), context_.get(), gen_module_.get())); + sdb_.get(), context_.get(), gen_module_.get(), + engine_.get())); XEEXPECTZERO(codegen_->Generate()); // Write to cache. @@ -248,14 +249,16 @@ void XeInvalidInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) { XELOGCPU("INVALID INSTRUCTION %.8X %.8X", cia, data); } -void XeTraceKernelCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia) { - // TODO(benvanik): get names - XELOGCPU("TRACE: %.8X -> k.%.8X", (uint32_t)call_ia - 4, (uint32_t)cia); +void XeTraceKernelCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, + KernelExport* kernel_export) { + XELOGCPU("TRACE: %.8X -> k.%.8X (%s)", (uint32_t)call_ia - 4, (uint32_t)cia, + kernel_export ? kernel_export->name : "unknown"); } -void XeTraceUserCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia) { - // TODO(benvanik): get names - XELOGCPU("TRACE: %.8X -> u.%.8X", (uint32_t)call_ia - 4, (uint32_t)cia); +void XeTraceUserCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, + FunctionSymbol* fn) { + XELOGCPU("TRACE: %.8X -> u.%.8X (%s)", (uint32_t)call_ia - 4, (uint32_t)cia, + fn->name); } void XeTraceInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) { @@ -271,8 +274,8 @@ void XeTraceInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) { int ExecModule::InjectGlobals() { LLVMContext& context = *context_.get(); const DataLayout* dl = engine_->getDataLayout(); - Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context)); Type* intPtrTy = dl->getIntPtrType(context); + Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context)); GlobalVariable* gv; // xe_memory_base @@ -326,6 +329,7 @@ int ExecModule::InjectGlobals() { traceCallArgs.push_back(int8PtrTy); traceCallArgs.push_back(Type::getInt64Ty(context)); traceCallArgs.push_back(Type::getInt64Ty(context)); + traceCallArgs.push_back(Type::getInt64Ty(context)); FunctionType* traceCallTy = FunctionType::get( Type::getVoidTy(context), traceCallArgs, false); std::vector traceInstructionArgs; @@ -371,10 +375,10 @@ int ExecModule::Init() { } else { if (kernel_export->is_implemented) { // Implemented - replace with pointer. - *slot = kernel_export->variable_ptr; + *slot = XESWAP32BE(kernel_export->variable_ptr); } else { // Not implemented - write with a dummy value. - *slot = 0xDEADBEEF; + *slot = XESWAP32BE(0xDEADBEEF); XELOGCPU("WARNING: imported a variable with no value: %s", kernel_export->name); } diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index 6c1ac0469..18f1478a2 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -9,6 +9,9 @@ #include +#include +#include + using namespace xe; using namespace xe::cpu; @@ -19,10 +22,12 @@ ThreadState::ThreadState( uint32_t stack_address, uint32_t stack_size) { stack_address_ = stack_address; stack_size_ = stack_size; + memory_ = processor->memory(); xe_zero_struct(&ppc_state_, sizeof(ppc_state_)); // Stash pointers to common structures that callbacks may need. + ppc_state_.membase = xe_memory_addr(memory_, 0); ppc_state_.processor = processor; ppc_state_.thread_state = this; @@ -31,6 +36,7 @@ ThreadState::ThreadState( } ThreadState::~ThreadState() { + xe_memory_release(memory_); } xe_ppc_state_t* ThreadState::ppc_state() { diff --git a/src/kernel/export.cc b/src/kernel/export.cc index e9ecf3c7c..13d788cc7 100644 --- a/src/kernel/export.cc +++ b/src/kernel/export.cc @@ -31,6 +31,7 @@ void ExportResolver::RegisterTable( for (size_t n = 0; n < count; n++) { exports[n].is_implemented = false; exports[n].variable_ptr = 0; + exports[n].function_data.shim_data = NULL; exports[n].function_data.shim = NULL; exports[n].function_data.impl = NULL; } @@ -69,13 +70,14 @@ void ExportResolver::SetVariableMapping(const char* library_name, kernel_export->variable_ptr = value; } -void ExportResolver::SetFunctionMapping(const char* library_name, - const uint32_t ordinal, - xe_kernel_export_shim_fn shim, - xe_kernel_export_impl_fn impl) { +void ExportResolver::SetFunctionMapping( + const char* library_name, const uint32_t ordinal, + void* shim_data, xe_kernel_export_shim_fn shim, + xe_kernel_export_impl_fn impl) { KernelExport* kernel_export = GetExportByOrdinal(library_name, ordinal); XEASSERTNOTNULL(kernel_export); kernel_export->is_implemented = true; + kernel_export->function_data.shim_data = shim_data; kernel_export->function_data.shim = shim; kernel_export->function_data.impl = impl; } diff --git a/src/kernel/modules/xboxkrnl/kernel_state.cc b/src/kernel/modules/xboxkrnl/kernel_state.cc new file mode 100644 index 000000000..f54a7880c --- /dev/null +++ b/src/kernel/modules/xboxkrnl/kernel_state.cc @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * 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 "kernel/modules/xboxkrnl/kernel_state.h" + + +using namespace xe; +using namespace xe::kernel; +using namespace xe::kernel::xboxkrnl; + + +namespace { + +} + + +KernelState::KernelState(xe_pal_ref pal, xe_memory_ref memory, + shared_ptr export_resolver) { + pal = xe_pal_retain(pal); + memory = xe_memory_retain(memory); + export_resolver_ = export_resolver; +} + +KernelState::~KernelState() { + xe_memory_release(memory); + xe_pal_release(pal); +} diff --git a/src/kernel/modules/xboxkrnl/kernel_state.h b/src/kernel/modules/xboxkrnl/kernel_state.h new file mode 100644 index 000000000..348e59721 --- /dev/null +++ b/src/kernel/modules/xboxkrnl/kernel_state.h @@ -0,0 +1,44 @@ +/** + ****************************************************************************** + * 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. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_KERNEL_STATE_H_ +#define XENIA_KERNEL_MODULES_XBOXKRNL_KERNEL_STATE_H_ + +#include +#include + +#include +#include + + +namespace xe { +namespace kernel { +namespace xboxkrnl { + + +class KernelState { +public: + KernelState(xe_pal_ref pal, xe_memory_ref memory, + shared_ptr export_resolver); + ~KernelState(); + + xe_pal_ref pal; + xe_memory_ref memory; + +private: + shared_ptr export_resolver_; +}; + + +} // namespace xboxkrnl +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_MODULES_XBOXKRNL_KERNEL_STATE_H_ diff --git a/src/kernel/modules/xboxkrnl/sources.gypi b/src/kernel/modules/xboxkrnl/sources.gypi index 57a78021d..a2126cc1e 100644 --- a/src/kernel/modules/xboxkrnl/sources.gypi +++ b/src/kernel/modules/xboxkrnl/sources.gypi @@ -1,6 +1,9 @@ # Copyright 2013 Ben Vanik. All Rights Reserved. { 'sources': [ + 'kernel_state.cc', + 'xboxkrnl_hal.cc', + 'xboxkrnl_memory.cc', 'xboxkrnl_module.cc', ], } diff --git a/src/kernel/modules/xboxkrnl/xboxkrnl_hal.cc b/src/kernel/modules/xboxkrnl/xboxkrnl_hal.cc new file mode 100644 index 000000000..42a8efed3 --- /dev/null +++ b/src/kernel/modules/xboxkrnl/xboxkrnl_hal.cc @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * 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 "kernel/modules/xboxkrnl/xboxkrnl_hal.h" + +#include "kernel/shim_utils.h" + + +using namespace xe; +using namespace xe::kernel; +using namespace xe::kernel::xboxkrnl; + + +namespace { + + +void HalReturnToFirmware_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + // void + // IN FIRMWARE_REENTRY Routine + + // Routine must be 1 'HalRebootRoutine' + uint32_t routine = SHIM_GET_ARG_32(0); + + XELOGD( + XT("HalReturnToFirmware(%d)"), + routine); + + // TODO(benvank): diediedie much more gracefully + // Not sure how to blast back up the stack in LLVM without exceptions, though. + XELOGE(XT("Game requested shutdown via HalReturnToFirmware")); + exit(0); +} + + +} + + +void xe::kernel::xboxkrnl::RegisterHalExports( + ExportResolver* export_resolver, KernelState* state) { + #define SHIM_SET_MAPPING(ordinal, shim, impl) \ + export_resolver->SetFunctionMapping("xboxkrnl.exe", ordinal, \ + state, (xe_kernel_export_shim_fn)shim, (xe_kernel_export_impl_fn)impl) + + SHIM_SET_MAPPING(0x00000028, HalReturnToFirmware_shim, NULL); + + #undef SET_MAPPING +} diff --git a/src/kernel/modules/xboxkrnl/xboxkrnl_hal.h b/src/kernel/modules/xboxkrnl/xboxkrnl_hal.h new file mode 100644 index 000000000..d23a9e4e9 --- /dev/null +++ b/src/kernel/modules/xboxkrnl/xboxkrnl_hal.h @@ -0,0 +1,29 @@ +/** + ****************************************************************************** + * 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. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_HAL_H_ +#define XENIA_KERNEL_MODULES_XBOXKRNL_HAL_H_ + +#include "kernel/modules/xboxkrnl/kernel_state.h" + + +namespace xe { +namespace kernel { +namespace xboxkrnl { + + +void RegisterHalExports(ExportResolver* export_resolver, KernelState* state); + + +} // namespace xboxkrnl +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_MODULES_XBOXKRNL_HAL_H_ diff --git a/src/kernel/modules/xboxkrnl/xboxkrnl_memory.cc b/src/kernel/modules/xboxkrnl/xboxkrnl_memory.cc new file mode 100644 index 000000000..bb3aef395 --- /dev/null +++ b/src/kernel/modules/xboxkrnl/xboxkrnl_memory.cc @@ -0,0 +1,112 @@ +/** + ****************************************************************************** + * 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 "kernel/modules/xboxkrnl/xboxkrnl_memory.h" + +#include "kernel/shim_utils.h" + + +using namespace xe; +using namespace xe::kernel; +using namespace xe::kernel::xboxkrnl; + + +namespace { + + +void NtAllocateVirtualMemory_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + // NTSTATUS + // _Inout_ PVOID *BaseAddress, + // _In_ ULONG_PTR ZeroBits, + // _Inout_ PSIZE_T RegionSize, + // _In_ ULONG AllocationType, + // _In_ ULONG Protect + // ? handle? + + uint32_t base_addr_ptr = SHIM_GET_ARG_32(0); + uint32_t base_addr_value = SHIM_MEM_32(base_addr_ptr); + uint32_t region_size_ptr = SHIM_GET_ARG_32(1); + uint32_t region_size_value = SHIM_MEM_32(region_size_ptr); + // MEM_COMMIT | MEM_PHYSICAL | MEM_RESERVE | MEM_RESET | MEM_TOP_DOWN + uint32_t allocation_type = SHIM_GET_ARG_32(2); + // PAGE_NOACCESS | PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE | + // PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_GUARD | PAGE_NOCACHE | + // PAGE_WRITECOMBINE + uint32_t protect_bits = SHIM_GET_ARG_32(3); + uint32_t unknown = SHIM_GET_ARG_32(4); + + XELOGD( + XT("NtAllocateVirtualMemory(%.8X(%.8X), %.8X(%.8X), %.8X, %.8X, %.8X)"), + base_addr_ptr, base_addr_value, + region_size_ptr, region_size_value, + allocation_type, protect_bits, unknown); + + // TODO(benvanik): alloc memory + + // Possible return codes: + // STATUS_ACCESS_DENIED + // STATUS_ALREADY_COMMITTED + // STATUS_COMMITMENT_LIMIT + // STATUS_CONFLICTING_ADDRESSES + // STATUS_INSUFFICIENT_RESOURCES + // STATUS_INVALID_HANDLE + // STATUS_INVALID_PAGE_PROTECTION + // STATUS_NO_MEMORY + // STATUS_OBJECT_TYPE_MISMATCH + // STATUS_PROCESS_IS_TERMINATING + SHIM_SET_RETURN(0xC0000017); +} + +void NtFreeVirtualMemory_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + // NTSTATUS + // _Inout_ PVOID *BaseAddress, + // _Inout_ PSIZE_T RegionSize, + // _In_ ULONG FreeType + // ? handle? + + uint32_t base_addr_ptr = SHIM_GET_ARG_32(0); + uint32_t base_addr_value = SHIM_MEM_32(base_addr_ptr); + uint32_t region_size_ptr = SHIM_GET_ARG_32(1); + uint32_t region_size_value = SHIM_MEM_32(region_size_ptr); + // MEM_DECOMMIT | MEM_RELEASE + uint32_t free_type = SHIM_GET_ARG_32(2); + uint32_t unknown = SHIM_GET_ARG_32(3); + + XELOGD( + XT("NtFreeVirtualMemory(%.8X(%.8X), %.8X(%.8X), %.8X, %.8X)"), + base_addr_ptr, base_addr_value, + region_size_ptr, region_size_value, + free_type, unknown); + + // TODO(benvanik): free memory + + // Possible return codes: + // STATUS_ACCESS_DENIED + // STATUS_INVALID_HANDLE + // STATUS_OBJECT_TYPE_MISMATCH + SHIM_SET_RETURN(0xFFFFFFFF); +} + + +} + + +void xe::kernel::xboxkrnl::RegisterMemoryExports( + ExportResolver* export_resolver, KernelState* state) { + #define SHIM_SET_MAPPING(ordinal, shim, impl) \ + export_resolver->SetFunctionMapping("xboxkrnl.exe", ordinal, \ + state, (xe_kernel_export_shim_fn)shim, (xe_kernel_export_impl_fn)impl) + + SHIM_SET_MAPPING(0x000000CC, NtAllocateVirtualMemory_shim, NULL); + SHIM_SET_MAPPING(0x000000DC, NtFreeVirtualMemory_shim, NULL); + + #undef SET_MAPPING +} diff --git a/src/kernel/modules/xboxkrnl/xboxkrnl_memory.h b/src/kernel/modules/xboxkrnl/xboxkrnl_memory.h new file mode 100644 index 000000000..216dca9a9 --- /dev/null +++ b/src/kernel/modules/xboxkrnl/xboxkrnl_memory.h @@ -0,0 +1,29 @@ +/** + ****************************************************************************** + * 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. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_MEMORY_H_ +#define XENIA_KERNEL_MODULES_XBOXKRNL_MEMORY_H_ + +#include "kernel/modules/xboxkrnl/kernel_state.h" + + +namespace xe { +namespace kernel { +namespace xboxkrnl { + + +void RegisterMemoryExports(ExportResolver* export_resolver, KernelState* state); + + +} // namespace xboxkrnl +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_MODULES_XBOXKRNL_MEMORY_H_ diff --git a/src/kernel/modules/xboxkrnl/xboxkrnl_module.cc b/src/kernel/modules/xboxkrnl/xboxkrnl_module.cc index 4599a9cd2..db71d9566 100644 --- a/src/kernel/modules/xboxkrnl/xboxkrnl_module.cc +++ b/src/kernel/modules/xboxkrnl/xboxkrnl_module.cc @@ -9,6 +9,9 @@ #include "kernel/modules/xboxkrnl/xboxkrnl_module.h" +#include "kernel/modules/xboxkrnl/kernel_state.h" +#include "kernel/modules/xboxkrnl/xboxkrnl_hal.h" +#include "kernel/modules/xboxkrnl/xboxkrnl_memory.h" #include "kernel/modules/xboxkrnl/xboxkrnl_table.h" @@ -48,6 +51,14 @@ XboxkrnlModule::XboxkrnlModule(xe_pal_ref pal, xe_memory_ref memory, resolver->RegisterTable( "xboxkrnl.exe", xboxkrnl_export_table, XECOUNT(xboxkrnl_export_table)); + // Setup the kernel state instance. + // This is where all kernel objects are kept while running. + kernel_state = auto_ptr(new KernelState(pal, memory, resolver)); + + // Register all exported functions. + RegisterHalExports(resolver.get(), kernel_state.get()); + RegisterMemoryExports(resolver.get(), kernel_state.get()); + // TODO(benvanik): alloc heap memory somewhere in user space // TODO(benvanik): tools for reading/writing to heap memory @@ -55,15 +66,15 @@ XboxkrnlModule::XboxkrnlModule(xe_pal_ref pal, xe_memory_ref memory, // KeDebugMonitorData resolver->SetVariableMapping( "xboxkrnl.exe", 0x00000059, - 0); + 0x40001000); // XboxHardwareInfo resolver->SetVariableMapping( "xboxkrnl.exe", 0x00000156, - 0); + 0x40002000); // XexExecutableModuleHandle resolver->SetVariableMapping( "xboxkrnl.exe", 0x00000193, - 0); + 0x40000000); // 0x0000012B, RtlImageXexHeaderField } diff --git a/src/kernel/modules/xboxkrnl/xboxkrnl_module.h b/src/kernel/modules/xboxkrnl/xboxkrnl_module.h index 3bd16c504..acb0f207c 100644 --- a/src/kernel/modules/xboxkrnl/xboxkrnl_module.h +++ b/src/kernel/modules/xboxkrnl/xboxkrnl_module.h @@ -21,12 +21,17 @@ namespace xe { namespace kernel { namespace xboxkrnl { +class KernelState; + class XboxkrnlModule : public KernelModule { public: XboxkrnlModule(xe_pal_ref pal, xe_memory_ref memory, shared_ptr resolver); virtual ~XboxkrnlModule(); + +private: + auto_ptr kernel_state; }; @@ -34,5 +39,4 @@ public: } // namespace kernel } // namespace xe - #endif // XENIA_KERNEL_MODULES_XBOXKRNL_MODULE_H_ diff --git a/src/kernel/shim_utils.h b/src/kernel/shim_utils.h new file mode 100644 index 000000000..e9333cb35 --- /dev/null +++ b/src/kernel/shim_utils.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * 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. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_SHIM_UTILS_H_ +#define XENIA_KERNEL_SHIM_UTILS_H_ + +#include +#include + +#include +#include +#include + + +namespace xe { +namespace kernel { + + +#define SHIM_MEM_ADDR(a) (ppc_state->membase + a) + +#define SHIM_MEM_32(a) (uint32_t)XEGETUINT32BE(SHIM_MEM_ADDR(a)); +#define SHIM_SET_MEM_32(a, v) (*(uint32_t*)SHIM_MEM_ADDR(a)) = XESWAP32(v) + +#define SHIM_GPR_32(n) (uint32_t)(ppc_state->r[n]) +#define SHIM_SET_GPR_32(n, v) ppc_state->r[n] = (uint64_t)((v) & UINT32_MAX) +#define SHIM_GPR_64(n) ppc_state->r[n] +#define SHIM_SET_GPR_64(n, v) ppc_state->r[n] = (uint64_t)(v) + +#define SHIM_GET_ARG_32(n) SHIM_GPR_32(3 + n) +#define SHIM_GET_ARG_64(n) SHIM_GPR_64(3 + n) +#define SHIM_SET_RETURN(v) SHIM_SET_GPR_64(3, v) + +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_SHIM_UTILS_H_