Cleanup before kernel export refactor.
This commit is contained in:
parent
fccab79a7a
commit
9c3d2b54fb
|
@ -417,18 +417,27 @@ uint64_t UndefinedCallExtern(void* raw_context, uint64_t symbol_info_ptr) {
|
||||||
}
|
}
|
||||||
void X64Emitter::CallExtern(const hir::Instr* instr,
|
void X64Emitter::CallExtern(const hir::Instr* instr,
|
||||||
const FunctionInfo* symbol_info) {
|
const FunctionInfo* symbol_info) {
|
||||||
assert_true(symbol_info->behavior() == FunctionInfo::BEHAVIOR_EXTERN);
|
|
||||||
|
|
||||||
if (!symbol_info->extern_handler()) {
|
if (!symbol_info->extern_handler()) {
|
||||||
CallNative(UndefinedCallExtern, reinterpret_cast<uint64_t>(symbol_info));
|
CallNative(UndefinedCallExtern, reinterpret_cast<uint64_t>(symbol_info));
|
||||||
} else {
|
} else if (symbol_info->behavior() == FunctionBehavior::kBuiltin) {
|
||||||
// rcx = context
|
// rcx = context
|
||||||
// rdx = target host function
|
// rdx = target host function
|
||||||
// r8 = arg0
|
// r8 = arg0
|
||||||
// r9 = arg1
|
// r9 = arg1
|
||||||
|
mov(rdx, reinterpret_cast<uint64_t>(symbol_info->builtin_handler()));
|
||||||
|
mov(r8, reinterpret_cast<uint64_t>(symbol_info->builtin_arg0()));
|
||||||
|
mov(r9, reinterpret_cast<uint64_t>(symbol_info->builtin_arg1()));
|
||||||
|
auto thunk = backend()->guest_to_host_thunk();
|
||||||
|
mov(rax, reinterpret_cast<uint64_t>(thunk));
|
||||||
|
call(rax);
|
||||||
|
ReloadECX();
|
||||||
|
ReloadEDX();
|
||||||
|
// rax = host return
|
||||||
|
} else if (symbol_info->behavior() == FunctionBehavior::kExtern) {
|
||||||
|
// rcx = context
|
||||||
|
// rdx = target host function
|
||||||
mov(rdx, reinterpret_cast<uint64_t>(symbol_info->extern_handler()));
|
mov(rdx, reinterpret_cast<uint64_t>(symbol_info->extern_handler()));
|
||||||
mov(r8, reinterpret_cast<uint64_t>(symbol_info->extern_arg0()));
|
mov(r8, qword[rcx + offsetof(cpu::frontend::PPCContext, kernel_state)]);
|
||||||
mov(r9, reinterpret_cast<uint64_t>(symbol_info->extern_arg1()));
|
|
||||||
auto thunk = backend()->guest_to_host_thunk();
|
auto thunk = backend()->guest_to_host_thunk();
|
||||||
mov(rax, reinterpret_cast<uint64_t>(thunk));
|
mov(rax, reinterpret_cast<uint64_t>(thunk));
|
||||||
call(rax);
|
call(rax);
|
||||||
|
|
|
@ -20,19 +20,17 @@ ExportResolver::ExportResolver() {}
|
||||||
ExportResolver::~ExportResolver() {}
|
ExportResolver::~ExportResolver() {}
|
||||||
|
|
||||||
void ExportResolver::RegisterTable(const std::string& library_name,
|
void ExportResolver::RegisterTable(const std::string& library_name,
|
||||||
KernelExport* exports, const size_t count) {
|
Export* exports, const size_t count) {
|
||||||
tables_.emplace_back(library_name, exports, count);
|
tables_.emplace_back(library_name, exports, count);
|
||||||
|
|
||||||
for (size_t n = 0; n < count; n++) {
|
for (size_t n = 0; n < count; n++) {
|
||||||
exports[n].is_implemented = false;
|
|
||||||
exports[n].variable_ptr = 0;
|
exports[n].variable_ptr = 0;
|
||||||
exports[n].function_data.shim_data = nullptr;
|
|
||||||
exports[n].function_data.shim = nullptr;
|
exports[n].function_data.shim = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KernelExport* ExportResolver::GetExportByOrdinal(
|
Export* ExportResolver::GetExportByOrdinal(const std::string& library_name,
|
||||||
const std::string& library_name, const uint32_t ordinal) {
|
const uint32_t ordinal) {
|
||||||
for (const auto& table : tables_) {
|
for (const auto& table : tables_) {
|
||||||
if (table.name == library_name || table.simple_name == library_name) {
|
if (table.name == library_name || table.simple_name == library_name) {
|
||||||
// TODO(benvanik): binary search?
|
// TODO(benvanik): binary search?
|
||||||
|
@ -50,20 +48,19 @@ KernelExport* ExportResolver::GetExportByOrdinal(
|
||||||
void ExportResolver::SetVariableMapping(const std::string& library_name,
|
void ExportResolver::SetVariableMapping(const std::string& library_name,
|
||||||
const uint32_t ordinal,
|
const uint32_t ordinal,
|
||||||
uint32_t value) {
|
uint32_t value) {
|
||||||
auto kernel_export = GetExportByOrdinal(library_name, ordinal);
|
auto export = GetExportByOrdinal(library_name, ordinal);
|
||||||
assert_not_null(kernel_export);
|
assert_not_null(export);
|
||||||
kernel_export->is_implemented = true;
|
export->tags |= ExportTag::kImplemented;
|
||||||
kernel_export->variable_ptr = value;
|
export->variable_ptr = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExportResolver::SetFunctionMapping(const std::string& library_name,
|
void ExportResolver::SetFunctionMapping(const std::string& library_name,
|
||||||
const uint32_t ordinal, void* shim_data,
|
const uint32_t ordinal,
|
||||||
xe_kernel_export_shim_fn shim) {
|
xe_kernel_export_shim_fn shim) {
|
||||||
auto kernel_export = GetExportByOrdinal(library_name, ordinal);
|
auto export = GetExportByOrdinal(library_name, ordinal);
|
||||||
assert_not_null(kernel_export);
|
assert_not_null(export);
|
||||||
kernel_export->is_implemented = true;
|
export->tags |= ExportTag::kImplemented;
|
||||||
kernel_export->function_data.shim_data = shim_data;
|
export->function_data.shim = shim;
|
||||||
kernel_export->function_data.shim = shim;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
|
|
|
@ -13,24 +13,51 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "xenia/cpu/frontend/ppc_context.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
|
struct ExportTag {
|
||||||
|
typedef uint32_t type;
|
||||||
|
|
||||||
|
static const type kImplemented = 1 << 0;
|
||||||
|
static const type kSketchy = 1 << 1;
|
||||||
|
static const type kHighFrequency = 1 << 2;
|
||||||
|
static const type kImportant = 1 << 3;
|
||||||
|
|
||||||
|
static const type kThreading = 1 << 10;
|
||||||
|
static const type kInput = 1 << 11;
|
||||||
|
static const type kAudio = 1 << 12;
|
||||||
|
static const type kVideo = 1 << 13;
|
||||||
|
static const type kFileSystem = 1 << 14;
|
||||||
|
static const type kModules = 1 << 15;
|
||||||
|
static const type kUserProfiles = 1 << 16;
|
||||||
|
|
||||||
|
static const type kLog = 1 << 31;
|
||||||
|
};
|
||||||
|
|
||||||
|
// DEPRECATED
|
||||||
typedef void (*xe_kernel_export_shim_fn)(void*, void*);
|
typedef void (*xe_kernel_export_shim_fn)(void*, void*);
|
||||||
|
|
||||||
class KernelExport {
|
class Export {
|
||||||
public:
|
public:
|
||||||
enum ExportType {
|
enum class Type {
|
||||||
Function = 0,
|
kFunction = 0,
|
||||||
Variable = 1,
|
kVariable = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t ordinal;
|
uint32_t ordinal;
|
||||||
ExportType type;
|
Type type;
|
||||||
uint32_t flags;
|
std::string name;
|
||||||
char name[96];
|
ExportTag::type tags;
|
||||||
|
|
||||||
bool is_implemented;
|
void (*trampoline)(xe::cpu::frontend::PPCContext* ppc_context);
|
||||||
|
uint64_t call_count;
|
||||||
|
|
||||||
|
bool is_implemented() const {
|
||||||
|
return (tags & ExportTag::kImplemented) == ExportTag::kImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
union {
|
union {
|
||||||
// Variable data. Only valid when kXEKernelExportFlagVariable is set.
|
// Variable data. Only valid when kXEKernelExportFlagVariable is set.
|
||||||
|
@ -39,9 +66,6 @@ class KernelExport {
|
||||||
uint32_t variable_ptr;
|
uint32_t variable_ptr;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
// Second argument passed to the shim function.
|
|
||||||
void* shim_data;
|
|
||||||
|
|
||||||
// Shimmed implementation.
|
// Shimmed implementation.
|
||||||
// This is called directly from generated code.
|
// This is called directly from generated code.
|
||||||
// It should parse args, do fixups, and call the impl.
|
// It should parse args, do fixups, and call the impl.
|
||||||
|
@ -55,25 +79,25 @@ class ExportResolver {
|
||||||
ExportResolver();
|
ExportResolver();
|
||||||
~ExportResolver();
|
~ExportResolver();
|
||||||
|
|
||||||
void RegisterTable(const std::string& library_name, KernelExport* exports,
|
void RegisterTable(const std::string& library_name, Export* exports,
|
||||||
const size_t count);
|
const size_t count);
|
||||||
|
|
||||||
KernelExport* GetExportByOrdinal(const std::string& library_name,
|
Export* GetExportByOrdinal(const std::string& library_name,
|
||||||
const uint32_t ordinal);
|
const uint32_t ordinal);
|
||||||
|
|
||||||
void SetVariableMapping(const std::string& library_name,
|
void SetVariableMapping(const std::string& library_name,
|
||||||
const uint32_t ordinal, uint32_t value);
|
const uint32_t ordinal, uint32_t value);
|
||||||
void SetFunctionMapping(const std::string& library_name,
|
void SetFunctionMapping(const std::string& library_name,
|
||||||
const uint32_t ordinal, void* shim_data,
|
const uint32_t ordinal,
|
||||||
xe_kernel_export_shim_fn shim);
|
xe_kernel_export_shim_fn shim);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct ExportTable {
|
struct ExportTable {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string simple_name; // without extension
|
std::string simple_name; // without extension
|
||||||
KernelExport* exports;
|
Export* exports;
|
||||||
size_t count;
|
size_t count;
|
||||||
ExportTable(const std::string& name, KernelExport* exports, size_t count)
|
ExportTable(const std::string& name, Export* exports, size_t count)
|
||||||
: name(name), exports(exports), count(count) {
|
: name(name), exports(exports), count(count) {
|
||||||
auto dot_pos = name.find_last_of('.');
|
auto dot_pos = name.find_last_of('.');
|
||||||
if (dot_pos != std::string::npos) {
|
if (dot_pos != std::string::npos) {
|
||||||
|
|
|
@ -78,12 +78,10 @@ void HandleGlobalLock(PPCContext* ppc_state, void* arg0, void* arg1) {
|
||||||
bool PPCFrontend::Initialize() {
|
bool PPCFrontend::Initialize() {
|
||||||
void* arg0 = reinterpret_cast<void*>(&builtins_.global_lock);
|
void* arg0 = reinterpret_cast<void*>(&builtins_.global_lock);
|
||||||
void* arg1 = reinterpret_cast<void*>(&builtins_.global_lock_taken);
|
void* arg1 = reinterpret_cast<void*>(&builtins_.global_lock_taken);
|
||||||
builtins_.check_global_lock = processor_->DefineBuiltin(
|
builtins_.check_global_lock =
|
||||||
"CheckGlobalLock", (FunctionInfo::ExternHandler)CheckGlobalLock, arg0,
|
processor_->DefineBuiltin("CheckGlobalLock", CheckGlobalLock, arg0, arg1);
|
||||||
arg1);
|
|
||||||
builtins_.handle_global_lock = processor_->DefineBuiltin(
|
builtins_.handle_global_lock = processor_->DefineBuiltin(
|
||||||
"HandleGlobalLock", (FunctionInfo::ExternHandler)HandleGlobalLock, arg0,
|
"HandleGlobalLock", HandleGlobalLock, arg0, arg1);
|
||||||
arg1);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ bool PPCScanner::IsRestGprLr(uint32_t address) {
|
||||||
if (!frontend_->processor()->LookupFunctionInfo(address, &symbol_info)) {
|
if (!frontend_->processor()->LookupFunctionInfo(address, &symbol_info)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return symbol_info->behavior() == FunctionInfo::BEHAVIOR_EPILOG_RETURN;
|
return symbol_info->behavior() == FunctionBehavior::kEpilogReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PPCScanner::Scan(FunctionInfo* symbol_info, DebugInfo* debug_info) {
|
bool PPCScanner::Scan(FunctionInfo* symbol_info, DebugInfo* debug_info) {
|
||||||
|
|
|
@ -75,14 +75,17 @@ bool Function::Call(ThreadState* thread_state, uint32_t return_address) {
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
if (symbol_info_->behavior() == FunctionInfo::BEHAVIOR_EXTERN) {
|
if (symbol_info_->behavior() == FunctionBehavior::kBuiltin) {
|
||||||
|
auto handler = symbol_info_->builtin_handler();
|
||||||
|
assert_not_null(handler);
|
||||||
|
handler(thread_state->context(), symbol_info_->builtin_arg0(),
|
||||||
|
symbol_info_->builtin_arg1());
|
||||||
|
} else if (symbol_info_->behavior() == FunctionBehavior::kExtern) {
|
||||||
auto handler = symbol_info_->extern_handler();
|
auto handler = symbol_info_->extern_handler();
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
handler(thread_state->context(), symbol_info_->extern_arg0(),
|
handler(thread_state->context(), thread_state->context()->kernel_state);
|
||||||
symbol_info_->extern_arg1());
|
|
||||||
} else {
|
} else {
|
||||||
XELOGW("undefined extern call to %.8llX %s", symbol_info_->address(),
|
XELOGW("undefined extern call to %.8X %s", symbol_info_->address(),
|
||||||
symbol_info_->name().c_str());
|
symbol_info_->name().c_str());
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ SymbolInfo* Module::LookupSymbol(uint32_t address, bool wait) {
|
||||||
const auto it = map_.find(address);
|
const auto it = map_.find(address);
|
||||||
SymbolInfo* symbol_info = it != map_.end() ? it->second : nullptr;
|
SymbolInfo* symbol_info = it != map_.end() ? it->second : nullptr;
|
||||||
if (symbol_info) {
|
if (symbol_info) {
|
||||||
if (symbol_info->status() == SymbolInfo::STATUS_DECLARING) {
|
if (symbol_info->status() == SymbolStatus::kDeclaring) {
|
||||||
// Some other thread is declaring the symbol - wait.
|
// Some other thread is declaring the symbol - wait.
|
||||||
if (wait) {
|
if (wait) {
|
||||||
do {
|
do {
|
||||||
|
@ -39,7 +39,7 @@ SymbolInfo* Module::LookupSymbol(uint32_t address, bool wait) {
|
||||||
// TODO(benvanik): sleep for less time?
|
// TODO(benvanik): sleep for less time?
|
||||||
xe::threading::Sleep(std::chrono::microseconds(100));
|
xe::threading::Sleep(std::chrono::microseconds(100));
|
||||||
lock_.lock();
|
lock_.lock();
|
||||||
} while (symbol_info->status() == SymbolInfo::STATUS_DECLARING);
|
} while (symbol_info->status() == SymbolStatus::kDeclaring);
|
||||||
} else {
|
} else {
|
||||||
// Immediate request, just return.
|
// Immediate request, just return.
|
||||||
symbol_info = nullptr;
|
symbol_info = nullptr;
|
||||||
|
@ -50,89 +50,88 @@ SymbolInfo* Module::LookupSymbol(uint32_t address, bool wait) {
|
||||||
return symbol_info;
|
return symbol_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolInfo::Status Module::DeclareSymbol(SymbolInfo::Type type,
|
SymbolStatus Module::DeclareSymbol(SymbolType type, uint32_t address,
|
||||||
uint32_t address,
|
SymbolInfo** out_symbol_info) {
|
||||||
SymbolInfo** out_symbol_info) {
|
|
||||||
*out_symbol_info = nullptr;
|
*out_symbol_info = nullptr;
|
||||||
lock_.lock();
|
lock_.lock();
|
||||||
auto it = map_.find(address);
|
auto it = map_.find(address);
|
||||||
SymbolInfo* symbol_info = it != map_.end() ? it->second : nullptr;
|
SymbolInfo* symbol_info = it != map_.end() ? it->second : nullptr;
|
||||||
SymbolInfo::Status status;
|
SymbolStatus status;
|
||||||
if (symbol_info) {
|
if (symbol_info) {
|
||||||
// If we exist but are the wrong type, die.
|
// If we exist but are the wrong type, die.
|
||||||
if (symbol_info->type() != type) {
|
if (symbol_info->type() != type) {
|
||||||
lock_.unlock();
|
lock_.unlock();
|
||||||
return SymbolInfo::STATUS_FAILED;
|
return SymbolStatus::kFailed;
|
||||||
}
|
}
|
||||||
// If we aren't ready yet spin and wait.
|
// If we aren't ready yet spin and wait.
|
||||||
if (symbol_info->status() == SymbolInfo::STATUS_DECLARING) {
|
if (symbol_info->status() == SymbolStatus::kDeclaring) {
|
||||||
// Still declaring, so spin.
|
// Still declaring, so spin.
|
||||||
do {
|
do {
|
||||||
lock_.unlock();
|
lock_.unlock();
|
||||||
// TODO(benvanik): sleep for less time?
|
// TODO(benvanik): sleep for less time?
|
||||||
xe::threading::Sleep(std::chrono::microseconds(100));
|
xe::threading::Sleep(std::chrono::microseconds(100));
|
||||||
lock_.lock();
|
lock_.lock();
|
||||||
} while (symbol_info->status() == SymbolInfo::STATUS_DECLARING);
|
} while (symbol_info->status() == SymbolStatus::kDeclaring);
|
||||||
}
|
}
|
||||||
status = symbol_info->status();
|
status = symbol_info->status();
|
||||||
} else {
|
} else {
|
||||||
// Create and return for initialization.
|
// Create and return for initialization.
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SymbolInfo::TYPE_FUNCTION:
|
case SymbolType::kFunction:
|
||||||
symbol_info = new FunctionInfo(this, address);
|
symbol_info = new FunctionInfo(this, address);
|
||||||
break;
|
break;
|
||||||
case SymbolInfo::TYPE_VARIABLE:
|
case SymbolType::kVariable:
|
||||||
symbol_info = new VariableInfo(this, address);
|
symbol_info = new VariableInfo(this, address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
map_[address] = symbol_info;
|
map_[address] = symbol_info;
|
||||||
list_.emplace_back(symbol_info);
|
list_.emplace_back(symbol_info);
|
||||||
status = SymbolInfo::STATUS_NEW;
|
status = SymbolStatus::kNew;
|
||||||
}
|
}
|
||||||
lock_.unlock();
|
lock_.unlock();
|
||||||
*out_symbol_info = symbol_info;
|
*out_symbol_info = symbol_info;
|
||||||
|
|
||||||
// Get debug info from providers, if this is new.
|
// Get debug info from providers, if this is new.
|
||||||
if (status == SymbolInfo::STATUS_NEW) {
|
if (status == SymbolStatus::kNew) {
|
||||||
// TODO(benvanik): lookup in map data/dwarf/etc?
|
// TODO(benvanik): lookup in map data/dwarf/etc?
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolInfo::Status Module::DeclareFunction(uint32_t address,
|
SymbolStatus Module::DeclareFunction(uint32_t address,
|
||||||
FunctionInfo** out_symbol_info) {
|
FunctionInfo** out_symbol_info) {
|
||||||
SymbolInfo* symbol_info;
|
SymbolInfo* symbol_info;
|
||||||
SymbolInfo::Status status =
|
SymbolStatus status =
|
||||||
DeclareSymbol(SymbolInfo::TYPE_FUNCTION, address, &symbol_info);
|
DeclareSymbol(SymbolType::kFunction, address, &symbol_info);
|
||||||
*out_symbol_info = (FunctionInfo*)symbol_info;
|
*out_symbol_info = (FunctionInfo*)symbol_info;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolInfo::Status Module::DeclareVariable(uint32_t address,
|
SymbolStatus Module::DeclareVariable(uint32_t address,
|
||||||
VariableInfo** out_symbol_info) {
|
VariableInfo** out_symbol_info) {
|
||||||
SymbolInfo* symbol_info;
|
SymbolInfo* symbol_info;
|
||||||
SymbolInfo::Status status =
|
SymbolStatus status =
|
||||||
DeclareSymbol(SymbolInfo::TYPE_VARIABLE, address, &symbol_info);
|
DeclareSymbol(SymbolType::kVariable, address, &symbol_info);
|
||||||
*out_symbol_info = (VariableInfo*)symbol_info;
|
*out_symbol_info = (VariableInfo*)symbol_info;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolInfo::Status Module::DefineSymbol(SymbolInfo* symbol_info) {
|
SymbolStatus Module::DefineSymbol(SymbolInfo* symbol_info) {
|
||||||
lock_.lock();
|
lock_.lock();
|
||||||
SymbolInfo::Status status;
|
SymbolStatus status;
|
||||||
if (symbol_info->status() == SymbolInfo::STATUS_DECLARED) {
|
if (symbol_info->status() == SymbolStatus::kDeclared) {
|
||||||
// Declared but undefined, so request caller define it.
|
// Declared but undefined, so request caller define it.
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DEFINING);
|
symbol_info->set_status(SymbolStatus::kDefining);
|
||||||
status = SymbolInfo::STATUS_NEW;
|
status = SymbolStatus::kNew;
|
||||||
} else if (symbol_info->status() == SymbolInfo::STATUS_DEFINING) {
|
} else if (symbol_info->status() == SymbolStatus::kDefining) {
|
||||||
// Still defining, so spin.
|
// Still defining, so spin.
|
||||||
do {
|
do {
|
||||||
lock_.unlock();
|
lock_.unlock();
|
||||||
// TODO(benvanik): sleep for less time?
|
// TODO(benvanik): sleep for less time?
|
||||||
xe::threading::Sleep(std::chrono::microseconds(100));
|
xe::threading::Sleep(std::chrono::microseconds(100));
|
||||||
lock_.lock();
|
lock_.lock();
|
||||||
} while (symbol_info->status() == SymbolInfo::STATUS_DEFINING);
|
} while (symbol_info->status() == SymbolStatus::kDefining);
|
||||||
status = symbol_info->status();
|
status = symbol_info->status();
|
||||||
} else {
|
} else {
|
||||||
status = symbol_info->status();
|
status = symbol_info->status();
|
||||||
|
@ -141,11 +140,11 @@ SymbolInfo::Status Module::DefineSymbol(SymbolInfo* symbol_info) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolInfo::Status Module::DefineFunction(FunctionInfo* symbol_info) {
|
SymbolStatus Module::DefineFunction(FunctionInfo* symbol_info) {
|
||||||
return DefineSymbol((SymbolInfo*)symbol_info);
|
return DefineSymbol((SymbolInfo*)symbol_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolInfo::Status Module::DefineVariable(VariableInfo* symbol_info) {
|
SymbolStatus Module::DefineVariable(VariableInfo* symbol_info) {
|
||||||
return DefineSymbol((SymbolInfo*)symbol_info);
|
return DefineSymbol((SymbolInfo*)symbol_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +152,7 @@ void Module::ForEachFunction(std::function<void(FunctionInfo*)> callback) {
|
||||||
SCOPE_profile_cpu_f("cpu");
|
SCOPE_profile_cpu_f("cpu");
|
||||||
std::lock_guard<xe::mutex> guard(lock_);
|
std::lock_guard<xe::mutex> guard(lock_);
|
||||||
for (auto& symbol_info : list_) {
|
for (auto& symbol_info : list_) {
|
||||||
if (symbol_info->type() == SymbolInfo::TYPE_FUNCTION) {
|
if (symbol_info->type() == SymbolType::kFunction) {
|
||||||
FunctionInfo* info = static_cast<FunctionInfo*>(symbol_info.get());
|
FunctionInfo* info = static_cast<FunctionInfo*>(symbol_info.get());
|
||||||
callback(info);
|
callback(info);
|
||||||
}
|
}
|
||||||
|
@ -168,7 +167,7 @@ void Module::ForEachFunction(size_t since, size_t& version,
|
||||||
version = count;
|
version = count;
|
||||||
for (size_t n = since; n < count; n++) {
|
for (size_t n = since; n < count; n++) {
|
||||||
auto& symbol_info = list_[n];
|
auto& symbol_info = list_[n];
|
||||||
if (symbol_info->type() == SymbolInfo::TYPE_FUNCTION) {
|
if (symbol_info->type() == SymbolType::kFunction) {
|
||||||
FunctionInfo* info = static_cast<FunctionInfo*>(symbol_info.get());
|
FunctionInfo* info = static_cast<FunctionInfo*>(symbol_info.get());
|
||||||
callback(info);
|
callback(info);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,13 +38,13 @@ class Module {
|
||||||
virtual bool ContainsAddress(uint32_t address);
|
virtual bool ContainsAddress(uint32_t address);
|
||||||
|
|
||||||
SymbolInfo* LookupSymbol(uint32_t address, bool wait = true);
|
SymbolInfo* LookupSymbol(uint32_t address, bool wait = true);
|
||||||
virtual SymbolInfo::Status DeclareFunction(uint32_t address,
|
virtual SymbolStatus DeclareFunction(uint32_t address,
|
||||||
FunctionInfo** out_symbol_info);
|
FunctionInfo** out_symbol_info);
|
||||||
virtual SymbolInfo::Status DeclareVariable(uint32_t address,
|
virtual SymbolStatus DeclareVariable(uint32_t address,
|
||||||
VariableInfo** out_symbol_info);
|
VariableInfo** out_symbol_info);
|
||||||
|
|
||||||
SymbolInfo::Status DefineFunction(FunctionInfo* symbol_info);
|
SymbolStatus DefineFunction(FunctionInfo* symbol_info);
|
||||||
SymbolInfo::Status DefineVariable(VariableInfo* symbol_info);
|
SymbolStatus DefineVariable(VariableInfo* symbol_info);
|
||||||
|
|
||||||
void ForEachFunction(std::function<void(FunctionInfo*)> callback);
|
void ForEachFunction(std::function<void(FunctionInfo*)> callback);
|
||||||
void ForEachFunction(size_t since, size_t& version,
|
void ForEachFunction(size_t since, size_t& version,
|
||||||
|
@ -53,9 +53,9 @@ class Module {
|
||||||
bool ReadMap(const char* file_name);
|
bool ReadMap(const char* file_name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SymbolInfo::Status DeclareSymbol(SymbolInfo::Type type, uint32_t address,
|
SymbolStatus DeclareSymbol(SymbolType type, uint32_t address,
|
||||||
SymbolInfo** out_symbol_info);
|
SymbolInfo** out_symbol_info);
|
||||||
SymbolInfo::Status DefineSymbol(SymbolInfo* symbol_info);
|
SymbolStatus DefineSymbol(SymbolInfo* symbol_info);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Processor* processor_;
|
Processor* processor_;
|
||||||
|
|
|
@ -76,18 +76,11 @@ Processor::Processor(xe::Memory* memory, ExportResolver* export_resolver,
|
||||||
debug_info_flags_(0),
|
debug_info_flags_(0),
|
||||||
builtin_module_(nullptr),
|
builtin_module_(nullptr),
|
||||||
next_builtin_address_(0xFFFF0000ul),
|
next_builtin_address_(0xFFFF0000ul),
|
||||||
export_resolver_(export_resolver),
|
export_resolver_(export_resolver) {
|
||||||
interrupt_thread_state_(nullptr),
|
|
||||||
interrupt_thread_block_(0) {
|
|
||||||
InitializeIfNeeded();
|
InitializeIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
Processor::~Processor() {
|
Processor::~Processor() {
|
||||||
if (interrupt_thread_block_) {
|
|
||||||
memory_->SystemHeapFree(interrupt_thread_block_);
|
|
||||||
delete interrupt_thread_state_;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<xe::mutex> guard(modules_lock_);
|
std::lock_guard<xe::mutex> guard(modules_lock_);
|
||||||
modules_.clear();
|
modules_.clear();
|
||||||
|
@ -144,18 +137,6 @@ bool Processor::Setup() {
|
||||||
backend_ = std::move(backend);
|
backend_ = std::move(backend);
|
||||||
frontend_ = std::move(frontend);
|
frontend_ = std::move(frontend);
|
||||||
|
|
||||||
// DEPRECATED: will be removed.
|
|
||||||
interrupt_thread_state_ =
|
|
||||||
new ThreadState(this, 0, ThreadStackType::kKernelStack, 0, 128 * 1024, 0);
|
|
||||||
interrupt_thread_state_->set_name("Interrupt");
|
|
||||||
interrupt_thread_block_ = memory_->SystemHeapAlloc(2048);
|
|
||||||
interrupt_thread_state_->context()->r[13] = interrupt_thread_block_;
|
|
||||||
XELOGI("Interrupt Thread %X Stack: %.8X-%.8X",
|
|
||||||
interrupt_thread_state_->thread_id(),
|
|
||||||
interrupt_thread_state_->stack_address(),
|
|
||||||
interrupt_thread_state_->stack_address() +
|
|
||||||
interrupt_thread_state_->stack_size());
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +166,7 @@ std::vector<Module*> Processor::GetModules() {
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionInfo* Processor::DefineBuiltin(const std::string& name,
|
FunctionInfo* Processor::DefineBuiltin(const std::string& name,
|
||||||
FunctionInfo::ExternHandler handler,
|
FunctionInfo::BuiltinHandler handler,
|
||||||
void* arg0, void* arg1) {
|
void* arg0, void* arg1) {
|
||||||
uint32_t address = next_builtin_address_;
|
uint32_t address = next_builtin_address_;
|
||||||
next_builtin_address_ += 4;
|
next_builtin_address_ += 4;
|
||||||
|
@ -194,8 +175,8 @@ FunctionInfo* Processor::DefineBuiltin(const std::string& name,
|
||||||
builtin_module_->DeclareFunction(address, &fn_info);
|
builtin_module_->DeclareFunction(address, &fn_info);
|
||||||
fn_info->set_end_address(address + 4);
|
fn_info->set_end_address(address + 4);
|
||||||
fn_info->set_name(name);
|
fn_info->set_name(name);
|
||||||
fn_info->SetupExtern(handler, arg0, arg1);
|
fn_info->SetupBuiltin(handler, arg0, arg1);
|
||||||
fn_info->set_status(SymbolInfo::STATUS_DECLARED);
|
fn_info->set_status(SymbolStatus::kDeclared);
|
||||||
|
|
||||||
return fn_info;
|
return fn_info;
|
||||||
}
|
}
|
||||||
|
@ -266,15 +247,14 @@ bool Processor::LookupFunctionInfo(Module* module, uint32_t address,
|
||||||
// Atomic create/lookup symbol in module.
|
// Atomic create/lookup symbol in module.
|
||||||
// If we get back the NEW flag we must declare it now.
|
// If we get back the NEW flag we must declare it now.
|
||||||
FunctionInfo* symbol_info = nullptr;
|
FunctionInfo* symbol_info = nullptr;
|
||||||
SymbolInfo::Status symbol_status =
|
SymbolStatus symbol_status = module->DeclareFunction(address, &symbol_info);
|
||||||
module->DeclareFunction(address, &symbol_info);
|
if (symbol_status == SymbolStatus::kNew) {
|
||||||
if (symbol_status == SymbolInfo::STATUS_NEW) {
|
|
||||||
// Symbol is undeclared, so declare now.
|
// Symbol is undeclared, so declare now.
|
||||||
if (!frontend_->DeclareFunction(symbol_info)) {
|
if (!frontend_->DeclareFunction(symbol_info)) {
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
symbol_info->set_status(SymbolStatus::kFailed);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
symbol_info->set_status(SymbolStatus::kDeclared);
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_symbol_info = symbol_info;
|
*out_symbol_info = symbol_info;
|
||||||
|
@ -288,12 +268,12 @@ bool Processor::DemandFunction(FunctionInfo* symbol_info,
|
||||||
// Lock function for generation. If it's already being generated
|
// Lock function for generation. If it's already being generated
|
||||||
// by another thread this will block and return DECLARED.
|
// by another thread this will block and return DECLARED.
|
||||||
Module* module = symbol_info->module();
|
Module* module = symbol_info->module();
|
||||||
SymbolInfo::Status symbol_status = module->DefineFunction(symbol_info);
|
SymbolStatus symbol_status = module->DefineFunction(symbol_info);
|
||||||
if (symbol_status == SymbolInfo::STATUS_NEW) {
|
if (symbol_status == SymbolStatus::kNew) {
|
||||||
// Symbol is undefined, so define now.
|
// Symbol is undefined, so define now.
|
||||||
Function* function = nullptr;
|
Function* function = nullptr;
|
||||||
if (!frontend_->DefineFunction(symbol_info, debug_info_flags_, &function)) {
|
if (!frontend_->DefineFunction(symbol_info, debug_info_flags_, &function)) {
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
symbol_info->set_status(SymbolStatus::kFailed);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
symbol_info->set_function(function);
|
symbol_info->set_function(function);
|
||||||
|
@ -303,11 +283,11 @@ bool Processor::DemandFunction(FunctionInfo* symbol_info,
|
||||||
debugger_->OnFunctionDefined(symbol_info, function);
|
debugger_->OnFunctionDefined(symbol_info, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DEFINED);
|
symbol_info->set_status(SymbolStatus::kDefined);
|
||||||
symbol_status = symbol_info->status();
|
symbol_status = symbol_info->status();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (symbol_status == SymbolInfo::STATUS_FAILED) {
|
if (symbol_status == SymbolStatus::kFailed) {
|
||||||
// Symbol likely failed.
|
// Symbol likely failed.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -374,18 +354,5 @@ void Processor::LowerIrql(Irql old_value) {
|
||||||
reinterpret_cast<volatile uint32_t*>(&irql_));
|
reinterpret_cast<volatile uint32_t*>(&irql_));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Processor::ExecuteInterrupt(uint32_t address, uint64_t args[],
|
|
||||||
size_t arg_count) {
|
|
||||||
SCOPE_profile_cpu_f("cpu");
|
|
||||||
|
|
||||||
// Acquire lock on interrupt thread (we can only dispatch one at a time).
|
|
||||||
std::lock_guard<xe::mutex> lock(interrupt_thread_lock_);
|
|
||||||
|
|
||||||
// Execute interrupt.
|
|
||||||
uint64_t result = Execute(interrupt_thread_state_, address, args, arg_count);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -58,7 +58,7 @@ class Processor {
|
||||||
|
|
||||||
Module* builtin_module() const { return builtin_module_; }
|
Module* builtin_module() const { return builtin_module_; }
|
||||||
FunctionInfo* DefineBuiltin(const std::string& name,
|
FunctionInfo* DefineBuiltin(const std::string& name,
|
||||||
FunctionInfo::ExternHandler handler, void* arg0,
|
FunctionInfo::BuiltinHandler handler, void* arg0,
|
||||||
void* arg1);
|
void* arg1);
|
||||||
|
|
||||||
std::vector<Function*> FindFunctionsWithAddress(uint32_t address);
|
std::vector<Function*> FindFunctionsWithAddress(uint32_t address);
|
||||||
|
@ -75,10 +75,6 @@ class Processor {
|
||||||
Irql RaiseIrql(Irql new_value);
|
Irql RaiseIrql(Irql new_value);
|
||||||
void LowerIrql(Irql old_value);
|
void LowerIrql(Irql old_value);
|
||||||
|
|
||||||
// DEPRECATED: will be removed.
|
|
||||||
uint64_t ExecuteInterrupt(uint32_t address, uint64_t args[],
|
|
||||||
size_t arg_count);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool DemandFunction(FunctionInfo* symbol_info, Function** out_function);
|
bool DemandFunction(FunctionInfo* symbol_info, Function** out_function);
|
||||||
|
|
||||||
|
@ -98,9 +94,6 @@ class Processor {
|
||||||
uint32_t next_builtin_address_;
|
uint32_t next_builtin_address_;
|
||||||
|
|
||||||
Irql irql_;
|
Irql irql_;
|
||||||
xe::mutex interrupt_thread_lock_;
|
|
||||||
ThreadState* interrupt_thread_state_;
|
|
||||||
uint32_t interrupt_thread_block_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
|
|
|
@ -12,34 +12,40 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
SymbolInfo::SymbolInfo(Type type, Module* module, uint32_t address)
|
SymbolInfo::SymbolInfo(SymbolType type, Module* module, uint32_t address)
|
||||||
: type_(type),
|
: type_(type),
|
||||||
module_(module),
|
module_(module),
|
||||||
status_(STATUS_DEFINING),
|
status_(SymbolStatus::kDefining),
|
||||||
address_(address),
|
address_(address),
|
||||||
name_("") {}
|
name_("") {}
|
||||||
|
|
||||||
SymbolInfo::~SymbolInfo() = default;
|
SymbolInfo::~SymbolInfo() = default;
|
||||||
|
|
||||||
FunctionInfo::FunctionInfo(Module* module, uint32_t address)
|
FunctionInfo::FunctionInfo(Module* module, uint32_t address)
|
||||||
: SymbolInfo(SymbolInfo::TYPE_FUNCTION, module, address),
|
: SymbolInfo(SymbolType::kFunction, module, address),
|
||||||
end_address_(0),
|
end_address_(0),
|
||||||
behavior_(BEHAVIOR_DEFAULT),
|
behavior_(FunctionBehavior::kDefault),
|
||||||
function_(0) {
|
function_(nullptr) {
|
||||||
std::memset(&extern_info_, 0, sizeof(extern_info_));
|
std::memset(&extern_info_, 0, sizeof(extern_info_));
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionInfo::~FunctionInfo() = default;
|
FunctionInfo::~FunctionInfo() = default;
|
||||||
|
|
||||||
void FunctionInfo::SetupExtern(ExternHandler handler, void* arg0, void* arg1) {
|
void FunctionInfo::SetupBuiltin(BuiltinHandler handler, void* arg0,
|
||||||
behavior_ = BEHAVIOR_EXTERN;
|
void* arg1) {
|
||||||
|
behavior_ = FunctionBehavior::kBuiltin;
|
||||||
|
builtin_info_.handler = handler;
|
||||||
|
builtin_info_.arg0 = arg0;
|
||||||
|
builtin_info_.arg1 = arg1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionInfo::SetupExtern(ExternHandler handler) {
|
||||||
|
behavior_ = FunctionBehavior::kExtern;
|
||||||
extern_info_.handler = handler;
|
extern_info_.handler = handler;
|
||||||
extern_info_.arg0 = arg0;
|
|
||||||
extern_info_.arg1 = arg1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VariableInfo::VariableInfo(Module* module, uint32_t address)
|
VariableInfo::VariableInfo(Module* module, uint32_t address)
|
||||||
: SymbolInfo(SymbolInfo::TYPE_VARIABLE, module, address) {}
|
: SymbolInfo(SymbolType::kVariable, module, address) {}
|
||||||
|
|
||||||
VariableInfo::~VariableInfo() = default;
|
VariableInfo::~VariableInfo() = default;
|
||||||
|
|
||||||
|
|
|
@ -13,59 +13,61 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "xenia/cpu/frontend/ppc_context.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
class Function;
|
class Function;
|
||||||
class Module;
|
class Module;
|
||||||
|
|
||||||
|
enum class SymbolType {
|
||||||
|
kFunction,
|
||||||
|
kVariable,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SymbolStatus {
|
||||||
|
kNew,
|
||||||
|
kDeclaring,
|
||||||
|
kDeclared,
|
||||||
|
kDefining,
|
||||||
|
kDefined,
|
||||||
|
kFailed,
|
||||||
|
};
|
||||||
|
|
||||||
class SymbolInfo {
|
class SymbolInfo {
|
||||||
public:
|
public:
|
||||||
enum Type {
|
SymbolInfo(SymbolType type, Module* module, uint32_t address);
|
||||||
TYPE_FUNCTION,
|
|
||||||
TYPE_VARIABLE,
|
|
||||||
};
|
|
||||||
enum Status {
|
|
||||||
STATUS_NEW,
|
|
||||||
STATUS_DECLARING,
|
|
||||||
STATUS_DECLARED,
|
|
||||||
STATUS_DEFINING,
|
|
||||||
STATUS_DEFINED,
|
|
||||||
STATUS_FAILED,
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
SymbolInfo(Type type, Module* module, uint32_t address);
|
|
||||||
virtual ~SymbolInfo();
|
virtual ~SymbolInfo();
|
||||||
|
|
||||||
Type type() const { return type_; }
|
SymbolType type() const { return type_; }
|
||||||
Module* module() const { return module_; }
|
Module* module() const { return module_; }
|
||||||
Status status() const { return status_; }
|
SymbolStatus status() const { return status_; }
|
||||||
void set_status(Status value) { status_ = value; }
|
void set_status(SymbolStatus value) { status_ = value; }
|
||||||
uint32_t address() const { return address_; }
|
uint32_t address() const { return address_; }
|
||||||
|
|
||||||
const std::string& name() const { return name_; }
|
const std::string& name() const { return name_; }
|
||||||
void set_name(const std::string& value) { name_ = value; }
|
void set_name(const std::string& value) { name_ = value; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Type type_;
|
SymbolType type_;
|
||||||
Module* module_;
|
Module* module_;
|
||||||
Status status_;
|
SymbolStatus status_;
|
||||||
uint32_t address_;
|
uint32_t address_;
|
||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FunctionInfo : public SymbolInfo {
|
enum class FunctionBehavior {
|
||||||
public:
|
kDefault = 0,
|
||||||
enum Behavior {
|
kProlog,
|
||||||
BEHAVIOR_DEFAULT = 0,
|
kEpilog,
|
||||||
BEHAVIOR_PROLOG,
|
kEpilogReturn,
|
||||||
BEHAVIOR_EPILOG,
|
kBuiltin,
|
||||||
BEHAVIOR_EPILOG_RETURN,
|
kExtern,
|
||||||
BEHAVIOR_EXTERN,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
|
class FunctionInfo : public SymbolInfo {
|
||||||
public:
|
public:
|
||||||
FunctionInfo(Module* module, uint32_t address);
|
FunctionInfo(Module* module, uint32_t address);
|
||||||
~FunctionInfo() override;
|
~FunctionInfo() override;
|
||||||
|
@ -74,27 +76,38 @@ class FunctionInfo : public SymbolInfo {
|
||||||
uint32_t end_address() const { return end_address_; }
|
uint32_t end_address() const { return end_address_; }
|
||||||
void set_end_address(uint32_t value) { end_address_ = value; }
|
void set_end_address(uint32_t value) { end_address_ = value; }
|
||||||
|
|
||||||
Behavior behavior() const { return behavior_; }
|
FunctionBehavior behavior() const { return behavior_; }
|
||||||
void set_behavior(Behavior value) { behavior_ = value; }
|
void set_behavior(FunctionBehavior value) { behavior_ = value; }
|
||||||
|
|
||||||
Function* function() const { return function_; }
|
Function* function() const { return function_; }
|
||||||
void set_function(Function* value) { function_ = value; }
|
void set_function(Function* value) { function_ = value; }
|
||||||
|
|
||||||
typedef void (*ExternHandler)(void* context, void* arg0, void* arg1);
|
typedef void (*BuiltinHandler)(frontend::PPCContext* ppc_context, void* arg0,
|
||||||
void SetupExtern(ExternHandler handler, void* arg0, void* arg1);
|
void* arg1);
|
||||||
|
void SetupBuiltin(BuiltinHandler handler, void* arg0, void* arg1);
|
||||||
|
BuiltinHandler builtin_handler() const { return builtin_info_.handler; }
|
||||||
|
void* builtin_arg0() const { return builtin_info_.arg0; }
|
||||||
|
void* builtin_arg1() const { return builtin_info_.arg1; }
|
||||||
|
|
||||||
|
typedef void (*ExternHandler)(frontend::PPCContext* ppc_context,
|
||||||
|
kernel::KernelState* kernel_state);
|
||||||
|
void SetupExtern(ExternHandler handler);
|
||||||
ExternHandler extern_handler() const { return extern_info_.handler; }
|
ExternHandler extern_handler() const { return extern_info_.handler; }
|
||||||
void* extern_arg0() const { return extern_info_.arg0; }
|
|
||||||
void* extern_arg1() const { return extern_info_.arg1; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t end_address_;
|
uint32_t end_address_;
|
||||||
Behavior behavior_;
|
FunctionBehavior behavior_;
|
||||||
Function* function_;
|
Function* function_;
|
||||||
struct {
|
union {
|
||||||
ExternHandler handler;
|
struct {
|
||||||
void* arg0;
|
ExternHandler handler;
|
||||||
void* arg1;
|
} extern_info_;
|
||||||
} extern_info_;
|
struct {
|
||||||
|
BuiltinHandler handler;
|
||||||
|
void* arg0;
|
||||||
|
void* arg1;
|
||||||
|
} builtin_info_;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class VariableInfo : public SymbolInfo {
|
class VariableInfo : public SymbolInfo {
|
||||||
|
|
|
@ -71,10 +71,10 @@ bool TestModule::ContainsAddress(uint32_t address) {
|
||||||
return contains_address_(address);
|
return contains_address_(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolInfo::Status TestModule::DeclareFunction(uint32_t address,
|
SymbolStatus TestModule::DeclareFunction(uint32_t address,
|
||||||
FunctionInfo** out_symbol_info) {
|
FunctionInfo** out_symbol_info) {
|
||||||
SymbolInfo::Status status = Module::DeclareFunction(address, out_symbol_info);
|
SymbolStatus status = Module::DeclareFunction(address, out_symbol_info);
|
||||||
if (status == SymbolInfo::STATUS_NEW) {
|
if (status == SymbolStatus::kNew) {
|
||||||
auto symbol_info = *out_symbol_info;
|
auto symbol_info = *out_symbol_info;
|
||||||
|
|
||||||
// Reset() all caching when we leave.
|
// Reset() all caching when we leave.
|
||||||
|
@ -82,8 +82,8 @@ SymbolInfo::Status TestModule::DeclareFunction(uint32_t address,
|
||||||
xe::make_reset_scope(assembler_);
|
xe::make_reset_scope(assembler_);
|
||||||
|
|
||||||
if (!generate_(*builder_.get())) {
|
if (!generate_(*builder_.get())) {
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
symbol_info->set_status(SymbolStatus::kFailed);
|
||||||
return SymbolInfo::STATUS_FAILED;
|
return SymbolStatus::kFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler_->Compile(builder_.get());
|
compiler_->Compile(builder_.get());
|
||||||
|
@ -92,7 +92,7 @@ SymbolInfo::Status TestModule::DeclareFunction(uint32_t address,
|
||||||
assembler_->Assemble(symbol_info, builder_.get(), 0, nullptr, &fn);
|
assembler_->Assemble(symbol_info, builder_.get(), 0, nullptr, &fn);
|
||||||
|
|
||||||
symbol_info->set_function(fn);
|
symbol_info->set_function(fn);
|
||||||
status = SymbolInfo::STATUS_DEFINED;
|
status = SymbolStatus::kDefined;
|
||||||
symbol_info->set_status(status);
|
symbol_info->set_status(status);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
|
|
|
@ -33,8 +33,8 @@ class TestModule : public Module {
|
||||||
|
|
||||||
bool ContainsAddress(uint32_t address) override;
|
bool ContainsAddress(uint32_t address) override;
|
||||||
|
|
||||||
SymbolInfo::Status DeclareFunction(uint32_t address,
|
SymbolStatus DeclareFunction(uint32_t address,
|
||||||
FunctionInfo** out_symbol_info) override;
|
FunctionInfo** out_symbol_info) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name_;
|
std::string name_;
|
||||||
|
|
|
@ -29,7 +29,8 @@ using namespace xe::kernel;
|
||||||
|
|
||||||
using PPCContext = xe::cpu::frontend::PPCContext;
|
using PPCContext = xe::cpu::frontend::PPCContext;
|
||||||
|
|
||||||
void UndefinedImport(PPCContext* ppc_state, void* arg0, void* arg1) {
|
void UndefinedImport(PPCContext* ppc_context,
|
||||||
|
kernel::KernelState* kernel_state) {
|
||||||
XELOGE("call to undefined import");
|
XELOGE("call to undefined import");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,8 +119,8 @@ bool XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
||||||
libname = libname.substr(0, dot);
|
libname = libname.substr(0, dot);
|
||||||
}
|
}
|
||||||
|
|
||||||
KernelExport* kernel_export = NULL; // kernel export info
|
Export* kernel_export = nullptr; // kernel export info
|
||||||
uint32_t user_export_addr = 0; // user export address
|
uint32_t user_export_addr = 0; // user export address
|
||||||
|
|
||||||
if (kernel_state_->IsKernelModule(library->name)) {
|
if (kernel_state_->IsKernelModule(library->name)) {
|
||||||
kernel_export =
|
kernel_export =
|
||||||
|
@ -145,15 +146,15 @@ bool XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
||||||
VariableInfo* var_info;
|
VariableInfo* var_info;
|
||||||
DeclareVariable(info->value_address, &var_info);
|
DeclareVariable(info->value_address, &var_info);
|
||||||
// var->set_name(name);
|
// var->set_name(name);
|
||||||
var_info->set_status(SymbolInfo::STATUS_DECLARED);
|
var_info->set_status(SymbolStatus::kDeclared);
|
||||||
DefineVariable(var_info);
|
DefineVariable(var_info);
|
||||||
// var->kernel_export = kernel_export;
|
// var->kernel_export = kernel_export;
|
||||||
var_info->set_status(SymbolInfo::STATUS_DEFINED);
|
var_info->set_status(SymbolStatus::kDefined);
|
||||||
|
|
||||||
// Grab, if available.
|
// Grab, if available.
|
||||||
auto slot = memory_->TranslateVirtual<uint32_t*>(info->value_address);
|
auto slot = memory_->TranslateVirtual<uint32_t*>(info->value_address);
|
||||||
if (kernel_export) {
|
if (kernel_export) {
|
||||||
if (kernel_export->type == KernelExport::Function) {
|
if (kernel_export->type == Export::Type::kFunction) {
|
||||||
// Not exactly sure what this should be...
|
// Not exactly sure what this should be...
|
||||||
if (info->thunk_address) {
|
if (info->thunk_address) {
|
||||||
*slot = xe::byte_swap(info->thunk_address);
|
*slot = xe::byte_swap(info->thunk_address);
|
||||||
|
@ -164,7 +165,7 @@ bool XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
||||||
*slot = xe::byte_swap(0xF00DF00D);
|
*slot = xe::byte_swap(0xF00DF00D);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (kernel_export->is_implemented) {
|
if (kernel_export->is_implemented()) {
|
||||||
// Implemented - replace with pointer.
|
// Implemented - replace with pointer.
|
||||||
xe::store_and_swap<uint32_t>(slot, kernel_export->variable_ptr);
|
xe::store_and_swap<uint32_t>(slot, kernel_export->variable_ptr);
|
||||||
} else {
|
} else {
|
||||||
|
@ -232,22 +233,19 @@ bool XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
||||||
xe::store_and_swap<uint32_t>(p + 0xC, 0x60000000);
|
xe::store_and_swap<uint32_t>(p + 0xC, 0x60000000);
|
||||||
|
|
||||||
FunctionInfo::ExternHandler handler = 0;
|
FunctionInfo::ExternHandler handler = 0;
|
||||||
void* handler_data = 0;
|
|
||||||
if (kernel_export) {
|
if (kernel_export) {
|
||||||
handler =
|
handler =
|
||||||
(FunctionInfo::ExternHandler)kernel_export->function_data.shim;
|
(FunctionInfo::ExternHandler)kernel_export->function_data.shim;
|
||||||
handler_data = kernel_export->function_data.shim_data;
|
|
||||||
} else {
|
} else {
|
||||||
handler = (FunctionInfo::ExternHandler)UndefinedImport;
|
handler = UndefinedImport;
|
||||||
handler_data = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionInfo* fn_info;
|
FunctionInfo* fn_info;
|
||||||
DeclareFunction(info->thunk_address, &fn_info);
|
DeclareFunction(info->thunk_address, &fn_info);
|
||||||
fn_info->set_end_address(info->thunk_address + 16 - 4);
|
fn_info->set_end_address(info->thunk_address + 16 - 4);
|
||||||
fn_info->set_name(name);
|
fn_info->set_name(name);
|
||||||
fn_info->SetupExtern(handler, handler_data, NULL);
|
fn_info->SetupExtern(handler);
|
||||||
fn_info->set_status(SymbolInfo::STATUS_DECLARED);
|
fn_info->set_status(SymbolStatus::kDeclared);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,8 +468,8 @@ bool XexModule::FindSaveRest() {
|
||||||
symbol_info->set_name(name);
|
symbol_info->set_name(name);
|
||||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagSaveGprLr;
|
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagSaveGprLr;
|
||||||
symbol_info->set_behavior(FunctionInfo::BEHAVIOR_PROLOG);
|
symbol_info->set_behavior(FunctionBehavior::kProlog);
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
symbol_info->set_status(SymbolStatus::kDeclared);
|
||||||
address += 4;
|
address += 4;
|
||||||
}
|
}
|
||||||
address = gplr_start + 20 * 4;
|
address = gplr_start + 20 * 4;
|
||||||
|
@ -483,8 +481,8 @@ bool XexModule::FindSaveRest() {
|
||||||
symbol_info->set_name(name);
|
symbol_info->set_name(name);
|
||||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagRestGprLr;
|
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagRestGprLr;
|
||||||
symbol_info->set_behavior(FunctionInfo::BEHAVIOR_EPILOG_RETURN);
|
symbol_info->set_behavior(FunctionBehavior::kEpilogReturn);
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
symbol_info->set_status(SymbolStatus::kDeclared);
|
||||||
address += 4;
|
address += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -498,8 +496,8 @@ bool XexModule::FindSaveRest() {
|
||||||
symbol_info->set_name(name);
|
symbol_info->set_name(name);
|
||||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagSaveFpr;
|
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagSaveFpr;
|
||||||
symbol_info->set_behavior(FunctionInfo::BEHAVIOR_PROLOG);
|
symbol_info->set_behavior(FunctionBehavior::kProlog);
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
symbol_info->set_status(SymbolStatus::kDeclared);
|
||||||
address += 4;
|
address += 4;
|
||||||
}
|
}
|
||||||
address = fpr_start + (18 * 4) + (1 * 4);
|
address = fpr_start + (18 * 4) + (1 * 4);
|
||||||
|
@ -511,8 +509,8 @@ bool XexModule::FindSaveRest() {
|
||||||
symbol_info->set_name(name);
|
symbol_info->set_name(name);
|
||||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagRestFpr;
|
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagRestFpr;
|
||||||
symbol_info->set_behavior(FunctionInfo::BEHAVIOR_EPILOG);
|
symbol_info->set_behavior(FunctionBehavior::kEpilog);
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
symbol_info->set_status(SymbolStatus::kDeclared);
|
||||||
address += 4;
|
address += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -530,8 +528,8 @@ bool XexModule::FindSaveRest() {
|
||||||
symbol_info->set_name(name);
|
symbol_info->set_name(name);
|
||||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagSaveVmx;
|
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagSaveVmx;
|
||||||
symbol_info->set_behavior(FunctionInfo::BEHAVIOR_PROLOG);
|
symbol_info->set_behavior(FunctionBehavior::kProlog);
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
symbol_info->set_status(SymbolStatus::kDeclared);
|
||||||
address += 2 * 4;
|
address += 2 * 4;
|
||||||
}
|
}
|
||||||
address += 4;
|
address += 4;
|
||||||
|
@ -542,8 +540,8 @@ bool XexModule::FindSaveRest() {
|
||||||
symbol_info->set_name(name);
|
symbol_info->set_name(name);
|
||||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagSaveVmx;
|
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagSaveVmx;
|
||||||
symbol_info->set_behavior(FunctionInfo::BEHAVIOR_PROLOG);
|
symbol_info->set_behavior(FunctionBehavior::kProlog);
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
symbol_info->set_status(SymbolStatus::kDeclared);
|
||||||
address += 2 * 4;
|
address += 2 * 4;
|
||||||
}
|
}
|
||||||
address = vmx_start + (18 * 2 * 4) + (1 * 4) + (64 * 2 * 4) + (1 * 4);
|
address = vmx_start + (18 * 2 * 4) + (1 * 4) + (64 * 2 * 4) + (1 * 4);
|
||||||
|
@ -554,8 +552,8 @@ bool XexModule::FindSaveRest() {
|
||||||
symbol_info->set_name(name);
|
symbol_info->set_name(name);
|
||||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagRestVmx;
|
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagRestVmx;
|
||||||
symbol_info->set_behavior(FunctionInfo::BEHAVIOR_EPILOG);
|
symbol_info->set_behavior(FunctionBehavior::kEpilog);
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
symbol_info->set_status(SymbolStatus::kDeclared);
|
||||||
address += 2 * 4;
|
address += 2 * 4;
|
||||||
}
|
}
|
||||||
address += 4;
|
address += 4;
|
||||||
|
@ -566,8 +564,8 @@ bool XexModule::FindSaveRest() {
|
||||||
symbol_info->set_name(name);
|
symbol_info->set_name(name);
|
||||||
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
// TODO(benvanik): set type fn->type = FunctionSymbol::User;
|
||||||
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagRestVmx;
|
// TODO(benvanik): set flags fn->flags |= FunctionSymbol::kFlagRestVmx;
|
||||||
symbol_info->set_behavior(FunctionInfo::BEHAVIOR_EPILOG);
|
symbol_info->set_behavior(FunctionBehavior::kEpilog);
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
symbol_info->set_status(SymbolStatus::kDeclared);
|
||||||
address += 2 * 4;
|
address += 2 * 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ uint32_t XKernelModule::GetProcAddressByOrdinal(uint16_t ordinal) {
|
||||||
// Export (or its parent library) not found.
|
// Export (or its parent library) not found.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (export->type == cpu::KernelExport::ExportType::Variable) {
|
if (export->type == cpu::Export::Type::kVariable) {
|
||||||
if (export->variable_ptr) {
|
if (export->variable_ptr) {
|
||||||
return export->variable_ptr;
|
return export->variable_ptr;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -338,11 +338,11 @@ void XUserModule::Dump() {
|
||||||
const xe_xex2_import_info_t* info = &import_infos[m];
|
const xe_xex2_import_info_t* info = &import_infos[m];
|
||||||
|
|
||||||
if (kernel_state_->IsKernelModule(library->name)) {
|
if (kernel_state_->IsKernelModule(library->name)) {
|
||||||
KernelExport* kernel_export =
|
auto kernel_export =
|
||||||
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
|
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
|
||||||
if (kernel_export) {
|
if (kernel_export) {
|
||||||
known_count++;
|
known_count++;
|
||||||
if (kernel_export->is_implemented) {
|
if (kernel_export->is_implemented()) {
|
||||||
impl_count++;
|
impl_count++;
|
||||||
} else {
|
} else {
|
||||||
unimpl_count++;
|
unimpl_count++;
|
||||||
|
@ -384,13 +384,13 @@ void XUserModule::Dump() {
|
||||||
const char* name = "UNKNOWN";
|
const char* name = "UNKNOWN";
|
||||||
bool implemented = false;
|
bool implemented = false;
|
||||||
|
|
||||||
KernelExport* kernel_export = nullptr;
|
Export* kernel_export = nullptr;
|
||||||
if (kernel_state_->IsKernelModule(library->name)) {
|
if (kernel_state_->IsKernelModule(library->name)) {
|
||||||
kernel_export =
|
kernel_export =
|
||||||
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
|
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
|
||||||
if (kernel_export) {
|
if (kernel_export) {
|
||||||
name = kernel_export->name;
|
name = kernel_export->name.c_str();
|
||||||
implemented = kernel_export->is_implemented;
|
implemented = kernel_export->is_implemented();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto module = kernel_state_->GetModule(library->name);
|
auto module = kernel_state_->GetModule(library->name);
|
||||||
|
@ -399,7 +399,7 @@ void XUserModule::Dump() {
|
||||||
implemented = true;
|
implemented = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (kernel_export && kernel_export->type == KernelExport::Variable) {
|
if (kernel_export && kernel_export->type == Export::Type::kVariable) {
|
||||||
printf(" V %.8X %.3X (%3d) %s %s\n", info->value_address,
|
printf(" V %.8X %.3X (%3d) %s %s\n", info->value_address,
|
||||||
info->ordinal, info->ordinal, implemented ? " " : "!!", name);
|
info->ordinal, info->ordinal, implemented ? " " : "!!", name);
|
||||||
} else if (info->thunk_address) {
|
} else if (info->thunk_address) {
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
*
|
*
|
||||||
* // 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 my_module_export_table[] = {
|
* static Export my_module_export_table[] = {
|
||||||
* #include "xenia/kernel/my_module/my_module_table.inc"
|
* #include "xenia/kernel/my_module/my_module_table.inc"
|
||||||
* };
|
* };
|
||||||
* #include "xenia/kernel/util/export_table_post.inc"
|
* #include "xenia/kernel/util/export_table_post.inc"
|
||||||
|
@ -23,11 +23,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define XE_EXPORT(module, ordinal, name, type, flags) \
|
#define XE_EXPORT(module, ordinal, name, type) \
|
||||||
{ \
|
{ \
|
||||||
ordinal, \
|
ordinal, \
|
||||||
xe::cpu::KernelExport::type, \
|
xe::cpu::Export::Type::type, \
|
||||||
flags, \
|
|
||||||
#name, \
|
#name, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define XE_EXPORT(module, ordinal, name, type, flags) \
|
#define XE_EXPORT(module, ordinal, name, type) \
|
||||||
name = ordinal
|
name = ordinal
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ using PPCContext = xe::cpu::frontend::PPCContext;
|
||||||
#define SHIM_CALL void _cdecl
|
#define SHIM_CALL void _cdecl
|
||||||
#define SHIM_SET_MAPPING(library_name, export_name, shim_data) \
|
#define SHIM_SET_MAPPING(library_name, export_name, shim_data) \
|
||||||
export_resolver->SetFunctionMapping( \
|
export_resolver->SetFunctionMapping( \
|
||||||
library_name, ordinals::##export_name, shim_data, \
|
library_name, ordinals::##export_name, \
|
||||||
(xe::cpu::xe_kernel_export_shim_fn)export_name##_shim);
|
(xe::cpu::xe_kernel_export_shim_fn)export_name##_shim);
|
||||||
|
|
||||||
#define SHIM_MEM_BASE ppc_state->virtual_membase
|
#define SHIM_MEM_BASE ppc_state->virtual_membase
|
||||||
|
|
|
@ -42,7 +42,7 @@ void XamModule::RegisterExportTable(xe::cpu::ExportResolver* export_resolver) {
|
||||||
|
|
||||||
// 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 xe::cpu::KernelExport xam_export_table[] = {
|
static xe::cpu::Export xam_export_table[] = {
|
||||||
#include "xenia/kernel/xam_table.inc"
|
#include "xenia/kernel/xam_table.inc"
|
||||||
};
|
};
|
||||||
#include "xenia/kernel/util/export_table_post.inc"
|
#include "xenia/kernel/util/export_table_post.inc"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -159,7 +159,7 @@ void XboxkrnlModule::RegisterExportTable(
|
||||||
|
|
||||||
// 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 xe::cpu::KernelExport xboxkrnl_export_table[] = {
|
static xe::cpu::Export xboxkrnl_export_table[] = {
|
||||||
#include "xenia/kernel/xboxkrnl_table.inc"
|
#include "xenia/kernel/xboxkrnl_table.inc"
|
||||||
};
|
};
|
||||||
#include "xenia/kernel/util/export_table_post.inc"
|
#include "xenia/kernel/util/export_table_post.inc"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue