Unifying kernel modules and user modules to XModule. XexLoadImage/etc.
This commit is contained in:
parent
7d6db5a6b6
commit
dc496e8102
|
@ -19,7 +19,7 @@
|
||||||
#include <xenia/debug/protocols/ws/simple_sha1.h>
|
#include <xenia/debug/protocols/ws/simple_sha1.h>
|
||||||
#include <xenia/kernel/kernel_state.h>
|
#include <xenia/kernel/kernel_state.h>
|
||||||
#include <xenia/kernel/xboxkrnl_module.h>
|
#include <xenia/kernel/xboxkrnl_module.h>
|
||||||
#include <xenia/kernel/objects/xmodule.h>
|
#include <xenia/kernel/objects/xuser_module.h>
|
||||||
|
|
||||||
#if XE_PLATFORM(WIN32)
|
#if XE_PLATFORM(WIN32)
|
||||||
// Required for wslay.
|
// Required for wslay.
|
||||||
|
@ -219,7 +219,7 @@ int WSClient::PerformHandshake() {
|
||||||
if (headers.find("GET /sessions") != std::string::npos) {
|
if (headers.find("GET /sessions") != std::string::npos) {
|
||||||
Emulator* emulator = debug_server_->emulator();
|
Emulator* emulator = debug_server_->emulator();
|
||||||
KernelState* kernel_state = emulator->xboxkrnl()->kernel_state();
|
KernelState* kernel_state = emulator->xboxkrnl()->kernel_state();
|
||||||
XModule* module = kernel_state->GetExecutableModule();
|
XUserModule* module = kernel_state->GetExecutableModule();
|
||||||
const xe_xex2_header_t* header = module->xex_header();
|
const xe_xex2_header_t* header = module->xex_header();
|
||||||
char title_id[9];
|
char title_id[9];
|
||||||
xesnprintfa(title_id, XECOUNT(title_id), "%.8X",
|
xesnprintfa(title_id, XECOUNT(title_id), "%.8X",
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* 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/emulator.h>
|
|
||||||
#include <xenia/export_resolver.h>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace xe;
|
|
||||||
using namespace xe::kernel;
|
|
||||||
|
|
||||||
|
|
||||||
KernelModule::KernelModule(Emulator* emulator, KernelState* kernel_state) :
|
|
||||||
emulator_(emulator), kernel_state_(kernel_state),
|
|
||||||
memory_(emulator->memory()) {
|
|
||||||
export_resolver_ = emulator->export_resolver();
|
|
||||||
}
|
|
||||||
|
|
||||||
KernelModule::~KernelModule() {
|
|
||||||
}
|
|
|
@ -10,10 +10,13 @@
|
||||||
#include <xenia/kernel/kernel_state.h>
|
#include <xenia/kernel/kernel_state.h>
|
||||||
|
|
||||||
#include <xenia/emulator.h>
|
#include <xenia/emulator.h>
|
||||||
|
#include <xenia/kernel/xam_module.h>
|
||||||
|
#include <xenia/kernel/xboxkrnl_module.h>
|
||||||
#include <xenia/kernel/xboxkrnl_private.h>
|
#include <xenia/kernel/xboxkrnl_private.h>
|
||||||
#include <xenia/kernel/xobject.h>
|
#include <xenia/kernel/xobject.h>
|
||||||
#include <xenia/kernel/objects/xmodule.h>
|
#include <xenia/kernel/objects/xmodule.h>
|
||||||
#include <xenia/kernel/objects/xthread.h>
|
#include <xenia/kernel/objects/xthread.h>
|
||||||
|
#include <xenia/kernel/objects/xuser_module.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace xe;
|
using namespace xe;
|
||||||
|
@ -55,12 +58,22 @@ KernelState* KernelState::shared() {
|
||||||
}
|
}
|
||||||
|
|
||||||
XModule* KernelState::GetModule(const char* name) {
|
XModule* KernelState::GetModule(const char* name) {
|
||||||
// TODO(benvanik): implement lookup. Most games seem to look for xam.xex/etc.
|
if (xestrcasecmpa(name, "xam.xex") == 0) {
|
||||||
|
auto module = emulator_->xam();
|
||||||
|
module->Retain();
|
||||||
|
return module;
|
||||||
|
} else if (xestrcasecmpa(name, "xboxkrnl.exe") == 0) {
|
||||||
|
auto module = emulator_->xboxkrnl();
|
||||||
|
module->Retain();
|
||||||
|
return module;
|
||||||
|
} else {
|
||||||
|
// TODO(benvanik): support user modules/loading/etc.
|
||||||
XEASSERTALWAYS();
|
XEASSERTALWAYS();
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XModule* KernelState::GetExecutableModule() {
|
XUserModule* KernelState::GetExecutableModule() {
|
||||||
if (!executable_module_) {
|
if (!executable_module_) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +82,7 @@ XModule* KernelState::GetExecutableModule() {
|
||||||
return executable_module_;
|
return executable_module_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::SetExecutableModule(XModule* module) {
|
void KernelState::SetExecutableModule(XUserModule* module) {
|
||||||
if (module == executable_module_) {
|
if (module == executable_module_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,15 @@
|
||||||
|
|
||||||
#include <xenia/export_resolver.h>
|
#include <xenia/export_resolver.h>
|
||||||
#include <xenia/xbox.h>
|
#include <xenia/xbox.h>
|
||||||
#include <xenia/kernel/kernel_module.h>
|
|
||||||
#include <xenia/kernel/object_table.h>
|
#include <xenia/kernel/object_table.h>
|
||||||
#include <xenia/kernel/fs/filesystem.h>
|
#include <xenia/kernel/fs/filesystem.h>
|
||||||
|
|
||||||
|
|
||||||
|
XEDECLARECLASS1(xe, Emulator);
|
||||||
XEDECLARECLASS2(xe, cpu, Processor);
|
XEDECLARECLASS2(xe, cpu, Processor);
|
||||||
XEDECLARECLASS2(xe, kernel, XModule);
|
XEDECLARECLASS2(xe, kernel, XModule);
|
||||||
XEDECLARECLASS2(xe, kernel, XThread);
|
XEDECLARECLASS2(xe, kernel, XThread);
|
||||||
|
XEDECLARECLASS2(xe, kernel, XUserModule);
|
||||||
XEDECLARECLASS3(xe, kernel, fs, FileSystem);
|
XEDECLARECLASS3(xe, kernel, fs, FileSystem);
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,8 +46,8 @@ public:
|
||||||
ObjectTable* object_table() const { return object_table_; }
|
ObjectTable* object_table() const { return object_table_; }
|
||||||
|
|
||||||
XModule* GetModule(const char* name);
|
XModule* GetModule(const char* name);
|
||||||
XModule* GetExecutableModule();
|
XUserModule* GetExecutableModule();
|
||||||
void SetExecutableModule(XModule* module);
|
void SetExecutableModule(XUserModule* module);
|
||||||
|
|
||||||
void RegisterThread(XThread* thread);
|
void RegisterThread(XThread* thread);
|
||||||
void UnregisterThread(XThread* thread);
|
void UnregisterThread(XThread* thread);
|
||||||
|
@ -62,7 +63,7 @@ private:
|
||||||
xe_mutex_t* object_mutex_;
|
xe_mutex_t* object_mutex_;
|
||||||
std::unordered_map<uint32_t, XThread*> threads_by_id_;
|
std::unordered_map<uint32_t, XThread*> threads_by_id_;
|
||||||
|
|
||||||
XModule* executable_module_;
|
XUserModule* executable_module_;
|
||||||
|
|
||||||
friend class XObject;
|
friend class XObject;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
'xevent.h',
|
'xevent.h',
|
||||||
'xfile.cc',
|
'xfile.cc',
|
||||||
'xfile.h',
|
'xfile.h',
|
||||||
|
'xkernel_module.cc',
|
||||||
|
'xkernel_module.h',
|
||||||
'xmodule.cc',
|
'xmodule.cc',
|
||||||
'xmodule.h',
|
'xmodule.h',
|
||||||
'xmutant.cc',
|
'xmutant.cc',
|
||||||
|
@ -17,5 +19,7 @@
|
||||||
'xthread.h',
|
'xthread.h',
|
||||||
'xtimer.cc',
|
'xtimer.cc',
|
||||||
'xtimer.h',
|
'xtimer.h',
|
||||||
|
'xuser_module.cc',
|
||||||
|
'xuser_module.h',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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/objects/xkernel_module.h>
|
||||||
|
|
||||||
|
#include <xenia/emulator.h>
|
||||||
|
#include <xenia/cpu/cpu.h>
|
||||||
|
#include <xenia/kernel/objects/xthread.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace xe;
|
||||||
|
using namespace xe::cpu;
|
||||||
|
using namespace xe::kernel;
|
||||||
|
|
||||||
|
|
||||||
|
XKernelModule::XKernelModule(KernelState* kernel_state, const char* path) :
|
||||||
|
XModule(kernel_state, path) {
|
||||||
|
emulator_ = kernel_state->emulator();
|
||||||
|
memory_ = emulator_->memory();
|
||||||
|
export_resolver_ = kernel_state->emulator()->export_resolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
XKernelModule::~XKernelModule() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void* XKernelModule::GetProcAddressByOrdinal(uint16_t ordinal) {
|
||||||
|
// TODO(benvanik): check export tables.
|
||||||
|
XELOGE("GetProcAddressByOrdinal not implemented");
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -7,12 +7,10 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XENIA_KERNEL_KERNEL_MODULE_H_
|
#ifndef XENIA_KERNEL_XBOXKRNL_XKERNEL_MODULE_H_
|
||||||
#define XENIA_KERNEL_KERNEL_MODULE_H_
|
#define XENIA_KERNEL_XBOXKRNL_XKERNEL_MODULE_H_
|
||||||
|
|
||||||
#include <xenia/common.h>
|
|
||||||
#include <xenia/core.h>
|
|
||||||
|
|
||||||
|
#include <xenia/kernel/objects/xmodule.h>
|
||||||
|
|
||||||
XEDECLARECLASS1(xe, Emulator);
|
XEDECLARECLASS1(xe, Emulator);
|
||||||
XEDECLARECLASS1(xe, ExportResolver);
|
XEDECLARECLASS1(xe, ExportResolver);
|
||||||
|
@ -23,17 +21,15 @@ namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
|
|
||||||
class KernelModule {
|
class XKernelModule : public XModule {
|
||||||
public:
|
public:
|
||||||
KernelModule(Emulator* emulator, KernelState* kernel_state);
|
XKernelModule(KernelState* kernel_state, const char* path);
|
||||||
virtual ~KernelModule();
|
virtual ~XKernelModule();
|
||||||
|
|
||||||
Emulator* emulator() const { return emulator_; }
|
virtual void* GetProcAddressByOrdinal(uint16_t ordinal);
|
||||||
KernelState* kernel_state() const { return kernel_state_; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Emulator* emulator_;
|
Emulator* emulator_;
|
||||||
KernelState* kernel_state_;
|
|
||||||
Memory* memory_;
|
Memory* memory_;
|
||||||
ExportResolver* export_resolver_;
|
ExportResolver* export_resolver_;
|
||||||
};
|
};
|
||||||
|
@ -43,4 +39,4 @@ protected:
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
#endif // XENIA_KERNEL_KERNEL_MODULE_H_
|
#endif // XENIA_KERNEL_XBOXKRNL_XKERNEL_MODULE_H_
|
|
@ -9,23 +9,14 @@
|
||||||
|
|
||||||
#include <xenia/kernel/objects/xmodule.h>
|
#include <xenia/kernel/objects/xmodule.h>
|
||||||
|
|
||||||
#include <xenia/emulator.h>
|
|
||||||
#include <xenia/cpu/cpu.h>
|
|
||||||
#include <xenia/kernel/objects/xthread.h>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace xe;
|
using namespace xe;
|
||||||
using namespace xe::cpu;
|
using namespace xe::cpu;
|
||||||
using namespace xe::kernel;
|
using namespace xe::kernel;
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
XModule::XModule(KernelState* kernel_state, const char* path) :
|
XModule::XModule(KernelState* kernel_state, const char* path) :
|
||||||
XObject(kernel_state, kTypeModule),
|
XObject(kernel_state, kTypeModule) {
|
||||||
xex_(NULL) {
|
|
||||||
XEIGNORE(xestrcpya(path_, XECOUNT(path_), path));
|
XEIGNORE(xestrcpya(path_, XECOUNT(path_), path));
|
||||||
const char* slash = xestrrchra(path, '/');
|
const char* slash = xestrrchra(path, '/');
|
||||||
if (!slash) {
|
if (!slash) {
|
||||||
|
@ -41,301 +32,4 @@ XModule::XModule(KernelState* kernel_state, const char* path) :
|
||||||
}
|
}
|
||||||
|
|
||||||
XModule::~XModule() {
|
XModule::~XModule() {
|
||||||
xe_xex2_release(xex_);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* XModule::path() {
|
|
||||||
return path_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* XModule::name() {
|
|
||||||
return name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
xe_xex2_ref XModule::xex() {
|
|
||||||
return xe_xex2_retain(xex_);
|
|
||||||
}
|
|
||||||
|
|
||||||
const xe_xex2_header_t* XModule::xex_header() {
|
|
||||||
return xe_xex2_get_header(xex_);
|
|
||||||
}
|
|
||||||
|
|
||||||
X_STATUS XModule::LoadFromFile(const char* path) {
|
|
||||||
// Resolve the file to open.
|
|
||||||
// TODO(benvanik): make this code shared?
|
|
||||||
fs::Entry* fs_entry = kernel_state()->file_system()->ResolvePath(path);
|
|
||||||
if (!fs_entry) {
|
|
||||||
XELOGE("File not found: %s", path);
|
|
||||||
return X_STATUS_NO_SUCH_FILE;
|
|
||||||
}
|
|
||||||
if (fs_entry->type() != fs::Entry::kTypeFile) {
|
|
||||||
XELOGE("Invalid file type: %s", path);
|
|
||||||
return X_STATUS_NO_SUCH_FILE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map into memory.
|
|
||||||
fs::MemoryMapping* mmap = fs_entry->CreateMemoryMapping(kXEFileModeRead, 0, 0);
|
|
||||||
if (!mmap) {
|
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the module.
|
|
||||||
X_STATUS return_code = LoadFromMemory(mmap->address(), mmap->length());
|
|
||||||
|
|
||||||
// Unmap memory and cleanup.
|
|
||||||
delete mmap;
|
|
||||||
delete fs_entry;
|
|
||||||
|
|
||||||
return return_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
X_STATUS XModule::LoadFromMemory(const void* addr, const size_t length) {
|
|
||||||
Processor* processor = kernel_state()->processor();
|
|
||||||
XenonRuntime* runtime = processor->runtime();
|
|
||||||
XexModule* xex_module = NULL;
|
|
||||||
|
|
||||||
// Load the XEX into memory and decrypt.
|
|
||||||
xe_xex2_options_t xex_options;
|
|
||||||
xe_zero_struct(&xex_options, sizeof(xex_options));
|
|
||||||
xex_ = xe_xex2_load(kernel_state()->memory(), addr, length, xex_options);
|
|
||||||
XEEXPECTNOTNULL(xex_);
|
|
||||||
|
|
||||||
// Prepare the module for execution.
|
|
||||||
// Runtime takes ownership.
|
|
||||||
xex_module = new XexModule(runtime);
|
|
||||||
XEEXPECTZERO(xex_module->Load(name_, path_, xex_));
|
|
||||||
XEEXPECTZERO(runtime->AddModule(xex_module));
|
|
||||||
|
|
||||||
return X_STATUS_SUCCESS;
|
|
||||||
|
|
||||||
XECLEANUP:
|
|
||||||
delete xex_module;
|
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
X_STATUS XModule::GetSection(const char* name,
|
|
||||||
uint32_t* out_data, uint32_t* out_size) {
|
|
||||||
const PESection* section = xe_xex2_get_pe_section(xex_, name);
|
|
||||||
if (!section) {
|
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
*out_data = section->address;
|
|
||||||
*out_size = section->size;
|
|
||||||
return X_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* XModule::GetProcAddressByOrdinal(uint16_t ordinal) {
|
|
||||||
// TODO(benvanik): check export tables.
|
|
||||||
XELOGE("GetProcAddressByOrdinal not implemented");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
X_STATUS XModule::Launch(uint32_t flags) {
|
|
||||||
const xe_xex2_header_t* header = xex_header();
|
|
||||||
|
|
||||||
XELOGI("Launching module...");
|
|
||||||
|
|
||||||
Dump();
|
|
||||||
|
|
||||||
// Create a thread to run in.
|
|
||||||
XThread* thread = new XThread(
|
|
||||||
kernel_state(),
|
|
||||||
header->exe_stack_size,
|
|
||||||
0,
|
|
||||||
header->exe_entry_point, NULL,
|
|
||||||
0);
|
|
||||||
|
|
||||||
X_STATUS result = thread->Create();
|
|
||||||
if (XFAILED(result)) {
|
|
||||||
XELOGE("Could not create launch thread: %.8X", result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until thread completes.
|
|
||||||
thread->Wait(0, 0, 0, NULL);
|
|
||||||
|
|
||||||
thread->Release();
|
|
||||||
|
|
||||||
return X_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XModule::Dump() {
|
|
||||||
ExportResolver* export_resolver =
|
|
||||||
kernel_state_->emulator()->export_resolver();
|
|
||||||
const xe_xex2_header_t* header = xe_xex2_get_header(xex_);
|
|
||||||
|
|
||||||
// XEX info.
|
|
||||||
printf("Module %s:\n\n", path_);
|
|
||||||
printf(" Module Flags: %.8X\n", header->module_flags);
|
|
||||||
printf(" System Flags: %.8X\n", header->system_flags);
|
|
||||||
printf("\n");
|
|
||||||
printf(" Address: %.8X\n", header->exe_address);
|
|
||||||
printf(" Entry Point: %.8X\n", header->exe_entry_point);
|
|
||||||
printf(" Stack Size: %.8X\n", header->exe_stack_size);
|
|
||||||
printf(" Heap Size: %.8X\n", header->exe_heap_size);
|
|
||||||
printf("\n");
|
|
||||||
printf(" Execution Info:\n");
|
|
||||||
printf(" Media ID: %.8X\n", header->execution_info.media_id);
|
|
||||||
printf(" Version: %d.%d.%d.%d\n",
|
|
||||||
header->execution_info.version.major,
|
|
||||||
header->execution_info.version.minor,
|
|
||||||
header->execution_info.version.build,
|
|
||||||
header->execution_info.version.qfe);
|
|
||||||
printf(" Base Version: %d.%d.%d.%d\n",
|
|
||||||
header->execution_info.base_version.major,
|
|
||||||
header->execution_info.base_version.minor,
|
|
||||||
header->execution_info.base_version.build,
|
|
||||||
header->execution_info.base_version.qfe);
|
|
||||||
printf(" Title ID: %.8X\n", header->execution_info.title_id);
|
|
||||||
printf(" Platform: %.8X\n", header->execution_info.platform);
|
|
||||||
printf(" Exec Table: %.8X\n", header->execution_info.executable_table);
|
|
||||||
printf(" Disc Number: %d\n", header->execution_info.disc_number);
|
|
||||||
printf(" Disc Count: %d\n", header->execution_info.disc_count);
|
|
||||||
printf(" Savegame ID: %.8X\n", header->execution_info.savegame_id);
|
|
||||||
printf("\n");
|
|
||||||
printf(" Loader Info:\n");
|
|
||||||
printf(" Image Flags: %.8X\n", header->loader_info.image_flags);
|
|
||||||
printf(" Game Regions: %.8X\n", header->loader_info.game_regions);
|
|
||||||
printf(" Media Flags: %.8X\n", header->loader_info.media_flags);
|
|
||||||
printf("\n");
|
|
||||||
printf(" TLS Info:\n");
|
|
||||||
printf(" Slot Count: %d\n", header->tls_info.slot_count);
|
|
||||||
printf(" Data Size: %db\n", header->tls_info.data_size);
|
|
||||||
printf(" Address: %.8X, %db\n", header->tls_info.raw_data_address,
|
|
||||||
header->tls_info.raw_data_size);
|
|
||||||
printf("\n");
|
|
||||||
printf(" Headers:\n");
|
|
||||||
for (size_t n = 0; n < header->header_count; n++) {
|
|
||||||
const xe_xex2_opt_header_t* opt_header = &header->headers[n];
|
|
||||||
printf(" %.8X (%.8X, %4db) %.8X = %11d\n",
|
|
||||||
opt_header->key, opt_header->offset, opt_header->length,
|
|
||||||
opt_header->value, opt_header->value);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
// Resources.
|
|
||||||
printf("Resources:\n");
|
|
||||||
printf(" %.8X, %db\n", header->resource_info.address,
|
|
||||||
header->resource_info.size);
|
|
||||||
printf(" TODO\n");
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
// Section info.
|
|
||||||
printf("Sections:\n");
|
|
||||||
for (size_t n = 0, i = 0; n < header->section_count; n++) {
|
|
||||||
const xe_xex2_section_t* section = &header->sections[n];
|
|
||||||
const char* type = "UNKNOWN";
|
|
||||||
switch (section->info.type) {
|
|
||||||
case XEX_SECTION_CODE:
|
|
||||||
type = "CODE ";
|
|
||||||
break;
|
|
||||||
case XEX_SECTION_DATA:
|
|
||||||
type = "RWDATA ";
|
|
||||||
break;
|
|
||||||
case XEX_SECTION_READONLY_DATA:
|
|
||||||
type = "RODATA ";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const size_t start_address =
|
|
||||||
header->exe_address + (i * xe_xex2_section_length);
|
|
||||||
const size_t end_address =
|
|
||||||
start_address + (section->info.page_count * xe_xex2_section_length);
|
|
||||||
printf(" %3d %s %3d pages %.8X - %.8X (%d bytes)\n",
|
|
||||||
(int)n, type, section->info.page_count, (int)start_address,
|
|
||||||
(int)end_address, section->info.page_count * xe_xex2_section_length);
|
|
||||||
i += section->info.page_count;
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
// Static libraries.
|
|
||||||
printf("Static Libraries:\n");
|
|
||||||
for (size_t n = 0; n < header->static_library_count; n++) {
|
|
||||||
const xe_xex2_static_library_t *library = &header->static_libraries[n];
|
|
||||||
printf(" %-8s : %d.%d.%d.%d\n",
|
|
||||||
library->name, library->major,
|
|
||||||
library->minor, library->build, library->qfe);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
// Imports.
|
|
||||||
printf("Imports:\n");
|
|
||||||
for (size_t n = 0; n < header->import_library_count; n++) {
|
|
||||||
const xe_xex2_import_library_t* library = &header->import_libraries[n];
|
|
||||||
|
|
||||||
xe_xex2_import_info_t* import_infos;
|
|
||||||
size_t import_info_count;
|
|
||||||
if (!xe_xex2_get_import_infos(xex_, library,
|
|
||||||
&import_infos, &import_info_count)) {
|
|
||||||
printf(" %s - %d imports\n", library->name, (int)import_info_count);
|
|
||||||
printf(" Version: %d.%d.%d.%d\n",
|
|
||||||
library->version.major, library->version.minor,
|
|
||||||
library->version.build, library->version.qfe);
|
|
||||||
printf(" Min Version: %d.%d.%d.%d\n",
|
|
||||||
library->min_version.major, library->min_version.minor,
|
|
||||||
library->min_version.build, library->min_version.qfe);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
// Counts.
|
|
||||||
int known_count = 0;
|
|
||||||
int unknown_count = 0;
|
|
||||||
int impl_count = 0;
|
|
||||||
int unimpl_count = 0;
|
|
||||||
for (size_t m = 0; m < import_info_count; m++) {
|
|
||||||
const xe_xex2_import_info_t* info = &import_infos[m];
|
|
||||||
KernelExport* kernel_export =
|
|
||||||
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
|
|
||||||
if (kernel_export) {
|
|
||||||
known_count++;
|
|
||||||
if (kernel_export->is_implemented) {
|
|
||||||
impl_count++;
|
|
||||||
} else {
|
|
||||||
unimpl_count++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unknown_count++;
|
|
||||||
unimpl_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf(" Total: %4u\n", import_info_count);
|
|
||||||
printf(" Known: %3d%% (%d known, %d unknown)\n",
|
|
||||||
(int)(known_count / (float)import_info_count * 100.0f),
|
|
||||||
known_count, unknown_count);
|
|
||||||
printf(" Implemented: %3d%% (%d implemented, %d unimplemented)\n",
|
|
||||||
(int)(impl_count / (float)import_info_count * 100.0f),
|
|
||||||
impl_count, unimpl_count);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
// Listing.
|
|
||||||
for (size_t m = 0; m < import_info_count; m++) {
|
|
||||||
const xe_xex2_import_info_t* info = &import_infos[m];
|
|
||||||
KernelExport* kernel_export = export_resolver->GetExportByOrdinal(
|
|
||||||
library->name, info->ordinal);
|
|
||||||
const char *name = "UNKNOWN";
|
|
||||||
bool implemented = false;
|
|
||||||
if (kernel_export) {
|
|
||||||
name = kernel_export->name;
|
|
||||||
implemented = kernel_export->is_implemented;
|
|
||||||
}
|
|
||||||
if (kernel_export && kernel_export->type == KernelExport::Variable) {
|
|
||||||
printf(" V %.8X %.3X (%3d) %s %s\n",
|
|
||||||
info->value_address, info->ordinal, info->ordinal,
|
|
||||||
implemented ? " " : "!!", name);
|
|
||||||
} else if (info->thunk_address) {
|
|
||||||
printf(" F %.8X %.8X %.3X (%3d) %s %s\n",
|
|
||||||
info->value_address, info->thunk_address, info->ordinal,
|
|
||||||
info->ordinal, implemented ? " " : "!!", name);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xe_free(import_infos);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exports.
|
|
||||||
printf("Exports:\n");
|
|
||||||
printf(" TODO\n");
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,7 @@
|
||||||
|
|
||||||
#include <xenia/kernel/xobject.h>
|
#include <xenia/kernel/xobject.h>
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <xenia/export_resolver.h>
|
|
||||||
#include <xenia/xbox.h>
|
#include <xenia/xbox.h>
|
||||||
#include <xenia/kernel/util/xex2.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -28,28 +24,14 @@ public:
|
||||||
XModule(KernelState* kernel_state, const char* path);
|
XModule(KernelState* kernel_state, const char* path);
|
||||||
virtual ~XModule();
|
virtual ~XModule();
|
||||||
|
|
||||||
const char* path();
|
const char* path() const { return path_; }
|
||||||
const char* name();
|
const char* name() const { return name_; }
|
||||||
xe_xex2_ref xex();
|
|
||||||
const xe_xex2_header_t* xex_header();
|
|
||||||
|
|
||||||
X_STATUS LoadFromFile(const char* path);
|
virtual void* GetProcAddressByOrdinal(uint16_t ordinal) = 0;
|
||||||
X_STATUS LoadFromMemory(const void* addr, const size_t length);
|
|
||||||
|
|
||||||
X_STATUS GetSection(const char* name, uint32_t* out_data, uint32_t* out_size);
|
|
||||||
void* GetProcAddressByOrdinal(uint16_t ordinal);
|
|
||||||
|
|
||||||
X_STATUS Launch(uint32_t flags);
|
|
||||||
|
|
||||||
void Dump();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int LoadPE();
|
|
||||||
|
|
||||||
|
protected:
|
||||||
char name_[256];
|
char name_[256];
|
||||||
char path_[XE_MAX_PATH];
|
char path_[XE_MAX_PATH];
|
||||||
|
|
||||||
xe_xex2_ref xex_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include <xenia/cpu/cpu.h>
|
#include <xenia/cpu/cpu.h>
|
||||||
#include <xenia/kernel/xboxkrnl_threading.h>
|
#include <xenia/kernel/xboxkrnl_threading.h>
|
||||||
#include <xenia/kernel/objects/xevent.h>
|
#include <xenia/kernel/objects/xevent.h>
|
||||||
#include <xenia/kernel/objects/xmodule.h>
|
#include <xenia/kernel/objects/xuser_module.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace alloy;
|
using namespace alloy;
|
||||||
|
@ -185,7 +185,7 @@ X_STATUS XThread::Create() {
|
||||||
// Set native info.
|
// Set native info.
|
||||||
SetNativePointer(thread_state_address_);
|
SetNativePointer(thread_state_address_);
|
||||||
|
|
||||||
XModule* module = kernel_state()->GetExecutableModule();
|
XUserModule* module = kernel_state()->GetExecutableModule();
|
||||||
|
|
||||||
// Allocate TLS block.
|
// Allocate TLS block.
|
||||||
const xe_xex2_header_t* header = module->xex_header();
|
const xe_xex2_header_t* header = module->xex_header();
|
||||||
|
|
|
@ -0,0 +1,317 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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/objects/xuser_module.h>
|
||||||
|
|
||||||
|
#include <xenia/emulator.h>
|
||||||
|
#include <xenia/cpu/cpu.h>
|
||||||
|
#include <xenia/kernel/objects/xthread.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace xe;
|
||||||
|
using namespace xe::cpu;
|
||||||
|
using namespace xe::kernel;
|
||||||
|
|
||||||
|
|
||||||
|
XUserModule::XUserModule(KernelState* kernel_state, const char* path) :
|
||||||
|
XModule(kernel_state, path),
|
||||||
|
xex_(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
XUserModule::~XUserModule() {
|
||||||
|
xe_xex2_release(xex_);
|
||||||
|
}
|
||||||
|
|
||||||
|
xe_xex2_ref XUserModule::xex() {
|
||||||
|
return xe_xex2_retain(xex_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const xe_xex2_header_t* XUserModule::xex_header() {
|
||||||
|
return xe_xex2_get_header(xex_);
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS XUserModule::LoadFromFile(const char* path) {
|
||||||
|
// Resolve the file to open.
|
||||||
|
// TODO(benvanik): make this code shared?
|
||||||
|
fs::Entry* fs_entry = kernel_state()->file_system()->ResolvePath(path);
|
||||||
|
if (!fs_entry) {
|
||||||
|
XELOGE("File not found: %s", path);
|
||||||
|
return X_STATUS_NO_SUCH_FILE;
|
||||||
|
}
|
||||||
|
if (fs_entry->type() != fs::Entry::kTypeFile) {
|
||||||
|
XELOGE("Invalid file type: %s", path);
|
||||||
|
return X_STATUS_NO_SUCH_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map into memory.
|
||||||
|
fs::MemoryMapping* mmap = fs_entry->CreateMemoryMapping(kXEFileModeRead, 0, 0);
|
||||||
|
if (!mmap) {
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the module.
|
||||||
|
X_STATUS return_code = LoadFromMemory(mmap->address(), mmap->length());
|
||||||
|
|
||||||
|
// Unmap memory and cleanup.
|
||||||
|
delete mmap;
|
||||||
|
delete fs_entry;
|
||||||
|
|
||||||
|
return return_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) {
|
||||||
|
Processor* processor = kernel_state()->processor();
|
||||||
|
XenonRuntime* runtime = processor->runtime();
|
||||||
|
XexModule* xex_module = NULL;
|
||||||
|
|
||||||
|
// Load the XEX into memory and decrypt.
|
||||||
|
xe_xex2_options_t xex_options;
|
||||||
|
xe_zero_struct(&xex_options, sizeof(xex_options));
|
||||||
|
xex_ = xe_xex2_load(kernel_state()->memory(), addr, length, xex_options);
|
||||||
|
XEEXPECTNOTNULL(xex_);
|
||||||
|
|
||||||
|
// Prepare the module for execution.
|
||||||
|
// Runtime takes ownership.
|
||||||
|
xex_module = new XexModule(runtime);
|
||||||
|
XEEXPECTZERO(xex_module->Load(name_, path_, xex_));
|
||||||
|
XEEXPECTZERO(runtime->AddModule(xex_module));
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
XECLEANUP:
|
||||||
|
delete xex_module;
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS XUserModule::GetSection(const char* name,
|
||||||
|
uint32_t* out_data, uint32_t* out_size) {
|
||||||
|
const PESection* section = xe_xex2_get_pe_section(xex_, name);
|
||||||
|
if (!section) {
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
*out_data = section->address;
|
||||||
|
*out_size = section->size;
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* XUserModule::GetProcAddressByOrdinal(uint16_t ordinal) {
|
||||||
|
// TODO(benvanik): check export tables.
|
||||||
|
XELOGE("GetProcAddressByOrdinal not implemented");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS XUserModule::Launch(uint32_t flags) {
|
||||||
|
const xe_xex2_header_t* header = xex_header();
|
||||||
|
|
||||||
|
XELOGI("Launching module...");
|
||||||
|
|
||||||
|
Dump();
|
||||||
|
|
||||||
|
// Create a thread to run in.
|
||||||
|
XThread* thread = new XThread(
|
||||||
|
kernel_state(),
|
||||||
|
header->exe_stack_size,
|
||||||
|
0,
|
||||||
|
header->exe_entry_point, NULL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
X_STATUS result = thread->Create();
|
||||||
|
if (XFAILED(result)) {
|
||||||
|
XELOGE("Could not create launch thread: %.8X", result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until thread completes.
|
||||||
|
thread->Wait(0, 0, 0, NULL);
|
||||||
|
|
||||||
|
thread->Release();
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XUserModule::Dump() {
|
||||||
|
ExportResolver* export_resolver =
|
||||||
|
kernel_state_->emulator()->export_resolver();
|
||||||
|
const xe_xex2_header_t* header = xe_xex2_get_header(xex_);
|
||||||
|
|
||||||
|
// XEX info.
|
||||||
|
printf("Module %s:\n\n", path_);
|
||||||
|
printf(" Module Flags: %.8X\n", header->module_flags);
|
||||||
|
printf(" System Flags: %.8X\n", header->system_flags);
|
||||||
|
printf("\n");
|
||||||
|
printf(" Address: %.8X\n", header->exe_address);
|
||||||
|
printf(" Entry Point: %.8X\n", header->exe_entry_point);
|
||||||
|
printf(" Stack Size: %.8X\n", header->exe_stack_size);
|
||||||
|
printf(" Heap Size: %.8X\n", header->exe_heap_size);
|
||||||
|
printf("\n");
|
||||||
|
printf(" Execution Info:\n");
|
||||||
|
printf(" Media ID: %.8X\n", header->execution_info.media_id);
|
||||||
|
printf(" Version: %d.%d.%d.%d\n",
|
||||||
|
header->execution_info.version.major,
|
||||||
|
header->execution_info.version.minor,
|
||||||
|
header->execution_info.version.build,
|
||||||
|
header->execution_info.version.qfe);
|
||||||
|
printf(" Base Version: %d.%d.%d.%d\n",
|
||||||
|
header->execution_info.base_version.major,
|
||||||
|
header->execution_info.base_version.minor,
|
||||||
|
header->execution_info.base_version.build,
|
||||||
|
header->execution_info.base_version.qfe);
|
||||||
|
printf(" Title ID: %.8X\n", header->execution_info.title_id);
|
||||||
|
printf(" Platform: %.8X\n", header->execution_info.platform);
|
||||||
|
printf(" Exec Table: %.8X\n", header->execution_info.executable_table);
|
||||||
|
printf(" Disc Number: %d\n", header->execution_info.disc_number);
|
||||||
|
printf(" Disc Count: %d\n", header->execution_info.disc_count);
|
||||||
|
printf(" Savegame ID: %.8X\n", header->execution_info.savegame_id);
|
||||||
|
printf("\n");
|
||||||
|
printf(" Loader Info:\n");
|
||||||
|
printf(" Image Flags: %.8X\n", header->loader_info.image_flags);
|
||||||
|
printf(" Game Regions: %.8X\n", header->loader_info.game_regions);
|
||||||
|
printf(" Media Flags: %.8X\n", header->loader_info.media_flags);
|
||||||
|
printf("\n");
|
||||||
|
printf(" TLS Info:\n");
|
||||||
|
printf(" Slot Count: %d\n", header->tls_info.slot_count);
|
||||||
|
printf(" Data Size: %db\n", header->tls_info.data_size);
|
||||||
|
printf(" Address: %.8X, %db\n", header->tls_info.raw_data_address,
|
||||||
|
header->tls_info.raw_data_size);
|
||||||
|
printf("\n");
|
||||||
|
printf(" Headers:\n");
|
||||||
|
for (size_t n = 0; n < header->header_count; n++) {
|
||||||
|
const xe_xex2_opt_header_t* opt_header = &header->headers[n];
|
||||||
|
printf(" %.8X (%.8X, %4db) %.8X = %11d\n",
|
||||||
|
opt_header->key, opt_header->offset, opt_header->length,
|
||||||
|
opt_header->value, opt_header->value);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// Resources.
|
||||||
|
printf("Resources:\n");
|
||||||
|
printf(" %.8X, %db\n", header->resource_info.address,
|
||||||
|
header->resource_info.size);
|
||||||
|
printf(" TODO\n");
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// Section info.
|
||||||
|
printf("Sections:\n");
|
||||||
|
for (size_t n = 0, i = 0; n < header->section_count; n++) {
|
||||||
|
const xe_xex2_section_t* section = &header->sections[n];
|
||||||
|
const char* type = "UNKNOWN";
|
||||||
|
switch (section->info.type) {
|
||||||
|
case XEX_SECTION_CODE:
|
||||||
|
type = "CODE ";
|
||||||
|
break;
|
||||||
|
case XEX_SECTION_DATA:
|
||||||
|
type = "RWDATA ";
|
||||||
|
break;
|
||||||
|
case XEX_SECTION_READONLY_DATA:
|
||||||
|
type = "RODATA ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const size_t start_address =
|
||||||
|
header->exe_address + (i * xe_xex2_section_length);
|
||||||
|
const size_t end_address =
|
||||||
|
start_address + (section->info.page_count * xe_xex2_section_length);
|
||||||
|
printf(" %3d %s %3d pages %.8X - %.8X (%d bytes)\n",
|
||||||
|
(int)n, type, section->info.page_count, (int)start_address,
|
||||||
|
(int)end_address, section->info.page_count * xe_xex2_section_length);
|
||||||
|
i += section->info.page_count;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// Static libraries.
|
||||||
|
printf("Static Libraries:\n");
|
||||||
|
for (size_t n = 0; n < header->static_library_count; n++) {
|
||||||
|
const xe_xex2_static_library_t *library = &header->static_libraries[n];
|
||||||
|
printf(" %-8s : %d.%d.%d.%d\n",
|
||||||
|
library->name, library->major,
|
||||||
|
library->minor, library->build, library->qfe);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// Imports.
|
||||||
|
printf("Imports:\n");
|
||||||
|
for (size_t n = 0; n < header->import_library_count; n++) {
|
||||||
|
const xe_xex2_import_library_t* library = &header->import_libraries[n];
|
||||||
|
|
||||||
|
xe_xex2_import_info_t* import_infos;
|
||||||
|
size_t import_info_count;
|
||||||
|
if (!xe_xex2_get_import_infos(xex_, library,
|
||||||
|
&import_infos, &import_info_count)) {
|
||||||
|
printf(" %s - %d imports\n", library->name, (int)import_info_count);
|
||||||
|
printf(" Version: %d.%d.%d.%d\n",
|
||||||
|
library->version.major, library->version.minor,
|
||||||
|
library->version.build, library->version.qfe);
|
||||||
|
printf(" Min Version: %d.%d.%d.%d\n",
|
||||||
|
library->min_version.major, library->min_version.minor,
|
||||||
|
library->min_version.build, library->min_version.qfe);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// Counts.
|
||||||
|
int known_count = 0;
|
||||||
|
int unknown_count = 0;
|
||||||
|
int impl_count = 0;
|
||||||
|
int unimpl_count = 0;
|
||||||
|
for (size_t m = 0; m < import_info_count; m++) {
|
||||||
|
const xe_xex2_import_info_t* info = &import_infos[m];
|
||||||
|
KernelExport* kernel_export =
|
||||||
|
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
|
||||||
|
if (kernel_export) {
|
||||||
|
known_count++;
|
||||||
|
if (kernel_export->is_implemented) {
|
||||||
|
impl_count++;
|
||||||
|
} else {
|
||||||
|
unimpl_count++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unknown_count++;
|
||||||
|
unimpl_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf(" Total: %4u\n", import_info_count);
|
||||||
|
printf(" Known: %3d%% (%d known, %d unknown)\n",
|
||||||
|
(int)(known_count / (float)import_info_count * 100.0f),
|
||||||
|
known_count, unknown_count);
|
||||||
|
printf(" Implemented: %3d%% (%d implemented, %d unimplemented)\n",
|
||||||
|
(int)(impl_count / (float)import_info_count * 100.0f),
|
||||||
|
impl_count, unimpl_count);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// Listing.
|
||||||
|
for (size_t m = 0; m < import_info_count; m++) {
|
||||||
|
const xe_xex2_import_info_t* info = &import_infos[m];
|
||||||
|
KernelExport* kernel_export = export_resolver->GetExportByOrdinal(
|
||||||
|
library->name, info->ordinal);
|
||||||
|
const char *name = "UNKNOWN";
|
||||||
|
bool implemented = false;
|
||||||
|
if (kernel_export) {
|
||||||
|
name = kernel_export->name;
|
||||||
|
implemented = kernel_export->is_implemented;
|
||||||
|
}
|
||||||
|
if (kernel_export && kernel_export->type == KernelExport::Variable) {
|
||||||
|
printf(" V %.8X %.3X (%3d) %s %s\n",
|
||||||
|
info->value_address, info->ordinal, info->ordinal,
|
||||||
|
implemented ? " " : "!!", name);
|
||||||
|
} else if (info->thunk_address) {
|
||||||
|
printf(" F %.8X %.8X %.3X (%3d) %s %s\n",
|
||||||
|
info->value_address, info->thunk_address, info->ordinal,
|
||||||
|
info->ordinal, implemented ? " " : "!!", name);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xe_free(import_infos);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exports.
|
||||||
|
printf("Exports:\n");
|
||||||
|
printf(" TODO\n");
|
||||||
|
printf("\n");
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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_XBOXKRNL_XUSER_MODULE_H_
|
||||||
|
#define XENIA_KERNEL_XBOXKRNL_XUSER_MODULE_H_
|
||||||
|
|
||||||
|
#include <xenia/kernel/objects/xmodule.h>
|
||||||
|
|
||||||
|
#include <xenia/export_resolver.h>
|
||||||
|
#include <xenia/xbox.h>
|
||||||
|
#include <xenia/kernel/util/xex2.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
|
||||||
|
class XUserModule : public XModule {
|
||||||
|
public:
|
||||||
|
XUserModule(KernelState* kernel_state, const char* path);
|
||||||
|
virtual ~XUserModule();
|
||||||
|
|
||||||
|
xe_xex2_ref xex();
|
||||||
|
const xe_xex2_header_t* xex_header();
|
||||||
|
|
||||||
|
X_STATUS LoadFromFile(const char* path);
|
||||||
|
X_STATUS LoadFromMemory(const void* addr, const size_t length);
|
||||||
|
|
||||||
|
X_STATUS GetSection(const char* name, uint32_t* out_data, uint32_t* out_size);
|
||||||
|
virtual void* GetProcAddressByOrdinal(uint16_t ordinal);
|
||||||
|
|
||||||
|
X_STATUS Launch(uint32_t flags);
|
||||||
|
|
||||||
|
void Dump();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int LoadPE();
|
||||||
|
|
||||||
|
xe_xex2_ref xex_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
|
#endif // XENIA_KERNEL_XBOXKRNL_XUSER_MODULE_H_
|
|
@ -4,8 +4,6 @@
|
||||||
'async_request.cc',
|
'async_request.cc',
|
||||||
'async_request.h',
|
'async_request.h',
|
||||||
'kernel.h',
|
'kernel.h',
|
||||||
'kernel_module.cc',
|
|
||||||
'kernel_module.h',
|
|
||||||
'kernel_state.cc',
|
'kernel_state.cc',
|
||||||
'kernel_state.h',
|
'kernel_state.h',
|
||||||
'modules.h',
|
'modules.h',
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
#include <alloy/frontend/ppc/ppc_context.h>
|
#include <alloy/frontend/ppc/ppc_context.h>
|
||||||
#include <xenia/export_resolver.h>
|
#include <xenia/export_resolver.h>
|
||||||
#include <xenia/kernel/kernel_module.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
|
@ -20,7 +20,7 @@ using namespace xe::kernel::xam;
|
||||||
|
|
||||||
|
|
||||||
XamModule::XamModule(Emulator* emulator, KernelState* kernel_state) :
|
XamModule::XamModule(Emulator* emulator, KernelState* kernel_state) :
|
||||||
KernelModule(emulator, kernel_state) {
|
XKernelModule(kernel_state, "xe:\\xam.xex") {
|
||||||
// Build the export table used for resolution.
|
// Build the export table used for resolution.
|
||||||
#include <xenia/kernel/util/export_table_pre.inc>
|
#include <xenia/kernel/util/export_table_pre.inc>
|
||||||
static KernelExport xam_export_table[] = {
|
static KernelExport xam_export_table[] = {
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
#include <xenia/core.h>
|
#include <xenia/core.h>
|
||||||
|
|
||||||
#include <xenia/export_resolver.h>
|
#include <xenia/export_resolver.h>
|
||||||
#include <xenia/kernel/kernel_module.h>
|
|
||||||
#include <xenia/kernel/xam_ordinals.h>
|
#include <xenia/kernel/xam_ordinals.h>
|
||||||
|
#include <xenia/kernel/objects/xkernel_module.h>
|
||||||
|
|
||||||
// All of the exported functions:
|
// All of the exported functions:
|
||||||
#include <xenia/kernel/xam_info.h>
|
#include <xenia/kernel/xam_info.h>
|
||||||
|
@ -25,7 +25,7 @@ namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
|
|
||||||
class XamModule : public KernelModule {
|
class XamModule : public XKernelModule {
|
||||||
public:
|
public:
|
||||||
XamModule(Emulator* emulator, KernelState* kernel_state);
|
XamModule(Emulator* emulator, KernelState* kernel_state);
|
||||||
virtual ~XamModule();
|
virtual ~XamModule();
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include <xenia/debug/debug_server.h>
|
#include <xenia/debug/debug_server.h>
|
||||||
#include <xenia/kernel/kernel_state.h>
|
#include <xenia/kernel/kernel_state.h>
|
||||||
#include <xenia/kernel/xboxkrnl_private.h>
|
#include <xenia/kernel/xboxkrnl_private.h>
|
||||||
#include <xenia/kernel/objects/xmodule.h>
|
#include <xenia/kernel/objects/xuser_module.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace xe;
|
using namespace xe;
|
||||||
|
@ -29,7 +29,7 @@ DEFINE_bool(abort_before_entry, false,
|
||||||
|
|
||||||
|
|
||||||
XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state) :
|
XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state) :
|
||||||
KernelModule(emulator, kernel_state) {
|
XKernelModule(kernel_state, "xe:\\xboxkrnl.exe") {
|
||||||
// Build the export table used for resolution.
|
// Build the export table used for resolution.
|
||||||
#include <xenia/kernel/util/export_table_pre.inc>
|
#include <xenia/kernel/util/export_table_pre.inc>
|
||||||
static KernelExport xboxkrnl_export_table[] = {
|
static KernelExport xboxkrnl_export_table[] = {
|
||||||
|
@ -144,7 +144,7 @@ XboxkrnlModule::~XboxkrnlModule() {
|
||||||
int XboxkrnlModule::LaunchModule(const char* path) {
|
int XboxkrnlModule::LaunchModule(const char* path) {
|
||||||
// Create and register the module. We keep it local to this function and
|
// Create and register the module. We keep it local to this function and
|
||||||
// dispose it on exit.
|
// dispose it on exit.
|
||||||
XModule* module = new XModule(kernel_state_, path);
|
XUserModule* module = new XUserModule(kernel_state_, path);
|
||||||
|
|
||||||
// Load the module into memory from the filesystem.
|
// Load the module into memory from the filesystem.
|
||||||
X_STATUS result_code = module->LoadFromFile(path);
|
X_STATUS result_code = module->LoadFromFile(path);
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
#include <xenia/core.h>
|
#include <xenia/core.h>
|
||||||
|
|
||||||
#include <xenia/export_resolver.h>
|
#include <xenia/export_resolver.h>
|
||||||
#include <xenia/kernel/kernel_module.h>
|
|
||||||
#include <xenia/kernel/xboxkrnl_ordinals.h>
|
#include <xenia/kernel/xboxkrnl_ordinals.h>
|
||||||
|
#include <xenia/kernel/objects/xkernel_module.h>
|
||||||
|
|
||||||
// All of the exported functions:
|
// All of the exported functions:
|
||||||
#include <xenia/kernel/xboxkrnl_debug.h>
|
#include <xenia/kernel/xboxkrnl_debug.h>
|
||||||
|
@ -33,7 +33,7 @@ namespace kernel {
|
||||||
class KernelState;
|
class KernelState;
|
||||||
|
|
||||||
|
|
||||||
class XboxkrnlModule : public KernelModule {
|
class XboxkrnlModule : public XKernelModule {
|
||||||
public:
|
public:
|
||||||
XboxkrnlModule(Emulator* emulator, KernelState* kernel_state);
|
XboxkrnlModule(Emulator* emulator, KernelState* kernel_state);
|
||||||
virtual ~XboxkrnlModule();
|
virtual ~XboxkrnlModule();
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
#include <xenia/kernel/kernel_state.h>
|
#include <xenia/kernel/kernel_state.h>
|
||||||
#include <xenia/kernel/xboxkrnl_private.h>
|
#include <xenia/kernel/xboxkrnl_private.h>
|
||||||
#include <xenia/kernel/objects/xmodule.h>
|
#include <xenia/kernel/objects/xuser_module.h>
|
||||||
#include <xenia/kernel/util/shim_utils.h>
|
#include <xenia/kernel/util/shim_utils.h>
|
||||||
#include <xenia/kernel/util/xex2.h>
|
#include <xenia/kernel/util/xex2.h>
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ int xeXexCheckExecutablePriviledge(uint32_t privilege) {
|
||||||
// Privilege=6 -> 0x00000040 -> XEX_SYSTEM_INSECURE_SOCKETS
|
// Privilege=6 -> 0x00000040 -> XEX_SYSTEM_INSECURE_SOCKETS
|
||||||
uint32_t mask = 1 << privilege;
|
uint32_t mask = 1 << privilege;
|
||||||
|
|
||||||
XModule* module = state->GetExecutableModule();
|
XUserModule* module = state->GetExecutableModule();
|
||||||
if (!module) {
|
if (!module) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -209,6 +209,51 @@ SHIM_CALL XexGetModuleHandle_shim(
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
SHIM_CALL XexLoadImage_shim(
|
||||||
|
PPCContext* ppc_state, KernelState* state) {
|
||||||
|
uint32_t module_name_ptr = SHIM_GET_ARG_32(0);
|
||||||
|
const char* module_name = (const char*)SHIM_MEM_ADDR(module_name_ptr);
|
||||||
|
uint32_t module_flags = SHIM_GET_ARG_32(1);
|
||||||
|
uint32_t min_version = SHIM_GET_ARG_32(2);
|
||||||
|
uint32_t handle_ptr = SHIM_GET_ARG_32(3);
|
||||||
|
|
||||||
|
XELOGD(
|
||||||
|
"XexLoadImage(%s, %.8X, %.8X, %.8X)",
|
||||||
|
module_name, module_flags, min_version, handle_ptr);
|
||||||
|
|
||||||
|
X_STATUS result = X_STATUS_NO_SUCH_FILE;
|
||||||
|
|
||||||
|
XModule* module = state->GetModule(module_name);
|
||||||
|
if (module) {
|
||||||
|
module->RetainHandle();
|
||||||
|
SHIM_SET_MEM_32(handle_ptr, module->handle());
|
||||||
|
module->Release();
|
||||||
|
|
||||||
|
result = X_STATUS_SUCCESS;
|
||||||
|
} else {
|
||||||
|
result = X_STATUS_NO_SUCH_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHIM_SET_RETURN(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHIM_CALL XexUnloadImage_shim(
|
||||||
|
PPCContext* ppc_state, KernelState* state) {
|
||||||
|
uint32_t handle = SHIM_GET_ARG_32(0);
|
||||||
|
|
||||||
|
XELOGD(
|
||||||
|
"XexUnloadImage(%.8X)",
|
||||||
|
handle);
|
||||||
|
|
||||||
|
X_STATUS result = X_STATUS_INVALID_HANDLE;
|
||||||
|
|
||||||
|
result = state->object_table()->RemoveHandle(handle);
|
||||||
|
|
||||||
|
SHIM_SET_RETURN(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SHIM_CALL XexGetProcedureAddress_shim(
|
SHIM_CALL XexGetProcedureAddress_shim(
|
||||||
PPCContext* ppc_state, KernelState* state) {
|
PPCContext* ppc_state, KernelState* state) {
|
||||||
uint32_t module_handle = SHIM_GET_ARG_32(0);
|
uint32_t module_handle = SHIM_GET_ARG_32(0);
|
||||||
|
@ -233,7 +278,7 @@ SHIM_CALL XexGetProcedureAddress_shim(
|
||||||
if (XSUCCEEDED(result)) {
|
if (XSUCCEEDED(result)) {
|
||||||
// TODO(benvanik): implement. May need to create stub functions on the fly.
|
// TODO(benvanik): implement. May need to create stub functions on the fly.
|
||||||
// module->GetProcAddressByOrdinal(ordinal);
|
// module->GetProcAddressByOrdinal(ordinal);
|
||||||
result = X_STATUS_INVALID_HANDLE;
|
result = X_STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
if (module) {
|
if (module) {
|
||||||
module->Release();
|
module->Release();
|
||||||
|
@ -279,6 +324,8 @@ void xe::kernel::xboxkrnl::RegisterModuleExports(
|
||||||
|
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", XexGetModuleHandle, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", XexGetModuleHandle, state);
|
||||||
// SHIM_SET_MAPPING("xboxkrnl.exe", XexGetModuleSection, state);
|
// SHIM_SET_MAPPING("xboxkrnl.exe", XexGetModuleSection, state);
|
||||||
|
SHIM_SET_MAPPING("xboxkrnl.exe", XexLoadImage, state);
|
||||||
|
SHIM_SET_MAPPING("xboxkrnl.exe", XexUnloadImage, state);
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", XexGetProcedureAddress, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", XexGetProcedureAddress, state);
|
||||||
|
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", ExRegisterTitleTerminateNotification, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", ExRegisterTitleTerminateNotification, state);
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
|
|
||||||
#include <xenia/kernel/kernel_state.h>
|
#include <xenia/kernel/kernel_state.h>
|
||||||
#include <xenia/kernel/xboxkrnl_private.h>
|
#include <xenia/kernel/xboxkrnl_private.h>
|
||||||
#include <xenia/kernel/objects/xmodule.h>
|
|
||||||
#include <xenia/kernel/objects/xthread.h>
|
#include <xenia/kernel/objects/xthread.h>
|
||||||
|
#include <xenia/kernel/objects/xuser_module.h>
|
||||||
#include <xenia/kernel/util/shim_utils.h>
|
#include <xenia/kernel/util/shim_utils.h>
|
||||||
#include <xenia/kernel/util/xex2.h>
|
#include <xenia/kernel/util/xex2.h>
|
||||||
|
|
||||||
|
@ -596,7 +596,7 @@ uint32_t xeRtlImageXexHeaderField(uint32_t xex_header_base_ptr,
|
||||||
// The only ImageField I've seen in the wild is
|
// The only ImageField I've seen in the wild is
|
||||||
// 0x20401 (XEX_HEADER_DEFAULT_HEAP_SIZE), so that's all we'll support.
|
// 0x20401 (XEX_HEADER_DEFAULT_HEAP_SIZE), so that's all we'll support.
|
||||||
|
|
||||||
XModule* module = NULL;
|
XUserModule* module = NULL;
|
||||||
|
|
||||||
// TODO(benvanik): use xex_header_base to dereference this.
|
// TODO(benvanik): use xex_header_base to dereference this.
|
||||||
// Right now we are only concerned with games making this call on their main
|
// Right now we are only concerned with games making this call on their main
|
||||||
|
|
Loading…
Reference in New Issue