Converting everything to C++ cause I'm a masochist.

This commit is contained in:
Ben Vanik 2013-01-20 01:13:59 -08:00
parent 8a5dcbc1dd
commit ca2908db32
47 changed files with 3966 additions and 3760 deletions

View File

@ -10,37 +10,6 @@
#ifndef XENIA_CPU_H_ #ifndef XENIA_CPU_H_
#define XENIA_CPU_H_ #define XENIA_CPU_H_
#include <xenia/common.h> #include <xenia/cpu/processor.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);
#endif // XENIA_CPU_H_ #endif // XENIA_CPU_H_

View File

@ -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_

View File

@ -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_

View File

@ -13,6 +13,12 @@
#include <xenia/common.h> #include <xenia/common.h>
namespace xe {
namespace cpu {
namespace ppc {
// TODO(benvanik): rename these
typedef enum { typedef enum {
kXEPPCInstrFormatI = 0, kXEPPCInstrFormatI = 0,
kXEPPCInstrFormatB = 1, kXEPPCInstrFormatB = 1,
@ -47,12 +53,11 @@ typedef enum {
} xe_ppc_instr_flag_e; } xe_ppc_instr_flag_e;
struct xe_ppc_instr_type; class InstrType;
typedef struct xe_ppc_instr_type xe_ppc_instr_type_t;
typedef struct { typedef struct {
xe_ppc_instr_type_t *type; InstrType* type;
uint32_t address; uint32_t address;
union { union {
@ -110,28 +115,36 @@ typedef struct {
// kXEPPCInstrFormatVX // kXEPPCInstrFormatVX
// kXEPPCInstrFormatVXR // kXEPPCInstrFormatVXR
} data; } data;
} xe_ppc_instr_t; } InstrData;
typedef struct { class Instr {
xe_ppc_instr_t instr; public:
InstrData instr;
// TODO(benvanik): registers changed, special bits, etc // 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); typedef int (*InstrEmitFn)(/* emit context */ Instr* instr);
struct xe_ppc_instr_type { class InstrType {
public:
uint32_t opcode; uint32_t opcode;
uint32_t format; // xe_ppc_instr_format_e uint32_t format; // xe_ppc_instr_format_e
uint32_t type; // xe_ppc_instr_type_e uint32_t type; // xe_ppc_instr_type_e
uint32_t flags; // xe_ppc_instr_flag_e uint32_t flags; // xe_ppc_instr_flag_e
char name[16]; char name[16];
xe_ppc_emit_fn emit; InstrEmitFn emit;
}; };
xe_ppc_instr_type_t *xe_ppc_get_instr_type(uint32_t code); InstrType* GetInstrType(uint32_t code);
int xe_ppc_register_instr_emit(uint32_t code, xe_ppc_emit_fn emit); int RegisterInstrEmit(uint32_t code, InstrEmitFn emit);
} // namespace ppc
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_PPC_INSTR_H_ #endif // XENIA_CPU_PPC_INSTR_H_

View File

@ -13,13 +13,33 @@
#include <xenia/common.h> #include <xenia/common.h>
namespace XE_PPC_SPR { namespace xe {
enum XE_PPC_SPR_e { namespace cpu {
namespace ppc {
namespace SPR {
enum SPR_e {
XER = 1, XER = 1,
LR = 8, LR = 8,
CTR = 9, 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 { typedef struct XECACHEALIGN64 {
@ -88,33 +108,24 @@ typedef struct XECACHEALIGN64 {
// 11 = toward -infinity // 11 = toward -infinity
} bits; } bits;
} fpscr; // Floating-point status and control register } 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 { typedef struct {
xe_ppc_registers_t registers; PpcRegisters registers;
} xe_ppc_state_t; } PpcState;
namespace XE_PPC_FPRF { } // namespace ppc
enum XE_PPC_FPRF_e { } // namespace cpu
QUIET_NAN = 0x00088000, } // namespace xe
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;
}
#endif // XENIA_CPU_PPC_STATE_H_ #endif // XENIA_CPU_PPC_STATE_H_

View File

@ -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_

View File

@ -12,79 +12,123 @@
#include <xenia/core.h> #include <xenia/core.h>
#include <list>
#include <map>
#include <vector> #include <vector>
#include <xenia/kernel/module.h> #include <xenia/kernel/user_module.h>
struct xe_sdb_function; namespace xe {
typedef struct xe_sdb_function xe_sdb_function_t; namespace cpu {
struct xe_sdb_variable; namespace sdb {
typedef struct xe_sdb_variable xe_sdb_variable_t;
typedef struct { class FunctionSymbol;
class VariableSymbol;
class FunctionCall {
public:
uint32_t address; uint32_t address;
xe_sdb_function_t *source; FunctionSymbol* source;
xe_sdb_function_t *target; FunctionSymbol* target;
} xe_sdb_function_call_t; };
typedef struct { class VariableAccess {
public:
uint32_t address; uint32_t address;
xe_sdb_function_t *source; FunctionSymbol* source;
xe_sdb_variable_t *target; VariableSymbol* target;
} xe_sdb_variable_access_t; };
typedef enum { class Symbol {
kXESDBFunctionUnknown = 0, public:
kXESDBFunctionKernel = 1, enum SymbolType {
kXESDBFunctionUser = 2, Function = 0,
} xe_sdb_function_type; 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() {}
struct xe_sdb_function {
uint32_t start_address; uint32_t start_address;
uint32_t end_address; uint32_t end_address;
char *name; char *name;
xe_sdb_function_type type; FunctionType type;
uint32_t flags; uint32_t flags;
std::vector<xe_sdb_function_call_t*> incoming_calls; vector<FunctionCall*> incoming_calls;
std::vector<xe_sdb_function_call_t*> outgoing_calls; vector<FunctionCall*> outgoing_calls;
std::vector<xe_sdb_variable_access_t*> variable_accesses; vector<VariableAccess*> variable_accesses;
}; };
struct xe_sdb_variable { class VariableSymbol : public Symbol {
public:
VariableSymbol() : Symbol(Variable) {}
virtual ~VariableSymbol() {}
uint32_t address; uint32_t address;
char *name; char *name;
}; };
typedef struct {
int type; class SymbolDatabase {
union { public:
xe_sdb_function_t* function; SymbolDatabase(xe_memory_ref memory, kernel::UserModule* user_module);
xe_sdb_variable_t* variable; ~SymbolDatabase();
};
} xe_sdb_symbol_t; 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; } // namespace sdb
typedef struct xe_sdb* xe_sdb_ref; } // namespace cpu
} // namespace xe
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);
#endif // XENIA_CPU_SDB_H_ #endif // XENIA_CPU_SDB_H_

View File

@ -10,42 +10,6 @@
#ifndef XENIA_KERNEL_H_ #ifndef XENIA_KERNEL_H_
#define XENIA_KERNEL_H_ #define XENIA_KERNEL_H_
#include <xenia/common.h> #include <xenia/kernel/runtime.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);
#endif // XENIA_KERNEL_H_ #endif // XENIA_KERNEL_H_

View File

@ -12,16 +12,24 @@
#include <xenia/core.h> #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 void (*xe_kernel_export_fn)();
typedef struct { class KernelExport {
public:
enum ExportType {
Function = 0,
Variable = 1,
};
uint32_t ordinal; uint32_t ordinal;
ExportType type;
uint32_t flags; uint32_t flags;
char signature[16]; char signature[16];
char name[96]; char name[96];
@ -39,38 +47,46 @@ typedef struct {
xe_kernel_export_fn shim; xe_kernel_export_fn shim;
} function_data; } 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, \ ordinal, \
KernelExport::type, \
flags, \ flags, \
#signature, \ #signature, \
#name, \ #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);
struct xe_kernel_export_resolver; KernelExport* GetExportByOrdinal(const char* library_name,
typedef struct xe_kernel_export_resolver* xe_kernel_export_resolver_ref;
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); const uint32_t ordinal);
xe_kernel_export_t *xe_kernel_export_resolver_get_by_name( KernelExport* GetExportByName(const char* library_name, const char* name);
xe_kernel_export_resolver_ref resolver, const char *library_name,
const char *name); private:
class ExportTable {
public:
char name[32];
KernelExport* exports;
size_t count;
};
std::vector<ExportTable> tables_;
};
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_EXPORT_H_ #endif // XENIA_KERNEL_EXPORT_H_

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -14,6 +14,14 @@
#include <xenia/platform_includes.h> #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 XE_EMPTY_MACRO do { } while(0)
#define XEUNREFERENCED(expr) (void)(expr) #define XEUNREFERENCED(expr) (void)(expr)

View File

@ -7,8 +7,9 @@
****************************************************************************** ******************************************************************************
*/ */
#include "cpu/codegen.h" #include <xenia/cpu/codegen.h>
#include <llvm/DIBuilder.h>
#include <llvm/Linker.h> #include <llvm/Linker.h>
#include <llvm/PassManager.h> #include <llvm/PassManager.h>
#include <llvm/DebugInfo.h> #include <llvm/DebugInfo.h>
@ -17,90 +18,90 @@
#include <llvm/IR/DataLayout.h> #include <llvm/IR/DataLayout.h>
#include <llvm/IR/DerivedTypes.h> #include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/IRBuilder.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.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h> #include <llvm/Transforms/IPO/PassManagerBuilder.h>
#include <xenia/cpu/ppc.h> #include <xenia/cpu/ppc.h>
using namespace llvm; 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); CodegenContext::CodegenContext(
void xe_codegen_add_missing_import( xe_memory_ref memory, ExportResolver* export_resolver,
xe_codegen_ctx_t *ctx, const xe_xex2_import_library_t *library, UserModule* module, SymbolDatabase* sdb,
const xe_xex2_import_info_t* info, xe_kernel_export_t *kernel_export); LLVMContext* context, Module* gen_module) {
void xe_codegen_add_import( memory_ = xe_memory_retain(memory);
xe_codegen_ctx_t *ctx, const xe_xex2_import_library_t *library, export_resolver_ = export_resolver;
const xe_xex2_import_info_t* info, xe_kernel_export_t *kernel_export); module_ = module;
void xe_codegen_add_function(xe_codegen_ctx_t *ctx, xe_sdb_function_t *fn); sdb_ = sdb;
void xe_codegen_optimize(Module *m, Function *fn); context_ = context;
gen_module_ = gen_module;
}
CodegenContext::~CodegenContext() {
xe_memory_release(memory_);
}
llvm::Module *xe_codegen(xe_codegen_ctx_t *ctx, int CodegenContext::GenerateModule() {
xe_codegen_options_t options) {
LLVMContext& context = *ctx->context;
std::string error_message; 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. // Setup a debug info builder.
// This is used when creating any debug info. We may want to go more // This is used when creating any debug info. We may want to go more
// fine grained than this, but for now it's something. // fine grained than this, but for now it's something.
xechar_t dir[2048]; 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, '/'); xechar_t *slash = xestrrchr(dir, '/');
if (slash) { if (slash) {
*(slash + 1) = 0; *(slash + 1) = 0;
} }
ctx->di_builder = new DIBuilder(*m); di_builder_ = new DIBuilder(*gen_module_);
ctx->di_builder->createCompileUnit( di_builder_->createCompileUnit(
0, 0,
StringRef(xe_module_get_name(ctx->module)), StringRef(module_->name()),
StringRef(dir), StringRef(dir),
StringRef("xenia"), StringRef("xenia"),
true, true,
StringRef(""), StringRef(""),
0); 0);
ctx->cu = (MDNode*)ctx->di_builder->getCU(); cu_ = (MDNode*)di_builder_->getCU();
// Add import thunks/etc. // Add import thunks/etc.
xe_codegen_add_imports(ctx); AddImports();
// Add export wrappers. // Add export wrappers.
// //
// Add all functions. // Add all functions.
xe_sdb_function_t **functions; std::vector<FunctionSymbol*> functions;
size_t function_count; if (!sdb_->GetAllFunctions(functions)) {
if (!xe_sdb_get_functions(ctx->sdb, &functions, &function_count)) { for (std::vector<FunctionSymbol*>::iterator it = functions.begin();
for (size_t n = 0; n < function_count; n++) { it != functions.end(); ++it) {
// kernel functions will be handled by the add imports handlers. // kernel functions will be handled by the add imports handlers.
if (functions[n]->type == kXESDBFunctionUser) { if ((*it)->type == FunctionSymbol::User) {
xe_codegen_add_function(ctx, functions[n]); 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) { void CodegenContext::AddImports() {
xe_xex2_ref xex = xe_module_get_xex(ctx->module); xe_xex2_ref xex = module_->xex();
const xe_xex2_header_t *header = xe_xex2_get_header(xex); const xe_xex2_header_t* header = xe_xex2_get_header(xex);
for (size_t n = 0; n < header->import_library_count; 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; xe_xex2_import_info_t* import_infos;
size_t import_info_count; size_t import_info_count;
@ -108,16 +109,15 @@ void xe_codegen_add_imports(xe_codegen_ctx_t *ctx) {
&import_infos, &import_info_count)); &import_infos, &import_info_count));
for (size_t i = 0; i < import_info_count; i++) { for (size_t i = 0; i < import_info_count; i++) {
const xe_xex2_import_info_t *info = &import_infos[i]; const xe_xex2_import_info_t* info = &import_infos[i];
xe_kernel_export_t *kernel_export = KernelExport* kernel_export = export_resolver_->GetExportByOrdinal(
xe_kernel_export_resolver_get_by_ordinal( library->name, info->ordinal);
ctx->export_resolver, library->name, info->ordinal); if (!kernel_export || !kernel_export->IsImplemented()) {
if (!kernel_export || !xe_kernel_export_is_implemented(kernel_export)) {
// Not implemented or known. // Not implemented or known.
xe_codegen_add_missing_import(ctx, library, info, kernel_export); AddMissingImport(library, info, kernel_export);
} else { } else {
// Implemented. // 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); xe_xex2_release(xex);
} }
void xe_codegen_add_missing_import( void CodegenContext::AddMissingImport(
xe_codegen_ctx_t *ctx, const xe_xex2_import_library_t *library, const xe_xex2_import_library_t* library,
const xe_xex2_import_info_t* info, xe_kernel_export_t *kernel_export) { const xe_xex2_import_info_t* info, KernelExport* kernel_export) {
Module *m = ctx->gen_module; Module* m = gen_module_;
LLVMContext& context = m->getContext(); LLVMContext& context = m->getContext();
char name[128]; char name[128];
@ -149,11 +149,11 @@ void xe_codegen_add_missing_import(
AttributeSet attrs = AttributeSet::get(context, awi); AttributeSet attrs = AttributeSet::get(context, awi);
std::vector<Type*> args; 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); ArrayRef<Type*>(args), false);
Function *f = cast<Function>(m->getOrInsertFunction( Function* f = cast<Function>(m->getOrInsertFunction(
StringRef(name), ft, attrs)); StringRef(name), ft, attrs));
f->setCallingConv(CallingConv::C); f->setCallingConv(CallingConv::C);
f->setVisibility(GlobalValue::DefaultVisibility); f->setVisibility(GlobalValue::DefaultVisibility);
@ -161,10 +161,10 @@ void xe_codegen_add_missing_import(
// TODO(benvanik): log errors. // TODO(benvanik): log errors.
BasicBlock* block = BasicBlock::Create(context, "entry", f); BasicBlock* block = BasicBlock::Create(context, "entry", f);
IRBuilder<> builder(block); IRBuilder<> builder(block);
Value *tmp = builder.getInt32(0); Value* tmp = builder.getInt32(0);
builder.CreateRet(tmp); builder.CreateRet(tmp);
xe_codegen_optimize(m, f); OptimizeFunction(m, f);
//GlobalAlias *alias = new GlobalAlias(f->getType(), GlobalValue::InternalLinkage, name, f, m); //GlobalAlias *alias = new GlobalAlias(f->getType(), GlobalValue::InternalLinkage, name, f, m);
// printf(" F %.8X %.8X %.3X (%3d) %s %s\n", // printf(" F %.8X %.8X %.3X (%3d) %s %s\n",
@ -177,17 +177,17 @@ void xe_codegen_add_missing_import(
} }
} }
void xe_codegen_add_import( void CodegenContext::AddPresentImport(
xe_codegen_ctx_t *ctx, const xe_xex2_import_library_t *library, const xe_xex2_import_library_t* library,
const xe_xex2_import_info_t* info, xe_kernel_export_t *kernel_export) { const xe_xex2_import_info_t* info, KernelExport* kernel_export) {
// Module *m = ctx->gen_module; // Module *m = gen_module_;
// LLVMContext& context = m->getContext(); // LLVMContext& context = m->getContext();
// TODO(benvanik): add import thunk code. // TODO(benvanik): add import thunk code.
} }
void xe_codegen_add_function(xe_codegen_ctx_t *ctx, xe_sdb_function_t *fn) { void CodegenContext::AddFunction(FunctionSymbol* fn) {
Module *m = ctx->gen_module; Module* m = gen_module_;
LLVMContext& context = m->getContext(); LLVMContext& context = m->getContext();
AttributeWithIndex awi[] = { 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); AttributeSet attrs = AttributeSet::get(context, awi);
std::vector<Type*> args; std::vector<Type*> args;
Type *return_type = Type::getInt32Ty(context); Type* return_type = Type::getInt32Ty(context);
char name[64]; char name[64];
char *pname = name; char* pname = name;
if (fn->name) { if (fn->name) {
pname = fn->name; pname = fn->name;
} else { } else {
xesnprintfa(name, XECOUNT(name), "fn_%.8X", fn->start_address); 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); ArrayRef<Type*>(args), false);
Function *f = cast<Function>(m->getOrInsertFunction( Function* f = cast<Function>(
StringRef(pname), ft, attrs)); m->getOrInsertFunction(StringRef(pname), ft, attrs));
f->setCallingConv(CallingConv::C); f->setCallingConv(CallingConv::C);
f->setVisibility(GlobalValue::DefaultVisibility); 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); BasicBlock* block = BasicBlock::Create(context, "entry", f);
IRBuilder<> builder(block); IRBuilder<> builder(block);
//builder.SetCurrentDebugLocation(DebugLoc::get(fn->start_address >> 8, fn->start_address & 0xFF, ctx->cu)); //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); builder.CreateRet(tmp);
// i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname))); // i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname)));
uint8_t *mem = xe_memory_addr(ctx->memory, 0); uint8_t* mem = xe_memory_addr(memory_, 0);
uint32_t *pc = (uint32_t*)(mem + fn->start_address); uint32_t* pc = (uint32_t*)(mem + fn->start_address);
uint32_t pcdata = XEGETUINT32BE(pc); uint32_t pcdata = XEGETUINT32BE(pc);
printf("data %.8X %.8X\n", fn->start_address, pcdata); 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) { if (instr_type) {
printf("instr %.8X %s\n", fn->start_address, instr_type->name); printf("instr %.8X %s\n", fn->start_address, instr_type->name);
xe_ppc_instr_t instr; // xe_ppc_instr_t instr;
instr.data.code = pcdata; // instr.data.code = pcdata;
printf("%d %d\n", instr.data.XFX.D, instr.data.XFX.spr); // printf("%d %d\n", instr.data.XFX.D, instr.data.XFX.spr);
} else { } else {
printf("instr not found\n"); 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. // Run the optimizer on the function.
// Doing this here keeps the size of the IR small and speeds up the later // Doing this here keeps the size of the IR small and speeds up the later
// passes. // 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); FunctionPassManager pm(m);
PassManagerBuilder pmb; PassManagerBuilder pmb;
pmb.OptLevel = 3; pmb.OptLevel = 3;

View File

@ -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_

View File

@ -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;
}

201
src/cpu/exec_module.cc Normal file
View File

@ -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();
}

View File

@ -9,46 +9,49 @@
#include <xenia/cpu/ppc/instr.h> #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) { using namespace xe::cpu::ppc;
xe_ppc_instr_type_t *slot = NULL;
InstrType* xe::cpu::ppc::GetInstrType(uint32_t code) {
InstrType* slot = NULL;
switch (code >> 26) { switch (code >> 26) {
case 4: case 4:
// Opcode = 4, index = bits 5-0 (6) // 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; break;
case 19: case 19:
// Opcode = 19, index = bits 10-1 (10) // 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; break;
case 30: case 30:
// Opcode = 30, index = bits 5-1 (5) // 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; break;
case 31: case 31:
// Opcode = 31, index = bits 10-1 (10) // 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; break;
case 58: case 58:
// Opcode = 58, index = bits 1-0 (2) // 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; break;
case 59: case 59:
// Opcode = 59, index = bits 5-1 (5) // 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; break;
case 62: case 62:
// Opcode = 62, index = bits 1-0 (2) // 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; break;
case 63: case 63:
// Opcode = 63, index = bits 10-1 (10) // 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; break;
default: default:
slot = &xe_ppc_instr_table[XESELECTBITS(code, 26, 31)]; slot = &xe::cpu::ppc::tables::instr_table[XESELECTBITS(code, 26, 31)];
break; break;
} }
if (!slot || !slot->opcode) { if (!slot || !slot->opcode) {
@ -57,8 +60,8 @@ xe_ppc_instr_type_t *xe_ppc_get_instr_type(uint32_t code) {
return slot; return slot;
} }
int xe_ppc_register_instr_emit(uint32_t code, xe_ppc_emit_fn emit) { int xe::cpu::ppc::RegisterInstrEmit(uint32_t code, InstrEmitFn emit) {
xe_ppc_instr_type_t *instr_type = xe_ppc_get_instr_type(code); InstrType* instr_type = GetInstrType(code);
if (!instr_type) { if (!instr_type) {
return 1; return 1;
} }

View File

@ -13,28 +13,47 @@
#include <xenia/cpu/ppc/instr.h> #include <xenia/cpu/ppc/instr.h>
typedef struct { namespace xe {
llvm::LLVMContext *context; namespace cpu {
llvm::Module *module; 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. // Address of the instruction being generated.
uint32_t cia; uint32_t cia;
llvm::Value *get_cia(); private:
void set_nia(llvm::Value *value); //
llvm::Value *get_spr(uint32_t n); };
void set_spr(uint32_t n, llvm::Value *value);
llvm::Value *get_cr();
void set_cr(llvm::Value *value);
llvm::Value *get_gpr(uint32_t n); } // namespace ppc
void set_gpr(uint32_t n, llvm::Value *value); } // namespace cpu
} // namespace xe
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;
#endif // XENIA_CPU_PPC_INSTR_CTX_H_ #endif // XENIA_CPU_PPC_INSTR_CTX_H_

View File

@ -13,11 +13,16 @@
#include <xenia/cpu/ppc/instr.h> #include <xenia/cpu/ppc/instr.h>
static xe_ppc_instr_type_t *xe_ppc_instr_table_prep( namespace xe {
xe_ppc_instr_type_t *unprep, int unprep_count, int a, int b) { 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); int prep_count = pow(2, b - a + 1);
xe_ppc_instr_type_t *prep = (xe_ppc_instr_type_t*)xe_calloc( InstrType* prep = (InstrType*)xe_calloc(prep_count * sizeof(InstrType));
prep_count * sizeof(xe_ppc_instr_type_t));
for (int n = 0; n < unprep_count; n++) { for (int n = 0; n < unprep_count; n++) {
int ordinal = XESELECTBITS(unprep[n].opcode, a, b); int ordinal = XESELECTBITS(unprep[n].opcode, a, b);
prep[ordinal] = unprep[n]; 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 // PowerISA_V2.06B_V2_PUBLIC.pdf
// Opcode = 4, index = bits 5-0 (6) // 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 // TODO: all of the vector ops
INSTRUCTION(vperm, 0x1000002B, VA , General , 0), INSTRUCTION(vperm, 0x1000002B, VA , General , 0),
}; };
static xe_ppc_instr_type_t *xe_ppc_instr_table_4 = xe_ppc_instr_table_prep( static InstrType* instr_table_4 = instr_table_prep(
xe_ppc_instr_table_4_unprep, XECOUNT(xe_ppc_instr_table_4_unprep), 0, 5); instr_table_4_unprep, XECOUNT(instr_table_4_unprep), 0, 5);
// Opcode = 19, index = bits 10-1 (10) // 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(mcrf, 0x4C000000, XL , General , 0),
INSTRUCTION(bclrx, 0x4C000020, XL , BranchCond , 0), INSTRUCTION(bclrx, 0x4C000020, XL , BranchCond , 0),
INSTRUCTION(crnor, 0x4C000042, XL , General , 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(cror, 0x4C000382, XL , General , 0),
INSTRUCTION(bcctrx, 0x4C000420, XL , BranchCond , 0), INSTRUCTION(bcctrx, 0x4C000420, XL , BranchCond , 0),
}; };
static xe_ppc_instr_type_t *xe_ppc_instr_table_19 = xe_ppc_instr_table_prep( static InstrType* instr_table_19 = instr_table_prep(
xe_ppc_instr_table_19_unprep, XECOUNT(xe_ppc_instr_table_19_unprep), 1, 10); instr_table_19_unprep, XECOUNT(instr_table_19_unprep), 1, 10);
// Opcode = 30, index = bits 5-1 (5) // 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(rldiclx, 0x78000000, MD , General , 0),
INSTRUCTION(rldicrx, 0x78000004, MD , General , 0), INSTRUCTION(rldicrx, 0x78000004, MD , General , 0),
INSTRUCTION(rldicx, 0x78000008, 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(rldclx, 0x78000010, MDS, General , 0),
INSTRUCTION(rldcrx, 0x78000012, 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( static InstrType* instr_table_30 = instr_table_prep(
xe_ppc_instr_table_30_unprep, XECOUNT(xe_ppc_instr_table_30_unprep), 1, 5); instr_table_30_unprep, XECOUNT(instr_table_30_unprep), 1, 5);
// Opcode = 31, index = bits 10-1 (10) // 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(cmp, 0x7C000000, X , General , 0),
INSTRUCTION(tw, 0x7C000008, X , General , 0), INSTRUCTION(tw, 0x7C000008, X , General , 0),
INSTRUCTION(lvsl, 0x7C00000C, 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(extswx, 0x7C0007B4, X , General , 0),
INSTRUCTION(dcbz, 0x7C0007EC, X , General , 0), // 0x7C2007EC = DCBZ128 INSTRUCTION(dcbz, 0x7C0007EC, X , General , 0), // 0x7C2007EC = DCBZ128
}; };
static xe_ppc_instr_type_t *xe_ppc_instr_table_31 = xe_ppc_instr_table_prep( static InstrType* instr_table_31 = instr_table_prep(
xe_ppc_instr_table_31_unprep, XECOUNT(xe_ppc_instr_table_31_unprep), 1, 10); instr_table_31_unprep, XECOUNT(instr_table_31_unprep), 1, 10);
// Opcode = 58, index = bits 1-0 (2) // 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(ld, 0xE8000000, DS , General , 0),
INSTRUCTION(ldu, 0xE8000001, DS , General , 0), INSTRUCTION(ldu, 0xE8000001, DS , General , 0),
INSTRUCTION(lwa, 0xE8000002, 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( static InstrType* instr_table_58 = instr_table_prep(
xe_ppc_instr_table_58_unprep, XECOUNT(xe_ppc_instr_table_58_unprep), 0, 1); instr_table_58_unprep, XECOUNT(instr_table_58_unprep), 0, 1);
// Opcode = 59, index = bits 5-1 (5) // 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(fdivsx, 0xEC000024, A , General , 0),
INSTRUCTION(fsubsx, 0xEC000028, A , General , 0), INSTRUCTION(fsubsx, 0xEC000028, A , General , 0),
INSTRUCTION(faddsx, 0xEC00002A, 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(fnmsubsx, 0xEC00003C, A , General , 0),
INSTRUCTION(fnmaddsx, 0xEC00003E, 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( static InstrType* instr_table_59 = instr_table_prep(
xe_ppc_instr_table_59_unprep, XECOUNT(xe_ppc_instr_table_59_unprep), 1, 5); instr_table_59_unprep, XECOUNT(instr_table_59_unprep), 1, 5);
// Opcode = 62, index = bits 1-0 (2) // 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(std, 0xF8000000, DS , General , 0),
INSTRUCTION(stdu, 0xF8000001, 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( static InstrType* instr_table_62 = instr_table_prep(
xe_ppc_instr_table_62_unprep, XECOUNT(xe_ppc_instr_table_62_unprep), 0, 1); instr_table_62_unprep, XECOUNT(instr_table_62_unprep), 0, 1);
// Opcode = 63, index = bits 10-1 (10) // 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(fcmpu, 0xFC000000, X , General , 0),
INSTRUCTION(frspx, 0xFC000018, X , General , 0), INSTRUCTION(frspx, 0xFC000018, X , General , 0),
INSTRUCTION(fctiwx, 0xFC00001C, 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(fctidzx, 0xFC00065E, X , General , 0),
INSTRUCTION(fcfidx, 0xFC00069C, 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( static InstrType* instr_table_63 = instr_table_prep(
xe_ppc_instr_table_63_unprep, XECOUNT(xe_ppc_instr_table_63_unprep), 1, 10); instr_table_63_unprep, XECOUNT(instr_table_63_unprep), 1, 10);
// Main table, index = bits 31-26 (6) : (code >> 26) // 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(tdi, 0x08000000, D , General , 0),
INSTRUCTION(twi, 0x0C000000, D , General , 0), INSTRUCTION(twi, 0x0C000000, D , General , 0),
INSTRUCTION(mulli, 0x1C000000, 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(stfd, 0xD8000000, D , General , 0),
INSTRUCTION(stfdu, 0xDC000000, D , General , 0), INSTRUCTION(stfdu, 0xDC000000, D , General , 0),
}; };
static xe_ppc_instr_type_t *xe_ppc_instr_table = xe_ppc_instr_table_prep( static InstrType* instr_table = instr_table_prep(
xe_ppc_instr_table_unprep, XECOUNT(xe_ppc_instr_table_unprep), 26, 31); instr_table_unprep, XECOUNT(instr_table_unprep), 26, 31);
#undef FLAG #undef FLAG
#undef INSTRUCTION #undef INSTRUCTION
#undef EMPTY #undef EMPTY
} // namespace tables
} // namespace ppc
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_PPC_INSTR_TABLE_H_ #endif // XENIA_CPU_PPC_INSTR_TABLE_H_

105
src/cpu/processor.cc Normal file
View File

@ -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;
}

View File

@ -13,151 +13,124 @@
#include <map> #include <map>
typedef std::map<uint32_t, xe_sdb_symbol_t> xe_sdb_symbol_map; using namespace xe;
typedef std::list<xe_sdb_function_t*> xe_sdb_function_queue; using namespace xe::cpu;
using namespace xe::cpu::sdb;
struct xe_sdb { using namespace xe::kernel;
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;
};
int xe_sdb_analyze_module(xe_sdb_ref sdb, xe_module_ref module); SymbolDatabase::SymbolDatabase(xe_memory_ref memory, UserModule* module) {
memory_ = xe_memory_retain(memory);
module_ = 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;
} }
void xe_sdb_dealloc(xe_sdb_ref sdb) { SymbolDatabase::~SymbolDatabase() {
// TODO(benvanik): release strdup results for (SymbolMap::iterator it = symbols_.begin(); it != symbols_.end(); ++it) {
delete it->second;
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;
}
} }
delete sdb->scan_queue; xe_memory_release(memory_);
delete sdb->symbols;
xe_memory_release(sdb->memory);
} }
xe_sdb_ref xe_sdb_retain(xe_sdb_ref sdb) { int SymbolDatabase::Analyze() {
xe_ref_retain((xe_ref)sdb); // Iteratively run passes over the db.
return sdb; // 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) { FunctionSymbol* SymbolDatabase::GetOrInsertFunction(uint32_t address) {
xe_ref_release((xe_ref)sdb, (xe_ref_dealloc_t)xe_sdb_dealloc); FunctionSymbol* fn = GetFunction(address);
}
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);
if (fn) { if (fn) {
return fn; return fn;
} }
printf("add fn %.8X\n", address); 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; fn->start_address = address;
xe_sdb_symbol_t symbol; function_count_++;
symbol.type = 0; symbols_.insert(SymbolMap::value_type(address, fn));
symbol.function = fn; scan_queue_.push_back(fn);
sdb->function_count++;
sdb->symbols->insert(xe_sdb_symbol_map::value_type(address, symbol));
sdb->scan_queue->push_back(fn);
return fn; return fn;
} }
xe_sdb_variable_t* xe_sdb_insert_variable(xe_sdb_ref sdb, uint32_t address) { VariableSymbol* SymbolDatabase::GetOrInsertVariable(uint32_t address) {
xe_sdb_variable_t *var = xe_sdb_get_variable(sdb, address); VariableSymbol* var = GetVariable(address);
if (var) { if (var) {
return var; return var;
} }
printf("add var %.8X\n", address); printf("add var %.8X\n", address);
var = (xe_sdb_variable_t*)xe_calloc(sizeof(xe_sdb_variable_t)); var = new VariableSymbol();
var->address = address; var->address = address;
xe_sdb_symbol_t symbol; variable_count_++;
symbol.type = 1; symbols_.insert(SymbolMap::value_type(address, var));
symbol.variable = var;
sdb->variable_count++;
sdb->symbols->insert(xe_sdb_symbol_map::value_type(address, symbol));
return var; return var;
} }
xe_sdb_function_t* xe_sdb_get_function(xe_sdb_ref sdb, uint32_t address) { FunctionSymbol* SymbolDatabase::GetFunction(uint32_t address) {
xe_sdb_symbol_map::iterator i = sdb->symbols->find(address); SymbolMap::iterator i = symbols_.find(address);
if (i != sdb->symbols->end() && if (i != symbols_.end() && i->second->symbol_type == Symbol::Function) {
i->second.type == 0) { return static_cast<FunctionSymbol*>(i->second);
return i->second.function;
} }
return NULL; return NULL;
} }
xe_sdb_variable_t* xe_sdb_get_variable(xe_sdb_ref sdb, uint32_t address) { VariableSymbol* SymbolDatabase::GetVariable(uint32_t address) {
xe_sdb_symbol_map::iterator i = sdb->symbols->find(address); SymbolMap::iterator i = symbols_.find(address);
if (i != sdb->symbols->end() && if (i != symbols_.end() && i->second->symbol_type == Symbol::Variable) {
i->second.type == 1) { return static_cast<VariableSymbol*>(i->second);
return i->second.variable;
} }
return NULL; return NULL;
} }
int xe_sdb_get_functions(xe_sdb_ref sdb, xe_sdb_function_t ***out_functions, int SymbolDatabase::GetAllFunctions(vector<FunctionSymbol*>& functions) {
size_t *out_function_count) { for (SymbolMap::iterator it = symbols_.begin(); it != symbols_.end(); ++it) {
xe_sdb_function_t **functions = (xe_sdb_function_t**)xe_malloc( if (it->second->symbol_type == Symbol::Function) {
sizeof(xe_sdb_function_t*) * sdb->function_count); functions.push_back(static_cast<FunctionSymbol*>(it->second));
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;
} }
} }
*out_functions = functions;
*out_function_count = sdb->function_count;
return 0; return 0;
} }
void xe_sdb_dump(xe_sdb_ref sdb) { void SymbolDatabase::Dump() {
uint32_t previous = 0; uint32_t previous = 0;
for (xe_sdb_symbol_map::iterator it = sdb->symbols->begin(); for (SymbolMap::iterator it = symbols_.begin(); it != symbols_.end(); ++it) {
it != sdb->symbols->end(); ++it) { switch (it->second->symbol_type) {
switch (it->second.type) { case Symbol::Function:
case 0:
{ {
xe_sdb_function_t *fn = it->second.function; FunctionSymbol* fn = static_cast<FunctionSymbol*>(it->second);
if (previous && (int)(fn->start_address - previous) > 0) { if (previous && (int)(fn->start_address - previous) > 0) {
printf("%.8X-%.8X (%5d) h\n", previous, fn->start_address, printf("%.8X-%.8X (%5d) h\n", previous, fn->start_address,
fn->start_address - previous); fn->start_address - previous);
@ -169,9 +142,9 @@ void xe_sdb_dump(xe_sdb_ref sdb) {
previous = fn->end_address + 4; previous = fn->end_address + 4;
} }
break; 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, printf("%.8X v %s\n", var->address,
var->name ? var->name : "<unknown>"); 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. // Special stack save/restore functions.
// __savegprlr_14 to __savegprlr_31 // __savegprlr_14 to __savegprlr_31
// __restgprlr_14 to __restgprlr_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; 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++) { 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 size_t start_address = header->exe_address + const size_t start_address =
(i * xe_xex2_section_length); header->exe_address + (i * xe_xex2_section_length);
const size_t end_address = start_address + (section->info.page_count * const size_t end_address =
xe_xex2_section_length); start_address + (section->info.page_count * xe_xex2_section_length);
if (section->info.type == XEX_SECTION_CODE) { if (section->info.type == XEX_SECTION_CODE) {
gplr_start = xe_memory_search_aligned( gplr_start = xe_memory_search_aligned(
sdb->memory, start_address, end_address, memory_, start_address, end_address,
code_values, XECOUNT(code_values)); code_values, XECOUNT(code_values));
if (gplr_start) { if (gplr_start) {
break; break;
@ -255,81 +228,82 @@ int xe_sdb_find_gplr(xe_sdb_ref sdb, xe_module_ref module) {
// Add function stubs. // Add function stubs.
char name[32]; char name[32];
uint32_t addr = gplr_start; uint32_t address = gplr_start;
for (int n = 14; n <= 31; n++) { for (int n = 14; n <= 31; n++) {
xesnprintf(name, XECOUNT(name), "__savegprlr_%d", 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->end_address = fn->start_address + (31 - n) * 4 + 2 * 4;
fn->name = xestrdup(name); fn->name = xestrdup(name);
fn->type = kXESDBFunctionUser; fn->type = FunctionSymbol::User;
addr += 4; address += 4;
} }
addr = gplr_start + 20 * 4; address = gplr_start + 20 * 4;
for (int n = 14; n <= 31; n++) { for (int n = 14; n <= 31; n++) {
xesnprintf(name, XECOUNT(name), "__restgprlr_%d", 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->end_address = fn->start_address + (31 - n) * 4 + 3 * 4;
fn->name = xestrdup(name); fn->name = xestrdup(name);
fn->type = kXESDBFunctionUser; fn->type = FunctionSymbol::User;
addr += 4; address += 4;
} }
return 0; return 0;
} }
int xe_sdb_add_imports(xe_sdb_ref sdb, xe_module_ref module, int SymbolDatabase::AddImports(const xe_xex2_import_library_t* library) {
const xe_xex2_import_library_t *library) { xe_xex2_ref xex = module_->xex();
xe_xex2_ref xex = xe_module_get_xex(module); xe_xex2_import_info_t* import_infos;
xe_xex2_import_info_t *import_infos;
size_t import_info_count; size_t import_info_count;
if (xe_xex2_get_import_infos(xex, library, &import_infos, if (xe_xex2_get_import_infos(xex, library, &import_infos,
&import_info_count)) { &import_info_count)) {
xe_xex2_release(xex);
return 1; return 1;
} }
char name[64]; char name[64];
for (size_t n = 0; n < import_info_count; n++) { for (size_t n = 0; n < import_info_count; n++) {
const xe_xex2_import_info_t *info = &import_infos[n]; const xe_xex2_import_info_t* info = &import_infos[n];
xe_sdb_variable_t *var = xe_sdb_insert_variable(sdb, info->value_address); VariableSymbol* var = GetOrInsertVariable(info->value_address);
// TODO(benvanik): use kernel name // TODO(benvanik): use kernel name
xesnprintf(name, XECOUNT(name), "__var_%s_%.3X", library->name, xesnprintf(name, XECOUNT(name), "__var_%s_%.3X", library->name,
info->ordinal); info->ordinal);
var->name = strdup(name); var->name = strdup(name);
if (info->thunk_address) { 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 // TODO(benvanik): use kernel name
xesnprintf(name, XECOUNT(name), "__thunk_%s_%.3X", library->name, xesnprintf(name, XECOUNT(name), "__thunk_%s_%.3X", library->name,
info->ordinal); info->ordinal);
fn->end_address = fn->start_address + 16 - 4; fn->end_address = fn->start_address + 16 - 4;
fn->name = strdup(name); fn->name = strdup(name);
fn->type = kXESDBFunctionKernel; fn->type = FunctionSymbol::Kernel;
} }
} }
xe_xex2_release(xex);
return 0; return 0;
} }
int xe_sdb_add_method_hints(xe_sdb_ref sdb, xe_module_ref module) { int SymbolDatabase::AddMethodHints() {
xe_module_pe_method_info_t *method_infos; PEMethodInfo* method_infos;
size_t method_info_count; 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; return 1;
} }
for (size_t n = 0; n < method_info_count; n++) { for (size_t n = 0; n < method_info_count; n++) {
xe_module_pe_method_info_t *method_info = &method_infos[n]; PEMethodInfo* method_info = &method_infos[n];
xe_sdb_function_t *fn = xe_sdb_insert_function(sdb, method_info->address); FunctionSymbol* fn = GetOrInsertFunction(method_info->address);
fn->end_address = method_info->address + method_info->total_length - 4; fn->end_address = method_info->address + method_info->total_length - 4;
fn->type = kXESDBFunctionUser; fn->type = FunctionSymbol::User;
// TODO(benvanik): something with prolog_length? // TODO(benvanik): something with prolog_length?
} }
return 0; 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. // Ignore functions already analyzed.
if (fn->type != kXESDBFunctionUnknown) { if (fn->type != FunctionSymbol::Unknown) {
return 0; return 0;
} }
@ -339,52 +313,21 @@ int xe_sdb_analyze_function(xe_sdb_ref sdb, xe_sdb_function_t *fn) {
return 0; return 0;
} }
int xe_sdb_flush_queue(xe_sdb_ref sdb) { int SymbolDatabase::FlushQueue() {
while (sdb->scan_queue->size()) { while (scan_queue_.size()) {
xe_sdb_function_t *fn = sdb->scan_queue->front(); FunctionSymbol* fn = scan_queue_.front();
sdb->scan_queue->pop_front(); scan_queue_.pop_front();
if (!xe_sdb_analyze_function(sdb, fn)) { if (!AnalyzeFunction(fn)) {
return 1; return 1;
} }
} }
return 0; return 0;
} }
int xe_sdb_analyze_module(xe_sdb_ref sdb, xe_module_ref module) { int SymbolDatabase::FillHoles() {
// Iteratively run passes over the db. // TODO(benvanik): scan all holes
// This uses a queue to do a breadth-first search of all accessible // If 4b, check if 0x00000000 and ignore (alignment padding)
// functions. Callbacks and such likely won't be hit. // If 8b, check if first value is within .text and ignore (EH entry)
// Else, add to scan queue as function?
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);
return 0; return 0;
} }

View File

@ -2,7 +2,8 @@
{ {
'sources': [ 'sources': [
'codegen.cc', 'codegen.cc',
'cpu.cc', 'exec_module.cc',
'processor.cc',
'sdb.cc', 'sdb.cc',
], ],

View File

@ -10,87 +10,62 @@
#include <xenia/kernel/export.h> #include <xenia/kernel/export.h>
bool xe_kernel_export_is_implemented(const xe_kernel_export_t *kernel_export) { using namespace xe;
if (kernel_export->flags & kXEKernelExportFlagFunction) { using namespace xe::kernel;
if (kernel_export->function_data.impl) {
bool KernelExport::IsImplemented() {
switch (type) {
case Function:
if (function_data.impl) {
return true; return true;
} }
} else if (kernel_export->flags & kXEKernelExportFlagVariable) { break;
if (kernel_export->variable_data) { case Variable:
if (variable_data) {
return true; return true;
} }
break;
} }
return false; return false;
} }
typedef struct {
char name[32];
xe_kernel_export_t *exports;
size_t count;
} xe_kernel_export_table_t;
#define kXEKernelExportResolverTableMaxCount 8
ExportResolver::ExportResolver() {
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;
} }
void xe_kernel_export_resolver_dealloc(xe_kernel_export_resolver_ref resolver) { ExportResolver::~ExportResolver() {
} }
xe_kernel_export_resolver_ref xe_kernel_export_resolver_retain( void ExportResolver::RegisterTable(
xe_kernel_export_resolver_ref resolver) { const char* library_name, KernelExport* exports, const size_t count) {
xe_ref_retain((xe_ref)resolver); ExportTable table;
return resolver; 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) { KernelExport* ExportResolver::GetExportByOrdinal(const char* library_name,
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) { const uint32_t ordinal) {
// TODO(benvanik): binary search everything. for (std::vector<ExportTable>::iterator it = tables_.begin();
for (size_t n = 0; n < resolver->table_count; n++) { it != tables_.end(); ++it) {
const xe_kernel_export_table_t *table = &resolver->tables[n]; if (!xestrcmp(library_name, it->name)) {
if (!xestrcmpa(library_name, table->name)) { // TODO(benvanik): binary search?
// TODO(benvanik): binary search table. for (size_t n = 0; n < it->count; n++) {
for (size_t m = 0; m < table->count; m++) { if (it->exports[n].ordinal == ordinal) {
if (table->exports[m].ordinal == ordinal) { return &it->exports[n];
return &table->exports[m];
} }
} }
return NULL;
} }
} }
return NULL; return NULL;
} }
xe_kernel_export_t *xe_kernel_export_resolver_get_by_name( KernelExport* ExportResolver::GetExportByName(const char* library_name,
xe_kernel_export_resolver_ref resolver, const char *library_name, const char* name) {
const char *name) { // TODO(benvanik): lookup by name.
XEASSERTALWAYS();
return NULL; return NULL;
} }

View File

@ -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) {
//
}

View File

@ -10,8 +10,8 @@
#ifndef XENIA_KERNEL_MODULES_H_ #ifndef XENIA_KERNEL_MODULES_H_
#define XENIA_KERNEL_MODULES_H_ #define XENIA_KERNEL_MODULES_H_
#include "kernel/modules/xam/xam.h" #include "kernel/modules/xam/xam_module.h"
#include "kernel/modules/xbdm/xbdm.h" #include "kernel/modules/xbdm/xbdm_module.h"
#include "kernel/modules/xboxkrnl/xboxkrnl.h" #include "kernel/modules/xboxkrnl/xboxkrnl_module.h"
#endif // XENIA_KERNEL_MODULES_H_ #endif // XENIA_KERNEL_MODULES_H_

View File

@ -1,6 +1,6 @@
# Copyright 2013 Ben Vanik. All Rights Reserved. # Copyright 2013 Ben Vanik. All Rights Reserved.
{ {
'sources': [ 'sources': [
'xam.cc', 'xam_module.cc',
], ],
} }

View File

@ -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);
}

View File

@ -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() {
}

View File

@ -14,18 +14,25 @@
#include <xenia/core.h> #include <xenia/core.h>
#include <xenia/kernel/export.h> #include <xenia/kernel/export.h>
#include <xenia/kernel/kernel_module.h>
struct xe_xam; namespace xe {
typedef struct xe_xam* xe_xam_ref; namespace kernel {
namespace xam {
xe_xam_ref xe_xam_create( class XamModule : public KernelModule {
xe_pal_ref pal, xe_memory_ref memory, public:
xe_kernel_export_resolver_ref export_resolver); 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_ #endif // XENIA_KERNEL_MODULES_XAM_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
# Copyright 2013 Ben Vanik. All Rights Reserved. # Copyright 2013 Ben Vanik. All Rights Reserved.
{ {
'sources': [ 'sources': [
'xbdm.cc', 'xbdm_module.cc',
], ],
} }

View File

@ -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);
}

View File

@ -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() {
}

View File

@ -7,25 +7,32 @@
****************************************************************************** ******************************************************************************
*/ */
#ifndef XENIA_KERNEL_MODULES_XBDM_H_ #ifndef XENIA_KERNEL_MODULES_XBDM_MODULE_H_
#define XENIA_KERNEL_MODULES_XBDM_H_ #define XENIA_KERNEL_MODULES_XBDM_MODULE_H_
#include <xenia/common.h> #include <xenia/common.h>
#include <xenia/core.h> #include <xenia/core.h>
#include <xenia/kernel/export.h> #include <xenia/kernel/export.h>
#include <xenia/kernel/kernel_module.h>
struct xe_xbdm; namespace xe {
typedef struct xe_xbdm* xe_xbdm_ref; namespace kernel {
namespace xbdm {
xe_xbdm_ref xe_xbdm_create( class XbdmModule : public KernelModule {
xe_pal_ref pal, xe_memory_ref memory, public:
xe_kernel_export_resolver_ref export_resolver); XbdmModule(xe_pal_ref pal, xe_memory_ref memory,
shared_ptr<ExportResolver> resolver);
xe_xbdm_ref xe_xbdm_retain(xe_xbdm_ref module); virtual ~XbdmModule();
void xe_xbdm_release(xe_xbdm_ref module); };
#endif // XENIA_KERNEL_MODULES_XBDM_H_ } // namespace xbdm
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_MODULES_XBDM_MODULE_H_

View File

@ -13,14 +13,24 @@
#include <xenia/kernel/export.h> #include <xenia/kernel/export.h>
namespace xe {
namespace kernel {
namespace xbdm {
#define FLAG(t) kXEKernelExportFlag##t #define FLAG(t) kXEKernelExportFlag##t
static xe_kernel_export_t xe_xbdm_export_table[] = { static KernelExport xbdm_export_table[] = {
}; };
#undef FLAG #undef FLAG
} // namespace xbdm
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_MODULES_XBDM_TABLE_H_ #endif // XENIA_KERNEL_MODULES_XBDM_TABLE_H_

View File

@ -1,6 +1,6 @@
# Copyright 2013 Ben Vanik. All Rights Reserved. # Copyright 2013 Ben Vanik. All Rights Reserved.
{ {
'sources': [ 'sources': [
'xboxkrnl.cc', 'xboxkrnl_module.cc',
], ],
} }

View File

@ -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);
}

View File

@ -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() {
}

View File

@ -7,25 +7,32 @@
****************************************************************************** ******************************************************************************
*/ */
#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_H_ #ifndef XENIA_KERNEL_MODULES_XBOXKRNL_MODULE_H_
#define XENIA_KERNEL_MODULES_XBOXKRNL_H_ #define XENIA_KERNEL_MODULES_XBOXKRNL_MODULE_H_
#include <xenia/common.h> #include <xenia/common.h>
#include <xenia/core.h> #include <xenia/core.h>
#include <xenia/kernel/export.h> #include <xenia/kernel/export.h>
#include <xenia/kernel/kernel_module.h>
struct xe_xboxkrnl; namespace xe {
typedef struct xe_xboxkrnl* xe_xboxkrnl_ref; namespace kernel {
namespace xboxkrnl {
xe_xboxkrnl_ref xe_xboxkrnl_create( class XboxkrnlModule : public KernelModule {
xe_pal_ref pal, xe_memory_ref memory, public:
xe_kernel_export_resolver_ref export_resolver); XboxkrnlModule(xe_pal_ref pal, xe_memory_ref memory,
shared_ptr<ExportResolver> resolver);
xe_xboxkrnl_ref xe_xboxkrnl_retain(xe_xboxkrnl_ref module); virtual ~XboxkrnlModule();
void xe_xboxkrnl_release(xe_xboxkrnl_ref module); };
#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

139
src/kernel/runtime.cc Normal file
View File

@ -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();
}

View File

@ -2,8 +2,8 @@
{ {
'sources': [ 'sources': [
'export.cc', 'export.cc',
'kernel.cc', 'runtime.cc',
'module.cc', 'user_module.cc',
'xex2.cc', 'xex2.cc',
], ],

View File

@ -7,97 +7,72 @@
****************************************************************************** ******************************************************************************
*/ */
#include <xenia/kernel/module.h> #include <xenia/kernel/user_module.h>
#include <third_party/pe/pe_image.h> #include <third_party/pe/pe_image.h>
#define kXEModuleMaxSectionCount 32 using namespace xe;
using namespace kernel;
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;
int xe_module_load_pe(xe_module_ref module); UserModule::UserModule(xe_memory_ref memory) {
memory_ = xe_memory_retain(memory);
xex_ = NULL;
}
UserModule::~UserModule() {
xe_module_ref xe_module_load(xe_memory_ref memory, for (std::vector<PESection*>::iterator it = sections_.begin();
xe_kernel_export_resolver_ref export_resolver, it != sections_.end(); ++it) {
const void *addr, const size_t length, delete *it;
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);
} }
module->memory = xe_memory_retain(memory); xe_xex2_release(xex_);
module->export_resolver = xe_kernel_export_resolver_retain(export_resolver); 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; xe_xex2_options_t xex_options;
module->xex = xe_xex2_load(memory, addr, length, xex_options); xex_ = xe_xex2_load(memory_, addr, length, xex_options);
XEEXPECTNOTNULL(module->xex); XEEXPECTNOTNULL(xex_);
XEEXPECTZERO(xe_module_load_pe(module)); XEEXPECTZERO(LoadPE());
return module; return 0;
XECLEANUP: XECLEANUP:
xe_module_release(module); return 1;
return NULL;
} }
void xe_module_dealloc(xe_module_ref module) { const xechar_t* UserModule::path() {
xe_kernel_export_resolver_release(module->export_resolver); return path_;
xe_memory_release(module->memory);
} }
xe_module_ref xe_module_retain(xe_module_ref module) { const xechar_t* UserModule::name() {
xe_ref_retain((xe_ref)module); return name_;
return module;
} }
void xe_module_release(xe_module_ref module) { uint32_t UserModule::handle() {
xe_ref_release((xe_ref)module, (xe_ref_dealloc_t)xe_module_dealloc); return handle_;
} }
const xechar_t *xe_module_get_path(xe_module_ref module) { xe_xex2_ref UserModule::xex() {
return module->options.path; return xe_xex2_retain(xex_);
} }
const xechar_t *xe_module_get_name(xe_module_ref module) { const xe_xex2_header_t* UserModule::xex_header() {
return module->name; return xe_xex2_get_header(xex_);
} }
uint32_t xe_module_get_handle(xe_module_ref module) { void* UserModule::GetProcAddress(const uint32_t ordinal) {
return module->handle; XEASSERTALWAYS();
}
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) {
return NULL; return NULL;
} }
@ -116,10 +91,10 @@ typedef struct IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY_t {
}; };
} IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY; } IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY;
int xe_module_load_pe(xe_module_ref module) { int UserModule::LoadPE() {
const xe_xex2_header_t *xex_header = xe_xex2_get_header(module->xex); const xe_xex2_header_t* xex_header = xe_xex2_get_header(xex_);
uint8_t *mem = (uint8_t*)xe_memory_addr(module->memory, 0); uint8_t* mem = xe_memory_addr(memory_, 0);
const uint8_t *p = mem + xex_header->exe_address; const uint8_t* p = mem + xex_header->exe_address;
// Verify DOS signature (MZ). // Verify DOS signature (MZ).
const IMAGE_DOS_HEADER* doshdr = (const IMAGE_DOS_HEADER*)p; 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 // IAT Import Address Table ptr
//opthdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_X].VirtualAddress / .Size //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. // Quick scan to determine bounds of sections.
size_t upper_address = 0; size_t upper_address = 0;
const IMAGE_SECTION_HEADER* sechdr = IMAGE_FIRST_SECTION(nthdr); 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. // Setup/load sections.
sechdr = IMAGE_FIRST_SECTION(nthdr); sechdr = IMAGE_FIRST_SECTION(nthdr);
for (size_t n = 0; n < filehdr->NumberOfSections; n++, sechdr++) { 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), xe_copy_memory(section->name, sizeof(section->name),
sechdr->Name, sizeof(sechdr->Name)); sechdr->Name, sizeof(sechdr->Name));
section->name[8] = 0; 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->address = xex_header->exe_address + sechdr->VirtualAddress;
section->size = sechdr->Misc.VirtualSize; section->size = sechdr->Misc.VirtualSize;
section->flags = sechdr->Characteristics; section->flags = sechdr->Characteristics;
sections_.push_back(section);
} }
//DumpTLSDirectory(pImageBase, pNTHeader, (PIMAGE_TLS_DIRECTORY32)0); //DumpTLSDirectory(pImageBase, pNTHeader, (PIMAGE_TLS_DIRECTORY32)0);
@ -208,48 +176,45 @@ int xe_module_load_pe(xe_module_ref module) {
return 0; return 0;
} }
xe_module_pe_section_t *xe_module_get_section(xe_module_ref module, PESection* UserModule::GetSection(const char *name) {
const char *name) { for (std::vector<PESection*>::iterator it = sections_.begin();
for (size_t n = 0; n < module->section_count; n++) { it != sections_.end(); ++it) {
if (xestrcmpa(module->sections[n].name, name) == 0) { if (!xestrcmpa((*it)->name, name)) {
return &module->sections[n]; return *it;
} }
} }
return NULL; return NULL;
} }
int xe_module_get_method_hints(xe_module_ref module, int UserModule::GetMethodHints(PEMethodInfo** out_method_infos,
xe_module_pe_method_info_t **out_method_infos, size_t* out_method_info_count) {
size_t *out_method_info_count) { uint8_t* mem = xe_memory_addr(memory_, 0);
uint8_t *mem = (uint8_t*)xe_memory_addr(module->memory, 0);
*out_method_infos = NULL; *out_method_infos = NULL;
*out_method_info_count = 0; *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. // 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) { if (!pdata) {
// No exception data to go on. // No exception data to go on.
return 0; return 0;
} }
// Resolve. // Resolve.
const uint8_t *p = mem + pdata->address; const uint8_t* p = mem + pdata->address;
// Entry count = pdata size / sizeof(entry). // Entry count = pdata size / sizeof(entry).
const size_t entry_count = size_t entry_count = pdata->size / sizeof(IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY);
pdata->size / sizeof(IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY); if (!entry_count) {
if (entry_count == 0) {
// Empty? // Empty?
return 0; return 0;
} }
// Allocate output. // Allocate output.
xe_module_pe_method_info_t *method_infos = PEMethodInfo* method_infos = (PEMethodInfo*)xe_calloc(
(xe_module_pe_method_info_t*)xe_calloc( entry_count * sizeof(PEMethodInfo));
entry_count * sizeof(xe_module_pe_method_info_t));
XEEXPECTNOTNULL(method_infos); XEEXPECTNOTNULL(method_infos);
// Parse entries. // Parse entries.
@ -258,7 +223,7 @@ int xe_module_get_method_hints(xe_module_ref module,
entry = (const IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY*)p; entry = (const IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY*)p;
IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY temp_entry; IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY temp_entry;
for (size_t n = 0; n < entry_count; n++, 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); method_info->address = XESWAP32BE(entry->FuncStart);
// The bitfield needs to be swapped by hand. // The bitfield needs to be swapped by hand.
@ -278,12 +243,12 @@ XECLEANUP:
return 1; return 1;
} }
void xe_module_dump(xe_module_ref module) { void UserModule::Dump(ExportResolver* export_resolver) {
//const uint8_t *mem = (const uint8_t*)xe_memory_addr(module->memory, 0); //const uint8_t *mem = (const uint8_t*)xe_memory_addr(memory_, 0);
const xe_xex2_header_t *header = xe_xex2_get_header(module->xex); const xe_xex2_header_t* header = xe_xex2_get_header(xex_);
// XEX info. // 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(" Module Flags: %.8X\n", header->module_flags);
printf(" System Flags: %.8X\n", header->system_flags); printf(" System Flags: %.8X\n", header->system_flags);
printf("\n"); printf("\n");
@ -324,7 +289,7 @@ void xe_module_dump(xe_module_ref module) {
printf("\n"); printf("\n");
printf(" Headers:\n"); printf(" Headers:\n");
for (size_t n = 0; n < header->header_count; 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", printf(" %.8X (%.8X, %4db) %.8X = %11d\n",
opt_header->key, opt_header->offset, opt_header->length, opt_header->key, opt_header->offset, opt_header->length,
opt_header->value, opt_header->value); opt_header->value, opt_header->value);
@ -341,7 +306,7 @@ void xe_module_dump(xe_module_ref module) {
// Section info. // Section info.
printf("Sections:\n"); printf("Sections:\n");
for (size_t n = 0, i = 0; n < header->section_count; 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"; const char* type = "UNKNOWN";
switch (section->info.type) { switch (section->info.type) {
case XEX_SECTION_CODE: case XEX_SECTION_CODE:
@ -354,10 +319,10 @@ void xe_module_dump(xe_module_ref module) {
type = "RODATA "; type = "RODATA ";
break; break;
} }
const size_t start_address = header->exe_address + const size_t start_address =
(i * xe_xex2_section_length); header->exe_address + (i * xe_xex2_section_length);
const size_t end_address = start_address + (section->info.page_count * const size_t end_address =
xe_xex2_section_length); start_address + (section->info.page_count * xe_xex2_section_length);
printf(" %3d %s %3d pages %.8X - %.8X (%d bytes)\n", printf(" %3d %s %3d pages %.8X - %.8X (%d bytes)\n",
(int)n, type, section->info.page_count, (int)start_address, (int)n, type, section->info.page_count, (int)start_address,
(int)end_address, section->info.page_count * xe_xex2_section_length); (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"); printf("Static Libraries:\n");
for (size_t n = 0; n < header->static_library_count; n++) { for (size_t n = 0; n < header->static_library_count; n++) {
const xe_xex2_static_library_t *library = &header->static_libraries[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); library->minor, library->build, library->qfe);
} }
printf("\n"); printf("\n");
@ -377,11 +343,11 @@ void xe_module_dump(xe_module_ref module) {
// Imports. // Imports.
printf("Imports:\n"); printf("Imports:\n");
for (size_t n = 0; n < header->import_library_count; 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; xe_xex2_import_info_t* import_infos;
size_t import_info_count; 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)) { &import_infos, &import_info_count)) {
printf(" %s - %d imports\n", library->name, (int)import_info_count); printf(" %s - %d imports\n", library->name, (int)import_info_count);
printf(" Version: %d.%d.%d.%d\n", printf(" Version: %d.%d.%d.%d\n",
@ -398,13 +364,12 @@ void xe_module_dump(xe_module_ref module) {
int impl_count = 0; int impl_count = 0;
int unimpl_count = 0; int unimpl_count = 0;
for (size_t m = 0; m < import_info_count; m++) { for (size_t m = 0; m < import_info_count; m++) {
const xe_xex2_import_info_t *info = &import_infos[m]; const xe_xex2_import_info_t* info = &import_infos[m];
const xe_kernel_export_t *kernel_export = KernelExport* kernel_export =
xe_kernel_export_resolver_get_by_ordinal( export_resolver->GetExportByOrdinal(library->name, info->ordinal);
module->export_resolver, library->name, info->ordinal);
if (kernel_export) { if (kernel_export) {
known_count++; known_count++;
if (xe_kernel_export_is_implemented(kernel_export)) { if (kernel_export->IsImplemented()) {
impl_count++; impl_count++;
} }
} else { } else {
@ -423,15 +388,14 @@ void xe_module_dump(xe_module_ref module) {
// Listing. // Listing.
for (size_t m = 0; m < import_info_count; m++) { for (size_t m = 0; m < import_info_count; m++) {
const xe_xex2_import_info_t *info = &import_infos[m]; const xe_xex2_import_info_t* info = &import_infos[m];
const xe_kernel_export_t *kernel_export = KernelExport* kernel_export = export_resolver->GetExportByOrdinal(
xe_kernel_export_resolver_get_by_ordinal( library->name, info->ordinal);
module->export_resolver, library->name, info->ordinal);
const char *name = "UNKNOWN"; const char *name = "UNKNOWN";
bool implemented = false; bool implemented = false;
if (kernel_export) { if (kernel_export) {
name = kernel_export->name; name = kernel_export->name;
implemented = xe_kernel_export_is_implemented(kernel_export); implemented = kernel_export->IsImplemented();
} }
if (info->thunk_address) { if (info->thunk_address) {
printf(" F %.8X %.8X %.3X (%3d) %s %s\n", printf(" F %.8X %.8X %.3X (%3d) %s %s\n",

View File

@ -10,14 +10,18 @@
#include <xenia/xenia.h> #include <xenia/xenia.h>
using namespace xe;
using namespace xe::cpu;
using namespace xe::kernel;
int xenia_info(int argc, xechar_t **argv) { int xenia_info(int argc, xechar_t **argv) {
int result_code = 1; int result_code = 1;
xe_pal_ref pal = NULL; xe_pal_ref pal = NULL;
xe_memory_ref memory = NULL; xe_memory_ref memory = NULL;
xe_cpu_ref cpu = NULL; shared_ptr<Processor> processor;
xe_kernel_ref kernel = NULL; shared_ptr<Runtime> runtime;
xe_module_ref module = NULL;
// TODO(benvanik): real command line parsing. // TODO(benvanik): real command line parsing.
if (argc < 2) { if (argc < 2) {
@ -36,26 +40,15 @@ int xenia_info(int argc, xechar_t **argv) {
memory = xe_memory_create(pal, memory_options); memory = xe_memory_create(pal, memory_options);
XEEXPECTNOTNULL(memory); XEEXPECTNOTNULL(memory);
xe_cpu_options_t cpu_options; processor = shared_ptr<Processor>(new Processor(pal, memory));
xe_zero_struct(&cpu_options, sizeof(cpu_options)); XEEXPECTZERO(processor->Setup());
cpu = xe_cpu_create(pal, memory, cpu_options);
XEEXPECTNOTNULL(cpu);
xe_kernel_options_t kernel_options; runtime = shared_ptr<Runtime>(new Runtime(pal, processor, XT("")));
xe_zero_struct(&kernel_options, sizeof(kernel_options));
kernel = xe_kernel_create(pal, cpu, kernel_options);
XEEXPECTNOTNULL(kernel);
module = xe_kernel_load_module(kernel, path); XEEXPECTZERO(runtime->LoadModule(path));
XEEXPECTNOTNULL(module);
xe_module_dump(module);
result_code = 0; result_code = 0;
XECLEANUP: XECLEANUP:
xe_module_release(module);
xe_kernel_release(kernel);
xe_cpu_release(cpu);
xe_memory_release(memory); xe_memory_release(memory);
xe_pal_release(pal); xe_pal_release(pal);
return result_code; return result_code;

View File

@ -10,52 +10,63 @@
#include <xenia/xenia.h> #include <xenia/xenia.h>
typedef struct { using namespace xe;
xe_pal_ref pal; using namespace xe::cpu;
xe_memory_ref memory; using namespace xe::kernel;
xe_cpu_ref cpu;
xe_kernel_ref kernel;
xe_module_ref module;
} xenia_run_t;
int setup_run(xenia_run_t *run, const xechar_t *path) { 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_pal_options_t pal_options;
xe_zero_struct(&pal_options, sizeof(pal_options)); xe_zero_struct(&pal_options, sizeof(pal_options));
run->pal = xe_pal_create(pal_options); pal_ = xe_pal_create(pal_options);
XEEXPECTNOTNULL(run->pal); XEEXPECTNOTNULL(pal_);
xe_memory_options_t memory_options; xe_memory_options_t memory_options;
xe_zero_struct(&memory_options, sizeof(memory_options)); xe_zero_struct(&memory_options, sizeof(memory_options));
run->memory = xe_memory_create(run->pal, memory_options); memory_ = xe_memory_create(pal_, memory_options);
XEEXPECTNOTNULL(run->memory); XEEXPECTNOTNULL(memory_);
xe_cpu_options_t cpu_options; processor_ = shared_ptr<Processor>(new Processor(pal_, memory_));
xe_zero_struct(&cpu_options, sizeof(cpu_options)); XEEXPECTZERO(processor_->Setup());
run->cpu = xe_cpu_create(run->pal, run->memory, cpu_options);
XEEXPECTNOTNULL(run->cpu);
xe_kernel_options_t kernel_options; runtime_ = shared_ptr<Runtime>(new Runtime(pal_, processor_, XT("")));
xe_zero_struct(&kernel_options, sizeof(kernel_options));
run->kernel = xe_kernel_create(run->pal, run->cpu, kernel_options);
XEEXPECTNOTNULL(run->kernel);
run->module = xe_kernel_load_module(run->kernel, path); XEEXPECTZERO(runtime_->LoadModule(path));
XEEXPECTNOTNULL(run->module); module_ = runtime_->GetModule(path);
return 0; return 0;
XECLEANUP: XECLEANUP:
return 1; return 1;
} }
void destroy_run(xenia_run_t *run) { int Run::Launch() {
xe_module_release(run->module); // TODO(benvanik): wait until the module thread exits
xe_kernel_release(run->kernel); runtime_->LaunchModule(module_);
xe_cpu_release(run->cpu); return 0;
xe_memory_release(run->memory);
xe_pal_release(run->pal);
xe_free(run);
} }
int xenia_run(int argc, xechar_t **argv) { 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]; const xechar_t *path = argv[1];
xenia_run_t *run = (xenia_run_t*)xe_calloc(sizeof(xenia_run_t)); auto_ptr<Run> run = auto_ptr<Run>(new Run());
XEEXPECTNOTNULL(run);
result_code = setup_run(run, path); result_code = run->Setup(path);
XEEXPECTZERO(result_code); 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; return 0;
XECLEANUP: XECLEANUP:
if (run) {
destroy_run(run);
}
return result_code; return result_code;
} }
XE_MAIN_THUNK(xenia_run); XE_MAIN_THUNK(xenia_run);