Converting everything to C++ cause I'm a masochist.
This commit is contained in:
parent
8a5dcbc1dd
commit
ca2908db32
|
@ -10,37 +10,6 @@
|
|||
#ifndef XENIA_CPU_H_
|
||||
#define XENIA_CPU_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/core.h>
|
||||
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/module.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
int reserved;
|
||||
} xe_cpu_options_t;
|
||||
|
||||
|
||||
struct xe_cpu;
|
||||
typedef struct xe_cpu* xe_cpu_ref;
|
||||
|
||||
|
||||
xe_cpu_ref xe_cpu_create(xe_pal_ref pal, xe_memory_ref memory,
|
||||
xe_cpu_options_t options);
|
||||
xe_cpu_ref xe_cpu_retain(xe_cpu_ref cpu);
|
||||
void xe_cpu_release(xe_cpu_ref cpu);
|
||||
|
||||
xe_pal_ref xe_cpu_get_pal(xe_cpu_ref cpu);
|
||||
xe_memory_ref xe_cpu_get_memory(xe_cpu_ref cpu);
|
||||
|
||||
int xe_cpu_prepare_module(xe_cpu_ref cpu, xe_module_ref module,
|
||||
xe_kernel_export_resolver_ref export_resolver);
|
||||
|
||||
int xe_cpu_execute(xe_cpu_ref cpu, uint32_t address);
|
||||
|
||||
uint32_t xe_cpu_create_callback(xe_cpu_ref cpu,
|
||||
void (*callback)(void*), void *data);
|
||||
|
||||
#include <xenia/cpu/processor.h>
|
||||
|
||||
#endif // XENIA_CPU_H_
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_CPU_CODEGEN_H_
|
||||
#define XENIA_CPU_CODEGEN_H_
|
||||
|
||||
#include <xenia/cpu/sdb.h>
|
||||
#include <xenia/core/memory.h>
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/user_module.h>
|
||||
|
||||
|
||||
namespace llvm {
|
||||
class LLVMContext;
|
||||
class Module;
|
||||
class Function;
|
||||
class DIBuilder;
|
||||
class MDNode;
|
||||
}
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace codegen {
|
||||
|
||||
|
||||
class CodegenContext {
|
||||
public:
|
||||
CodegenContext(
|
||||
xe_memory_ref memory, kernel::ExportResolver* export_resolver,
|
||||
kernel::UserModule* module, sdb::SymbolDatabase* sdb,
|
||||
llvm::LLVMContext* context, llvm::Module* gen_module);
|
||||
~CodegenContext();
|
||||
|
||||
int GenerateModule();
|
||||
|
||||
private:
|
||||
void AddImports();
|
||||
void AddMissingImport(
|
||||
const xe_xex2_import_library_t *library,
|
||||
const xe_xex2_import_info_t* info, kernel::KernelExport* kernel_export);
|
||||
void AddPresentImport(
|
||||
const xe_xex2_import_library_t *library,
|
||||
const xe_xex2_import_info_t* info, kernel::KernelExport* kernel_export);
|
||||
void AddFunction(sdb::FunctionSymbol* fn);
|
||||
void OptimizeFunction(llvm::Module* m, llvm::Function* fn);
|
||||
|
||||
xe_memory_ref memory_;
|
||||
kernel::ExportResolver* export_resolver_;
|
||||
kernel::UserModule* module_;
|
||||
sdb::SymbolDatabase* sdb_;
|
||||
|
||||
llvm::LLVMContext* context_;
|
||||
llvm::Module* gen_module_;
|
||||
llvm::DIBuilder* di_builder_;
|
||||
llvm::MDNode* cu_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace codegen
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_CPU_CODEGEN_H_
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_CPU_USERMODULE_H_
|
||||
#define XENIA_CPU_USERMODULE_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/core.h>
|
||||
|
||||
#include <xenia/cpu/sdb.h>
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/user_module.h>
|
||||
|
||||
|
||||
namespace llvm {
|
||||
class LLVMContext;
|
||||
class Module;
|
||||
class ExecutionEngine;
|
||||
}
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
|
||||
class ExecModule {
|
||||
public:
|
||||
ExecModule(
|
||||
xe_memory_ref memory, shared_ptr<kernel::ExportResolver> export_resolver,
|
||||
kernel::UserModule* user_module,
|
||||
shared_ptr<llvm::ExecutionEngine>& engine);
|
||||
~ExecModule();
|
||||
|
||||
int Prepare();
|
||||
|
||||
void Dump();
|
||||
|
||||
private:
|
||||
int Init();
|
||||
int Uninit();
|
||||
|
||||
xe_memory_ref memory_;
|
||||
shared_ptr<kernel::ExportResolver> export_resolver_;
|
||||
kernel::UserModule* module_;
|
||||
shared_ptr<llvm::ExecutionEngine> engine_;
|
||||
shared_ptr<sdb::SymbolDatabase> sdb_;
|
||||
shared_ptr<llvm::LLVMContext> context_;
|
||||
shared_ptr<llvm::Module> gen_module_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_CPU_USERMODULE_H_
|
|
@ -13,6 +13,12 @@
|
|||
#include <xenia/common.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
// TODO(benvanik): rename these
|
||||
typedef enum {
|
||||
kXEPPCInstrFormatI = 0,
|
||||
kXEPPCInstrFormatB = 1,
|
||||
|
@ -47,13 +53,12 @@ typedef enum {
|
|||
} xe_ppc_instr_flag_e;
|
||||
|
||||
|
||||
struct xe_ppc_instr_type;
|
||||
typedef struct xe_ppc_instr_type xe_ppc_instr_type_t;
|
||||
class InstrType;
|
||||
|
||||
|
||||
typedef struct {
|
||||
xe_ppc_instr_type_t *type;
|
||||
uint32_t address;
|
||||
InstrType* type;
|
||||
uint32_t address;
|
||||
|
||||
union {
|
||||
uint32_t code;
|
||||
|
@ -110,28 +115,36 @@ typedef struct {
|
|||
// kXEPPCInstrFormatVX
|
||||
// kXEPPCInstrFormatVXR
|
||||
} data;
|
||||
} xe_ppc_instr_t;
|
||||
} InstrData;
|
||||
|
||||
typedef struct {
|
||||
xe_ppc_instr_t instr;
|
||||
class Instr {
|
||||
public:
|
||||
InstrData instr;
|
||||
|
||||
// TODO(benvanik): registers changed, special bits, etc
|
||||
} xe_ppc_dec_instr_t;
|
||||
|
||||
typedef int (*xe_ppc_emit_fn)(/* emit context */ xe_ppc_instr_t *instr);
|
||||
|
||||
struct xe_ppc_instr_type {
|
||||
uint32_t opcode;
|
||||
uint32_t format; // xe_ppc_instr_format_e
|
||||
uint32_t type; // xe_ppc_instr_type_e
|
||||
uint32_t flags; // xe_ppc_instr_flag_e
|
||||
char name[16];
|
||||
|
||||
xe_ppc_emit_fn emit;
|
||||
};
|
||||
|
||||
xe_ppc_instr_type_t *xe_ppc_get_instr_type(uint32_t code);
|
||||
int xe_ppc_register_instr_emit(uint32_t code, xe_ppc_emit_fn emit);
|
||||
typedef int (*InstrEmitFn)(/* emit context */ Instr* instr);
|
||||
|
||||
class InstrType {
|
||||
public:
|
||||
uint32_t opcode;
|
||||
uint32_t format; // xe_ppc_instr_format_e
|
||||
uint32_t type; // xe_ppc_instr_type_e
|
||||
uint32_t flags; // xe_ppc_instr_flag_e
|
||||
char name[16];
|
||||
|
||||
InstrEmitFn emit;
|
||||
};
|
||||
|
||||
InstrType* GetInstrType(uint32_t code);
|
||||
int RegisterInstrEmit(uint32_t code, InstrEmitFn emit);
|
||||
|
||||
|
||||
} // namespace ppc
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_CPU_PPC_INSTR_H_
|
||||
|
||||
|
|
|
@ -13,13 +13,33 @@
|
|||
#include <xenia/common.h>
|
||||
|
||||
|
||||
namespace XE_PPC_SPR {
|
||||
enum XE_PPC_SPR_e {
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
namespace SPR {
|
||||
enum SPR_e {
|
||||
XER = 1,
|
||||
LR = 8,
|
||||
CTR = 9,
|
||||
};
|
||||
} // XE_PPC_SPR
|
||||
} // SPR
|
||||
|
||||
|
||||
namespace FPRF {
|
||||
enum FPRF_e {
|
||||
QUIET_NAN = 0x00088000,
|
||||
NEG_INFINITY = 0x00090000,
|
||||
NEG_NORMALIZED = 0x00010000,
|
||||
NEG_DENORMALIZED = 0x00018000,
|
||||
NEG_ZERO = 0x00048000,
|
||||
POS_ZERO = 0x00040000,
|
||||
POS_DENORMALIZED = 0x00028000,
|
||||
POS_NORMALIZED = 0x00020000,
|
||||
POS_INFINITY = 0x000A0000,
|
||||
};
|
||||
} // FPRF
|
||||
|
||||
|
||||
typedef struct XECACHEALIGN64 {
|
||||
|
@ -88,33 +108,24 @@ typedef struct XECACHEALIGN64 {
|
|||
// 11 = toward -infinity
|
||||
} bits;
|
||||
} fpscr; // Floating-point status and control register
|
||||
} xe_ppc_registers_t;
|
||||
|
||||
uint32_t get_fprf() {
|
||||
return fpscr.value & 0x000F8000;
|
||||
}
|
||||
void set_fprf(const uint32_t v) {
|
||||
fpscr.value = (fpscr.value & ~0x000F8000) | v;
|
||||
}
|
||||
} PpcRegisters;
|
||||
|
||||
|
||||
typedef struct {
|
||||
xe_ppc_registers_t registers;
|
||||
} xe_ppc_state_t;
|
||||
PpcRegisters registers;
|
||||
} PpcState;
|
||||
|
||||
|
||||
namespace XE_PPC_FPRF {
|
||||
enum XE_PPC_FPRF_e {
|
||||
QUIET_NAN = 0x00088000,
|
||||
NEG_INFINITY = 0x00090000,
|
||||
NEG_NORMALIZED = 0x00010000,
|
||||
NEG_DENORMALIZED = 0x00018000,
|
||||
NEG_ZERO = 0x00048000,
|
||||
POS_ZERO = 0x00040000,
|
||||
POS_DENORMALIZED = 0x00028000,
|
||||
POS_NORMALIZED = 0x00020000,
|
||||
POS_INFINITY = 0x000A0000,
|
||||
};
|
||||
} // XE_PPC_FPRF
|
||||
uint32_t xe_ppc_get_fprf(const xe_ppc_registers_t *r) {
|
||||
return r->fpscr.value & 0x000F8000;
|
||||
}
|
||||
void xe_ppc_set_fprf(xe_ppc_registers_t *r, const uint32_t v) {
|
||||
r->fpscr.value = (r->fpscr.value & ~0x000F8000) | v;
|
||||
}
|
||||
} // namespace ppc
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_CPU_PPC_STATE_H_
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_CPU_PROCESSOR_H_
|
||||
#define XENIA_CPU_PROCESSOR_H_
|
||||
|
||||
#include <xenia/core.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <xenia/cpu/exec_module.h>
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/user_module.h>
|
||||
|
||||
|
||||
namespace llvm {
|
||||
class ExecutionEngine;
|
||||
}
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
|
||||
class Processor {
|
||||
public:
|
||||
Processor(xe_pal_ref pal, xe_memory_ref memory);
|
||||
~Processor();
|
||||
|
||||
xe_pal_ref pal();
|
||||
xe_memory_ref memory();
|
||||
|
||||
int Setup();
|
||||
|
||||
int PrepareModule(kernel::UserModule* user_module,
|
||||
shared_ptr<kernel::ExportResolver> export_resolver);
|
||||
|
||||
int Execute(uint32_t address);
|
||||
uint32_t CreateCallback(void (*callback)(void* data), void* data);
|
||||
|
||||
private:
|
||||
xe_pal_ref pal_;
|
||||
xe_memory_ref memory_;
|
||||
shared_ptr<llvm::ExecutionEngine> engine_;
|
||||
|
||||
std::vector<ExecModule*> modules_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_CPU_PROCESSOR_H_
|
|
@ -12,79 +12,123 @@
|
|||
|
||||
#include <xenia/core.h>
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <xenia/kernel/module.h>
|
||||
#include <xenia/kernel/user_module.h>
|
||||
|
||||
|
||||
struct xe_sdb_function;
|
||||
typedef struct xe_sdb_function xe_sdb_function_t;
|
||||
struct xe_sdb_variable;
|
||||
typedef struct xe_sdb_variable xe_sdb_variable_t;
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace sdb {
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t address;
|
||||
xe_sdb_function_t *source;
|
||||
xe_sdb_function_t *target;
|
||||
} xe_sdb_function_call_t;
|
||||
class FunctionSymbol;
|
||||
class VariableSymbol;
|
||||
|
||||
typedef struct {
|
||||
uint32_t address;
|
||||
xe_sdb_function_t *source;
|
||||
xe_sdb_variable_t *target;
|
||||
} xe_sdb_variable_access_t;
|
||||
|
||||
typedef enum {
|
||||
kXESDBFunctionUnknown = 0,
|
||||
kXESDBFunctionKernel = 1,
|
||||
kXESDBFunctionUser = 2,
|
||||
} xe_sdb_function_type;
|
||||
|
||||
struct xe_sdb_function {
|
||||
uint32_t start_address;
|
||||
uint32_t end_address;
|
||||
char *name;
|
||||
xe_sdb_function_type type;
|
||||
uint32_t flags;
|
||||
|
||||
std::vector<xe_sdb_function_call_t*> incoming_calls;
|
||||
std::vector<xe_sdb_function_call_t*> outgoing_calls;
|
||||
std::vector<xe_sdb_variable_access_t*> variable_accesses;
|
||||
class FunctionCall {
|
||||
public:
|
||||
uint32_t address;
|
||||
FunctionSymbol* source;
|
||||
FunctionSymbol* target;
|
||||
};
|
||||
|
||||
struct xe_sdb_variable {
|
||||
class VariableAccess {
|
||||
public:
|
||||
uint32_t address;
|
||||
FunctionSymbol* source;
|
||||
VariableSymbol* target;
|
||||
};
|
||||
|
||||
class Symbol {
|
||||
public:
|
||||
enum SymbolType {
|
||||
Function = 0,
|
||||
Variable = 1,
|
||||
};
|
||||
|
||||
virtual ~Symbol() {}
|
||||
|
||||
SymbolType symbol_type;
|
||||
|
||||
protected:
|
||||
Symbol(SymbolType type) : symbol_type(type) {}
|
||||
};
|
||||
|
||||
class FunctionSymbol : public Symbol {
|
||||
public:
|
||||
enum FunctionType {
|
||||
Unknown = 0,
|
||||
Kernel = 1,
|
||||
User = 2,
|
||||
};
|
||||
|
||||
FunctionSymbol() : Symbol(Function) {}
|
||||
virtual ~FunctionSymbol() {}
|
||||
|
||||
uint32_t start_address;
|
||||
uint32_t end_address;
|
||||
char *name;
|
||||
FunctionType type;
|
||||
uint32_t flags;
|
||||
|
||||
vector<FunctionCall*> incoming_calls;
|
||||
vector<FunctionCall*> outgoing_calls;
|
||||
vector<VariableAccess*> variable_accesses;
|
||||
};
|
||||
|
||||
class VariableSymbol : public Symbol {
|
||||
public:
|
||||
VariableSymbol() : Symbol(Variable) {}
|
||||
virtual ~VariableSymbol() {}
|
||||
|
||||
uint32_t address;
|
||||
char *name;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
union {
|
||||
xe_sdb_function_t* function;
|
||||
xe_sdb_variable_t* variable;
|
||||
};
|
||||
} xe_sdb_symbol_t;
|
||||
|
||||
class SymbolDatabase {
|
||||
public:
|
||||
SymbolDatabase(xe_memory_ref memory, kernel::UserModule* user_module);
|
||||
~SymbolDatabase();
|
||||
|
||||
int Analyze();
|
||||
|
||||
FunctionSymbol* GetOrInsertFunction(uint32_t address);
|
||||
VariableSymbol* GetOrInsertVariable(uint32_t address);
|
||||
FunctionSymbol* GetFunction(uint32_t address);
|
||||
VariableSymbol* GetVariable(uint32_t address);
|
||||
Symbol* GetSymbol(uint32_t address);
|
||||
|
||||
int GetAllFunctions(vector<FunctionSymbol*>& functions);
|
||||
|
||||
void Dump();
|
||||
|
||||
private:
|
||||
typedef std::map<uint32_t, Symbol*> SymbolMap;
|
||||
typedef std::list<FunctionSymbol*> FunctionList;
|
||||
|
||||
int FindGplr();
|
||||
int AddImports(const xe_xex2_import_library_t *library);
|
||||
int AddMethodHints();
|
||||
int AnalyzeFunction(FunctionSymbol* fn);
|
||||
int FillHoles();
|
||||
int FlushQueue();
|
||||
|
||||
xe_memory_ref memory_;
|
||||
kernel::UserModule* module_;
|
||||
size_t function_count_;
|
||||
size_t variable_count_;
|
||||
SymbolMap symbols_;
|
||||
FunctionList scan_queue_;
|
||||
};
|
||||
|
||||
|
||||
struct xe_sdb;
|
||||
typedef struct xe_sdb* xe_sdb_ref;
|
||||
|
||||
|
||||
xe_sdb_ref xe_sdb_create(xe_memory_ref memory, xe_module_ref module);
|
||||
xe_sdb_ref xe_sdb_retain(xe_sdb_ref sdb);
|
||||
void xe_sdb_release(xe_sdb_ref sdb);
|
||||
|
||||
xe_sdb_function_t* xe_sdb_insert_function(xe_sdb_ref sdb, uint32_t address);
|
||||
xe_sdb_variable_t* xe_sdb_insert_variable(xe_sdb_ref sdb, uint32_t address);
|
||||
|
||||
xe_sdb_function_t* xe_sdb_get_function(xe_sdb_ref sdb, uint32_t address);
|
||||
xe_sdb_variable_t* xe_sdb_get_variable(xe_sdb_ref sdb, uint32_t address);
|
||||
|
||||
int xe_sdb_get_functions(xe_sdb_ref sdb, xe_sdb_function_t ***out_functions,
|
||||
size_t *out_function_count);
|
||||
|
||||
void xe_sdb_dump(xe_sdb_ref sdb);
|
||||
} // namespace sdb
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_CPU_SDB_H_
|
||||
|
|
|
@ -10,42 +10,6 @@
|
|||
#ifndef XENIA_KERNEL_H_
|
||||
#define XENIA_KERNEL_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/core.h>
|
||||
#include <xenia/cpu.h>
|
||||
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/module.h>
|
||||
#include <xenia/kernel/xex2.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
xechar_t command_line[2048];
|
||||
} xe_kernel_options_t;
|
||||
|
||||
|
||||
struct xe_kernel;
|
||||
typedef struct xe_kernel* xe_kernel_ref;
|
||||
|
||||
|
||||
xe_kernel_ref xe_kernel_create(xe_pal_ref pal, xe_cpu_ref cpu,
|
||||
xe_kernel_options_t options);
|
||||
xe_kernel_ref xe_kernel_retain(xe_kernel_ref kernel);
|
||||
void xe_kernel_release(xe_kernel_ref kernel);
|
||||
|
||||
xe_pal_ref xe_kernel_get_pal(xe_kernel_ref kernel);
|
||||
xe_memory_ref xe_kernel_get_memory(xe_kernel_ref kernel);
|
||||
xe_cpu_ref xe_kernel_get_cpu(xe_kernel_ref kernel);
|
||||
|
||||
const xechar_t *xe_kernel_get_command_line(xe_kernel_ref kernel);
|
||||
|
||||
xe_kernel_export_resolver_ref xe_kernel_get_export_resolver(
|
||||
xe_kernel_ref kernel);
|
||||
|
||||
xe_module_ref xe_kernel_load_module(xe_kernel_ref kernel, const xechar_t *path);
|
||||
void xe_kernel_launch_module(xe_kernel_ref kernel, xe_module_ref module);
|
||||
xe_module_ref xe_kernel_get_module(xe_kernel_ref kernel, const xechar_t *path);
|
||||
void xe_kernel_unload_module(xe_kernel_ref kernel, xe_module_ref module);
|
||||
|
||||
#include <xenia/kernel/runtime.h>
|
||||
|
||||
#endif // XENIA_KERNEL_H_
|
||||
|
|
|
@ -12,16 +12,24 @@
|
|||
|
||||
#include <xenia/core.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
typedef enum {
|
||||
kXEKernelExportFlagFunction = 1 << 0,
|
||||
kXEKernelExportFlagVariable = 1 << 1,
|
||||
} xe_kernel_export_flags;
|
||||
|
||||
typedef void (*xe_kernel_export_fn)();
|
||||
|
||||
typedef struct {
|
||||
class KernelExport {
|
||||
public:
|
||||
enum ExportType {
|
||||
Function = 0,
|
||||
Variable = 1,
|
||||
};
|
||||
|
||||
uint32_t ordinal;
|
||||
ExportType type;
|
||||
uint32_t flags;
|
||||
char signature[16];
|
||||
char name[96];
|
||||
|
@ -39,38 +47,46 @@ typedef struct {
|
|||
xe_kernel_export_fn shim;
|
||||
} function_data;
|
||||
};
|
||||
} xe_kernel_export_t;
|
||||
|
||||
#define XE_DECLARE_EXPORT(module, ordinal, name, signature, flags) \
|
||||
bool IsImplemented();
|
||||
};
|
||||
|
||||
#define XE_DECLARE_EXPORT(module, ordinal, name, signature, type, flags) \
|
||||
{ \
|
||||
ordinal, \
|
||||
KernelExport::type, \
|
||||
flags, \
|
||||
#signature, \
|
||||
#name, \
|
||||
}
|
||||
|
||||
|
||||
bool xe_kernel_export_is_implemented(const xe_kernel_export_t *kernel_export);
|
||||
class ExportResolver {
|
||||
public:
|
||||
ExportResolver();
|
||||
~ExportResolver();
|
||||
|
||||
void RegisterTable(const char* library_name, KernelExport* exports,
|
||||
const size_t count);
|
||||
|
||||
KernelExport* GetExportByOrdinal(const char* library_name,
|
||||
const uint32_t ordinal);
|
||||
KernelExport* GetExportByName(const char* library_name, const char* name);
|
||||
|
||||
private:
|
||||
class ExportTable {
|
||||
public:
|
||||
char name[32];
|
||||
KernelExport* exports;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
std::vector<ExportTable> tables_;
|
||||
};
|
||||
|
||||
|
||||
struct xe_kernel_export_resolver;
|
||||
typedef struct xe_kernel_export_resolver* xe_kernel_export_resolver_ref;
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
xe_kernel_export_resolver_ref xe_kernel_export_resolver_create();
|
||||
xe_kernel_export_resolver_ref xe_kernel_export_resolver_retain(
|
||||
xe_kernel_export_resolver_ref resolver);
|
||||
void xe_kernel_export_resolver_release(xe_kernel_export_resolver_ref resolver);
|
||||
|
||||
void xe_kernel_export_resolver_register_table(
|
||||
xe_kernel_export_resolver_ref resolver, const char *library_name,
|
||||
xe_kernel_export_t *exports, const size_t count);
|
||||
|
||||
xe_kernel_export_t *xe_kernel_export_resolver_get_by_ordinal(
|
||||
xe_kernel_export_resolver_ref resolver, const char *library_name,
|
||||
const uint32_t ordinal);
|
||||
xe_kernel_export_t *xe_kernel_export_resolver_get_by_name(
|
||||
xe_kernel_export_resolver_ref resolver, const char *library_name,
|
||||
const char *name);
|
||||
|
||||
#endif // XENIA_KERNEL_EXPORT_H_
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_KERNEL_MODULE_H_
|
||||
#define XENIA_KERNEL_KERNEL_MODULE_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/core.h>
|
||||
|
||||
#include <xenia/kernel/export.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
|
||||
class KernelModule {
|
||||
public:
|
||||
KernelModule(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> resolver) {
|
||||
pal_ = xe_pal_retain(pal);
|
||||
memory_ = xe_memory_retain(memory);
|
||||
resolver_ = resolver;
|
||||
}
|
||||
|
||||
virtual ~KernelModule() {
|
||||
xe_memory_release(memory_);
|
||||
xe_pal_release(pal_);
|
||||
}
|
||||
|
||||
protected:
|
||||
xe_pal_ref pal_;
|
||||
xe_memory_ref memory_;
|
||||
shared_ptr<ExportResolver> resolver_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_KERNEL_MODULE_H_
|
|
@ -1,72 +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. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_MODULE_H_
|
||||
#define XENIA_KERNEL_MODULE_H_
|
||||
|
||||
#include <xenia/core.h>
|
||||
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/xex2.h>
|
||||
|
||||
typedef struct {
|
||||
xechar_t path[2048];
|
||||
} xe_module_options_t;
|
||||
|
||||
struct xe_module;
|
||||
typedef struct xe_module* xe_module_ref;
|
||||
|
||||
|
||||
#define kXEPESectionContainsCode 0x00000020
|
||||
#define kXEPESectionContainsDataInit 0x00000040
|
||||
#define kXEPESectionContainsDataUninit 0x00000080
|
||||
#define kXEPESectionMemoryExecute 0x20000000
|
||||
#define kXEPESectionMemoryRead 0x40000000
|
||||
#define kXEPESectionMemoryWrite 0x80000000
|
||||
typedef struct {
|
||||
char name[9]; // 8 + 1 for \0
|
||||
uint32_t raw_address;
|
||||
size_t raw_size;
|
||||
uint32_t address;
|
||||
size_t size;
|
||||
uint32_t flags; // kXEPESection*
|
||||
} xe_module_pe_section_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t address;
|
||||
size_t total_length; // in bytes
|
||||
size_t prolog_length; // in bytes
|
||||
} xe_module_pe_method_info_t;
|
||||
|
||||
|
||||
xe_module_ref xe_module_load(xe_memory_ref memory,
|
||||
xe_kernel_export_resolver_ref export_resolver,
|
||||
const void* addr, const size_t length,
|
||||
xe_module_options_t options);
|
||||
xe_module_ref xe_module_retain(xe_module_ref module);
|
||||
void xe_module_release(xe_module_ref module);
|
||||
|
||||
const xechar_t *xe_module_get_path(xe_module_ref module);
|
||||
const xechar_t *xe_module_get_name(xe_module_ref module);
|
||||
uint32_t xe_module_get_handle(xe_module_ref module);
|
||||
xe_xex2_ref xe_module_get_xex(xe_module_ref module);
|
||||
const xe_xex2_header_t *xe_module_get_xex_header(xe_module_ref module);
|
||||
|
||||
void *xe_module_get_proc_address(xe_module_ref module, const uint32_t ordinal);
|
||||
|
||||
xe_module_pe_section_t *xe_module_get_section(xe_module_ref module,
|
||||
const char *name);
|
||||
int xe_module_get_method_hints(xe_module_ref module,
|
||||
xe_module_pe_method_info_t **out_method_infos,
|
||||
size_t *out_method_info_count);
|
||||
|
||||
void xe_module_dump(xe_module_ref module);
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_MODULE_H_
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_RUNTIME_H_
|
||||
#define XENIA_KERNEL_RUNTIME_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/core.h>
|
||||
#include <xenia/cpu.h>
|
||||
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/user_module.h>
|
||||
#include <xenia/kernel/xex2.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
class Processor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
class KernelModule;
|
||||
|
||||
|
||||
class Runtime {
|
||||
public:
|
||||
Runtime(xe_pal_ref pal, shared_ptr<cpu::Processor> processor,
|
||||
const xechar_t* command_line);
|
||||
~Runtime();
|
||||
|
||||
xe_pal_ref pal();
|
||||
xe_memory_ref memory();
|
||||
shared_ptr<cpu::Processor> processor();
|
||||
shared_ptr<ExportResolver> export_resolver();
|
||||
const xechar_t* command_line();
|
||||
|
||||
int LoadModule(const xechar_t* path);
|
||||
void LaunchModule(UserModule* user_module);
|
||||
UserModule* GetModule(const xechar_t* path);
|
||||
void UnloadModule(UserModule* user_module);
|
||||
|
||||
private:
|
||||
xe_pal_ref pal_;
|
||||
xe_memory_ref memory_;
|
||||
shared_ptr<cpu::Processor> processor_;
|
||||
xechar_t command_line_[2048];
|
||||
shared_ptr<ExportResolver> export_resolver_;
|
||||
|
||||
std::vector<KernelModule*> kernel_modules_;
|
||||
std::map<const xechar_t*, UserModule*> user_modules_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_RUNTIME_H_
|
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_USER_MODULE_H_
|
||||
#define XENIA_KERNEL_USER_MODULE_H_
|
||||
|
||||
#include <xenia/core.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/xex2.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
|
||||
#define kXEPESectionContainsCode 0x00000020
|
||||
#define kXEPESectionContainsDataInit 0x00000040
|
||||
#define kXEPESectionContainsDataUninit 0x00000080
|
||||
#define kXEPESectionMemoryExecute 0x20000000
|
||||
#define kXEPESectionMemoryRead 0x40000000
|
||||
#define kXEPESectionMemoryWrite 0x80000000
|
||||
|
||||
class PESection {
|
||||
public:
|
||||
char name[9]; // 8 + 1 for \0
|
||||
uint32_t raw_address;
|
||||
size_t raw_size;
|
||||
uint32_t address;
|
||||
size_t size;
|
||||
uint32_t flags; // kXEPESection*
|
||||
};
|
||||
|
||||
class PEMethodInfo {
|
||||
public:
|
||||
uint32_t address;
|
||||
size_t total_length; // in bytes
|
||||
size_t prolog_length; // in bytes
|
||||
};
|
||||
|
||||
|
||||
class UserModule {
|
||||
public:
|
||||
UserModule(xe_memory_ref memory);
|
||||
~UserModule();
|
||||
|
||||
int Load(const void* addr, const size_t length, const xechar_t* path);
|
||||
|
||||
const xechar_t* path();
|
||||
const xechar_t* name();
|
||||
uint32_t handle();
|
||||
xe_xex2_ref xex();
|
||||
const xe_xex2_header_t* xex_header();
|
||||
|
||||
void* GetProcAddress(const uint32_t ordinal);
|
||||
PESection* GetSection(const char* name);
|
||||
int GetMethodHints(PEMethodInfo** out_method_infos,
|
||||
size_t* out_method_info_count);
|
||||
|
||||
void Dump(ExportResolver* export_resolver);
|
||||
|
||||
private:
|
||||
int LoadPE();
|
||||
|
||||
xe_memory_ref memory_;
|
||||
|
||||
xechar_t path_[2048];
|
||||
xechar_t name_[256];
|
||||
|
||||
uint32_t handle_;
|
||||
xe_xex2_ref xex_;
|
||||
|
||||
std::vector<PESection*> sections_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_USER_MODULE_H_
|
|
@ -14,6 +14,14 @@
|
|||
#include <xenia/platform_includes.h>
|
||||
|
||||
|
||||
#include <tr1/memory>
|
||||
namespace xe {
|
||||
// TODO(benvanik): support other compilers/etc
|
||||
using namespace std;
|
||||
using namespace std::tr1;
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#define XE_EMPTY_MACRO do { } while(0)
|
||||
|
||||
#define XEUNREFERENCED(expr) (void)(expr)
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "cpu/codegen.h"
|
||||
#include <xenia/cpu/codegen.h>
|
||||
|
||||
#include <llvm/DIBuilder.h>
|
||||
#include <llvm/Linker.h>
|
||||
#include <llvm/PassManager.h>
|
||||
#include <llvm/DebugInfo.h>
|
||||
|
@ -17,90 +18,90 @@
|
|||
#include <llvm/IR/DataLayout.h>
|
||||
#include <llvm/IR/DerivedTypes.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/Transforms/IPO.h>
|
||||
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
||||
|
||||
#include <xenia/cpu/ppc.h>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace xe;
|
||||
using namespace xe::cpu;
|
||||
using namespace xe::cpu::codegen;
|
||||
using namespace xe::cpu::ppc;
|
||||
using namespace xe::cpu::sdb;
|
||||
using namespace xe::kernel;
|
||||
|
||||
|
||||
void xe_codegen_add_imports(xe_codegen_ctx_t *ctx);
|
||||
void xe_codegen_add_missing_import(
|
||||
xe_codegen_ctx_t *ctx, const xe_xex2_import_library_t *library,
|
||||
const xe_xex2_import_info_t* info, xe_kernel_export_t *kernel_export);
|
||||
void xe_codegen_add_import(
|
||||
xe_codegen_ctx_t *ctx, const xe_xex2_import_library_t *library,
|
||||
const xe_xex2_import_info_t* info, xe_kernel_export_t *kernel_export);
|
||||
void xe_codegen_add_function(xe_codegen_ctx_t *ctx, xe_sdb_function_t *fn);
|
||||
void xe_codegen_optimize(Module *m, Function *fn);
|
||||
CodegenContext::CodegenContext(
|
||||
xe_memory_ref memory, ExportResolver* export_resolver,
|
||||
UserModule* module, SymbolDatabase* sdb,
|
||||
LLVMContext* context, Module* gen_module) {
|
||||
memory_ = xe_memory_retain(memory);
|
||||
export_resolver_ = export_resolver;
|
||||
module_ = module;
|
||||
sdb_ = sdb;
|
||||
context_ = context;
|
||||
gen_module_ = gen_module;
|
||||
}
|
||||
|
||||
CodegenContext::~CodegenContext() {
|
||||
xe_memory_release(memory_);
|
||||
}
|
||||
|
||||
llvm::Module *xe_codegen(xe_codegen_ctx_t *ctx,
|
||||
xe_codegen_options_t options) {
|
||||
LLVMContext& context = *ctx->context;
|
||||
int CodegenContext::GenerateModule() {
|
||||
std::string error_message;
|
||||
|
||||
// Initialize the module.
|
||||
Module *m = new Module(xe_module_get_name(ctx->module), context);
|
||||
ctx->gen_module = m;
|
||||
// TODO(benavnik): addModuleFlag?
|
||||
|
||||
// Link shared module into generated module.
|
||||
// This gives us a single module that we can optimize and prevents the need
|
||||
// for foreward declarations.
|
||||
Linker::LinkModules(m, ctx->shared_module, 0, &error_message);
|
||||
|
||||
// Setup a debug info builder.
|
||||
// This is used when creating any debug info. We may want to go more
|
||||
// fine grained than this, but for now it's something.
|
||||
xechar_t dir[2048];
|
||||
xestrcpy(dir, XECOUNT(dir), xe_module_get_path(ctx->module));
|
||||
XEIGNORE(xestrcpy(dir, XECOUNT(dir), module_->path()));
|
||||
xechar_t *slash = xestrrchr(dir, '/');
|
||||
if (slash) {
|
||||
*(slash + 1) = 0;
|
||||
}
|
||||
ctx->di_builder = new DIBuilder(*m);
|
||||
ctx->di_builder->createCompileUnit(
|
||||
di_builder_ = new DIBuilder(*gen_module_);
|
||||
di_builder_->createCompileUnit(
|
||||
0,
|
||||
StringRef(xe_module_get_name(ctx->module)),
|
||||
StringRef(module_->name()),
|
||||
StringRef(dir),
|
||||
StringRef("xenia"),
|
||||
true,
|
||||
StringRef(""),
|
||||
0);
|
||||
ctx->cu = (MDNode*)ctx->di_builder->getCU();
|
||||
cu_ = (MDNode*)di_builder_->getCU();
|
||||
|
||||
// Add import thunks/etc.
|
||||
xe_codegen_add_imports(ctx);
|
||||
AddImports();
|
||||
|
||||
// Add export wrappers.
|
||||
//
|
||||
|
||||
// Add all functions.
|
||||
xe_sdb_function_t **functions;
|
||||
size_t function_count;
|
||||
if (!xe_sdb_get_functions(ctx->sdb, &functions, &function_count)) {
|
||||
for (size_t n = 0; n < function_count; n++) {
|
||||
std::vector<FunctionSymbol*> functions;
|
||||
if (!sdb_->GetAllFunctions(functions)) {
|
||||
for (std::vector<FunctionSymbol*>::iterator it = functions.begin();
|
||||
it != functions.end(); ++it) {
|
||||
// kernel functions will be handled by the add imports handlers.
|
||||
if (functions[n]->type == kXESDBFunctionUser) {
|
||||
xe_codegen_add_function(ctx, functions[n]);
|
||||
if ((*it)->type == FunctionSymbol::User) {
|
||||
AddFunction(*it);
|
||||
}
|
||||
}
|
||||
xe_free(functions);
|
||||
}
|
||||
|
||||
ctx->di_builder->finalize();
|
||||
di_builder_->finalize();
|
||||
|
||||
return m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xe_codegen_add_imports(xe_codegen_ctx_t *ctx) {
|
||||
xe_xex2_ref xex = xe_module_get_xex(ctx->module);
|
||||
const xe_xex2_header_t *header = xe_xex2_get_header(xex);
|
||||
void CodegenContext::AddImports() {
|
||||
xe_xex2_ref xex = module_->xex();
|
||||
const xe_xex2_header_t* header = xe_xex2_get_header(xex);
|
||||
|
||||
for (size_t n = 0; n < header->import_library_count; n++) {
|
||||
const xe_xex2_import_library_t *library = &header->import_libraries[n];
|
||||
const xe_xex2_import_library_t* library = &header->import_libraries[n];
|
||||
|
||||
xe_xex2_import_info_t* import_infos;
|
||||
size_t import_info_count;
|
||||
|
@ -108,16 +109,15 @@ void xe_codegen_add_imports(xe_codegen_ctx_t *ctx) {
|
|||
&import_infos, &import_info_count));
|
||||
|
||||
for (size_t i = 0; i < import_info_count; i++) {
|
||||
const xe_xex2_import_info_t *info = &import_infos[i];
|
||||
xe_kernel_export_t *kernel_export =
|
||||
xe_kernel_export_resolver_get_by_ordinal(
|
||||
ctx->export_resolver, library->name, info->ordinal);
|
||||
if (!kernel_export || !xe_kernel_export_is_implemented(kernel_export)) {
|
||||
const xe_xex2_import_info_t* info = &import_infos[i];
|
||||
KernelExport* kernel_export = export_resolver_->GetExportByOrdinal(
|
||||
library->name, info->ordinal);
|
||||
if (!kernel_export || !kernel_export->IsImplemented()) {
|
||||
// Not implemented or known.
|
||||
xe_codegen_add_missing_import(ctx, library, info, kernel_export);
|
||||
AddMissingImport(library, info, kernel_export);
|
||||
} else {
|
||||
// Implemented.
|
||||
xe_codegen_add_import(ctx, library, info, kernel_export);
|
||||
AddPresentImport(library, info, kernel_export);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,10 +127,10 @@ void xe_codegen_add_imports(xe_codegen_ctx_t *ctx) {
|
|||
xe_xex2_release(xex);
|
||||
}
|
||||
|
||||
void xe_codegen_add_missing_import(
|
||||
xe_codegen_ctx_t *ctx, const xe_xex2_import_library_t *library,
|
||||
const xe_xex2_import_info_t* info, xe_kernel_export_t *kernel_export) {
|
||||
Module *m = ctx->gen_module;
|
||||
void CodegenContext::AddMissingImport(
|
||||
const xe_xex2_import_library_t* library,
|
||||
const xe_xex2_import_info_t* info, KernelExport* kernel_export) {
|
||||
Module* m = gen_module_;
|
||||
LLVMContext& context = m->getContext();
|
||||
|
||||
char name[128];
|
||||
|
@ -149,11 +149,11 @@ void xe_codegen_add_missing_import(
|
|||
AttributeSet attrs = AttributeSet::get(context, awi);
|
||||
|
||||
std::vector<Type*> args;
|
||||
Type *return_type = Type::getInt32Ty(context);
|
||||
Type* return_type = Type::getInt32Ty(context);
|
||||
|
||||
FunctionType *ft = FunctionType::get(return_type,
|
||||
FunctionType* ft = FunctionType::get(return_type,
|
||||
ArrayRef<Type*>(args), false);
|
||||
Function *f = cast<Function>(m->getOrInsertFunction(
|
||||
Function* f = cast<Function>(m->getOrInsertFunction(
|
||||
StringRef(name), ft, attrs));
|
||||
f->setCallingConv(CallingConv::C);
|
||||
f->setVisibility(GlobalValue::DefaultVisibility);
|
||||
|
@ -161,10 +161,10 @@ void xe_codegen_add_missing_import(
|
|||
// TODO(benvanik): log errors.
|
||||
BasicBlock* block = BasicBlock::Create(context, "entry", f);
|
||||
IRBuilder<> builder(block);
|
||||
Value *tmp = builder.getInt32(0);
|
||||
Value* tmp = builder.getInt32(0);
|
||||
builder.CreateRet(tmp);
|
||||
|
||||
xe_codegen_optimize(m, f);
|
||||
OptimizeFunction(m, f);
|
||||
|
||||
//GlobalAlias *alias = new GlobalAlias(f->getType(), GlobalValue::InternalLinkage, name, f, m);
|
||||
// printf(" F %.8X %.8X %.3X (%3d) %s %s\n",
|
||||
|
@ -177,17 +177,17 @@ void xe_codegen_add_missing_import(
|
|||
}
|
||||
}
|
||||
|
||||
void xe_codegen_add_import(
|
||||
xe_codegen_ctx_t *ctx, const xe_xex2_import_library_t *library,
|
||||
const xe_xex2_import_info_t* info, xe_kernel_export_t *kernel_export) {
|
||||
// Module *m = ctx->gen_module;
|
||||
void CodegenContext::AddPresentImport(
|
||||
const xe_xex2_import_library_t* library,
|
||||
const xe_xex2_import_info_t* info, KernelExport* kernel_export) {
|
||||
// Module *m = gen_module_;
|
||||
// LLVMContext& context = m->getContext();
|
||||
|
||||
// TODO(benvanik): add import thunk code.
|
||||
}
|
||||
|
||||
void xe_codegen_add_function(xe_codegen_ctx_t *ctx, xe_sdb_function_t *fn) {
|
||||
Module *m = ctx->gen_module;
|
||||
void CodegenContext::AddFunction(FunctionSymbol* fn) {
|
||||
Module* m = gen_module_;
|
||||
LLVMContext& context = m->getContext();
|
||||
|
||||
AttributeWithIndex awi[] = {
|
||||
|
@ -198,20 +198,20 @@ void xe_codegen_add_function(xe_codegen_ctx_t *ctx, xe_sdb_function_t *fn) {
|
|||
AttributeSet attrs = AttributeSet::get(context, awi);
|
||||
|
||||
std::vector<Type*> args;
|
||||
Type *return_type = Type::getInt32Ty(context);
|
||||
Type* return_type = Type::getInt32Ty(context);
|
||||
|
||||
char name[64];
|
||||
char *pname = name;
|
||||
char* pname = name;
|
||||
if (fn->name) {
|
||||
pname = fn->name;
|
||||
} else {
|
||||
xesnprintfa(name, XECOUNT(name), "fn_%.8X", fn->start_address);
|
||||
}
|
||||
|
||||
FunctionType *ft = FunctionType::get(return_type,
|
||||
FunctionType* ft = FunctionType::get(return_type,
|
||||
ArrayRef<Type*>(args), false);
|
||||
Function *f = cast<Function>(m->getOrInsertFunction(
|
||||
StringRef(pname), ft, attrs));
|
||||
Function* f = cast<Function>(
|
||||
m->getOrInsertFunction(StringRef(pname), ft, attrs));
|
||||
f->setCallingConv(CallingConv::C);
|
||||
f->setVisibility(GlobalValue::DefaultVisibility);
|
||||
|
||||
|
@ -219,21 +219,21 @@ void xe_codegen_add_function(xe_codegen_ctx_t *ctx, xe_sdb_function_t *fn) {
|
|||
BasicBlock* block = BasicBlock::Create(context, "entry", f);
|
||||
IRBuilder<> builder(block);
|
||||
//builder.SetCurrentDebugLocation(DebugLoc::get(fn->start_address >> 8, fn->start_address & 0xFF, ctx->cu));
|
||||
Value *tmp = builder.getInt32(0);
|
||||
Value* tmp = builder.getInt32(0);
|
||||
builder.CreateRet(tmp);
|
||||
|
||||
// i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname)));
|
||||
|
||||
uint8_t *mem = xe_memory_addr(ctx->memory, 0);
|
||||
uint32_t *pc = (uint32_t*)(mem + fn->start_address);
|
||||
uint8_t* mem = xe_memory_addr(memory_, 0);
|
||||
uint32_t* pc = (uint32_t*)(mem + fn->start_address);
|
||||
uint32_t pcdata = XEGETUINT32BE(pc);
|
||||
printf("data %.8X %.8X\n", fn->start_address, pcdata);
|
||||
xe_ppc_instr_type_t *instr_type = xe_ppc_get_instr_type(pcdata);
|
||||
InstrType* instr_type = ppc::GetInstrType(pcdata);
|
||||
if (instr_type) {
|
||||
printf("instr %.8X %s\n", fn->start_address, instr_type->name);
|
||||
xe_ppc_instr_t instr;
|
||||
instr.data.code = pcdata;
|
||||
printf("%d %d\n", instr.data.XFX.D, instr.data.XFX.spr);
|
||||
// xe_ppc_instr_t instr;
|
||||
// instr.data.code = pcdata;
|
||||
// printf("%d %d\n", instr.data.XFX.D, instr.data.XFX.spr);
|
||||
} else {
|
||||
printf("instr not found\n");
|
||||
}
|
||||
|
@ -241,10 +241,10 @@ void xe_codegen_add_function(xe_codegen_ctx_t *ctx, xe_sdb_function_t *fn) {
|
|||
// Run the optimizer on the function.
|
||||
// Doing this here keeps the size of the IR small and speeds up the later
|
||||
// passes.
|
||||
xe_codegen_optimize(m, f);
|
||||
OptimizeFunction(m, f);
|
||||
}
|
||||
|
||||
void xe_codegen_optimize(Module *m, Function *fn) {
|
||||
void CodegenContext::OptimizeFunction(Module* m, Function* fn) {
|
||||
FunctionPassManager pm(m);
|
||||
PassManagerBuilder pmb;
|
||||
pmb.OptLevel = 3;
|
||||
|
|
|
@ -1,44 +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. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_CPU_CODEGEN_H_
|
||||
#define XENIA_CPU_CODEGEN_H_
|
||||
|
||||
#include <xenia/cpu/sdb.h>
|
||||
#include <xenia/core/memory.h>
|
||||
#include <xenia/kernel/module.h>
|
||||
|
||||
#include <llvm/DIBuilder.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
int reserved;
|
||||
} xe_codegen_options_t;
|
||||
|
||||
typedef struct {
|
||||
xe_memory_ref memory;
|
||||
xe_kernel_export_resolver_ref export_resolver;
|
||||
xe_module_ref module;
|
||||
xe_sdb_ref sdb;
|
||||
|
||||
llvm::LLVMContext *context;
|
||||
llvm::Module *shared_module;
|
||||
llvm::Module *gen_module;
|
||||
llvm::DIBuilder *di_builder;
|
||||
llvm::MDNode *cu;
|
||||
} xe_codegen_ctx_t;
|
||||
|
||||
|
||||
llvm::Module *xe_codegen(xe_codegen_ctx_t *ctx,
|
||||
xe_codegen_options_t options);
|
||||
|
||||
|
||||
#endif // XENIA_CPU_CODEGEN_H_
|
306
src/cpu/cpu.cc
306
src/cpu/cpu.cc
|
@ -1,306 +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/cpu.h>
|
||||
|
||||
#include <llvm/PassManager.h>
|
||||
#include <llvm/Analysis/Verifier.h>
|
||||
#include <llvm/Bitcode/ReaderWriter.h>
|
||||
#include <llvm/ExecutionEngine/GenericValue.h>
|
||||
#include <llvm/ExecutionEngine/ExecutionEngine.h>
|
||||
#include <llvm/ExecutionEngine/Interpreter.h>
|
||||
#include <llvm/ExecutionEngine/JIT.h>
|
||||
#include <llvm/IR/DataLayout.h>
|
||||
#include <llvm/IR/DerivedTypes.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/Support/Host.h>
|
||||
#include <llvm/Support/ManagedStatic.h>
|
||||
#include <llvm/Support/MemoryBuffer.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <llvm/Support/system_error.h>
|
||||
#include <llvm/Support/TargetSelect.h>
|
||||
#include <llvm/Support/Threading.h>
|
||||
#include <llvm/Transforms/IPO.h>
|
||||
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
||||
|
||||
#include <xenia/cpu/sdb.h>
|
||||
|
||||
#include "cpu/codegen.h"
|
||||
#include "cpu/xethunk/xethunk.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
|
||||
typedef struct {
|
||||
xe_module_ref module;
|
||||
xe_sdb_ref sdb;
|
||||
LLVMContext *context;
|
||||
Module *m;
|
||||
} xe_cpu_module_entry_t;
|
||||
|
||||
typedef struct xe_cpu {
|
||||
xe_ref_t ref;
|
||||
|
||||
xe_cpu_options_t options;
|
||||
|
||||
xe_pal_ref pal;
|
||||
xe_memory_ref memory;
|
||||
|
||||
std::vector<xe_cpu_module_entry_t> entries;
|
||||
|
||||
ExecutionEngine *engine;
|
||||
} xe_cpu_t;
|
||||
|
||||
|
||||
int xe_cpu_setup_engine(xe_cpu_ref cpu, Module *gen_module);
|
||||
int xe_cpu_init_module(xe_cpu_ref, Module *gen_module);
|
||||
void xe_cpu_uninit_module(xe_cpu_ref cpu, xe_cpu_module_entry_t *module_entry);
|
||||
|
||||
|
||||
xe_cpu_ref xe_cpu_create(xe_pal_ref pal, xe_memory_ref memory,
|
||||
xe_cpu_options_t options) {
|
||||
xe_cpu_ref cpu = (xe_cpu_ref)xe_calloc(sizeof(xe_cpu));
|
||||
xe_ref_init((xe_ref)cpu);
|
||||
|
||||
xe_copy_struct(&cpu->options, &options, sizeof(xe_cpu_options_t));
|
||||
|
||||
cpu->pal = xe_pal_retain(pal);
|
||||
cpu->memory = xe_memory_retain(memory);
|
||||
|
||||
LLVMLinkInInterpreter();
|
||||
LLVMLinkInJIT();
|
||||
InitializeNativeTarget();
|
||||
XEEXPECTTRUE(llvm_start_multithreaded());
|
||||
|
||||
return cpu;
|
||||
|
||||
XECLEANUP:
|
||||
xe_cpu_release(cpu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xe_cpu_dealloc(xe_cpu_ref cpu) {
|
||||
// Cleanup all modules.
|
||||
for (std::vector<xe_cpu_module_entry_t>::iterator it = cpu->entries.begin();
|
||||
it != cpu->entries.end(); ++it) {
|
||||
xe_cpu_uninit_module(cpu, &*it);
|
||||
cpu->engine->removeModule(it->m);
|
||||
delete it->m;
|
||||
delete it->context;
|
||||
xe_sdb_release(it->sdb);
|
||||
xe_module_release(it->module);
|
||||
}
|
||||
|
||||
delete cpu->engine;
|
||||
llvm_shutdown();
|
||||
|
||||
xe_memory_release(cpu->memory);
|
||||
xe_pal_release(cpu->pal);
|
||||
}
|
||||
|
||||
xe_cpu_ref xe_cpu_retain(xe_cpu_ref cpu) {
|
||||
xe_ref_retain((xe_ref)cpu);
|
||||
return cpu;
|
||||
}
|
||||
|
||||
void xe_cpu_release(xe_cpu_ref cpu) {
|
||||
xe_ref_release((xe_ref)cpu, (xe_ref_dealloc_t)xe_cpu_dealloc);
|
||||
}
|
||||
|
||||
xe_pal_ref xe_cpu_get_pal(xe_cpu_ref cpu) {
|
||||
return xe_pal_retain(cpu->pal);
|
||||
}
|
||||
|
||||
xe_memory_ref xe_cpu_get_memory(xe_cpu_ref cpu) {
|
||||
return xe_memory_retain(cpu->memory);
|
||||
}
|
||||
|
||||
int xe_cpu_setup_engine(xe_cpu_ref cpu, Module *gen_module) {
|
||||
if (cpu->engine) {
|
||||
// Engine already initialized - just add the module.
|
||||
cpu->engine->addModule(gen_module);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string error_message;
|
||||
cpu->engine = ExecutionEngine::create(gen_module, false, &error_message,
|
||||
CodeGenOpt::Aggressive);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xe_cpu_prepare_module(xe_cpu_ref cpu, xe_module_ref module,
|
||||
xe_kernel_export_resolver_ref export_resolver) {
|
||||
int result_code = 1;
|
||||
std::string error_message;
|
||||
|
||||
xe_sdb_ref sdb = NULL;
|
||||
LLVMContext *context = NULL;
|
||||
OwningPtr<MemoryBuffer> shared_module_buffer;
|
||||
Module *gen_module = NULL;
|
||||
Module *shared_module = NULL;
|
||||
raw_ostream *outs = NULL;
|
||||
|
||||
PassManager pm;
|
||||
PassManagerBuilder pmb;
|
||||
|
||||
// TODO(benvanik): embed the bc file into the emulator.
|
||||
const char *thunk_path = "src/cpu/xethunk/xethunk.bc";
|
||||
|
||||
// Create a LLVM context for this prepare.
|
||||
// This is required to ensure thread safety/etc.
|
||||
context = new LLVMContext();
|
||||
|
||||
// Calculate a cache path based on the module, the CPU version, and other
|
||||
// bits.
|
||||
// TODO(benvanik): cache path calculation.
|
||||
const char *cache_path = "build/generated.bc";
|
||||
|
||||
// Check the cache to see if the bitcode exists.
|
||||
// If it does, load that module directly. In the future we could also cache
|
||||
// on linked binaries but that requires more safety around versioning.
|
||||
// TODO(benvanik): check cache for module bitcode and load.
|
||||
// if (path_exists(cache_key)) {
|
||||
// gen_module = load_bitcode(cache_key);
|
||||
// sdb = load_symbol_table(cache_key);
|
||||
// }
|
||||
|
||||
// If not found in cache, generate a new module.
|
||||
if (!gen_module) {
|
||||
// Load shared bitcode files.
|
||||
// These contain globals and common thunk code that are used by the
|
||||
// generated code.
|
||||
XEEXPECTZERO(MemoryBuffer::getFile(thunk_path, shared_module_buffer));
|
||||
shared_module = ParseBitcodeFile(&*shared_module_buffer, *context,
|
||||
&error_message);
|
||||
XEEXPECTNOTNULL(shared_module);
|
||||
|
||||
// Analyze the module and add its symbols to the symbol database.
|
||||
sdb = xe_sdb_create(cpu->memory, module);
|
||||
XEEXPECTNOTNULL(sdb);
|
||||
xe_sdb_dump(sdb);
|
||||
|
||||
// Build the module from the source code.
|
||||
xe_codegen_options_t codegen_options;
|
||||
xe_zero_struct(&codegen_options, sizeof(codegen_options));
|
||||
xe_codegen_ctx_t codegen_ctx;
|
||||
xe_zero_struct(&codegen_ctx, sizeof(codegen_ctx));
|
||||
codegen_ctx.memory = cpu->memory;
|
||||
codegen_ctx.export_resolver = export_resolver;
|
||||
codegen_ctx.module = module;
|
||||
codegen_ctx.sdb = sdb;
|
||||
codegen_ctx.context = context;
|
||||
codegen_ctx.shared_module = shared_module;
|
||||
gen_module = xe_codegen(&codegen_ctx, codegen_options);
|
||||
|
||||
// Write to cache.
|
||||
outs = new raw_fd_ostream(cache_path, error_message,
|
||||
raw_fd_ostream::F_Binary);
|
||||
XEEXPECTTRUE(error_message.empty());
|
||||
WriteBitcodeToFile(gen_module, *outs);
|
||||
}
|
||||
|
||||
// Link optimizations.
|
||||
XEEXPECTZERO(gen_module->MaterializeAllPermanently(&error_message));
|
||||
|
||||
// Reset target triple (ignore what's in xethunk).
|
||||
gen_module->setTargetTriple(llvm::sys::getDefaultTargetTriple());
|
||||
|
||||
// Run full module optimizations.
|
||||
pm.add(new DataLayout(gen_module));
|
||||
pm.add(createVerifierPass());
|
||||
pmb.OptLevel = 3;
|
||||
pmb.SizeLevel = 0;
|
||||
pmb.Inliner = createFunctionInliningPass();
|
||||
pmb.Vectorize = true;
|
||||
pmb.LoopVectorize = true;
|
||||
pmb.populateModulePassManager(pm);
|
||||
pmb.populateLTOPassManager(pm, false, true);
|
||||
pm.add(createVerifierPass());
|
||||
pm.run(*gen_module);
|
||||
|
||||
// TODO(benvanik): experiment with LLD to see if we can write out a dll.
|
||||
|
||||
// Setup the execution engine (if needed).
|
||||
// The engine is required to get the data layout and other values.
|
||||
XEEXPECTZERO(xe_cpu_setup_engine(cpu, gen_module));
|
||||
|
||||
// Initialize the module.
|
||||
XEEXPECTZERO(xe_cpu_init_module(cpu, gen_module));
|
||||
|
||||
// Force JIT of all functions.
|
||||
for (Module::iterator I = gen_module->begin(), E = gen_module->end();
|
||||
I != E; I++) {
|
||||
Function* fn = &*I;
|
||||
if (!fn->isDeclaration()) {
|
||||
cpu->engine->getPointerToFunction(fn);
|
||||
}
|
||||
}
|
||||
|
||||
gen_module->dump();
|
||||
|
||||
// Stash the module entry to allow cleanup later.
|
||||
xe_cpu_module_entry_t module_entry;
|
||||
module_entry.module = xe_module_retain(module);
|
||||
module_entry.sdb = xe_sdb_retain(sdb);
|
||||
module_entry.context = context;
|
||||
module_entry.m = gen_module;
|
||||
cpu->entries.push_back(module_entry);
|
||||
|
||||
result_code = 0;
|
||||
XECLEANUP:
|
||||
delete outs;
|
||||
delete shared_module;
|
||||
if (result_code) {
|
||||
delete gen_module;
|
||||
delete context;
|
||||
}
|
||||
xe_sdb_release(sdb);
|
||||
return result_code;
|
||||
}
|
||||
|
||||
int xe_cpu_init_module(xe_cpu_ref cpu, Module *gen_module) {
|
||||
// Run static initializers. I'm not sure we'll have any, but who knows.
|
||||
cpu->engine->runStaticConstructorsDestructors(gen_module, false);
|
||||
|
||||
// Prepare init options.
|
||||
xe_module_init_options_t init_options;
|
||||
xe_zero_struct(&init_options, sizeof(init_options));
|
||||
init_options.memory_base = xe_memory_addr(cpu->memory, 0);
|
||||
|
||||
// Grab the init function and call it.
|
||||
Function *xe_module_init = gen_module->getFunction("xe_module_init");
|
||||
std::vector<GenericValue> args;
|
||||
args.push_back(GenericValue(&init_options));
|
||||
GenericValue ret = cpu->engine->runFunction(xe_module_init, args);
|
||||
|
||||
return ret.IntVal.getSExtValue();
|
||||
}
|
||||
|
||||
void xe_cpu_uninit_module(xe_cpu_ref cpu, xe_cpu_module_entry_t *module_entry) {
|
||||
// Grab function and call it.
|
||||
Function *xe_module_uninit = module_entry->m->getFunction("xe_module_uninit");
|
||||
std::vector<GenericValue> args;
|
||||
cpu->engine->runFunction(xe_module_uninit, args);
|
||||
|
||||
// Run static destructors.
|
||||
cpu->engine->runStaticConstructorsDestructors(module_entry->m, true);
|
||||
}
|
||||
|
||||
int xe_cpu_execute(xe_cpu_ref cpu, uint32_t address) {
|
||||
// TODO(benvanik): implement execute.
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t xe_cpu_create_callback(xe_cpu_ref cpu,
|
||||
void (*callback)(void*), void *data) {
|
||||
// TODO(benvanik): implement callback creation.
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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/cpu/exec_module.h>
|
||||
|
||||
#include <llvm/Linker.h>
|
||||
#include <llvm/PassManager.h>
|
||||
#include <llvm/Analysis/Verifier.h>
|
||||
#include <llvm/Bitcode/ReaderWriter.h>
|
||||
#include <llvm/ExecutionEngine/GenericValue.h>
|
||||
#include <llvm/ExecutionEngine/ExecutionEngine.h>
|
||||
#include <llvm/IR/DataLayout.h>
|
||||
#include <llvm/IR/DerivedTypes.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/Support/Host.h>
|
||||
#include <llvm/Support/MemoryBuffer.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <llvm/Support/system_error.h>
|
||||
#include <llvm/Support/Threading.h>
|
||||
#include <llvm/Transforms/IPO.h>
|
||||
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
||||
|
||||
#include <xenia/cpu/codegen.h>
|
||||
#include <xenia/cpu/sdb.h>
|
||||
|
||||
#include "cpu/xethunk/xethunk.h"
|
||||
|
||||
|
||||
using namespace llvm;
|
||||
using namespace xe;
|
||||
using namespace xe::cpu;
|
||||
using namespace xe::cpu::codegen;
|
||||
using namespace xe::kernel;
|
||||
|
||||
|
||||
ExecModule::ExecModule(
|
||||
xe_memory_ref memory, shared_ptr<ExportResolver> export_resolver,
|
||||
UserModule* user_module, shared_ptr<llvm::ExecutionEngine>& engine) {
|
||||
memory_ = xe_memory_retain(memory);
|
||||
export_resolver_ = export_resolver;
|
||||
module_ = user_module;
|
||||
engine_ = engine;
|
||||
sdb_ = shared_ptr<sdb::SymbolDatabase>(
|
||||
new sdb::SymbolDatabase(memory_, module_));
|
||||
|
||||
context_ = shared_ptr<LLVMContext>(new LLVMContext());
|
||||
}
|
||||
|
||||
ExecModule::~ExecModule() {
|
||||
if (gen_module_) {
|
||||
Uninit();
|
||||
engine_->removeModule(gen_module_.get());
|
||||
}
|
||||
|
||||
xe_memory_release(memory_);
|
||||
}
|
||||
|
||||
int ExecModule::Prepare() {
|
||||
int result_code = 1;
|
||||
std::string error_message;
|
||||
|
||||
OwningPtr<MemoryBuffer> shared_module_buffer;
|
||||
auto_ptr<Module> shared_module;
|
||||
auto_ptr<raw_ostream> outs;
|
||||
auto_ptr<CodegenContext> codegen;
|
||||
|
||||
PassManager pm;
|
||||
PassManagerBuilder pmb;
|
||||
|
||||
// TODO(benvanik): embed the bc file into the emulator.
|
||||
const char *thunk_path = "src/cpu/xethunk/xethunk.bc";
|
||||
|
||||
// Calculate a cache path based on the module, the CPU version, and other
|
||||
// bits.
|
||||
// TODO(benvanik): cache path calculation.
|
||||
const char *cache_path = "build/generated.bc";
|
||||
|
||||
// Check the cache to see if the bitcode exists.
|
||||
// If it does, load that module directly. In the future we could also cache
|
||||
// on linked binaries but that requires more safety around versioning.
|
||||
// TODO(benvanik): check cache for module bitcode and load.
|
||||
// if (path_exists(cache_key)) {
|
||||
// exec_module = load_bitcode(cache_key);
|
||||
// sdb = load_symbol_table(cache_key);
|
||||
// }
|
||||
|
||||
// If not found in cache, generate a new module.
|
||||
if (!gen_module_.get()) {
|
||||
// Load shared bitcode files.
|
||||
// These contain globals and common thunk code that are used by the
|
||||
// generated code.
|
||||
XEEXPECTZERO(MemoryBuffer::getFile(thunk_path, shared_module_buffer));
|
||||
shared_module = auto_ptr<Module>(ParseBitcodeFile(
|
||||
&*shared_module_buffer, *context_, &error_message));
|
||||
XEEXPECTNOTNULL(shared_module.get());
|
||||
|
||||
// Analyze the module and add its symbols to the symbol database.
|
||||
XEEXPECTZERO(sdb_->Analyze());
|
||||
|
||||
// Initialize the module.
|
||||
gen_module_ = shared_ptr<Module>(
|
||||
new Module(module_->name(), *context_.get()));
|
||||
// TODO(benavnik): addModuleFlag?
|
||||
|
||||
// Link shared module into generated module.
|
||||
// This gives us a single module that we can optimize and prevents the need
|
||||
// for foreward declarations.
|
||||
Linker::LinkModules(gen_module_.get(), shared_module.get(), 0,
|
||||
&error_message);
|
||||
|
||||
// Build the module from the source code.
|
||||
codegen = auto_ptr<CodegenContext>(new CodegenContext(
|
||||
memory_, export_resolver_.get(), module_, sdb_.get(),
|
||||
context_.get(), gen_module_.get()));
|
||||
XEEXPECTZERO(codegen->GenerateModule());
|
||||
|
||||
// Write to cache.
|
||||
outs = auto_ptr<raw_ostream>(new raw_fd_ostream(
|
||||
cache_path, error_message, raw_fd_ostream::F_Binary));
|
||||
XEEXPECTTRUE(error_message.empty());
|
||||
WriteBitcodeToFile(gen_module_.get(), *outs);
|
||||
}
|
||||
|
||||
// Link optimizations.
|
||||
XEEXPECTZERO(gen_module_->MaterializeAllPermanently(&error_message));
|
||||
|
||||
// Reset target triple (ignore what's in xethunk).
|
||||
gen_module_->setTargetTriple(llvm::sys::getDefaultTargetTriple());
|
||||
|
||||
// Run full module optimizations.
|
||||
pm.add(new DataLayout(gen_module_.get()));
|
||||
pm.add(createVerifierPass());
|
||||
pmb.OptLevel = 3;
|
||||
pmb.SizeLevel = 0;
|
||||
pmb.Inliner = createFunctionInliningPass();
|
||||
pmb.Vectorize = true;
|
||||
pmb.LoopVectorize = true;
|
||||
pmb.populateModulePassManager(pm);
|
||||
pmb.populateLTOPassManager(pm, false, true);
|
||||
pm.add(createVerifierPass());
|
||||
pm.run(*gen_module_);
|
||||
|
||||
// TODO(benvanik): experiment with LLD to see if we can write out a dll.
|
||||
|
||||
// Initialize the module.
|
||||
XEEXPECTZERO(Init());
|
||||
|
||||
// Force JIT of all functions.
|
||||
for (Module::iterator I = gen_module_->begin(), E = gen_module_->end();
|
||||
I != E; I++) {
|
||||
Function* fn = &*I;
|
||||
if (!fn->isDeclaration()) {
|
||||
engine_->getPointerToFunction(fn);
|
||||
}
|
||||
}
|
||||
|
||||
result_code = 0;
|
||||
XECLEANUP:
|
||||
return result_code;
|
||||
}
|
||||
|
||||
int ExecModule::Init() {
|
||||
// Run static initializers. I'm not sure we'll have any, but who knows.
|
||||
engine_->runStaticConstructorsDestructors(gen_module_.get(), false);
|
||||
|
||||
// Prepare init options.
|
||||
xe_module_init_options_t init_options;
|
||||
xe_zero_struct(&init_options, sizeof(init_options));
|
||||
init_options.memory_base = xe_memory_addr(memory_, 0);
|
||||
|
||||
// Grab the init function and call it.
|
||||
Function* xe_module_init = gen_module_->getFunction("xe_module_init");
|
||||
std::vector<GenericValue> args;
|
||||
args.push_back(GenericValue(&init_options));
|
||||
GenericValue ret = engine_->runFunction(xe_module_init, args);
|
||||
|
||||
return ret.IntVal.getSExtValue();
|
||||
}
|
||||
|
||||
int ExecModule::Uninit() {
|
||||
// Grab function and call it.
|
||||
Function* xe_module_uninit = gen_module_->getFunction("xe_module_uninit");
|
||||
std::vector<GenericValue> args;
|
||||
engine_->runFunction(xe_module_uninit, args);
|
||||
|
||||
// Run static destructors.
|
||||
engine_->runStaticConstructorsDestructors(gen_module_.get(), true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ExecModule::Dump() {
|
||||
gen_module_->dump();
|
||||
}
|
|
@ -9,46 +9,49 @@
|
|||
|
||||
#include <xenia/cpu/ppc/instr.h>
|
||||
|
||||
#include "cpu/ppc/instr_table.h"
|
||||
#include "cpu/ppc/instr_tables.h"
|
||||
|
||||
|
||||
xe_ppc_instr_type_t *xe_ppc_get_instr_type(uint32_t code) {
|
||||
xe_ppc_instr_type_t *slot = NULL;
|
||||
using namespace xe::cpu::ppc;
|
||||
|
||||
|
||||
InstrType* xe::cpu::ppc::GetInstrType(uint32_t code) {
|
||||
InstrType* slot = NULL;
|
||||
switch (code >> 26) {
|
||||
case 4:
|
||||
// Opcode = 4, index = bits 5-0 (6)
|
||||
slot = &xe_ppc_instr_table_4[XESELECTBITS(code, 0, 5)];
|
||||
slot = &xe::cpu::ppc::tables::instr_table_4[XESELECTBITS(code, 0, 5)];
|
||||
break;
|
||||
case 19:
|
||||
// Opcode = 19, index = bits 10-1 (10)
|
||||
slot = &xe_ppc_instr_table_19[XESELECTBITS(code, 1, 10)];
|
||||
slot = &xe::cpu::ppc::tables::instr_table_19[XESELECTBITS(code, 1, 10)];
|
||||
break;
|
||||
case 30:
|
||||
// Opcode = 30, index = bits 5-1 (5)
|
||||
slot = &xe_ppc_instr_table_30[XESELECTBITS(code, 1, 5)];
|
||||
slot = &xe::cpu::ppc::tables::instr_table_30[XESELECTBITS(code, 1, 5)];
|
||||
break;
|
||||
case 31:
|
||||
// Opcode = 31, index = bits 10-1 (10)
|
||||
slot = &xe_ppc_instr_table_31[XESELECTBITS(code, 1, 10)];
|
||||
slot = &xe::cpu::ppc::tables::instr_table_31[XESELECTBITS(code, 1, 10)];
|
||||
break;
|
||||
case 58:
|
||||
// Opcode = 58, index = bits 1-0 (2)
|
||||
slot = &xe_ppc_instr_table_58[XESELECTBITS(code, 0, 1)];
|
||||
slot = &xe::cpu::ppc::tables::instr_table_58[XESELECTBITS(code, 0, 1)];
|
||||
break;
|
||||
case 59:
|
||||
// Opcode = 59, index = bits 5-1 (5)
|
||||
slot = &xe_ppc_instr_table_59[XESELECTBITS(code, 1, 5)];
|
||||
slot = &xe::cpu::ppc::tables::instr_table_59[XESELECTBITS(code, 1, 5)];
|
||||
break;
|
||||
case 62:
|
||||
// Opcode = 62, index = bits 1-0 (2)
|
||||
slot = &xe_ppc_instr_table_62[XESELECTBITS(code, 0, 1)];
|
||||
slot = &xe::cpu::ppc::tables::instr_table_62[XESELECTBITS(code, 0, 1)];
|
||||
break;
|
||||
case 63:
|
||||
// Opcode = 63, index = bits 10-1 (10)
|
||||
slot = &xe_ppc_instr_table_63[XESELECTBITS(code, 1, 10)];
|
||||
slot = &xe::cpu::ppc::tables::instr_table_63[XESELECTBITS(code, 1, 10)];
|
||||
break;
|
||||
default:
|
||||
slot = &xe_ppc_instr_table[XESELECTBITS(code, 26, 31)];
|
||||
slot = &xe::cpu::ppc::tables::instr_table[XESELECTBITS(code, 26, 31)];
|
||||
break;
|
||||
}
|
||||
if (!slot || !slot->opcode) {
|
||||
|
@ -57,8 +60,8 @@ xe_ppc_instr_type_t *xe_ppc_get_instr_type(uint32_t code) {
|
|||
return slot;
|
||||
}
|
||||
|
||||
int xe_ppc_register_instr_emit(uint32_t code, xe_ppc_emit_fn emit) {
|
||||
xe_ppc_instr_type_t *instr_type = xe_ppc_get_instr_type(code);
|
||||
int xe::cpu::ppc::RegisterInstrEmit(uint32_t code, InstrEmitFn emit) {
|
||||
InstrType* instr_type = GetInstrType(code);
|
||||
if (!instr_type) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -13,28 +13,47 @@
|
|||
#include <xenia/cpu/ppc/instr.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
llvm::LLVMContext *context;
|
||||
llvm::Module *module;
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace ppc {
|
||||
|
||||
|
||||
class InstrContext {
|
||||
using namespace llvm;
|
||||
public:
|
||||
InstrContext();
|
||||
|
||||
Value* cia();
|
||||
Value* nia();
|
||||
void set_nia(Value* value);
|
||||
Value* spr(uint32_t n);
|
||||
void set_spr(uint32_t n, Value* value);
|
||||
|
||||
Value* cr();
|
||||
void set_cr(Value* value);
|
||||
|
||||
Value* gpr(uint32_t n);
|
||||
void set_gpr(uint32_t n, Value* value);
|
||||
|
||||
Value* get_memory_addr(uint32_t addr);
|
||||
Value* read_memory(Value* addr, uint32_t size, bool extend);
|
||||
void write_memory(Value* addr, uint32_t size, Value* value);
|
||||
|
||||
LLVMContext& context;
|
||||
Module& module;
|
||||
// TODO(benvanik): IRBuilder/etc
|
||||
|
||||
// Address of the instruction being generated.
|
||||
uint32_t cia;
|
||||
uint32_t cia;
|
||||
|
||||
llvm::Value *get_cia();
|
||||
void set_nia(llvm::Value *value);
|
||||
llvm::Value *get_spr(uint32_t n);
|
||||
void set_spr(uint32_t n, llvm::Value *value);
|
||||
private:
|
||||
//
|
||||
};
|
||||
|
||||
llvm::Value *get_cr();
|
||||
void set_cr(llvm::Value *value);
|
||||
|
||||
llvm::Value *get_gpr(uint32_t n);
|
||||
void set_gpr(uint32_t n, llvm::Value *value);
|
||||
|
||||
llvm::Value *get_memory_addr(uint32_t addr);
|
||||
llvm::Value *read_memory(llvm::Value *addr, uint32_t size, bool extend);
|
||||
void write_memory(llvm::Value *addr, uint32_t size, llvm::Value *value);
|
||||
} xe_ppc_instr_ctx_t;
|
||||
} // namespace ppc
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_CPU_PPC_INSTR_CTX_H_
|
||||
|
|
|
@ -13,11 +13,16 @@
|
|||
#include <xenia/cpu/ppc/instr.h>
|
||||
|
||||
|
||||
static xe_ppc_instr_type_t *xe_ppc_instr_table_prep(
|
||||
xe_ppc_instr_type_t *unprep, int unprep_count, int a, int b) {
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace ppc {
|
||||
namespace tables {
|
||||
|
||||
|
||||
static InstrType* instr_table_prep(
|
||||
InstrType* unprep, int unprep_count, int a, int b) {
|
||||
int prep_count = pow(2, b - a + 1);
|
||||
xe_ppc_instr_type_t *prep = (xe_ppc_instr_type_t*)xe_calloc(
|
||||
prep_count * sizeof(xe_ppc_instr_type_t));
|
||||
InstrType* prep = (InstrType*)xe_calloc(prep_count * sizeof(InstrType));
|
||||
for (int n = 0; n < unprep_count; n++) {
|
||||
int ordinal = XESELECTBITS(unprep[n].opcode, a, b);
|
||||
prep[ordinal] = unprep[n];
|
||||
|
@ -42,15 +47,15 @@ static xe_ppc_instr_type_t *xe_ppc_instr_table_prep(
|
|||
// PowerISA_V2.06B_V2_PUBLIC.pdf
|
||||
|
||||
// Opcode = 4, index = bits 5-0 (6)
|
||||
static xe_ppc_instr_type_t xe_ppc_instr_table_4_unprep[] = {
|
||||
static InstrType instr_table_4_unprep[] = {
|
||||
// TODO: all of the vector ops
|
||||
INSTRUCTION(vperm, 0x1000002B, VA , General , 0),
|
||||
};
|
||||
static xe_ppc_instr_type_t *xe_ppc_instr_table_4 = xe_ppc_instr_table_prep(
|
||||
xe_ppc_instr_table_4_unprep, XECOUNT(xe_ppc_instr_table_4_unprep), 0, 5);
|
||||
static InstrType* instr_table_4 = instr_table_prep(
|
||||
instr_table_4_unprep, XECOUNT(instr_table_4_unprep), 0, 5);
|
||||
|
||||
// Opcode = 19, index = bits 10-1 (10)
|
||||
static xe_ppc_instr_type_t xe_ppc_instr_table_19_unprep[] = {
|
||||
static InstrType instr_table_19_unprep[] = {
|
||||
INSTRUCTION(mcrf, 0x4C000000, XL , General , 0),
|
||||
INSTRUCTION(bclrx, 0x4C000020, XL , BranchCond , 0),
|
||||
INSTRUCTION(crnor, 0x4C000042, XL , General , 0),
|
||||
|
@ -64,11 +69,11 @@ static xe_ppc_instr_type_t xe_ppc_instr_table_19_unprep[] = {
|
|||
INSTRUCTION(cror, 0x4C000382, XL , General , 0),
|
||||
INSTRUCTION(bcctrx, 0x4C000420, XL , BranchCond , 0),
|
||||
};
|
||||
static xe_ppc_instr_type_t *xe_ppc_instr_table_19 = xe_ppc_instr_table_prep(
|
||||
xe_ppc_instr_table_19_unprep, XECOUNT(xe_ppc_instr_table_19_unprep), 1, 10);
|
||||
static InstrType* instr_table_19 = instr_table_prep(
|
||||
instr_table_19_unprep, XECOUNT(instr_table_19_unprep), 1, 10);
|
||||
|
||||
// Opcode = 30, index = bits 5-1 (5)
|
||||
static xe_ppc_instr_type_t xe_ppc_instr_table_30_unprep[] = {
|
||||
static InstrType instr_table_30_unprep[] = {
|
||||
INSTRUCTION(rldiclx, 0x78000000, MD , General , 0),
|
||||
INSTRUCTION(rldicrx, 0x78000004, MD , General , 0),
|
||||
INSTRUCTION(rldicx, 0x78000008, MD , General , 0),
|
||||
|
@ -76,11 +81,11 @@ static xe_ppc_instr_type_t xe_ppc_instr_table_30_unprep[] = {
|
|||
INSTRUCTION(rldclx, 0x78000010, MDS, General , 0),
|
||||
INSTRUCTION(rldcrx, 0x78000012, MDS, General , 0),
|
||||
};
|
||||
static xe_ppc_instr_type_t *xe_ppc_instr_table_30 = xe_ppc_instr_table_prep(
|
||||
xe_ppc_instr_table_30_unprep, XECOUNT(xe_ppc_instr_table_30_unprep), 1, 5);
|
||||
static InstrType* instr_table_30 = instr_table_prep(
|
||||
instr_table_30_unprep, XECOUNT(instr_table_30_unprep), 1, 5);
|
||||
|
||||
// Opcode = 31, index = bits 10-1 (10)
|
||||
static xe_ppc_instr_type_t xe_ppc_instr_table_31_unprep[] = {
|
||||
static InstrType instr_table_31_unprep[] = {
|
||||
INSTRUCTION(cmp, 0x7C000000, X , General , 0),
|
||||
INSTRUCTION(tw, 0x7C000008, X , General , 0),
|
||||
INSTRUCTION(lvsl, 0x7C00000C, X , General , 0),
|
||||
|
@ -199,20 +204,20 @@ static xe_ppc_instr_type_t xe_ppc_instr_table_31_unprep[] = {
|
|||
INSTRUCTION(extswx, 0x7C0007B4, X , General , 0),
|
||||
INSTRUCTION(dcbz, 0x7C0007EC, X , General , 0), // 0x7C2007EC = DCBZ128
|
||||
};
|
||||
static xe_ppc_instr_type_t *xe_ppc_instr_table_31 = xe_ppc_instr_table_prep(
|
||||
xe_ppc_instr_table_31_unprep, XECOUNT(xe_ppc_instr_table_31_unprep), 1, 10);
|
||||
static InstrType* instr_table_31 = instr_table_prep(
|
||||
instr_table_31_unprep, XECOUNT(instr_table_31_unprep), 1, 10);
|
||||
|
||||
// Opcode = 58, index = bits 1-0 (2)
|
||||
static xe_ppc_instr_type_t xe_ppc_instr_table_58_unprep[] = {
|
||||
static InstrType instr_table_58_unprep[] = {
|
||||
INSTRUCTION(ld, 0xE8000000, DS , General , 0),
|
||||
INSTRUCTION(ldu, 0xE8000001, DS , General , 0),
|
||||
INSTRUCTION(lwa, 0xE8000002, DS , General , 0),
|
||||
};
|
||||
static xe_ppc_instr_type_t *xe_ppc_instr_table_58 = xe_ppc_instr_table_prep(
|
||||
xe_ppc_instr_table_58_unprep, XECOUNT(xe_ppc_instr_table_58_unprep), 0, 1);
|
||||
static InstrType* instr_table_58 = instr_table_prep(
|
||||
instr_table_58_unprep, XECOUNT(instr_table_58_unprep), 0, 1);
|
||||
|
||||
// Opcode = 59, index = bits 5-1 (5)
|
||||
static xe_ppc_instr_type_t xe_ppc_instr_table_59_unprep[] = {
|
||||
static InstrType instr_table_59_unprep[] = {
|
||||
INSTRUCTION(fdivsx, 0xEC000024, A , General , 0),
|
||||
INSTRUCTION(fsubsx, 0xEC000028, A , General , 0),
|
||||
INSTRUCTION(faddsx, 0xEC00002A, A , General , 0),
|
||||
|
@ -224,19 +229,19 @@ static xe_ppc_instr_type_t xe_ppc_instr_table_59_unprep[] = {
|
|||
INSTRUCTION(fnmsubsx, 0xEC00003C, A , General , 0),
|
||||
INSTRUCTION(fnmaddsx, 0xEC00003E, A , General , 0),
|
||||
};
|
||||
static xe_ppc_instr_type_t *xe_ppc_instr_table_59 = xe_ppc_instr_table_prep(
|
||||
xe_ppc_instr_table_59_unprep, XECOUNT(xe_ppc_instr_table_59_unprep), 1, 5);
|
||||
static InstrType* instr_table_59 = instr_table_prep(
|
||||
instr_table_59_unprep, XECOUNT(instr_table_59_unprep), 1, 5);
|
||||
|
||||
// Opcode = 62, index = bits 1-0 (2)
|
||||
static xe_ppc_instr_type_t xe_ppc_instr_table_62_unprep[] = {
|
||||
static InstrType instr_table_62_unprep[] = {
|
||||
INSTRUCTION(std, 0xF8000000, DS , General , 0),
|
||||
INSTRUCTION(stdu, 0xF8000001, DS , General , 0),
|
||||
};
|
||||
static xe_ppc_instr_type_t *xe_ppc_instr_table_62 = xe_ppc_instr_table_prep(
|
||||
xe_ppc_instr_table_62_unprep, XECOUNT(xe_ppc_instr_table_62_unprep), 0, 1);
|
||||
static InstrType* instr_table_62 = instr_table_prep(
|
||||
instr_table_62_unprep, XECOUNT(instr_table_62_unprep), 0, 1);
|
||||
|
||||
// Opcode = 63, index = bits 10-1 (10)
|
||||
static xe_ppc_instr_type_t xe_ppc_instr_table_63_unprep[] = {
|
||||
static InstrType instr_table_63_unprep[] = {
|
||||
INSTRUCTION(fcmpu, 0xFC000000, X , General , 0),
|
||||
INSTRUCTION(frspx, 0xFC000018, X , General , 0),
|
||||
INSTRUCTION(fctiwx, 0xFC00001C, X , General , 0),
|
||||
|
@ -267,11 +272,11 @@ static xe_ppc_instr_type_t xe_ppc_instr_table_63_unprep[] = {
|
|||
INSTRUCTION(fctidzx, 0xFC00065E, X , General , 0),
|
||||
INSTRUCTION(fcfidx, 0xFC00069C, X , General , 0),
|
||||
};
|
||||
static xe_ppc_instr_type_t *xe_ppc_instr_table_63 = xe_ppc_instr_table_prep(
|
||||
xe_ppc_instr_table_63_unprep, XECOUNT(xe_ppc_instr_table_63_unprep), 1, 10);
|
||||
static InstrType* instr_table_63 = instr_table_prep(
|
||||
instr_table_63_unprep, XECOUNT(instr_table_63_unprep), 1, 10);
|
||||
|
||||
// Main table, index = bits 31-26 (6) : (code >> 26)
|
||||
static xe_ppc_instr_type_t xe_ppc_instr_table_unprep[64] = {
|
||||
static InstrType instr_table_unprep[64] = {
|
||||
INSTRUCTION(tdi, 0x08000000, D , General , 0),
|
||||
INSTRUCTION(twi, 0x0C000000, D , General , 0),
|
||||
INSTRUCTION(mulli, 0x1C000000, D , General , 0),
|
||||
|
@ -319,12 +324,19 @@ static xe_ppc_instr_type_t xe_ppc_instr_table_unprep[64] = {
|
|||
INSTRUCTION(stfd, 0xD8000000, D , General , 0),
|
||||
INSTRUCTION(stfdu, 0xDC000000, D , General , 0),
|
||||
};
|
||||
static xe_ppc_instr_type_t *xe_ppc_instr_table = xe_ppc_instr_table_prep(
|
||||
xe_ppc_instr_table_unprep, XECOUNT(xe_ppc_instr_table_unprep), 26, 31);
|
||||
static InstrType* instr_table = instr_table_prep(
|
||||
instr_table_unprep, XECOUNT(instr_table_unprep), 26, 31);
|
||||
|
||||
|
||||
#undef FLAG
|
||||
#undef INSTRUCTION
|
||||
#undef EMPTY
|
||||
|
||||
|
||||
} // namespace tables
|
||||
} // namespace ppc
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_CPU_PPC_INSTR_TABLE_H_
|
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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/cpu/processor.h>
|
||||
|
||||
#include <llvm/ExecutionEngine/ExecutionEngine.h>
|
||||
#include <llvm/ExecutionEngine/Interpreter.h>
|
||||
#include <llvm/ExecutionEngine/JIT.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/Support/ManagedStatic.h>
|
||||
#include <llvm/Support/TargetSelect.h>
|
||||
|
||||
|
||||
using namespace llvm;
|
||||
using namespace xe;
|
||||
using namespace xe::cpu;
|
||||
using namespace xe::kernel;
|
||||
|
||||
|
||||
Processor::Processor(xe_pal_ref pal, xe_memory_ref memory) {
|
||||
pal_ = xe_pal_retain(pal);
|
||||
memory_ = xe_memory_retain(memory);
|
||||
|
||||
LLVMLinkInInterpreter();
|
||||
LLVMLinkInJIT();
|
||||
InitializeNativeTarget();
|
||||
}
|
||||
|
||||
Processor::~Processor() {
|
||||
// Cleanup all modules.
|
||||
for (std::vector<ExecModule*>::iterator it = modules_.begin();
|
||||
it != modules_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
|
||||
engine_.reset();
|
||||
llvm_shutdown();
|
||||
|
||||
xe_memory_release(memory_);
|
||||
xe_pal_release(pal_);
|
||||
}
|
||||
|
||||
xe_pal_ref Processor::pal() {
|
||||
return xe_pal_retain(pal_);
|
||||
}
|
||||
|
||||
xe_memory_ref Processor::memory() {
|
||||
return xe_memory_retain(memory_);
|
||||
}
|
||||
|
||||
int Processor::Setup() {
|
||||
XEASSERTNULL(engine_);
|
||||
|
||||
if (!llvm_start_multithreaded()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
LLVMContext* dummy_context = new LLVMContext();
|
||||
Module* dummy_module = new Module("dummy", *dummy_context);
|
||||
|
||||
std::string error_message;
|
||||
engine_ = shared_ptr<ExecutionEngine>(
|
||||
ExecutionEngine::create(dummy_module, false, &error_message,
|
||||
CodeGenOpt::Aggressive));
|
||||
if (!engine_) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Processor::PrepareModule(UserModule* user_module,
|
||||
shared_ptr<ExportResolver> export_resolver) {
|
||||
ExecModule* exec_module = new ExecModule(
|
||||
memory_, export_resolver, user_module, engine_);
|
||||
|
||||
if (exec_module->Prepare()) {
|
||||
delete exec_module;
|
||||
return 1;
|
||||
}
|
||||
|
||||
modules_.push_back(exec_module);
|
||||
|
||||
user_module->Dump(export_resolver.get());
|
||||
exec_module->Dump();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Processor::Execute(uint32_t address) {
|
||||
// TODO(benvanik): implement execute.
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Processor::CreateCallback(void (*callback)(void* data), void* data) {
|
||||
// TODO(benvanik): implement callback creation.
|
||||
return 0;
|
||||
}
|
297
src/cpu/sdb.cc
297
src/cpu/sdb.cc
|
@ -13,151 +13,124 @@
|
|||
#include <map>
|
||||
|
||||
|
||||
typedef std::map<uint32_t, xe_sdb_symbol_t> xe_sdb_symbol_map;
|
||||
typedef std::list<xe_sdb_function_t*> xe_sdb_function_queue;
|
||||
|
||||
struct xe_sdb {
|
||||
xe_ref_t ref;
|
||||
|
||||
xe_memory_ref memory;
|
||||
|
||||
size_t function_count;
|
||||
size_t variable_count;
|
||||
xe_sdb_symbol_map *symbols;
|
||||
xe_sdb_function_queue *scan_queue;
|
||||
};
|
||||
using namespace xe;
|
||||
using namespace xe::cpu;
|
||||
using namespace xe::cpu::sdb;
|
||||
using namespace xe::kernel;
|
||||
|
||||
|
||||
int xe_sdb_analyze_module(xe_sdb_ref sdb, xe_module_ref module);
|
||||
|
||||
|
||||
xe_sdb_ref xe_sdb_create(xe_memory_ref memory, xe_module_ref module) {
|
||||
xe_sdb_ref sdb = (xe_sdb_ref)xe_calloc(sizeof(xe_sdb));
|
||||
xe_ref_init((xe_ref)sdb);
|
||||
|
||||
sdb->memory = xe_memory_retain(memory);
|
||||
|
||||
sdb->symbols = new xe_sdb_symbol_map();
|
||||
sdb->scan_queue = new xe_sdb_function_queue();
|
||||
|
||||
XEEXPECTZERO(xe_sdb_analyze_module(sdb, module));
|
||||
|
||||
return sdb;
|
||||
|
||||
XECLEANUP:
|
||||
xe_sdb_release(sdb);
|
||||
return NULL;
|
||||
SymbolDatabase::SymbolDatabase(xe_memory_ref memory, UserModule* module) {
|
||||
memory_ = xe_memory_retain(memory);
|
||||
module_ = module;
|
||||
}
|
||||
|
||||
void xe_sdb_dealloc(xe_sdb_ref sdb) {
|
||||
// TODO(benvanik): release strdup results
|
||||
|
||||
for (xe_sdb_symbol_map::iterator it = sdb->symbols->begin(); it !=
|
||||
sdb->symbols->end(); ++it) {
|
||||
switch (it->second.type) {
|
||||
case 0:
|
||||
delete it->second.function;
|
||||
break;
|
||||
case 1:
|
||||
delete it->second.variable;
|
||||
break;
|
||||
}
|
||||
SymbolDatabase::~SymbolDatabase() {
|
||||
for (SymbolMap::iterator it = symbols_.begin(); it != symbols_.end(); ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
delete sdb->scan_queue;
|
||||
delete sdb->symbols;
|
||||
|
||||
xe_memory_release(sdb->memory);
|
||||
xe_memory_release(memory_);
|
||||
}
|
||||
|
||||
xe_sdb_ref xe_sdb_retain(xe_sdb_ref sdb) {
|
||||
xe_ref_retain((xe_ref)sdb);
|
||||
return sdb;
|
||||
int SymbolDatabase::Analyze() {
|
||||
// Iteratively run passes over the db.
|
||||
// This uses a queue to do a breadth-first search of all accessible
|
||||
// functions. Callbacks and such likely won't be hit.
|
||||
|
||||
const xe_xex2_header_t *header = module_->xex_header();
|
||||
|
||||
// Find __savegprlr_* and __restgprlr_*.
|
||||
FindGplr();
|
||||
|
||||
// Add each import thunk.
|
||||
for (size_t n = 0; n < header->import_library_count; n++) {
|
||||
AddImports(&header->import_libraries[n]);
|
||||
}
|
||||
|
||||
// Add each export root.
|
||||
// TODO(benvanik): exports.
|
||||
// - insert fn or variable
|
||||
// - queue fn
|
||||
|
||||
// Add method hints, if available.
|
||||
// Not all XEXs have these.
|
||||
AddMethodHints();
|
||||
|
||||
// Queue entry point of the application.
|
||||
FunctionSymbol* fn = GetOrInsertFunction(header->exe_entry_point);
|
||||
fn->name = strdup("<entry>");
|
||||
|
||||
// Keep pumping the queue until there's nothing left to do.
|
||||
FlushQueue();
|
||||
|
||||
// Do a pass over the functions to fill holes.
|
||||
FillHoles();
|
||||
FlushQueue();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xe_sdb_release(xe_sdb_ref sdb) {
|
||||
xe_ref_release((xe_ref)sdb, (xe_ref_dealloc_t)xe_sdb_dealloc);
|
||||
}
|
||||
|
||||
xe_sdb_function_t* xe_sdb_insert_function(xe_sdb_ref sdb, uint32_t address) {
|
||||
xe_sdb_function_t *fn = xe_sdb_get_function(sdb, address);
|
||||
FunctionSymbol* SymbolDatabase::GetOrInsertFunction(uint32_t address) {
|
||||
FunctionSymbol* fn = GetFunction(address);
|
||||
if (fn) {
|
||||
return fn;
|
||||
}
|
||||
|
||||
printf("add fn %.8X\n", address);
|
||||
fn = (xe_sdb_function_t*)xe_calloc(sizeof(xe_sdb_function_t));
|
||||
fn = new FunctionSymbol();
|
||||
fn->start_address = address;
|
||||
xe_sdb_symbol_t symbol;
|
||||
symbol.type = 0;
|
||||
symbol.function = fn;
|
||||
sdb->function_count++;
|
||||
sdb->symbols->insert(xe_sdb_symbol_map::value_type(address, symbol));
|
||||
sdb->scan_queue->push_back(fn);
|
||||
function_count_++;
|
||||
symbols_.insert(SymbolMap::value_type(address, fn));
|
||||
scan_queue_.push_back(fn);
|
||||
return fn;
|
||||
}
|
||||
|
||||
xe_sdb_variable_t* xe_sdb_insert_variable(xe_sdb_ref sdb, uint32_t address) {
|
||||
xe_sdb_variable_t *var = xe_sdb_get_variable(sdb, address);
|
||||
VariableSymbol* SymbolDatabase::GetOrInsertVariable(uint32_t address) {
|
||||
VariableSymbol* var = GetVariable(address);
|
||||
if (var) {
|
||||
return var;
|
||||
}
|
||||
|
||||
printf("add var %.8X\n", address);
|
||||
var = (xe_sdb_variable_t*)xe_calloc(sizeof(xe_sdb_variable_t));
|
||||
var = new VariableSymbol();
|
||||
var->address = address;
|
||||
xe_sdb_symbol_t symbol;
|
||||
symbol.type = 1;
|
||||
symbol.variable = var;
|
||||
sdb->variable_count++;
|
||||
sdb->symbols->insert(xe_sdb_symbol_map::value_type(address, symbol));
|
||||
variable_count_++;
|
||||
symbols_.insert(SymbolMap::value_type(address, var));
|
||||
return var;
|
||||
}
|
||||
|
||||
xe_sdb_function_t* xe_sdb_get_function(xe_sdb_ref sdb, uint32_t address) {
|
||||
xe_sdb_symbol_map::iterator i = sdb->symbols->find(address);
|
||||
if (i != sdb->symbols->end() &&
|
||||
i->second.type == 0) {
|
||||
return i->second.function;
|
||||
FunctionSymbol* SymbolDatabase::GetFunction(uint32_t address) {
|
||||
SymbolMap::iterator i = symbols_.find(address);
|
||||
if (i != symbols_.end() && i->second->symbol_type == Symbol::Function) {
|
||||
return static_cast<FunctionSymbol*>(i->second);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xe_sdb_variable_t* xe_sdb_get_variable(xe_sdb_ref sdb, uint32_t address) {
|
||||
xe_sdb_symbol_map::iterator i = sdb->symbols->find(address);
|
||||
if (i != sdb->symbols->end() &&
|
||||
i->second.type == 1) {
|
||||
return i->second.variable;
|
||||
VariableSymbol* SymbolDatabase::GetVariable(uint32_t address) {
|
||||
SymbolMap::iterator i = symbols_.find(address);
|
||||
if (i != symbols_.end() && i->second->symbol_type == Symbol::Variable) {
|
||||
return static_cast<VariableSymbol*>(i->second);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int xe_sdb_get_functions(xe_sdb_ref sdb, xe_sdb_function_t ***out_functions,
|
||||
size_t *out_function_count) {
|
||||
xe_sdb_function_t **functions = (xe_sdb_function_t**)xe_malloc(
|
||||
sizeof(xe_sdb_function_t*) * sdb->function_count);
|
||||
int n = 0;
|
||||
for (xe_sdb_symbol_map::iterator it = sdb->symbols->begin();
|
||||
it != sdb->symbols->end(); ++it) {
|
||||
switch (it->second.type) {
|
||||
case 0:
|
||||
functions[n++] = it->second.function;
|
||||
break;
|
||||
int SymbolDatabase::GetAllFunctions(vector<FunctionSymbol*>& functions) {
|
||||
for (SymbolMap::iterator it = symbols_.begin(); it != symbols_.end(); ++it) {
|
||||
if (it->second->symbol_type == Symbol::Function) {
|
||||
functions.push_back(static_cast<FunctionSymbol*>(it->second));
|
||||
}
|
||||
}
|
||||
*out_functions = functions;
|
||||
*out_function_count = sdb->function_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xe_sdb_dump(xe_sdb_ref sdb) {
|
||||
void SymbolDatabase::Dump() {
|
||||
uint32_t previous = 0;
|
||||
for (xe_sdb_symbol_map::iterator it = sdb->symbols->begin();
|
||||
it != sdb->symbols->end(); ++it) {
|
||||
switch (it->second.type) {
|
||||
case 0:
|
||||
for (SymbolMap::iterator it = symbols_.begin(); it != symbols_.end(); ++it) {
|
||||
switch (it->second->symbol_type) {
|
||||
case Symbol::Function:
|
||||
{
|
||||
xe_sdb_function_t *fn = it->second.function;
|
||||
FunctionSymbol* fn = static_cast<FunctionSymbol*>(it->second);
|
||||
if (previous && (int)(fn->start_address - previous) > 0) {
|
||||
printf("%.8X-%.8X (%5d) h\n", previous, fn->start_address,
|
||||
fn->start_address - previous);
|
||||
|
@ -169,9 +142,9 @@ void xe_sdb_dump(xe_sdb_ref sdb) {
|
|||
previous = fn->end_address + 4;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case Symbol::Variable:
|
||||
{
|
||||
xe_sdb_variable_t *var = it->second.variable;
|
||||
VariableSymbol* var = static_cast<VariableSymbol*>(it->second);
|
||||
printf("%.8X v %s\n", var->address,
|
||||
var->name ? var->name : "<unknown>");
|
||||
}
|
||||
|
@ -180,7 +153,7 @@ void xe_sdb_dump(xe_sdb_ref sdb) {
|
|||
}
|
||||
}
|
||||
|
||||
int xe_sdb_find_gplr(xe_sdb_ref sdb, xe_module_ref module) {
|
||||
int SymbolDatabase::FindGplr() {
|
||||
// Special stack save/restore functions.
|
||||
// __savegprlr_14 to __savegprlr_31
|
||||
// __restgprlr_14 to __restgprlr_31
|
||||
|
@ -232,16 +205,16 @@ int xe_sdb_find_gplr(xe_sdb_ref sdb, xe_module_ref module) {
|
|||
};
|
||||
|
||||
uint32_t gplr_start = 0;
|
||||
const xe_xex2_header_t *header = xe_module_get_xex_header(module);
|
||||
const xe_xex2_header_t* header = module_->xex_header();
|
||||
for (size_t n = 0, i = 0; n < header->section_count; n++) {
|
||||
const xe_xex2_section_t *section = &header->sections[n];
|
||||
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);
|
||||
const xe_xex2_section_t* section = &header->sections[n];
|
||||
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);
|
||||
if (section->info.type == XEX_SECTION_CODE) {
|
||||
gplr_start = xe_memory_search_aligned(
|
||||
sdb->memory, start_address, end_address,
|
||||
memory_, start_address, end_address,
|
||||
code_values, XECOUNT(code_values));
|
||||
if (gplr_start) {
|
||||
break;
|
||||
|
@ -255,81 +228,82 @@ int xe_sdb_find_gplr(xe_sdb_ref sdb, xe_module_ref module) {
|
|||
|
||||
// Add function stubs.
|
||||
char name[32];
|
||||
uint32_t addr = gplr_start;
|
||||
uint32_t address = gplr_start;
|
||||
for (int n = 14; n <= 31; n++) {
|
||||
xesnprintf(name, XECOUNT(name), "__savegprlr_%d", n);
|
||||
xe_sdb_function_t *fn = xe_sdb_insert_function(sdb, addr);
|
||||
FunctionSymbol* fn = GetOrInsertFunction(address);
|
||||
fn->end_address = fn->start_address + (31 - n) * 4 + 2 * 4;
|
||||
fn->name = xestrdup(name);
|
||||
fn->type = kXESDBFunctionUser;
|
||||
addr += 4;
|
||||
fn->type = FunctionSymbol::User;
|
||||
address += 4;
|
||||
}
|
||||
addr = gplr_start + 20 * 4;
|
||||
address = gplr_start + 20 * 4;
|
||||
for (int n = 14; n <= 31; n++) {
|
||||
xesnprintf(name, XECOUNT(name), "__restgprlr_%d", n);
|
||||
xe_sdb_function_t *fn = xe_sdb_insert_function(sdb, addr);
|
||||
FunctionSymbol* fn = GetOrInsertFunction(address);
|
||||
fn->end_address = fn->start_address + (31 - n) * 4 + 3 * 4;
|
||||
fn->name = xestrdup(name);
|
||||
fn->type = kXESDBFunctionUser;
|
||||
addr += 4;
|
||||
fn->type = FunctionSymbol::User;
|
||||
address += 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xe_sdb_add_imports(xe_sdb_ref sdb, xe_module_ref module,
|
||||
const xe_xex2_import_library_t *library) {
|
||||
xe_xex2_ref xex = xe_module_get_xex(module);
|
||||
xe_xex2_import_info_t *import_infos;
|
||||
int SymbolDatabase::AddImports(const xe_xex2_import_library_t* library) {
|
||||
xe_xex2_ref xex = module_->xex();
|
||||
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)) {
|
||||
xe_xex2_release(xex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char name[64];
|
||||
for (size_t n = 0; n < import_info_count; n++) {
|
||||
const xe_xex2_import_info_t *info = &import_infos[n];
|
||||
xe_sdb_variable_t *var = xe_sdb_insert_variable(sdb, info->value_address);
|
||||
const xe_xex2_import_info_t* info = &import_infos[n];
|
||||
VariableSymbol* var = GetOrInsertVariable(info->value_address);
|
||||
// TODO(benvanik): use kernel name
|
||||
xesnprintf(name, XECOUNT(name), "__var_%s_%.3X", library->name,
|
||||
info->ordinal);
|
||||
var->name = strdup(name);
|
||||
if (info->thunk_address) {
|
||||
xe_sdb_function_t *fn = xe_sdb_insert_function(sdb, info->thunk_address);
|
||||
FunctionSymbol* fn = GetOrInsertFunction(info->thunk_address);
|
||||
// TODO(benvanik): use kernel name
|
||||
xesnprintf(name, XECOUNT(name), "__thunk_%s_%.3X", library->name,
|
||||
info->ordinal);
|
||||
fn->end_address = fn->start_address + 16 - 4;
|
||||
fn->name = strdup(name);
|
||||
fn->type = kXESDBFunctionKernel;
|
||||
fn->type = FunctionSymbol::Kernel;
|
||||
}
|
||||
}
|
||||
|
||||
xe_xex2_release(xex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xe_sdb_add_method_hints(xe_sdb_ref sdb, xe_module_ref module) {
|
||||
xe_module_pe_method_info_t *method_infos;
|
||||
int SymbolDatabase::AddMethodHints() {
|
||||
PEMethodInfo* method_infos;
|
||||
size_t method_info_count;
|
||||
if (xe_module_get_method_hints(module, &method_infos, &method_info_count)) {
|
||||
if (module_->GetMethodHints(&method_infos, &method_info_count)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < method_info_count; n++) {
|
||||
xe_module_pe_method_info_t *method_info = &method_infos[n];
|
||||
xe_sdb_function_t *fn = xe_sdb_insert_function(sdb, method_info->address);
|
||||
PEMethodInfo* method_info = &method_infos[n];
|
||||
FunctionSymbol* fn = GetOrInsertFunction(method_info->address);
|
||||
fn->end_address = method_info->address + method_info->total_length - 4;
|
||||
fn->type = kXESDBFunctionUser;
|
||||
fn->type = FunctionSymbol::User;
|
||||
// TODO(benvanik): something with prolog_length?
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xe_sdb_analyze_function(xe_sdb_ref sdb, xe_sdb_function_t *fn) {
|
||||
int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
|
||||
// Ignore functions already analyzed.
|
||||
if (fn->type != kXESDBFunctionUnknown) {
|
||||
if (fn->type != FunctionSymbol::Unknown) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -339,52 +313,21 @@ int xe_sdb_analyze_function(xe_sdb_ref sdb, xe_sdb_function_t *fn) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int xe_sdb_flush_queue(xe_sdb_ref sdb) {
|
||||
while (sdb->scan_queue->size()) {
|
||||
xe_sdb_function_t *fn = sdb->scan_queue->front();
|
||||
sdb->scan_queue->pop_front();
|
||||
if (!xe_sdb_analyze_function(sdb, fn)) {
|
||||
int SymbolDatabase::FlushQueue() {
|
||||
while (scan_queue_.size()) {
|
||||
FunctionSymbol* fn = scan_queue_.front();
|
||||
scan_queue_.pop_front();
|
||||
if (!AnalyzeFunction(fn)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xe_sdb_analyze_module(xe_sdb_ref sdb, xe_module_ref module) {
|
||||
// Iteratively run passes over the db.
|
||||
// This uses a queue to do a breadth-first search of all accessible
|
||||
// functions. Callbacks and such likely won't be hit.
|
||||
|
||||
const xe_xex2_header_t *header = xe_module_get_xex_header(module);
|
||||
|
||||
// Find __savegprlr_* and __restgprlr_*.
|
||||
xe_sdb_find_gplr(sdb, module);
|
||||
|
||||
// Add each import thunk.
|
||||
for (size_t n = 0; n < header->import_library_count; n++) {
|
||||
const xe_xex2_import_library_t *library = &header->import_libraries[n];
|
||||
xe_sdb_add_imports(sdb, module, library);
|
||||
}
|
||||
|
||||
// Add each export root.
|
||||
// TODO(benvanik): exports.
|
||||
// - insert fn or variable
|
||||
// - queue fn
|
||||
|
||||
// Add method hints, if available.
|
||||
// Not all XEXs have these.
|
||||
xe_sdb_add_method_hints(sdb, module);
|
||||
|
||||
// Queue entry point of the application.
|
||||
xe_sdb_function_t *fn = xe_sdb_insert_function(sdb, header->exe_entry_point);
|
||||
fn->name = strdup("<entry>");
|
||||
|
||||
// Keep pumping the queue until there's nothing left to do.
|
||||
xe_sdb_flush_queue(sdb);
|
||||
|
||||
// Do a pass over the functions to fill holes.
|
||||
// TODO(benvanik): hole filling.
|
||||
xe_sdb_flush_queue(sdb);
|
||||
|
||||
int SymbolDatabase::FillHoles() {
|
||||
// TODO(benvanik): scan all holes
|
||||
// If 4b, check if 0x00000000 and ignore (alignment padding)
|
||||
// If 8b, check if first value is within .text and ignore (EH entry)
|
||||
// Else, add to scan queue as function?
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
{
|
||||
'sources': [
|
||||
'codegen.cc',
|
||||
'cpu.cc',
|
||||
'exec_module.cc',
|
||||
'processor.cc',
|
||||
'sdb.cc',
|
||||
],
|
||||
|
||||
|
|
|
@ -10,87 +10,62 @@
|
|||
#include <xenia/kernel/export.h>
|
||||
|
||||
|
||||
bool xe_kernel_export_is_implemented(const xe_kernel_export_t *kernel_export) {
|
||||
if (kernel_export->flags & kXEKernelExportFlagFunction) {
|
||||
if (kernel_export->function_data.impl) {
|
||||
using namespace xe;
|
||||
using namespace xe::kernel;
|
||||
|
||||
|
||||
bool KernelExport::IsImplemented() {
|
||||
switch (type) {
|
||||
case Function:
|
||||
if (function_data.impl) {
|
||||
return true;
|
||||
}
|
||||
} else if (kernel_export->flags & kXEKernelExportFlagVariable) {
|
||||
if (kernel_export->variable_data) {
|
||||
break;
|
||||
case Variable:
|
||||
if (variable_data) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char name[32];
|
||||
xe_kernel_export_t *exports;
|
||||
size_t count;
|
||||
} xe_kernel_export_table_t;
|
||||
#define kXEKernelExportResolverTableMaxCount 8
|
||||
|
||||
|
||||
struct xe_kernel_export_resolver {
|
||||
xe_ref_t ref;
|
||||
|
||||
xe_kernel_export_table_t tables[kXEKernelExportResolverTableMaxCount];
|
||||
size_t table_count;
|
||||
};
|
||||
|
||||
|
||||
xe_kernel_export_resolver_ref xe_kernel_export_resolver_create() {
|
||||
xe_kernel_export_resolver_ref resolver = (xe_kernel_export_resolver_ref)
|
||||
xe_calloc(sizeof(xe_kernel_export_resolver));
|
||||
xe_ref_init((xe_ref)resolver);
|
||||
|
||||
return resolver;
|
||||
ExportResolver::ExportResolver() {
|
||||
}
|
||||
|
||||
void xe_kernel_export_resolver_dealloc(xe_kernel_export_resolver_ref resolver) {
|
||||
ExportResolver::~ExportResolver() {
|
||||
}
|
||||
|
||||
xe_kernel_export_resolver_ref xe_kernel_export_resolver_retain(
|
||||
xe_kernel_export_resolver_ref resolver) {
|
||||
xe_ref_retain((xe_ref)resolver);
|
||||
return resolver;
|
||||
void ExportResolver::RegisterTable(
|
||||
const char* library_name, KernelExport* exports, const size_t count) {
|
||||
ExportTable table;
|
||||
XEIGNORE(xestrcpya(table.name, XECOUNT(table.name), library_name));
|
||||
table.exports = exports;
|
||||
table.count = count;
|
||||
tables_.push_back(table);
|
||||
}
|
||||
|
||||
void xe_kernel_export_resolver_release(xe_kernel_export_resolver_ref resolver) {
|
||||
xe_ref_release((xe_ref)resolver,
|
||||
(xe_ref_dealloc_t)xe_kernel_export_resolver_dealloc);
|
||||
}
|
||||
|
||||
void xe_kernel_export_resolver_register_table(
|
||||
xe_kernel_export_resolver_ref resolver, const char *library_name,
|
||||
xe_kernel_export_t *exports, const size_t count) {
|
||||
XEASSERT(resolver->table_count + 1 < kXEKernelExportResolverTableMaxCount);
|
||||
xe_kernel_export_table_t *table = &resolver->tables[resolver->table_count++];
|
||||
XEIGNORE(xestrcpya(table->name, XECOUNT(table->name), library_name));
|
||||
table->exports = exports;
|
||||
table->count = count;
|
||||
}
|
||||
|
||||
xe_kernel_export_t *xe_kernel_export_resolver_get_by_ordinal(
|
||||
xe_kernel_export_resolver_ref resolver, const char *library_name,
|
||||
const uint32_t ordinal) {
|
||||
// TODO(benvanik): binary search everything.
|
||||
for (size_t n = 0; n < resolver->table_count; n++) {
|
||||
const xe_kernel_export_table_t *table = &resolver->tables[n];
|
||||
if (!xestrcmpa(library_name, table->name)) {
|
||||
// TODO(benvanik): binary search table.
|
||||
for (size_t m = 0; m < table->count; m++) {
|
||||
if (table->exports[m].ordinal == ordinal) {
|
||||
return &table->exports[m];
|
||||
KernelExport* ExportResolver::GetExportByOrdinal(const char* library_name,
|
||||
const uint32_t ordinal) {
|
||||
for (std::vector<ExportTable>::iterator it = tables_.begin();
|
||||
it != tables_.end(); ++it) {
|
||||
if (!xestrcmp(library_name, it->name)) {
|
||||
// TODO(benvanik): binary search?
|
||||
for (size_t n = 0; n < it->count; n++) {
|
||||
if (it->exports[n].ordinal == ordinal) {
|
||||
return &it->exports[n];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xe_kernel_export_t *xe_kernel_export_resolver_get_by_name(
|
||||
xe_kernel_export_resolver_ref resolver, const char *library_name,
|
||||
const char *name) {
|
||||
KernelExport* ExportResolver::GetExportByName(const char* library_name,
|
||||
const char* name) {
|
||||
// TODO(benvanik): lookup by name.
|
||||
XEASSERTALWAYS();
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1,164 +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.h>
|
||||
|
||||
#include "kernel/modules/modules.h"
|
||||
|
||||
|
||||
typedef struct xe_kernel {
|
||||
xe_ref_t ref;
|
||||
|
||||
xe_kernel_options_t options;
|
||||
|
||||
xe_pal_ref pal;
|
||||
xe_memory_ref memory;
|
||||
xe_cpu_ref cpu;
|
||||
xe_kernel_export_resolver_ref export_resolver;
|
||||
|
||||
struct {
|
||||
xe_xam_ref xam;
|
||||
xe_xbdm_ref xbdm;
|
||||
xe_xboxkrnl_ref xboxkrnl;
|
||||
} modules;
|
||||
} xe_kernel_t;
|
||||
|
||||
|
||||
xe_kernel_ref xe_kernel_create(xe_pal_ref pal, xe_cpu_ref cpu,
|
||||
xe_kernel_options_t options) {
|
||||
xe_kernel_ref kernel = (xe_kernel_ref)xe_calloc(sizeof(xe_kernel));
|
||||
xe_ref_init((xe_ref)kernel);
|
||||
|
||||
xe_copy_struct(&kernel->options, &options, sizeof(xe_kernel_options_t));
|
||||
|
||||
kernel->pal = xe_pal_retain(pal);
|
||||
kernel->memory = xe_cpu_get_memory(cpu);
|
||||
kernel->cpu = xe_cpu_retain(cpu);
|
||||
kernel->export_resolver = xe_kernel_export_resolver_create();
|
||||
|
||||
kernel->modules.xam =
|
||||
xe_xam_create(kernel->pal, kernel->memory, kernel->export_resolver);
|
||||
kernel->modules.xbdm =
|
||||
xe_xbdm_create(kernel->pal, kernel->memory, kernel->export_resolver);
|
||||
kernel->modules.xboxkrnl =
|
||||
xe_xboxkrnl_create(kernel->pal, kernel->memory, kernel->export_resolver);
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
void xe_kernel_dealloc(xe_kernel_ref kernel) {
|
||||
xe_xboxkrnl_release(kernel->modules.xboxkrnl);
|
||||
xe_xbdm_release(kernel->modules.xbdm);
|
||||
xe_xam_release(kernel->modules.xam);
|
||||
|
||||
xe_kernel_export_resolver_release(kernel->export_resolver);
|
||||
xe_cpu_release(kernel->cpu);
|
||||
xe_memory_release(kernel->memory);
|
||||
xe_pal_release(kernel->pal);
|
||||
}
|
||||
|
||||
xe_kernel_ref xe_kernel_retain(xe_kernel_ref kernel) {
|
||||
xe_ref_retain((xe_ref)kernel);
|
||||
return kernel;
|
||||
}
|
||||
|
||||
void xe_kernel_release(xe_kernel_ref kernel) {
|
||||
xe_ref_release((xe_ref)kernel, (xe_ref_dealloc_t)xe_kernel_dealloc);
|
||||
}
|
||||
|
||||
xe_pal_ref xe_kernel_get_pal(xe_kernel_ref kernel) {
|
||||
return xe_pal_retain(kernel->pal);
|
||||
}
|
||||
|
||||
xe_memory_ref xe_kernel_get_memory(xe_kernel_ref kernel) {
|
||||
return xe_memory_retain(kernel->memory);
|
||||
}
|
||||
|
||||
xe_cpu_ref xe_kernel_get_cpu(xe_kernel_ref kernel) {
|
||||
return xe_cpu_retain(kernel->cpu);
|
||||
}
|
||||
|
||||
const xechar_t *xe_kernel_get_command_line(xe_kernel_ref kernel) {
|
||||
return kernel->options.command_line;
|
||||
}
|
||||
|
||||
xe_kernel_export_resolver_ref xe_kernel_get_export_resolver(
|
||||
xe_kernel_ref kernel) {
|
||||
return xe_kernel_export_resolver_retain(kernel->export_resolver);
|
||||
}
|
||||
|
||||
xe_module_ref xe_kernel_load_module(xe_kernel_ref kernel,
|
||||
const xechar_t *path) {
|
||||
xe_module_ref module = xe_kernel_get_module(kernel, path);
|
||||
if (module) {
|
||||
return module;
|
||||
}
|
||||
|
||||
// TODO(benvanik): map file from filesystem
|
||||
xe_mmap_ref mmap = xe_mmap_open(kernel->pal, kXEFileModeRead, path, 0, 0);
|
||||
if (!mmap) {
|
||||
return NULL;
|
||||
}
|
||||
void *addr = xe_mmap_get_addr(mmap);
|
||||
size_t length = xe_mmap_get_length(mmap);
|
||||
|
||||
xe_module_options_t options;
|
||||
xe_zero_struct(&options, sizeof(xe_module_options_t));
|
||||
XEIGNORE(xestrcpy(options.path, XECOUNT(options.path), path));
|
||||
module = xe_module_load(kernel->memory, kernel->export_resolver,
|
||||
addr, length, options);
|
||||
|
||||
// TODO(benvanik): retain memory somehow? is it needed?
|
||||
xe_mmap_release(mmap);
|
||||
|
||||
if (!module) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Prepare the module.
|
||||
XEEXPECTZERO(xe_cpu_prepare_module(kernel->cpu, module,
|
||||
kernel->export_resolver));
|
||||
|
||||
// Stash in modules list (takes reference).
|
||||
// TODO(benvanik): stash in list.
|
||||
return xe_module_retain(module);
|
||||
|
||||
XECLEANUP:
|
||||
xe_module_release(module);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xe_kernel_launch_module(xe_kernel_ref kernel, xe_module_ref module) {
|
||||
//const xe_xex2_header_t *xex_header = xe_module_get_xex_header(module);
|
||||
|
||||
// TODO(benvanik): set as main module/etc
|
||||
// xekXexExecutableModuleHandle = xe_module_get_handle(module);
|
||||
|
||||
// XEEXPECTTRUE(XECPUPrepareModule(XEGetCPU(), module->xex, module->pe, module->address_space, module->address_space_size));
|
||||
|
||||
// Setup the heap (and TLS?).
|
||||
// xex_header->exe_heap_size;
|
||||
|
||||
// Launch thread.
|
||||
// XHANDLE thread_handle;
|
||||
// XDWORD thread_id;
|
||||
// XBOOL result = xekExCreateThread(&thread_handle, xex_header->exe_stack_size, &thread_id, NULL, (void*)xex_header->exe_entry_point, NULL, 0);
|
||||
|
||||
// Wait until thread completes.
|
||||
// XLARGE_INTEGER timeout = XINFINITE;
|
||||
// xekNtWaitForSingleObjectEx(thread_handle, TRUE, &timeout);
|
||||
}
|
||||
|
||||
xe_module_ref xe_kernel_get_module(xe_kernel_ref kernel, const xechar_t *path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xe_kernel_unload_module(xe_kernel_ref kernel, xe_module_ref module) {
|
||||
//
|
||||
}
|
|
@ -10,8 +10,8 @@
|
|||
#ifndef XENIA_KERNEL_MODULES_H_
|
||||
#define XENIA_KERNEL_MODULES_H_
|
||||
|
||||
#include "kernel/modules/xam/xam.h"
|
||||
#include "kernel/modules/xbdm/xbdm.h"
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl.h"
|
||||
#include "kernel/modules/xam/xam_module.h"
|
||||
#include "kernel/modules/xbdm/xbdm_module.h"
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl_module.h"
|
||||
|
||||
#endif // XENIA_KERNEL_MODULES_H_
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'xam.cc',
|
||||
'xam_module.cc',
|
||||
],
|
||||
}
|
||||
|
|
|
@ -1,42 +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 "kernel/modules/xam/xam.h"
|
||||
|
||||
#include "kernel/modules/xam/xam_table.h"
|
||||
|
||||
|
||||
struct xe_xam {
|
||||
xe_ref_t ref;
|
||||
};
|
||||
|
||||
|
||||
xe_xam_ref xe_xam_create(
|
||||
xe_pal_ref pal, xe_memory_ref memory,
|
||||
xe_kernel_export_resolver_ref export_resolver) {
|
||||
xe_xam_ref module = (xe_xam_ref)xe_calloc(sizeof(xe_xam));
|
||||
xe_ref_init((xe_ref)module);
|
||||
|
||||
xe_kernel_export_resolver_register_table(export_resolver, "xam.xex",
|
||||
xe_xam_export_table, XECOUNT(xe_xam_export_table));
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
void xe_xam_dealloc(xe_xam_ref module) {
|
||||
}
|
||||
|
||||
xe_xam_ref xe_xam_retain(xe_xam_ref module) {
|
||||
xe_ref_retain((xe_ref)module);
|
||||
return module;
|
||||
}
|
||||
|
||||
void xe_xam_release(xe_xam_ref module) {
|
||||
xe_ref_release((xe_ref)module, (xe_ref_dealloc_t)xe_xam_dealloc);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "kernel/modules/xam/xam_module.h"
|
||||
|
||||
#include "kernel/modules/xam/xam_table.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
using namespace xe::kernel;
|
||||
using namespace xe::kernel::xam;
|
||||
|
||||
|
||||
XamModule::XamModule(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> resolver) :
|
||||
KernelModule(pal, memory, resolver) {
|
||||
resolver->RegisterTable(
|
||||
"xam.xex", xam_export_table, XECOUNT(xam_export_table));
|
||||
}
|
||||
|
||||
XamModule::~XamModule() {
|
||||
}
|
|
@ -14,18 +14,25 @@
|
|||
#include <xenia/core.h>
|
||||
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/kernel_module.h>
|
||||
|
||||
|
||||
struct xe_xam;
|
||||
typedef struct xe_xam* xe_xam_ref;
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xam {
|
||||
|
||||
|
||||
xe_xam_ref xe_xam_create(
|
||||
xe_pal_ref pal, xe_memory_ref memory,
|
||||
xe_kernel_export_resolver_ref export_resolver);
|
||||
class XamModule : public KernelModule {
|
||||
public:
|
||||
XamModule(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> resolver);
|
||||
virtual ~XamModule();
|
||||
};
|
||||
|
||||
xe_xam_ref xe_xam_retain(xe_xam_ref module);
|
||||
void xe_xam_release(xe_xam_ref module);
|
||||
|
||||
} // namespace xam
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_MODULES_XAM_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'xbdm.cc',
|
||||
'xbdm_module.cc',
|
||||
],
|
||||
}
|
||||
|
|
|
@ -1,42 +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 "kernel/modules/xbdm/xbdm.h"
|
||||
|
||||
#include "kernel/modules/xbdm/xbdm_table.h"
|
||||
|
||||
|
||||
struct xe_xbdm {
|
||||
xe_ref_t ref;
|
||||
};
|
||||
|
||||
|
||||
xe_xbdm_ref xe_xbdm_create(
|
||||
xe_pal_ref pal, xe_memory_ref memory,
|
||||
xe_kernel_export_resolver_ref export_resolver) {
|
||||
xe_xbdm_ref module = (xe_xbdm_ref)xe_calloc(sizeof(xe_xbdm));
|
||||
xe_ref_init((xe_ref)module);
|
||||
|
||||
xe_kernel_export_resolver_register_table(export_resolver, "xbdm.exe",
|
||||
xe_xbdm_export_table, XECOUNT(xe_xbdm_export_table));
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
void xe_xbdm_dealloc(xe_xbdm_ref module) {
|
||||
}
|
||||
|
||||
xe_xbdm_ref xe_xbdm_retain(xe_xbdm_ref module) {
|
||||
xe_ref_retain((xe_ref)module);
|
||||
return module;
|
||||
}
|
||||
|
||||
void xe_xbdm_release(xe_xbdm_ref module) {
|
||||
xe_ref_release((xe_ref)module, (xe_ref_dealloc_t)xe_xbdm_dealloc);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "kernel/modules/xbdm/xbdm_module.h"
|
||||
|
||||
#include "kernel/modules/xbdm/xbdm_table.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
using namespace xe::kernel;
|
||||
using namespace xe::kernel::xbdm;
|
||||
|
||||
|
||||
XbdmModule::XbdmModule(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> resolver) :
|
||||
KernelModule(pal, memory, resolver) {
|
||||
resolver->RegisterTable(
|
||||
"xbdm.exe", xbdm_export_table, XECOUNT(xbdm_export_table));
|
||||
}
|
||||
|
||||
XbdmModule::~XbdmModule() {
|
||||
}
|
|
@ -7,25 +7,32 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_MODULES_XBDM_H_
|
||||
#define XENIA_KERNEL_MODULES_XBDM_H_
|
||||
#ifndef XENIA_KERNEL_MODULES_XBDM_MODULE_H_
|
||||
#define XENIA_KERNEL_MODULES_XBDM_MODULE_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/core.h>
|
||||
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/kernel_module.h>
|
||||
|
||||
|
||||
struct xe_xbdm;
|
||||
typedef struct xe_xbdm* xe_xbdm_ref;
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xbdm {
|
||||
|
||||
|
||||
xe_xbdm_ref xe_xbdm_create(
|
||||
xe_pal_ref pal, xe_memory_ref memory,
|
||||
xe_kernel_export_resolver_ref export_resolver);
|
||||
|
||||
xe_xbdm_ref xe_xbdm_retain(xe_xbdm_ref module);
|
||||
void xe_xbdm_release(xe_xbdm_ref module);
|
||||
class XbdmModule : public KernelModule {
|
||||
public:
|
||||
XbdmModule(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> resolver);
|
||||
virtual ~XbdmModule();
|
||||
};
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_MODULES_XBDM_H_
|
||||
} // namespace xbdm
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_MODULES_XBDM_MODULE_H_
|
|
@ -13,14 +13,24 @@
|
|||
#include <xenia/kernel/export.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xbdm {
|
||||
|
||||
|
||||
#define FLAG(t) kXEKernelExportFlag##t
|
||||
|
||||
|
||||
static xe_kernel_export_t xe_xbdm_export_table[] = {
|
||||
static KernelExport xbdm_export_table[] = {
|
||||
};
|
||||
|
||||
|
||||
#undef FLAG
|
||||
|
||||
|
||||
} // namespace xbdm
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_MODULES_XBDM_TABLE_H_
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'xboxkrnl.cc',
|
||||
'xboxkrnl_module.cc',
|
||||
],
|
||||
}
|
||||
|
|
|
@ -1,42 +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 "kernel/modules/xboxkrnl/xboxkrnl.h"
|
||||
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl_table.h"
|
||||
|
||||
|
||||
struct xe_xboxkrnl {
|
||||
xe_ref_t ref;
|
||||
};
|
||||
|
||||
|
||||
xe_xboxkrnl_ref xe_xboxkrnl_create(
|
||||
xe_pal_ref pal, xe_memory_ref memory,
|
||||
xe_kernel_export_resolver_ref export_resolver) {
|
||||
xe_xboxkrnl_ref module = (xe_xboxkrnl_ref)xe_calloc(sizeof(xe_xboxkrnl));
|
||||
xe_ref_init((xe_ref)module);
|
||||
|
||||
xe_kernel_export_resolver_register_table(export_resolver, "xboxkrnl.exe",
|
||||
xe_xboxkrnl_export_table, XECOUNT(xe_xboxkrnl_export_table));
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
void xe_xboxkrnl_dealloc(xe_xboxkrnl_ref module) {
|
||||
}
|
||||
|
||||
xe_xboxkrnl_ref xe_xboxkrnl_retain(xe_xboxkrnl_ref module) {
|
||||
xe_ref_retain((xe_ref)module);
|
||||
return module;
|
||||
}
|
||||
|
||||
void xe_xboxkrnl_release(xe_xboxkrnl_ref module) {
|
||||
xe_ref_release((xe_ref)module, (xe_ref_dealloc_t)xe_xboxkrnl_dealloc);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl_module.h"
|
||||
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl_table.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
using namespace xe::kernel;
|
||||
using namespace xe::kernel::xboxkrnl;
|
||||
|
||||
|
||||
XboxkrnlModule::XboxkrnlModule(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> resolver) :
|
||||
KernelModule(pal, memory, resolver) {
|
||||
resolver->RegisterTable(
|
||||
"xboxkrnl.exe", xboxkrnl_export_table, XECOUNT(xboxkrnl_export_table));
|
||||
}
|
||||
|
||||
XboxkrnlModule::~XboxkrnlModule() {
|
||||
}
|
|
@ -7,25 +7,32 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_H_
|
||||
#define XENIA_KERNEL_MODULES_XBOXKRNL_H_
|
||||
#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_MODULE_H_
|
||||
#define XENIA_KERNEL_MODULES_XBOXKRNL_MODULE_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/core.h>
|
||||
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/kernel_module.h>
|
||||
|
||||
|
||||
struct xe_xboxkrnl;
|
||||
typedef struct xe_xboxkrnl* xe_xboxkrnl_ref;
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
||||
|
||||
xe_xboxkrnl_ref xe_xboxkrnl_create(
|
||||
xe_pal_ref pal, xe_memory_ref memory,
|
||||
xe_kernel_export_resolver_ref export_resolver);
|
||||
|
||||
xe_xboxkrnl_ref xe_xboxkrnl_retain(xe_xboxkrnl_ref module);
|
||||
void xe_xboxkrnl_release(xe_xboxkrnl_ref module);
|
||||
class XboxkrnlModule : public KernelModule {
|
||||
public:
|
||||
XboxkrnlModule(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> resolver);
|
||||
virtual ~XboxkrnlModule();
|
||||
};
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_MODULES_XBOXKRNL_H_
|
||||
} // namespace xboxkrnl
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_MODULES_XBOXKRNL_MODULE_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,139 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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/runtime.h>
|
||||
|
||||
#include "kernel/modules/modules.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
using namespace xe::kernel;
|
||||
|
||||
|
||||
Runtime::Runtime(xe_pal_ref pal, shared_ptr<cpu::Processor> processor,
|
||||
const xechar_t* command_line) {
|
||||
pal_ = xe_pal_retain(pal);
|
||||
memory_ = processor->memory();
|
||||
processor_ = processor;
|
||||
XEIGNORE(xestrcpy(command_line_, XECOUNT(command_line_), command_line));
|
||||
export_resolver_ = shared_ptr<ExportResolver>(new ExportResolver());
|
||||
|
||||
kernel_modules_.push_back(
|
||||
new xboxkrnl::XboxkrnlModule(pal_, memory_, export_resolver_));
|
||||
kernel_modules_.push_back(
|
||||
new xbdm::XbdmModule(pal_, memory_, export_resolver_));
|
||||
kernel_modules_.push_back(
|
||||
new xam::XamModule(pal_, memory_, export_resolver_));
|
||||
}
|
||||
|
||||
Runtime::~Runtime() {
|
||||
for (std::map<const xechar_t*, UserModule*>::iterator it =
|
||||
user_modules_.begin(); it != user_modules_.end(); ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
for (std::vector<KernelModule*>::iterator it = kernel_modules_.begin();
|
||||
it != kernel_modules_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
|
||||
xe_memory_release(memory_);
|
||||
xe_pal_release(pal_);
|
||||
}
|
||||
|
||||
xe_pal_ref Runtime::pal() {
|
||||
return xe_pal_retain(pal_);
|
||||
}
|
||||
|
||||
xe_memory_ref Runtime::memory() {
|
||||
return xe_memory_retain(memory_);
|
||||
}
|
||||
|
||||
shared_ptr<cpu::Processor> Runtime::processor() {
|
||||
return processor_;
|
||||
}
|
||||
|
||||
shared_ptr<ExportResolver> Runtime::export_resolver() {
|
||||
return export_resolver_;
|
||||
}
|
||||
|
||||
const xechar_t* Runtime::command_line() {
|
||||
return command_line_;
|
||||
}
|
||||
|
||||
int Runtime::LoadModule(const xechar_t* path) {
|
||||
if (GetModule(path)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO(benvanik): map file from filesystem
|
||||
xe_mmap_ref mmap = xe_mmap_open(pal_, kXEFileModeRead, path, 0, 0);
|
||||
if (!mmap) {
|
||||
return NULL;
|
||||
}
|
||||
void* addr = xe_mmap_get_addr(mmap);
|
||||
size_t length = xe_mmap_get_length(mmap);
|
||||
|
||||
UserModule* module = new UserModule(memory_);
|
||||
int result_code = module->Load(addr, length, path);
|
||||
|
||||
// TODO(benvanik): retain memory somehow? is it needed?
|
||||
xe_mmap_release(mmap);
|
||||
|
||||
if (result_code) {
|
||||
delete module;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Prepare the module.
|
||||
XEEXPECTZERO(processor_->PrepareModule(module, export_resolver_));
|
||||
|
||||
// Stash in modules list (takes reference).
|
||||
user_modules_.insert(std::pair<const xechar_t*, UserModule*>(path, module));
|
||||
|
||||
return 0;
|
||||
|
||||
XECLEANUP:
|
||||
delete module;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Runtime::LaunchModule(UserModule* user_module) {
|
||||
//const xe_xex2_header_t *xex_header = xe_module_get_xex_header(module);
|
||||
|
||||
// TODO(benvanik): set as main module/etc
|
||||
// xekXexExecutableModuleHandle = xe_module_get_handle(module);
|
||||
|
||||
// XEEXPECTTRUE(XECPUPrepareModule(XEGetCPU(), module->xex, module->pe, module->address_space, module->address_space_size));
|
||||
|
||||
// Setup the heap (and TLS?).
|
||||
// xex_header->exe_heap_size;
|
||||
|
||||
// Launch thread.
|
||||
// XHANDLE thread_handle;
|
||||
// XDWORD thread_id;
|
||||
// XBOOL result = xekExCreateThread(&thread_handle, xex_header->exe_stack_size, &thread_id, NULL, (void*)xex_header->exe_entry_point, NULL, 0);
|
||||
|
||||
// Wait until thread completes.
|
||||
// XLARGE_INTEGER timeout = XINFINITE;
|
||||
// xekNtWaitForSingleObjectEx(thread_handle, TRUE, &timeout);
|
||||
}
|
||||
|
||||
UserModule* Runtime::GetModule(const xechar_t* path) {
|
||||
std::map<const xechar_t*, UserModule*>::iterator it =
|
||||
user_modules_.find(path);
|
||||
if (it != user_modules_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Runtime::UnloadModule(UserModule* user_module) {
|
||||
// TODO(benvanik): unload module
|
||||
XEASSERTALWAYS();
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
{
|
||||
'sources': [
|
||||
'export.cc',
|
||||
'kernel.cc',
|
||||
'module.cc',
|
||||
'runtime.cc',
|
||||
'user_module.cc',
|
||||
'xex2.cc',
|
||||
],
|
||||
|
||||
|
|
|
@ -7,97 +7,72 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <xenia/kernel/module.h>
|
||||
#include <xenia/kernel/user_module.h>
|
||||
|
||||
#include <third_party/pe/pe_image.h>
|
||||
|
||||
|
||||
#define kXEModuleMaxSectionCount 32
|
||||
|
||||
typedef struct xe_module {
|
||||
xe_ref_t ref;
|
||||
|
||||
xe_module_options_t options;
|
||||
xechar_t name[256];
|
||||
|
||||
xe_memory_ref memory;
|
||||
xe_kernel_export_resolver_ref export_resolver;
|
||||
|
||||
uint32_t handle;
|
||||
xe_xex2_ref xex;
|
||||
|
||||
size_t section_count;
|
||||
xe_module_pe_section_t sections[kXEModuleMaxSectionCount];
|
||||
} xe_module_t;
|
||||
using namespace xe;
|
||||
using namespace kernel;
|
||||
|
||||
|
||||
int xe_module_load_pe(xe_module_ref module);
|
||||
UserModule::UserModule(xe_memory_ref memory) {
|
||||
memory_ = xe_memory_retain(memory);
|
||||
xex_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
xe_module_ref xe_module_load(xe_memory_ref memory,
|
||||
xe_kernel_export_resolver_ref export_resolver,
|
||||
const void *addr, const size_t length,
|
||||
xe_module_options_t options) {
|
||||
xe_module_ref module = (xe_module_ref)xe_calloc(sizeof(xe_module));
|
||||
xe_ref_init((xe_ref)module);
|
||||
|
||||
xe_copy_struct(&module->options, &options, sizeof(xe_module_options_t));
|
||||
xechar_t *slash = xestrrchr(options.path, '/');
|
||||
if (slash) {
|
||||
xestrcpy(module->name, XECOUNT(module->name), slash + 1);
|
||||
UserModule::~UserModule() {
|
||||
for (std::vector<PESection*>::iterator it = sections_.begin();
|
||||
it != sections_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
|
||||
module->memory = xe_memory_retain(memory);
|
||||
module->export_resolver = xe_kernel_export_resolver_retain(export_resolver);
|
||||
xe_xex2_release(xex_);
|
||||
xe_memory_release(memory_);
|
||||
}
|
||||
|
||||
int UserModule::Load(const void* addr, const size_t length,
|
||||
const xechar_t* path) {
|
||||
XEIGNORE(xestrcpy(path_, XECOUNT(path_), path));
|
||||
const xechar_t *slash = xestrrchr(path, '/');
|
||||
if (slash) {
|
||||
XEIGNORE(xestrcpy(name_, XECOUNT(name_), slash + 1));
|
||||
}
|
||||
|
||||
xe_xex2_options_t xex_options;
|
||||
module->xex = xe_xex2_load(memory, addr, length, xex_options);
|
||||
XEEXPECTNOTNULL(module->xex);
|
||||
xex_ = xe_xex2_load(memory_, addr, length, xex_options);
|
||||
XEEXPECTNOTNULL(xex_);
|
||||
|
||||
XEEXPECTZERO(xe_module_load_pe(module));
|
||||
XEEXPECTZERO(LoadPE());
|
||||
|
||||
return module;
|
||||
return 0;
|
||||
|
||||
XECLEANUP:
|
||||
xe_module_release(module);
|
||||
return NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void xe_module_dealloc(xe_module_ref module) {
|
||||
xe_kernel_export_resolver_release(module->export_resolver);
|
||||
xe_memory_release(module->memory);
|
||||
const xechar_t* UserModule::path() {
|
||||
return path_;
|
||||
}
|
||||
|
||||
xe_module_ref xe_module_retain(xe_module_ref module) {
|
||||
xe_ref_retain((xe_ref)module);
|
||||
return module;
|
||||
const xechar_t* UserModule::name() {
|
||||
return name_;
|
||||
}
|
||||
|
||||
void xe_module_release(xe_module_ref module) {
|
||||
xe_ref_release((xe_ref)module, (xe_ref_dealloc_t)xe_module_dealloc);
|
||||
uint32_t UserModule::handle() {
|
||||
return handle_;
|
||||
}
|
||||
|
||||
const xechar_t *xe_module_get_path(xe_module_ref module) {
|
||||
return module->options.path;
|
||||
xe_xex2_ref UserModule::xex() {
|
||||
return xe_xex2_retain(xex_);
|
||||
}
|
||||
|
||||
const xechar_t *xe_module_get_name(xe_module_ref module) {
|
||||
return module->name;
|
||||
const xe_xex2_header_t* UserModule::xex_header() {
|
||||
return xe_xex2_get_header(xex_);
|
||||
}
|
||||
|
||||
uint32_t xe_module_get_handle(xe_module_ref module) {
|
||||
return module->handle;
|
||||
}
|
||||
|
||||
xe_xex2_ref xe_module_get_xex(xe_module_ref module) {
|
||||
return xe_xex2_retain(module->xex);
|
||||
}
|
||||
|
||||
const xe_xex2_header_t *xe_module_get_xex_header(xe_module_ref module) {
|
||||
return xe_xex2_get_header(module->xex);
|
||||
}
|
||||
|
||||
void *xe_module_get_proc_address(xe_module_ref module, const uint32_t ordinal) {
|
||||
void* UserModule::GetProcAddress(const uint32_t ordinal) {
|
||||
XEASSERTALWAYS();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -116,10 +91,10 @@ typedef struct IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY_t {
|
|||
};
|
||||
} IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY;
|
||||
|
||||
int xe_module_load_pe(xe_module_ref module) {
|
||||
const xe_xex2_header_t *xex_header = xe_xex2_get_header(module->xex);
|
||||
uint8_t *mem = (uint8_t*)xe_memory_addr(module->memory, 0);
|
||||
const uint8_t *p = mem + xex_header->exe_address;
|
||||
int UserModule::LoadPE() {
|
||||
const xe_xex2_header_t* xex_header = xe_xex2_get_header(xex_);
|
||||
uint8_t* mem = xe_memory_addr(memory_, 0);
|
||||
const uint8_t* p = mem + xex_header->exe_address;
|
||||
|
||||
// Verify DOS signature (MZ).
|
||||
const IMAGE_DOS_HEADER* doshdr = (const IMAGE_DOS_HEADER*)p;
|
||||
|
@ -172,14 +147,6 @@ int xe_module_load_pe(xe_module_ref module) {
|
|||
// IAT Import Address Table ptr
|
||||
//opthdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_X].VirtualAddress / .Size
|
||||
|
||||
// Verify section count not overrun.
|
||||
// NOTE: if this ever asserts, change to a dynamic section list.
|
||||
XEASSERT(filehdr->NumberOfSections <= kXEModuleMaxSectionCount);
|
||||
if (filehdr->NumberOfSections > kXEModuleMaxSectionCount) {
|
||||
return 1;
|
||||
}
|
||||
module->section_count = filehdr->NumberOfSections;
|
||||
|
||||
// Quick scan to determine bounds of sections.
|
||||
size_t upper_address = 0;
|
||||
const IMAGE_SECTION_HEADER* sechdr = IMAGE_FIRST_SECTION(nthdr);
|
||||
|
@ -192,7 +159,7 @@ int xe_module_load_pe(xe_module_ref module) {
|
|||
// Setup/load sections.
|
||||
sechdr = IMAGE_FIRST_SECTION(nthdr);
|
||||
for (size_t n = 0; n < filehdr->NumberOfSections; n++, sechdr++) {
|
||||
xe_module_pe_section_t *section = &module->sections[n];
|
||||
PESection* section = (PESection*)xe_calloc(sizeof(PESection));
|
||||
xe_copy_memory(section->name, sizeof(section->name),
|
||||
sechdr->Name, sizeof(sechdr->Name));
|
||||
section->name[8] = 0;
|
||||
|
@ -201,6 +168,7 @@ int xe_module_load_pe(xe_module_ref module) {
|
|||
section->address = xex_header->exe_address + sechdr->VirtualAddress;
|
||||
section->size = sechdr->Misc.VirtualSize;
|
||||
section->flags = sechdr->Characteristics;
|
||||
sections_.push_back(section);
|
||||
}
|
||||
|
||||
//DumpTLSDirectory(pImageBase, pNTHeader, (PIMAGE_TLS_DIRECTORY32)0);
|
||||
|
@ -208,48 +176,45 @@ int xe_module_load_pe(xe_module_ref module) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
xe_module_pe_section_t *xe_module_get_section(xe_module_ref module,
|
||||
const char *name) {
|
||||
for (size_t n = 0; n < module->section_count; n++) {
|
||||
if (xestrcmpa(module->sections[n].name, name) == 0) {
|
||||
return &module->sections[n];
|
||||
PESection* UserModule::GetSection(const char *name) {
|
||||
for (std::vector<PESection*>::iterator it = sections_.begin();
|
||||
it != sections_.end(); ++it) {
|
||||
if (!xestrcmpa((*it)->name, name)) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int xe_module_get_method_hints(xe_module_ref module,
|
||||
xe_module_pe_method_info_t **out_method_infos,
|
||||
size_t *out_method_info_count) {
|
||||
uint8_t *mem = (uint8_t*)xe_memory_addr(module->memory, 0);
|
||||
int UserModule::GetMethodHints(PEMethodInfo** out_method_infos,
|
||||
size_t* out_method_info_count) {
|
||||
uint8_t* mem = xe_memory_addr(memory_, 0);
|
||||
|
||||
*out_method_infos = NULL;
|
||||
*out_method_info_count = 0;
|
||||
|
||||
const IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY *entry = NULL;
|
||||
const IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY* entry = NULL;
|
||||
|
||||
// Find pdata, which contains the exception handling entries.
|
||||
xe_module_pe_section_t *pdata = xe_module_get_section(module, ".pdata");
|
||||
PESection* pdata = GetSection(".pdata");
|
||||
if (!pdata) {
|
||||
// No exception data to go on.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Resolve.
|
||||
const uint8_t *p = mem + pdata->address;
|
||||
const uint8_t* p = mem + pdata->address;
|
||||
|
||||
// Entry count = pdata size / sizeof(entry).
|
||||
const size_t entry_count =
|
||||
pdata->size / sizeof(IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY);
|
||||
if (entry_count == 0) {
|
||||
size_t entry_count = pdata->size / sizeof(IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY);
|
||||
if (!entry_count) {
|
||||
// Empty?
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate output.
|
||||
xe_module_pe_method_info_t *method_infos =
|
||||
(xe_module_pe_method_info_t*)xe_calloc(
|
||||
entry_count * sizeof(xe_module_pe_method_info_t));
|
||||
PEMethodInfo* method_infos = (PEMethodInfo*)xe_calloc(
|
||||
entry_count * sizeof(PEMethodInfo));
|
||||
XEEXPECTNOTNULL(method_infos);
|
||||
|
||||
// Parse entries.
|
||||
|
@ -258,7 +223,7 @@ int xe_module_get_method_hints(xe_module_ref module,
|
|||
entry = (const IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY*)p;
|
||||
IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY temp_entry;
|
||||
for (size_t n = 0; n < entry_count; n++, entry++) {
|
||||
xe_module_pe_method_info_t *method_info = &method_infos[n];
|
||||
PEMethodInfo* method_info = &method_infos[n];
|
||||
method_info->address = XESWAP32BE(entry->FuncStart);
|
||||
|
||||
// The bitfield needs to be swapped by hand.
|
||||
|
@ -278,12 +243,12 @@ XECLEANUP:
|
|||
return 1;
|
||||
}
|
||||
|
||||
void xe_module_dump(xe_module_ref module) {
|
||||
//const uint8_t *mem = (const uint8_t*)xe_memory_addr(module->memory, 0);
|
||||
const xe_xex2_header_t *header = xe_xex2_get_header(module->xex);
|
||||
void UserModule::Dump(ExportResolver* export_resolver) {
|
||||
//const uint8_t *mem = (const uint8_t*)xe_memory_addr(memory_, 0);
|
||||
const xe_xex2_header_t* header = xe_xex2_get_header(xex_);
|
||||
|
||||
// XEX info.
|
||||
printf("Module %s:\n\n", module->options.path);
|
||||
printf("Module %s:\n\n", path_);
|
||||
printf(" Module Flags: %.8X\n", header->module_flags);
|
||||
printf(" System Flags: %.8X\n", header->system_flags);
|
||||
printf("\n");
|
||||
|
@ -320,11 +285,11 @@ void xe_module_dump(xe_module_ref module) {
|
|||
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);
|
||||
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];
|
||||
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);
|
||||
|
@ -334,14 +299,14 @@ void xe_module_dump(xe_module_ref module) {
|
|||
// Resources.
|
||||
printf("Resources:\n");
|
||||
printf(" %.8X, %db\n", header->resource_info.address,
|
||||
header->resource_info.size);
|
||||
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 xe_xex2_section_t* section = &header->sections[n];
|
||||
const char* type = "UNKNOWN";
|
||||
switch (section->info.type) {
|
||||
case XEX_SECTION_CODE:
|
||||
|
@ -354,10 +319,10 @@ void xe_module_dump(xe_module_ref module) {
|
|||
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);
|
||||
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);
|
||||
|
@ -369,7 +334,8 @@ void xe_module_dump(xe_module_ref module) {
|
|||
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,
|
||||
printf(" %-8s : %d.%d.%d.%d\n",
|
||||
library->name, library->major,
|
||||
library->minor, library->build, library->qfe);
|
||||
}
|
||||
printf("\n");
|
||||
|
@ -377,11 +343,11 @@ void xe_module_dump(xe_module_ref module) {
|
|||
// 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];
|
||||
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(module->xex, library,
|
||||
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",
|
||||
|
@ -398,13 +364,12 @@ void xe_module_dump(xe_module_ref module) {
|
|||
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];
|
||||
const xe_kernel_export_t *kernel_export =
|
||||
xe_kernel_export_resolver_get_by_ordinal(
|
||||
module->export_resolver, library->name, info->ordinal);
|
||||
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 (xe_kernel_export_is_implemented(kernel_export)) {
|
||||
if (kernel_export->IsImplemented()) {
|
||||
impl_count++;
|
||||
}
|
||||
} else {
|
||||
|
@ -423,15 +388,14 @@ void xe_module_dump(xe_module_ref module) {
|
|||
|
||||
// Listing.
|
||||
for (size_t m = 0; m < import_info_count; m++) {
|
||||
const xe_xex2_import_info_t *info = &import_infos[m];
|
||||
const xe_kernel_export_t *kernel_export =
|
||||
xe_kernel_export_resolver_get_by_ordinal(
|
||||
module->export_resolver, library->name, info->ordinal);
|
||||
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 = xe_kernel_export_is_implemented(kernel_export);
|
||||
implemented = kernel_export->IsImplemented();
|
||||
}
|
||||
if (info->thunk_address) {
|
||||
printf(" F %.8X %.8X %.3X (%3d) %s %s\n",
|
|
@ -10,14 +10,18 @@
|
|||
#include <xenia/xenia.h>
|
||||
|
||||
|
||||
using namespace xe;
|
||||
using namespace xe::cpu;
|
||||
using namespace xe::kernel;
|
||||
|
||||
|
||||
int xenia_info(int argc, xechar_t **argv) {
|
||||
int result_code = 1;
|
||||
|
||||
xe_pal_ref pal = NULL;
|
||||
xe_memory_ref memory = NULL;
|
||||
xe_cpu_ref cpu = NULL;
|
||||
xe_kernel_ref kernel = NULL;
|
||||
xe_module_ref module = NULL;
|
||||
shared_ptr<Processor> processor;
|
||||
shared_ptr<Runtime> runtime;
|
||||
|
||||
// TODO(benvanik): real command line parsing.
|
||||
if (argc < 2) {
|
||||
|
@ -36,26 +40,15 @@ int xenia_info(int argc, xechar_t **argv) {
|
|||
memory = xe_memory_create(pal, memory_options);
|
||||
XEEXPECTNOTNULL(memory);
|
||||
|
||||
xe_cpu_options_t cpu_options;
|
||||
xe_zero_struct(&cpu_options, sizeof(cpu_options));
|
||||
cpu = xe_cpu_create(pal, memory, cpu_options);
|
||||
XEEXPECTNOTNULL(cpu);
|
||||
processor = shared_ptr<Processor>(new Processor(pal, memory));
|
||||
XEEXPECTZERO(processor->Setup());
|
||||
|
||||
xe_kernel_options_t kernel_options;
|
||||
xe_zero_struct(&kernel_options, sizeof(kernel_options));
|
||||
kernel = xe_kernel_create(pal, cpu, kernel_options);
|
||||
XEEXPECTNOTNULL(kernel);
|
||||
runtime = shared_ptr<Runtime>(new Runtime(pal, processor, XT("")));
|
||||
|
||||
module = xe_kernel_load_module(kernel, path);
|
||||
XEEXPECTNOTNULL(module);
|
||||
|
||||
xe_module_dump(module);
|
||||
XEEXPECTZERO(runtime->LoadModule(path));
|
||||
|
||||
result_code = 0;
|
||||
XECLEANUP:
|
||||
xe_module_release(module);
|
||||
xe_kernel_release(kernel);
|
||||
xe_cpu_release(cpu);
|
||||
xe_memory_release(memory);
|
||||
xe_pal_release(pal);
|
||||
return result_code;
|
||||
|
|
|
@ -10,52 +10,63 @@
|
|||
#include <xenia/xenia.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
xe_pal_ref pal;
|
||||
xe_memory_ref memory;
|
||||
xe_cpu_ref cpu;
|
||||
xe_kernel_ref kernel;
|
||||
xe_module_ref module;
|
||||
} xenia_run_t;
|
||||
using namespace xe;
|
||||
using namespace xe::cpu;
|
||||
using namespace xe::kernel;
|
||||
|
||||
|
||||
int setup_run(xenia_run_t *run, const xechar_t *path) {
|
||||
xe_pal_options_t pal_options;
|
||||
class Run {
|
||||
public:
|
||||
Run();
|
||||
~Run();
|
||||
|
||||
int Setup(const xechar_t* path);
|
||||
int Launch();
|
||||
|
||||
private:
|
||||
xe_pal_ref pal_;
|
||||
xe_memory_ref memory_;
|
||||
shared_ptr<Processor> processor_;
|
||||
shared_ptr<Runtime> runtime_;
|
||||
UserModule* module_;
|
||||
};
|
||||
|
||||
Run::Run() {
|
||||
}
|
||||
|
||||
Run::~Run() {
|
||||
xe_memory_release(memory_);
|
||||
xe_pal_release(pal_);
|
||||
}
|
||||
|
||||
int Run::Setup(const xechar_t* path) {
|
||||
xe_pal_options_t pal_options;
|
||||
xe_zero_struct(&pal_options, sizeof(pal_options));
|
||||
run->pal = xe_pal_create(pal_options);
|
||||
XEEXPECTNOTNULL(run->pal);
|
||||
pal_ = xe_pal_create(pal_options);
|
||||
XEEXPECTNOTNULL(pal_);
|
||||
|
||||
xe_memory_options_t memory_options;
|
||||
xe_zero_struct(&memory_options, sizeof(memory_options));
|
||||
run->memory = xe_memory_create(run->pal, memory_options);
|
||||
XEEXPECTNOTNULL(run->memory);
|
||||
memory_ = xe_memory_create(pal_, memory_options);
|
||||
XEEXPECTNOTNULL(memory_);
|
||||
|
||||
xe_cpu_options_t cpu_options;
|
||||
xe_zero_struct(&cpu_options, sizeof(cpu_options));
|
||||
run->cpu = xe_cpu_create(run->pal, run->memory, cpu_options);
|
||||
XEEXPECTNOTNULL(run->cpu);
|
||||
processor_ = shared_ptr<Processor>(new Processor(pal_, memory_));
|
||||
XEEXPECTZERO(processor_->Setup());
|
||||
|
||||
xe_kernel_options_t kernel_options;
|
||||
xe_zero_struct(&kernel_options, sizeof(kernel_options));
|
||||
run->kernel = xe_kernel_create(run->pal, run->cpu, kernel_options);
|
||||
XEEXPECTNOTNULL(run->kernel);
|
||||
runtime_ = shared_ptr<Runtime>(new Runtime(pal_, processor_, XT("")));
|
||||
|
||||
run->module = xe_kernel_load_module(run->kernel, path);
|
||||
XEEXPECTNOTNULL(run->module);
|
||||
XEEXPECTZERO(runtime_->LoadModule(path));
|
||||
module_ = runtime_->GetModule(path);
|
||||
|
||||
return 0;
|
||||
|
||||
XECLEANUP:
|
||||
return 1;
|
||||
}
|
||||
|
||||
void destroy_run(xenia_run_t *run) {
|
||||
xe_module_release(run->module);
|
||||
xe_kernel_release(run->kernel);
|
||||
xe_cpu_release(run->cpu);
|
||||
xe_memory_release(run->memory);
|
||||
xe_pal_release(run->pal);
|
||||
xe_free(run);
|
||||
int Run::Launch() {
|
||||
// TODO(benvanik): wait until the module thread exits
|
||||
runtime_->LaunchModule(module_);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xenia_run(int argc, xechar_t **argv) {
|
||||
|
@ -71,24 +82,18 @@ int xenia_run(int argc, xechar_t **argv) {
|
|||
}
|
||||
const xechar_t *path = argv[1];
|
||||
|
||||
xenia_run_t *run = (xenia_run_t*)xe_calloc(sizeof(xenia_run_t));
|
||||
XEEXPECTNOTNULL(run);
|
||||
auto_ptr<Run> run = auto_ptr<Run>(new Run());
|
||||
|
||||
result_code = setup_run(run, path);
|
||||
result_code = run->Setup(path);
|
||||
XEEXPECTZERO(result_code);
|
||||
|
||||
xe_module_dump(run->module);
|
||||
//xe_module_dump(run->module);
|
||||
|
||||
xe_kernel_launch_module(run->kernel, run->module);
|
||||
run->Launch();
|
||||
|
||||
// TODO(benvanik): wait until the module thread exits
|
||||
destroy_run(run);
|
||||
return 0;
|
||||
|
||||
XECLEANUP:
|
||||
if (run) {
|
||||
destroy_run(run);
|
||||
}
|
||||
return result_code;
|
||||
}
|
||||
XE_MAIN_THUNK(xenia_run);
|
||||
|
|
Loading…
Reference in New Issue