Drop dependency on old-style xex2 headers
This commit is contained in:
parent
fe87c08424
commit
029babaf5d
|
@ -78,6 +78,18 @@ bool XexModule::GetOptHeader(const xex2_header* header, xe_xex2_header_keys key,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool XexModule::GetOptHeader(xe_xex2_header_keys key, void** out_ptr) const {
|
||||
return XexModule::GetOptHeader(xex_header_, key, out_ptr);
|
||||
}
|
||||
|
||||
uint32_t XexModule::GetProcAddress(uint16_t ordinal) const {
|
||||
return xe_xex2_lookup_export(xex_, ordinal);
|
||||
}
|
||||
|
||||
uint32_t XexModule::GetProcAddress(const char* name) const {
|
||||
return xe_xex2_lookup_export(xex_, name);
|
||||
}
|
||||
|
||||
bool XexModule::ApplyPatch(XexModule* module) {
|
||||
auto header = reinterpret_cast<const xex2_header*>(module->xex_header());
|
||||
if (!(header->module_flags &
|
||||
|
|
|
@ -40,6 +40,10 @@ class XexModule : public xe::cpu::Module {
|
|||
// not a pointer!
|
||||
static bool GetOptHeader(const xex2_header* header, xe_xex2_header_keys key,
|
||||
void** out_ptr);
|
||||
bool GetOptHeader(xe_xex2_header_keys key, void** out_ptr) const;
|
||||
|
||||
uint32_t GetProcAddress(uint16_t ordinal) const;
|
||||
uint32_t GetProcAddress(const char* name) const;
|
||||
|
||||
bool ApplyPatch(XexModule* module);
|
||||
bool Load(const std::string& name, const std::string& path,
|
||||
|
|
|
@ -120,7 +120,16 @@ KernelState* KernelState::shared() { return shared_kernel_state_; }
|
|||
|
||||
uint32_t KernelState::title_id() const {
|
||||
assert_not_null(executable_module_);
|
||||
return executable_module_->xex_header()->execution_info.title_id;
|
||||
|
||||
xex2_opt_execution_info* exec_info = 0;
|
||||
executable_module_->GetOptHeader(XEX_HEADER_EXECUTION_INFO,
|
||||
(void**)&exec_info);
|
||||
|
||||
if (exec_info) {
|
||||
return exec_info->title_id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t KernelState::process_type() const {
|
||||
|
@ -192,13 +201,14 @@ void KernelState::SetExecutableModule(object_ref<XUserModule> module) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto header = executable_module_->xex_header();
|
||||
if (header) {
|
||||
xex2_opt_tls_info* tls_header = nullptr;
|
||||
executable_module_->GetOptHeader(XEX_HEADER_TLS_INFO, (void**)&tls_header);
|
||||
if (tls_header) {
|
||||
auto pib = memory_->TranslateVirtual<ProcessInfoBlock*>(
|
||||
process_info_block_address_);
|
||||
pib->tls_data_size = header->tls_info.data_size;
|
||||
pib->tls_raw_data_size = header->tls_info.raw_data_size;
|
||||
pib->tls_slot_size = header->tls_info.slot_count * 4;
|
||||
pib->tls_data_size = tls_header->data_size;
|
||||
pib->tls_raw_data_size = tls_header->raw_data_size;
|
||||
pib->tls_slot_size = tls_header->slot_count * 4;
|
||||
}
|
||||
|
||||
// Setup the kernel's XexExecutableModuleHandle field.
|
||||
|
@ -275,8 +285,7 @@ object_ref<XUserModule> KernelState::LoadUserModule(const char* raw_name) {
|
|||
|
||||
module->Dump();
|
||||
|
||||
auto xex_header = module->xex_header();
|
||||
if (xex_header->exe_entry_point) {
|
||||
if (module->entry_point()) {
|
||||
// Call DllMain(DLL_PROCESS_ATTACH):
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx
|
||||
uint64_t args[] = {
|
||||
|
@ -285,7 +294,7 @@ object_ref<XUserModule> KernelState::LoadUserModule(const char* raw_name) {
|
|||
0, // 0 because always dynamic
|
||||
};
|
||||
auto thread_state = XThread::GetCurrentThread()->thread_state();
|
||||
processor()->Execute(thread_state, xex_header->exe_entry_point, args,
|
||||
processor()->Execute(thread_state, module->entry_point(), args,
|
||||
xe::countof(args));
|
||||
}
|
||||
|
||||
|
@ -323,14 +332,13 @@ void KernelState::OnThreadExecute(XThread* thread) {
|
|||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx
|
||||
auto thread_state = thread->thread_state();
|
||||
for (auto user_module : user_modules_) {
|
||||
auto xex_header = user_module->xex_header();
|
||||
if (xex_header->exe_entry_point) {
|
||||
if (user_module->entry_point()) {
|
||||
uint64_t args[] = {
|
||||
user_module->handle(),
|
||||
2, // DLL_THREAD_ATTACH
|
||||
0, // 0 because always dynamic
|
||||
};
|
||||
processor()->Execute(thread_state, xex_header->exe_entry_point, args,
|
||||
processor()->Execute(thread_state, user_module->entry_point(), args,
|
||||
xe::countof(args));
|
||||
}
|
||||
}
|
||||
|
@ -346,14 +354,13 @@ void KernelState::OnThreadExit(XThread* thread) {
|
|||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx
|
||||
auto thread_state = thread->thread_state();
|
||||
for (auto user_module : user_modules_) {
|
||||
auto xex_header = user_module->xex_header();
|
||||
if (xex_header->exe_entry_point) {
|
||||
if (user_module->entry_point()) {
|
||||
uint64_t args[] = {
|
||||
user_module->handle(),
|
||||
3, // DLL_THREAD_DETACH
|
||||
0, // 0 because always dynamic
|
||||
};
|
||||
processor()->Execute(thread_state, xex_header->exe_entry_point, args,
|
||||
processor()->Execute(thread_state, user_module->entry_point(), args,
|
||||
xe::countof(args));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,14 +164,18 @@ X_STATUS XThread::Create() {
|
|||
|
||||
// Allocate TLS block.
|
||||
// Games will specify a certain number of 4b slots that each thread will get.
|
||||
xex2_opt_tls_info* tls_header = nullptr;
|
||||
if (module) {
|
||||
module->GetOptHeader(XEX_HEADER_TLS_INFO, (void**)&tls_header);
|
||||
}
|
||||
|
||||
const uint32_t kDefaultTlsSlotCount = 32;
|
||||
uint32_t tls_slots = 0;
|
||||
uint32_t tls_extended_size = 0;
|
||||
if (module && module->xex_header()) {
|
||||
const xe_xex2_header_t* header = module->xex_header();
|
||||
tls_slots = header->tls_info.slot_count ? header->tls_info.slot_count
|
||||
: kDefaultTlsSlotCount;
|
||||
tls_extended_size = header->tls_info.data_size;
|
||||
if (tls_header) {
|
||||
tls_slots =
|
||||
tls_header->slot_count ? tls_header->slot_count : kDefaultTlsSlotCount;
|
||||
tls_extended_size = tls_header->data_size;
|
||||
} else {
|
||||
tls_slots = kDefaultTlsSlotCount;
|
||||
}
|
||||
|
@ -192,10 +196,9 @@ X_STATUS XThread::Create() {
|
|||
memory()->Fill(tls_address_, tls_total_size, 0);
|
||||
if (tls_extended_size) {
|
||||
// If game has extended data, copy in the default values.
|
||||
const xe_xex2_header_t* header = module->xex_header();
|
||||
assert_not_zero(header->tls_info.raw_data_address);
|
||||
memory()->Copy(tls_address_, header->tls_info.raw_data_address,
|
||||
header->tls_info.raw_data_size);
|
||||
assert_not_zero(tls_header->raw_data_address);
|
||||
memory()->Copy(tls_address_, tls_header->raw_data_address,
|
||||
tls_header->raw_data_size);
|
||||
}
|
||||
|
||||
// Allocate thread state block from heap.
|
||||
|
@ -583,8 +586,11 @@ void XThread::DeliverAPCs(void* data) {
|
|||
// kernel_routine(apc_address, &normal_routine, &normal_context,
|
||||
// &system_arg1, &system_arg2)
|
||||
uint64_t kernel_args[] = {
|
||||
apc_ptr, thread->scratch_address_ + 0, thread->scratch_address_ + 4,
|
||||
thread->scratch_address_ + 8, thread->scratch_address_ + 12,
|
||||
apc_ptr,
|
||||
thread->scratch_address_ + 0,
|
||||
thread->scratch_address_ + 4,
|
||||
thread->scratch_address_ + 8,
|
||||
thread->scratch_address_ + 12,
|
||||
};
|
||||
processor->Execute(thread->thread_state(), apc->kernel_routine,
|
||||
kernel_args, xe::countof(kernel_args));
|
||||
|
|
|
@ -22,13 +22,9 @@ namespace kernel {
|
|||
using namespace xe::cpu;
|
||||
|
||||
XUserModule::XUserModule(KernelState* kernel_state, const char* path)
|
||||
: XModule(kernel_state, ModuleType::kUserModule, path), xex_(nullptr) {}
|
||||
: XModule(kernel_state, ModuleType::kUserModule, path) {}
|
||||
|
||||
XUserModule::~XUserModule() { xe_xex2_dealloc(xex_); }
|
||||
|
||||
const xe_xex2_header_t* XUserModule::xex_header() {
|
||||
return xe_xex2_get_header(xex_);
|
||||
}
|
||||
XUserModule::~XUserModule() {}
|
||||
|
||||
X_STATUS XUserModule::LoadFromFile(std::string path) {
|
||||
X_STATUS result = X_STATUS_UNSUCCESSFUL;
|
||||
|
@ -86,7 +82,6 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) {
|
|||
if (!xex_module->Load(name_, path_, addr, length)) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
xex_ = xex_module->xex();
|
||||
processor_module_ = xex_module.get();
|
||||
if (!processor->AddModule(std::move(xex_module))) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
|
@ -106,34 +101,60 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) {
|
|||
ldr_data->dll_base = 0; // GetProcAddress will read this.
|
||||
ldr_data->xex_header_base = guest_xex_header_;
|
||||
|
||||
// Cache some commonly used headers...
|
||||
this->xex_module()->GetOptHeader(XEX_HEADER_ENTRY_POINT,
|
||||
(void**)&entry_point_);
|
||||
this->xex_module()->GetOptHeader(XEX_HEADER_DEFAULT_STACK_SIZE,
|
||||
(void**)&stack_size_);
|
||||
|
||||
OnLoad();
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t XUserModule::GetProcAddressByOrdinal(uint16_t ordinal) {
|
||||
return xe_xex2_lookup_export(xex_, ordinal);
|
||||
return xex_module()->GetProcAddress(ordinal);
|
||||
}
|
||||
|
||||
uint32_t XUserModule::GetProcAddressByName(const char* name) {
|
||||
return xe_xex2_lookup_export(xex_, name);
|
||||
return xex_module()->GetProcAddress(name);
|
||||
}
|
||||
|
||||
X_STATUS XUserModule::GetSection(const char* name, uint32_t* out_section_data,
|
||||
uint32_t* out_section_size) {
|
||||
auto header = xe_xex2_get_header(xex_);
|
||||
for (size_t n = 0; n < header->resource_info_count; n++) {
|
||||
auto& res = header->resource_infos[n];
|
||||
xex2_opt_resource_info* resource_header = nullptr;
|
||||
if (!XexModule::GetOptHeader(xex_header(), XEX_HEADER_RESOURCE_INFO,
|
||||
(void**)&resource_header)) {
|
||||
// No resources.
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
uint32_t count = (resource_header->size - 4) / 16;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
auto& res = resource_header->resources[i];
|
||||
if (strcmp(name, res.name) == 0) {
|
||||
// Found!
|
||||
*out_section_data = res.address;
|
||||
*out_section_size = res.size;
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
X_STATUS XUserModule::GetOptHeader(xe_xex2_header_keys key, void** out_ptr) {
|
||||
assert_not_null(out_ptr);
|
||||
|
||||
bool ret = xex_module()->GetOptHeader(key, out_ptr);
|
||||
if (!ret) {
|
||||
return X_STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS XUserModule::GetOptHeader(xe_xex2_header_keys key,
|
||||
uint32_t* out_header_guest_ptr) {
|
||||
auto header = xex_module()->xex_header();
|
||||
|
@ -180,16 +201,21 @@ X_STATUS XUserModule::GetOptHeader(uint8_t* membase, const xex2_header* header,
|
|||
}
|
||||
|
||||
X_STATUS XUserModule::Launch(uint32_t flags) {
|
||||
const xe_xex2_header_t* header = xex_header();
|
||||
|
||||
XELOGI("Launching module...");
|
||||
|
||||
Dump();
|
||||
|
||||
// Grab some important variables...
|
||||
auto header = xex_header();
|
||||
uint32_t exe_stack_size = 0;
|
||||
uint32_t exe_entry_point = 0;
|
||||
XexModule::GetOptHeader(xex_header(), XEX_HEADER_DEFAULT_STACK_SIZE,
|
||||
(void**)&exe_stack_size);
|
||||
XexModule::GetOptHeader(xex_header(), XEX_HEADER_ENTRY_POINT,
|
||||
(void**)&exe_entry_point);
|
||||
|
||||
// Create a thread to run in.
|
||||
auto thread =
|
||||
object_ref<XThread>(new XThread(kernel_state(), header->exe_stack_size, 0,
|
||||
header->exe_entry_point, 0, 0));
|
||||
auto thread = object_ref<XThread>(
|
||||
new XThread(kernel_state(), exe_stack_size, 0, exe_entry_point, 0, 0));
|
||||
|
||||
X_STATUS result = thread->Create();
|
||||
if (XFAILED(result)) {
|
||||
|
@ -206,11 +232,14 @@ X_STATUS XUserModule::Launch(uint32_t flags) {
|
|||
void XUserModule::Dump() {
|
||||
xe::cpu::ExportResolver* export_resolver =
|
||||
kernel_state_->emulator()->export_resolver();
|
||||
const xe_xex2_header_t* header = xe_xex2_get_header(xex_);
|
||||
auto header = xex_header();
|
||||
|
||||
// TODO: Need to loop through the optional headers one-by-one.
|
||||
|
||||
// XEX info.
|
||||
printf("Module %s:\n\n", path_.c_str());
|
||||
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);
|
||||
|
@ -249,7 +278,7 @@ void XUserModule::Dump() {
|
|||
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];
|
||||
const xex2_opt_header* 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);
|
||||
|
@ -440,6 +469,7 @@ void XUserModule::Dump() {
|
|||
|
||||
printf("\n");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
} // namespace kernel
|
||||
|
|
|
@ -13,15 +13,12 @@
|
|||
#include <string>
|
||||
|
||||
#include "xenia/cpu/export_resolver.h"
|
||||
#include "xenia/cpu/xex_module.h"
|
||||
#include "xenia/kernel/objects/xmodule.h"
|
||||
#include "xenia/kernel/util/xex2.h"
|
||||
#include "xenia/kernel/util/xex2_info.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
class XexModule;
|
||||
} // namespace cpu
|
||||
|
||||
namespace kernel {
|
||||
|
||||
class XUserModule : public XModule {
|
||||
|
@ -29,11 +26,15 @@ class XUserModule : public XModule {
|
|||
XUserModule(KernelState* kernel_state, const char* path);
|
||||
~XUserModule() override;
|
||||
|
||||
const xe_xex2_header_t* xex_header();
|
||||
const xe::cpu::XexModule* xex_module() const {
|
||||
return reinterpret_cast<xe::cpu::XexModule*>(processor_module_);
|
||||
}
|
||||
|
||||
const xex2_header* xex_header() const { return xex_module()->xex_header(); }
|
||||
|
||||
uint32_t entry_point() const { return entry_point_; }
|
||||
uint32_t stack_size() const { return stack_size_; }
|
||||
|
||||
X_STATUS LoadFromFile(std::string path);
|
||||
X_STATUS LoadFromMemory(const void* addr, const size_t length);
|
||||
|
||||
|
@ -42,6 +43,8 @@ class XUserModule : public XModule {
|
|||
X_STATUS GetSection(const char* name, uint32_t* out_section_data,
|
||||
uint32_t* out_section_size) override;
|
||||
|
||||
X_STATUS GetOptHeader(xe_xex2_header_keys key, void** out_ptr);
|
||||
|
||||
X_STATUS GetOptHeader(xe_xex2_header_keys key,
|
||||
uint32_t* out_header_guest_ptr);
|
||||
static X_STATUS GetOptHeader(uint8_t* membase, const xex2_header* header,
|
||||
|
@ -53,8 +56,10 @@ class XUserModule : public XModule {
|
|||
void Dump();
|
||||
|
||||
private:
|
||||
xe_xex2_ref xex_;
|
||||
uint32_t guest_xex_header_;
|
||||
|
||||
uint32_t entry_point_;
|
||||
uint32_t stack_size_;
|
||||
};
|
||||
|
||||
} // namespace kernel
|
||||
|
|
|
@ -480,6 +480,26 @@ union xex2_version {
|
|||
};
|
||||
};
|
||||
|
||||
struct xex2_opt_tls_info {
|
||||
xe::be<uint32_t> slot_count; // 0x0
|
||||
xe::be<uint32_t> raw_data_address; // 0x4
|
||||
xe::be<uint32_t> data_size; // 0x8
|
||||
xe::be<uint32_t> raw_data_size; // 0xC
|
||||
};
|
||||
static_assert_size(xex2_opt_tls_info, 0x10);
|
||||
|
||||
struct xex2_resource {
|
||||
char name[8]; // 0x0
|
||||
xe::be<uint32_t> address; // 0x8
|
||||
xe::be<uint32_t> size; // 0xC
|
||||
};
|
||||
static_assert_size(xex2_resource, 0x10);
|
||||
|
||||
struct xex2_opt_resource_info {
|
||||
xe::be<uint32_t> size; // 0x0 Resource count is (size - 4) / 16
|
||||
xex2_resource resources[1]; // 0x4
|
||||
};
|
||||
|
||||
struct xex2_opt_delta_patch_descriptor {
|
||||
xe::be<uint32_t> size; // 0x0
|
||||
xex2_version target_version; // 0x4
|
||||
|
|
|
@ -142,10 +142,10 @@ SHIM_CALL XexCheckExecutablePrivilege_shim(PPCContext* ppc_context,
|
|||
return;
|
||||
}
|
||||
|
||||
auto header = module->xex_header();
|
||||
uint32_t result = (header->system_flags & mask) > 0;
|
||||
uint32_t flags = 0;
|
||||
module->GetOptHeader(XEX_HEADER_SYSTEM_FLAGS, (void **)&flags);
|
||||
|
||||
SHIM_SET_RETURN_32(result);
|
||||
SHIM_SET_RETURN_32((flags & mask) > 0);
|
||||
}
|
||||
|
||||
SHIM_CALL XexGetModuleHandle_shim(PPCContext* ppc_context,
|
||||
|
|
|
@ -109,8 +109,7 @@ SHIM_CALL ExCreateThread_shim(PPCContext* ppc_context,
|
|||
|
||||
// Inherit default stack size
|
||||
if (stack_size == 0) {
|
||||
stack_size =
|
||||
kernel_state->GetExecutableModule()->xex_header()->exe_stack_size;
|
||||
stack_size = kernel_state->GetExecutableModule()->stack_size();
|
||||
}
|
||||
|
||||
// Stack must be aligned to 16kb pages
|
||||
|
|
Loading…
Reference in New Issue