Merge remote-tracking branch 'upstream/master' into canary

This commit is contained in:
illusion98 2019-08-25 23:58:43 -05:00
commit b50feba296
27 changed files with 409 additions and 200 deletions

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -401,4 +401,5 @@ int xenia_main(const std::vector<std::wstring>& args) {
} // namespace app
} // namespace xe
DEFINE_ENTRY_POINT(L"xenia", L"xenia some.xex", xe::app::xenia_main);
DEFINE_ENTRY_POINT(L"xenia", xe::app::xenia_main, "[Path to .iso/.xex]",
"target");

View File

@ -113,9 +113,7 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
context_data_last_ptr_ =
context_data_first_ptr_ + (sizeof(XMA_CONTEXT_DATA) * kContextCount - 1);
register_file_[XE_XMA_REG_CONTEXT_ARRAY_ADDRESS].u32 =
memory()
->LookupHeap(context_data_first_ptr_)
->GetPhysicalAddress(context_data_first_ptr_);
memory()->GetPhysicalAddress(context_data_first_ptr_);
// Setup XMA contexts.
for (int i = 0; i < kContextCount; ++i) {

View File

@ -1,3 +1,12 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "cvar.h"
namespace cvar {
@ -13,7 +22,9 @@ void PrintHelpAndExit() {
exit(0);
}
void ParseLaunchArguments(int argc, char** argv) {
void ParseLaunchArguments(int argc, char** argv,
const std::string& positional_help,
const std::vector<std::string>& positional_options) {
options.add_options()("help", "Prints help and exit.");
if (!CmdVars) CmdVars = new std::map<std::string, ICommandVar*>();
if (!ConfigVars) ConfigVars = new std::map<std::string, IConfigVar*>();
@ -29,8 +40,8 @@ void ParseLaunchArguments(int argc, char** argv) {
configVar->AddToLaunchOptions(&options);
}
try {
options.positional_help("[Path to .iso/.xex]");
options.parse_positional({"target"});
options.positional_help(positional_help);
options.parse_positional(positional_options);
auto result = options.parse(argc, argv);
if (result.count("help")) {

View File

@ -1,10 +1,23 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_CVAR_H_
#define XENIA_CVAR_H_
#include <map>
#include <string>
#include <vector>
#include "cpptoml/include/cpptoml.h"
#include "cxxopts/include/cxxopts.hpp"
#include "xenia/base/string_util.h"
namespace cvar {
namespace toml {
@ -204,7 +217,9 @@ inline void AddCommandVar(ICommandVar* cv) {
if (!CmdVars) CmdVars = new std::map<std::string, ICommandVar*>();
CmdVars->insert(std::pair<std::string, ICommandVar*>(cv->name(), cv));
}
void ParseLaunchArguments(int argc, char** argv);
void ParseLaunchArguments(int argc, char** argv,
const std::string& positional_help,
const std::vector<std::string>& positional_options);
template <typename T>
T* define_configvar(const char* name, T* default_value, const char* description,
@ -221,8 +236,6 @@ T* define_cmdvar(const char* name, T* default_value, const char* description) {
AddCommandVar(cmdVar);
return default_value;
}
#define DEFINE_double(name, default_value, description, category) \
DEFINE_CVar(name, default_value, description, category, false, double)
#define DEFINE_int32(name, default_value, description, category) \
DEFINE_CVar(name, default_value, description, category, false, int32_t)
@ -230,6 +243,9 @@ T* define_cmdvar(const char* name, T* default_value, const char* description) {
#define DEFINE_uint64(name, default_value, description, category) \
DEFINE_CVar(name, default_value, description, category, false, uint64_t)
#define DEFINE_double(name, default_value, description, category) \
DEFINE_CVar(name, default_value, description, category, false, double)
#define DEFINE_string(name, default_value, description, category) \
DEFINE_CVar(name, default_value, description, category, false, std::string)
@ -275,4 +291,5 @@ T* define_cmdvar(const char* name, T* default_value, const char* description) {
}
} // namespace cvar
#endif // XENIA_CVAR_H_

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -13,6 +13,7 @@
#include <string>
#include <vector>
#include "xenia/base/cvar.h"
#include "xenia/base/platform.h"
namespace xe {
@ -24,14 +25,19 @@ bool has_console_attached();
// launch.
struct EntryInfo {
std::wstring name;
std::wstring usage;
std::string positional_usage;
std::vector<std::string> positional_options;
int (*entry_point)(const std::vector<std::wstring>& args);
};
EntryInfo GetEntryInfo();
#define DEFINE_ENTRY_POINT(name, usage, entry_point) \
xe::EntryInfo xe::GetEntryInfo() { \
return xe::EntryInfo({name, usage, entry_point}); \
#define DEFINE_ENTRY_POINT(name, entry_point, positional_usage, ...) \
xe::EntryInfo xe::GetEntryInfo() { \
std::initializer_list<std::string> positional_options = {__VA_ARGS__}; \
return xe::EntryInfo( \
{name, positional_usage, \
std::vector<std::string>(std::move(positional_options)), \
entry_point}); \
}
} // namespace xe

View File

@ -22,7 +22,8 @@ bool has_console_attached() { return true; }
extern "C" int main(int argc, char** argv) {
auto entry_info = xe::GetEntryInfo();
cvar::ParseLaunchArguments(argc, argv);
cvar::ParseLaunchArguments(argc, argv, entry_info.positional_usage,
entry_info.positional_options);
std::vector<std::wstring> args;
for (int n = 0; n < argc; n++) {

View File

@ -105,7 +105,8 @@ int Main() {
std::wcstombs(argva[n], argv[n], len + 1);
}
cvar::ParseLaunchArguments(argca, argva);
cvar::ParseLaunchArguments(argca, argva, entry_info.positional_usage,
entry_info.positional_options);
// Widen all remaining flags and convert to usable strings.
std::vector<std::wstring> args;

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -407,13 +407,27 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() {
// rdx = arg0 (context)
// r8 = arg1 (guest return address)
struct _code_offsets {
size_t prolog;
size_t prolog_stack_alloc;
size_t body;
size_t epilog;
size_t tail;
} code_offsets = {};
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
code_offsets.prolog = getSize();
// rsp + 0 = return address
mov(qword[rsp + 8 * 3], r8);
mov(qword[rsp + 8 * 2], rdx);
mov(qword[rsp + 8 * 1], rcx);
sub(rsp, stack_size);
code_offsets.prolog_stack_alloc = getSize();
code_offsets.body = getSize();
// Save nonvolatile registers.
EmitSaveNonvolatileRegs();
@ -424,13 +438,28 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() {
EmitLoadNonvolatileRegs();
code_offsets.epilog = getSize();
add(rsp, stack_size);
mov(rcx, qword[rsp + 8 * 1]);
mov(rdx, qword[rsp + 8 * 2]);
mov(r8, qword[rsp + 8 * 3]);
ret();
void* fn = Emplace(stack_size);
code_offsets.tail = getSize();
assert_zero(code_offsets.prolog);
EmitFunctionInfo func_info = {};
func_info.code_size.total = getSize();
func_info.code_size.prolog = code_offsets.body - code_offsets.prolog;
func_info.code_size.body = code_offsets.epilog - code_offsets.body;
func_info.code_size.epilog = code_offsets.tail - code_offsets.epilog;
func_info.code_size.tail = getSize() - code_offsets.tail;
func_info.prolog_stack_alloc_offset =
code_offsets.prolog_stack_alloc - code_offsets.prolog;
func_info.stack_size = stack_size;
void* fn = Emplace(func_info);
return (HostToGuestThunk)fn;
}
@ -440,10 +469,24 @@ GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() {
// r8 = arg1
// r9 = arg2
struct _code_offsets {
size_t prolog;
size_t prolog_stack_alloc;
size_t body;
size_t epilog;
size_t tail;
} code_offsets = {};
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
code_offsets.prolog = getSize();
// rsp + 0 = return address
sub(rsp, stack_size);
code_offsets.prolog_stack_alloc = getSize();
code_offsets.body = getSize();
// Save off volatile registers.
EmitSaveVolatileRegs();
@ -453,10 +496,25 @@ GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() {
EmitLoadVolatileRegs();
code_offsets.epilog = getSize();
add(rsp, stack_size);
ret();
void* fn = Emplace(stack_size);
code_offsets.tail = getSize();
assert_zero(code_offsets.prolog);
EmitFunctionInfo func_info = {};
func_info.code_size.total = getSize();
func_info.code_size.prolog = code_offsets.body - code_offsets.prolog;
func_info.code_size.body = code_offsets.epilog - code_offsets.body;
func_info.code_size.epilog = code_offsets.tail - code_offsets.epilog;
func_info.code_size.tail = getSize() - code_offsets.tail;
func_info.prolog_stack_alloc_offset =
code_offsets.prolog_stack_alloc - code_offsets.prolog;
func_info.stack_size = stack_size;
void* fn = Emplace(func_info);
return (GuestToHostThunk)fn;
}
@ -466,11 +524,25 @@ extern "C" uint64_t ResolveFunction(void* raw_context, uint32_t target_address);
ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() {
// ebx = target PPC address
// rcx = context
struct _code_offsets {
size_t prolog;
size_t prolog_stack_alloc;
size_t body;
size_t epilog;
size_t tail;
} code_offsets = {};
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
code_offsets.prolog = getSize();
// rsp + 0 = return address
sub(rsp, stack_size);
code_offsets.prolog_stack_alloc = getSize();
code_offsets.body = getSize();
// Save volatile registers
EmitSaveVolatileRegs();
@ -481,10 +553,25 @@ ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() {
EmitLoadVolatileRegs();
code_offsets.epilog = getSize();
add(rsp, stack_size);
jmp(rax);
void* fn = Emplace(stack_size);
code_offsets.tail = getSize();
assert_zero(code_offsets.prolog);
EmitFunctionInfo func_info = {};
func_info.code_size.total = getSize();
func_info.code_size.prolog = code_offsets.body - code_offsets.prolog;
func_info.code_size.body = code_offsets.epilog - code_offsets.body;
func_info.code_size.epilog = code_offsets.tail - code_offsets.epilog;
func_info.code_size.tail = getSize() - code_offsets.tail;
func_info.prolog_stack_alloc_offset =
code_offsets.prolog_stack_alloc - code_offsets.prolog;
func_info.stack_size = stack_size;
void* fn = Emplace(func_info);
return (ResolveFunctionThunk)fn;
}

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -125,21 +125,21 @@ void X64CodeCache::CommitExecutableRange(uint32_t guest_low,
}
void* X64CodeCache::PlaceHostCode(uint32_t guest_address, void* machine_code,
size_t code_size, size_t stack_size) {
const EmitFunctionInfo& func_info) {
// Same for now. We may use different pools or whatnot later on, like when
// we only want to place guest code in a serialized cache on disk.
return PlaceGuestCode(guest_address, machine_code, code_size, stack_size,
nullptr);
return PlaceGuestCode(guest_address, machine_code, func_info, nullptr);
}
void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code,
size_t code_size, size_t stack_size,
const EmitFunctionInfo& func_info,
GuestFunction* function_info) {
// Hold a lock while we bump the pointers up. This is important as the
// unwind table requires entries AND code to be sorted in order.
size_t low_mark;
size_t high_mark;
uint8_t* code_address = nullptr;
size_t code_offset;
uint8_t* code_address;
UnwindReservation unwind_reservation;
{
auto global_lock = global_critical_region_.Acquire();
@ -148,15 +148,16 @@ void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code,
// Reserve code.
// Always move the code to land on 16b alignment.
code_address = generated_code_base_ + generated_code_offset_;
generated_code_offset_ += xe::round_up(code_size, 16);
code_offset = generated_code_offset_;
code_address = generated_code_base_ + code_offset;
generated_code_offset_ += xe::round_up(func_info.code_size.total, 16);
// Reserve unwind info.
// We go on the high size of the unwind info as we don't know how big we
// need it, and a few extra bytes of padding isn't the worst thing.
unwind_reservation =
RequestUnwindReservation(generated_code_base_ + generated_code_offset_);
generated_code_offset_ += unwind_reservation.data_size;
generated_code_offset_ += xe::round_up(unwind_reservation.data_size, 16);
high_mark = generated_code_offset_;
@ -187,15 +188,14 @@ void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code,
old_commit_mark, new_commit_mark));
// Copy code.
std::memcpy(code_address, machine_code, code_size);
std::memcpy(code_address, machine_code, func_info.code_size.total);
// Fill unused slots with 0xCC
std::memset(
code_address + code_size, 0xCC,
xe::round_up(code_size + unwind_reservation.data_size, 16) - code_size);
std::memset(code_address + func_info.code_size.total, 0xCC,
generated_code_offset_ - code_offset);
// Notify subclasses of placed code.
PlaceCode(guest_address, machine_code, code_size, stack_size, code_address,
PlaceCode(guest_address, machine_code, func_info, code_address,
unwind_reservation);
}

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -25,6 +25,18 @@ namespace cpu {
namespace backend {
namespace x64 {
struct EmitFunctionInfo {
struct _code_size {
size_t prolog;
size_t body;
size_t epilog;
size_t tail;
size_t total;
} code_size;
size_t prolog_stack_alloc_offset; // offset of instruction after stack alloc
size_t stack_size;
};
class X64CodeCache : public CodeCache {
public:
~X64CodeCache() override;
@ -48,9 +60,9 @@ class X64CodeCache : public CodeCache {
void CommitExecutableRange(uint32_t guest_low, uint32_t guest_high);
void* PlaceHostCode(uint32_t guest_address, void* machine_code,
size_t code_size, size_t stack_size);
const EmitFunctionInfo& func_info);
void* PlaceGuestCode(uint32_t guest_address, void* machine_code,
size_t code_size, size_t stack_size,
const EmitFunctionInfo& func_info,
GuestFunction* function_info);
uint32_t PlaceData(const void* data, size_t length);
@ -84,8 +96,7 @@ class X64CodeCache : public CodeCache {
return UnwindReservation();
}
virtual void PlaceCode(uint32_t guest_address, void* machine_code,
size_t code_size, size_t stack_size,
void* code_address,
const EmitFunctionInfo& func_info, void* code_address,
UnwindReservation unwind_reservation) {}
std::wstring file_name_;

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -21,16 +21,10 @@
#include "xenia/cpu/function.h"
// Function pointer definitions
typedef DWORD(NTAPI* FnRtlAddGrowableFunctionTable)(
_Out_ PVOID* DynamicTable,
_In_reads_(MaximumEntryCount) PRUNTIME_FUNCTION FunctionTable,
_In_ DWORD EntryCount, _In_ DWORD MaximumEntryCount,
_In_ ULONG_PTR RangeBase, _In_ ULONG_PTR RangeEnd);
typedef VOID(NTAPI* FnRtlGrowFunctionTable)(_Inout_ PVOID DynamicTable,
_In_ DWORD NewEntryCount);
typedef VOID(NTAPI* FnRtlDeleteGrowableFunctionTable)(_In_ PVOID DynamicTable);
using FnRtlAddGrowableFunctionTable = decltype(&RtlAddGrowableFunctionTable);
using FnRtlGrowFunctionTable = decltype(&RtlGrowFunctionTable);
using FnRtlDeleteGrowableFunctionTable =
decltype(&RtlDeleteGrowableFunctionTable);
namespace xe {
namespace cpu {
@ -112,13 +106,13 @@ class Win32X64CodeCache : public X64CodeCache {
private:
UnwindReservation RequestUnwindReservation(uint8_t* entry_address) override;
void PlaceCode(uint32_t guest_address, void* machine_code, size_t code_size,
size_t stack_size, void* code_address,
void PlaceCode(uint32_t guest_address, void* machine_code,
const EmitFunctionInfo& func_info, void* code_address,
UnwindReservation unwind_reservation) override;
void InitializeUnwindEntry(uint8_t* unwind_entry_address,
size_t unwind_table_slot, void* code_address,
size_t code_size, size_t stack_size);
const EmitFunctionInfo& func_info);
// Growable function table system handle.
void* unwind_table_handle_ = nullptr;
@ -163,12 +157,19 @@ bool Win32X64CodeCache::Initialize() {
unwind_table_.resize(kMaximumFunctionCount);
// Check if this version of Windows supports growable function tables.
add_growable_table_ = (FnRtlAddGrowableFunctionTable)GetProcAddress(
GetModuleHandleW(L"ntdll.dll"), "RtlAddGrowableFunctionTable");
delete_growable_table_ = (FnRtlDeleteGrowableFunctionTable)GetProcAddress(
GetModuleHandleW(L"ntdll.dll"), "RtlDeleteGrowableFunctionTable");
grow_table_ = (FnRtlGrowFunctionTable)GetProcAddress(
GetModuleHandleW(L"ntdll.dll"), "RtlGrowFunctionTable");
auto ntdll_handle = GetModuleHandleW(L"ntdll.dll");
if (!ntdll_handle) {
add_growable_table_ = nullptr;
delete_growable_table_ = nullptr;
grow_table_ = nullptr;
} else {
add_growable_table_ = (FnRtlAddGrowableFunctionTable)GetProcAddress(
ntdll_handle, "RtlAddGrowableFunctionTable");
delete_growable_table_ = (FnRtlDeleteGrowableFunctionTable)GetProcAddress(
ntdll_handle, "RtlDeleteGrowableFunctionTable");
grow_table_ = (FnRtlGrowFunctionTable)GetProcAddress(
ntdll_handle, "RtlGrowFunctionTable");
}
supports_growable_table_ =
add_growable_table_ && delete_growable_table_ && grow_table_;
@ -205,23 +206,21 @@ bool Win32X64CodeCache::Initialize() {
Win32X64CodeCache::UnwindReservation
Win32X64CodeCache::RequestUnwindReservation(uint8_t* entry_address) {
assert_false(unwind_table_count_ >= kMaximumFunctionCount);
UnwindReservation unwind_reservation;
unwind_reservation.data_size = xe::round_up(kUnwindInfoSize, 16);
unwind_reservation.table_slot = ++unwind_table_count_;
unwind_reservation.table_slot = unwind_table_count_++;
unwind_reservation.entry_address = entry_address;
assert_false(unwind_table_count_ >= kMaximumFunctionCount);
return unwind_reservation;
}
void Win32X64CodeCache::PlaceCode(uint32_t guest_address, void* machine_code,
size_t code_size, size_t stack_size,
const EmitFunctionInfo& func_info,
void* code_address,
UnwindReservation unwind_reservation) {
// Add unwind info.
InitializeUnwindEntry(unwind_reservation.entry_address,
unwind_reservation.table_slot, code_address, code_size,
stack_size);
unwind_reservation.table_slot, code_address, func_info);
if (supports_growable_table_) {
// Notify that the unwind table has grown.
@ -230,29 +229,33 @@ void Win32X64CodeCache::PlaceCode(uint32_t guest_address, void* machine_code,
}
// This isn't needed on x64 (probably), but is convention.
FlushInstructionCache(GetCurrentProcess(), code_address, code_size);
FlushInstructionCache(GetCurrentProcess(), code_address,
func_info.code_size.total);
}
void Win32X64CodeCache::InitializeUnwindEntry(uint8_t* unwind_entry_address,
size_t unwind_table_slot,
void* code_address,
size_t code_size,
size_t stack_size) {
void Win32X64CodeCache::InitializeUnwindEntry(
uint8_t* unwind_entry_address, size_t unwind_table_slot, void* code_address,
const EmitFunctionInfo& func_info) {
auto unwind_info = reinterpret_cast<UNWIND_INFO*>(unwind_entry_address);
UNWIND_CODE* unwind_code = nullptr;
if (!stack_size) {
// https://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
assert_true(func_info.code_size.prolog < 256); // needs to fit into a uint8_t
auto prolog_size = static_cast<uint8_t>(func_info.code_size.prolog);
assert_true(func_info.prolog_stack_alloc_offset <
256); // needs to fit into a uint8_t
auto prolog_stack_alloc_offset =
static_cast<uint8_t>(func_info.prolog_stack_alloc_offset);
if (!func_info.stack_size) {
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info
unwind_info->Version = 1;
unwind_info->Flags = 0;
unwind_info->SizeOfProlog = 0;
unwind_info->SizeOfProlog = prolog_size;
unwind_info->CountOfCodes = 0;
unwind_info->FrameRegister = 0;
unwind_info->FrameOffset = 0;
} else if (stack_size <= 128) {
uint8_t prolog_size = 4;
// https://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
} else if (func_info.stack_size <= 128) {
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info
unwind_info->Version = 1;
unwind_info->Flags = 0;
unwind_info->SizeOfProlog = prolog_size;
@ -260,17 +263,15 @@ void Win32X64CodeCache::InitializeUnwindEntry(uint8_t* unwind_entry_address,
unwind_info->FrameRegister = 0;
unwind_info->FrameOffset = 0;
// https://msdn.microsoft.com/en-us/library/ck9asaa9.aspx
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_code
unwind_code = &unwind_info->UnwindCode[unwind_info->CountOfCodes++];
unwind_code->CodeOffset =
14; // end of instruction + 1 == offset of next instruction
unwind_code->CodeOffset = prolog_stack_alloc_offset;
unwind_code->UnwindOp = UWOP_ALLOC_SMALL;
unwind_code->OpInfo = stack_size / 8 - 1;
unwind_code->OpInfo = (func_info.stack_size / 8) - 1;
} else {
// TODO(benvanik): take as parameters?
uint8_t prolog_size = 7;
// https://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info
unwind_info->Version = 1;
unwind_info->Flags = 0;
unwind_info->SizeOfProlog = prolog_size;
@ -278,16 +279,15 @@ void Win32X64CodeCache::InitializeUnwindEntry(uint8_t* unwind_entry_address,
unwind_info->FrameRegister = 0;
unwind_info->FrameOffset = 0;
// https://msdn.microsoft.com/en-us/library/ck9asaa9.aspx
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_code
unwind_code = &unwind_info->UnwindCode[unwind_info->CountOfCodes++];
unwind_code->CodeOffset =
7; // end of instruction + 1 == offset of next instruction
unwind_code->CodeOffset = prolog_stack_alloc_offset;
unwind_code->UnwindOp = UWOP_ALLOC_LARGE;
unwind_code->OpInfo = 0; // One slot for size
assert_true((stack_size / 8) < 65536u);
assert_true((func_info.stack_size / 8) < 65536u);
unwind_code = &unwind_info->UnwindCode[unwind_info->CountOfCodes++];
unwind_code->FrameOffset = (USHORT)(stack_size) / 8;
unwind_code->FrameOffset = (USHORT)(func_info.stack_size) / 8;
}
if (unwind_info->CountOfCodes % 1) {
@ -300,13 +300,14 @@ void Win32X64CodeCache::InitializeUnwindEntry(uint8_t* unwind_entry_address,
auto& fn_entry = unwind_table_[unwind_table_slot];
fn_entry.BeginAddress =
(DWORD)(reinterpret_cast<uint8_t*>(code_address) - generated_code_base_);
fn_entry.EndAddress = (DWORD)(fn_entry.BeginAddress + code_size);
fn_entry.EndAddress =
(DWORD)(fn_entry.BeginAddress + func_info.code_size.total);
fn_entry.UnwindData = (DWORD)(unwind_entry_address - generated_code_base_);
}
void* Win32X64CodeCache::LookupUnwindInfo(uint64_t host_pc) {
return std::bsearch(
&host_pc, unwind_table_.data(), unwind_table_count_ + 1,
&host_pc, unwind_table_.data(), unwind_table_count_,
sizeof(RUNTIME_FUNCTION),
[](const void* key_ptr, const void* element_ptr) {
auto key =

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -102,14 +102,14 @@ bool X64Emitter::Emit(GuestFunction* function, HIRBuilder* builder,
source_map_arena_.Reset();
// Fill the generator with code.
size_t stack_size = 0;
if (!Emit(builder, &stack_size)) {
EmitFunctionInfo func_info = {};
if (!Emit(builder, func_info)) {
return false;
}
// Copy the final code to the cache and relocate it.
*out_code_size = getSize();
*out_code_address = Emplace(stack_size, function);
*out_code_address = Emplace(func_info, function);
// Stash source map.
source_map_arena_.CloneContents(out_source_map);
@ -117,18 +117,20 @@ bool X64Emitter::Emit(GuestFunction* function, HIRBuilder* builder,
return true;
}
void* X64Emitter::Emplace(size_t stack_size, GuestFunction* function) {
void* X64Emitter::Emplace(const EmitFunctionInfo& func_info,
GuestFunction* function) {
// To avoid changing xbyak, we do a switcharoo here.
// top_ points to the Xbyak buffer, and since we are in AutoGrow mode
// it has pending relocations. We copy the top_ to our buffer, swap the
// pointer, relocate, then return the original scratch pointer for use.
uint8_t* old_address = top_;
void* new_address;
assert_true(func_info.code_size.total == size_);
if (function) {
new_address = code_cache_->PlaceGuestCode(function->address(), top_, size_,
stack_size, function);
new_address = code_cache_->PlaceGuestCode(function->address(), top_,
func_info, function);
} else {
new_address = code_cache_->PlaceHostCode(0, top_, size_, stack_size);
new_address = code_cache_->PlaceHostCode(0, top_, func_info);
}
top_ = reinterpret_cast<uint8_t*>(new_address);
ready();
@ -137,7 +139,7 @@ void* X64Emitter::Emplace(size_t stack_size, GuestFunction* function) {
return new_address;
}
bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
bool X64Emitter::Emit(HIRBuilder* builder, EmitFunctionInfo& func_info) {
Xbyak::Label epilog_label;
epilog_label_ = &epilog_label;
@ -159,6 +161,16 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
stack_offset -= StackLayout::GUEST_STACK_SIZE;
stack_offset = xe::align(stack_offset, static_cast<size_t>(16));
struct _code_offsets {
size_t prolog;
size_t prolog_stack_alloc;
size_t body;
size_t epilog;
size_t tail;
} code_offsets = {};
code_offsets.prolog = getSize();
// Function prolog.
// Must be 16b aligned.
// Windows is very strict about the form of this and the epilog:
@ -168,10 +180,14 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
// Adding or changing anything here must be matched!
const size_t stack_size = StackLayout::GUEST_STACK_SIZE + stack_offset;
assert_true((stack_size + 8) % 16 == 0);
*out_stack_size = stack_size;
func_info.stack_size = stack_size;
stack_size_ = stack_size;
sub(rsp, (uint32_t)stack_size);
code_offsets.prolog_stack_alloc = getSize();
code_offsets.body = getSize();
mov(qword[rsp + StackLayout::GUEST_CTX_HOME], GetContextReg());
mov(qword[rsp + StackLayout::GUEST_RET_ADDR], rcx);
mov(qword[rsp + StackLayout::GUEST_CALL_RET_ADDR], 0);
@ -241,9 +257,14 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
epilog_label_ = nullptr;
EmitTraceUserCallReturn();
mov(GetContextReg(), qword[rsp + StackLayout::GUEST_CTX_HOME]);
code_offsets.epilog = getSize();
add(rsp, (uint32_t)stack_size);
ret();
code_offsets.tail = getSize();
if (cvars::emit_source_annotations) {
nop();
nop();
@ -252,6 +273,15 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
nop();
}
assert_zero(code_offsets.prolog);
func_info.code_size.total = getSize();
func_info.code_size.prolog = code_offsets.body - code_offsets.prolog;
func_info.code_size.body = code_offsets.epilog - code_offsets.body;
func_info.code_size.epilog = code_offsets.tail - code_offsets.epilog;
func_info.code_size.tail = getSize() - code_offsets.tail;
func_info.prolog_stack_alloc_offset =
code_offsets.prolog_stack_alloc - code_offsets.prolog;
return true;
}

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -39,6 +39,8 @@ namespace x64 {
class X64Backend;
class X64CodeCache;
struct EmitFunctionInfo;
enum RegisterFlags {
REG_DEST = (1 << 0),
REG_ABCD = (1 << 1),
@ -203,8 +205,6 @@ class X64Emitter : public Xbyak::CodeGenerator {
void nop(size_t length = 1);
// TODO(benvanik): Label for epilog (don't use strings).
// Moves a 64bit immediate into memory.
bool ConstantFitsIn32Reg(uint64_t v);
void MovMem64(const Xbyak::RegExp& addr, uint64_t v);
@ -224,8 +224,9 @@ class X64Emitter : public Xbyak::CodeGenerator {
size_t stack_size() const { return stack_size_; }
protected:
void* Emplace(size_t stack_size, GuestFunction* function = nullptr);
bool Emit(hir::HIRBuilder* builder, size_t* out_stack_size);
void* Emplace(const EmitFunctionInfo& func_info,
GuestFunction* function = nullptr);
bool Emit(hir::HIRBuilder* builder, EmitFunctionInfo& func_info);
void EmitGetCurrentThreadId();
void EmitTraceUserCallReturn();

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -27,6 +27,7 @@ DEFINE_string(test_path, "src/xenia/cpu/ppc/testing/",
"Directory scanned for test files.", "Other");
DEFINE_string(test_bin_path, "src/xenia/cpu/ppc/testing/bin/",
"Directory with binary outputs of the test files.", "Other");
DEFINE_transient_string(test_name, "", "Specifies test name.", "General");
namespace xe {
namespace cpu {
@ -472,5 +473,5 @@ int main(const std::vector<std::wstring>& args) {
} // namespace cpu
} // namespace xe
DEFINE_ENTRY_POINT(L"xenia-cpu-ppc-test", L"xenia-cpu-ppc-test [test name]",
xe::cpu::test::main);
DEFINE_ENTRY_POINT(L"xenia-cpu-ppc-test", xe::cpu::test::main, "[test name]",
"test_name");

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -179,6 +179,5 @@ int shader_compiler_main(const std::vector<std::wstring>& args) {
} // namespace gpu
} // namespace xe
DEFINE_ENTRY_POINT(L"xenia-gpu-shader-compiler",
L"xenia-gpu-shader-compiler shader.bin",
xe::gpu::shader_compiler_main);
DEFINE_ENTRY_POINT(L"xenia-gpu-shader-compiler", xe::gpu::shader_compiler_main,
"shader.bin", "shader_input");

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -36,5 +36,5 @@ int trace_dump_main(const std::vector<std::wstring>& args) {
} // namespace xe
DEFINE_ENTRY_POINT(L"xenia-gpu-vulkan-trace-dump",
L"xenia-gpu-vulkan-trace-dump some.trace",
xe::gpu::vulkan::trace_dump_main);
xe::gpu::vulkan::trace_dump_main, "some.trace",
"target_trace_file");

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -72,5 +72,5 @@ int trace_viewer_main(const std::vector<std::wstring>& args) {
} // namespace xe
DEFINE_ENTRY_POINT(L"xenia-gpu-vulkan-trace-viewer",
L"xenia-gpu-vulkan-trace-viewer some.trace",
xe::gpu::vulkan::trace_viewer_main);
xe::gpu::vulkan::trace_viewer_main, "some.trace",
"target_trace_file");

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2017 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -215,5 +215,4 @@ void DrawInputStatus() {
} // namespace hid
} // namespace xe
DEFINE_ENTRY_POINT(L"xenia-hid-demo", L"xenia-hid-demo",
xe::hid::hid_demo_main);
DEFINE_ENTRY_POINT(L"xenia-hid-demo", xe::hid::hid_demo_main, "");

View File

@ -11,6 +11,7 @@
#include "xenia/apu/audio_system.h"
#include "xenia/apu/xma_decoder.h"
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/emulator.h"
#include "xenia/kernel/kernel_state.h"
@ -184,9 +185,19 @@ DECLARE_XBOXKRNL_EXPORT2(XMASetInputBufferReadOffset, kAudio, kImplemented,
dword_result_t XMASetInputBuffer0(lpvoid_t context_ptr, lpvoid_t buffer,
dword_t packet_count) {
uint32_t buffer_physical_address =
kernel_memory()->GetPhysicalAddress(buffer.guest_address());
assert_true(buffer_physical_address != UINT32_MAX);
if (buffer_physical_address == UINT32_MAX) {
// Xenia-specific safety check.
XELOGE("XMASetInputBuffer0: Invalid buffer virtual address %.8X",
buffer.guest_address());
return X_E_FALSE;
}
XMA_CONTEXT_DATA context(context_ptr);
context.input_buffer_0_ptr = buffer.guest_address();
context.input_buffer_0_ptr = buffer_physical_address;
context.input_buffer_0_packet_count = packet_count;
context.Store(context_ptr);
@ -215,9 +226,19 @@ DECLARE_XBOXKRNL_EXPORT2(XMASetInputBuffer0Valid, kAudio, kImplemented,
dword_result_t XMASetInputBuffer1(lpvoid_t context_ptr, lpvoid_t buffer,
dword_t packet_count) {
uint32_t buffer_physical_address =
kernel_memory()->GetPhysicalAddress(buffer.guest_address());
assert_true(buffer_physical_address != UINT32_MAX);
if (buffer_physical_address == UINT32_MAX) {
// Xenia-specific safety check.
XELOGE("XMASetInputBuffer1: Invalid buffer virtual address %.8X",
buffer.guest_address());
return X_E_FALSE;
}
XMA_CONTEXT_DATA context(context_ptr);
context.input_buffer_1_ptr = buffer.guest_address();
context.input_buffer_1_ptr = buffer_physical_address;
context.input_buffer_1_packet_count = packet_count;
context.Store(context_ptr);

View File

@ -330,9 +330,20 @@ dword_result_t MmAllocatePhysicalMemoryEx(dword_t flags, dword_t region_size,
uint32_t allocation_type = kMemoryAllocationReserve | kMemoryAllocationCommit;
uint32_t protect = FromXdkProtectFlags(protect_bits);
bool top_down = true;
auto heap = kernel_memory()->LookupHeapByType(true, page_size);
auto heap = static_cast<PhysicalHeap*>(
kernel_memory()->LookupHeapByType(true, page_size));
// min_addr_range/max_addr_range are bounds in physical memory, not virtual.
uint32_t heap_base = heap->heap_base();
uint32_t heap_physical_address_offset = heap->GetPhysicalAddress(heap_base);
uint32_t heap_min_addr =
xe::sat_sub(min_addr_range.value(), heap_physical_address_offset);
uint32_t heap_max_addr =
xe::sat_sub(max_addr_range.value(), heap_physical_address_offset);
uint32_t heap_size = heap->heap_size();
heap_min_addr = heap_base + std::min(heap_min_addr, heap_size);
heap_max_addr = heap_base + std::min(heap_max_addr, heap_size);
uint32_t base_address;
if (!heap->AllocRange(min_addr_range, max_addr_range, adjusted_size,
if (!heap->AllocRange(heap_min_addr, heap_max_addr, adjusted_size,
adjusted_alignment, allocation_type, protect, top_down,
&base_address)) {
// Failed - assume no memory available.
@ -502,13 +513,11 @@ dword_result_t MmGetPhysicalAddress(dword_t base_address) {
// _In_ PVOID BaseAddress
// );
// base_address = result of MmAllocatePhysicalMemory.
assert_true(base_address >= 0xA0000000);
uint32_t physical_address = base_address & 0x1FFFFFFF;
if (base_address >= 0xE0000000) {
physical_address += 0x1000;
uint32_t physical_address = kernel_memory()->GetPhysicalAddress(base_address);
assert_true(physical_address != UINT32_MAX);
if (physical_address == UINT32_MAX) {
physical_address = 0;
}
return physical_address;
}
DECLARE_XBOXKRNL_EXPORT1(MmGetPhysicalAddress, kMemory, kImplemented);

View File

@ -362,13 +362,26 @@ void VdSwap(lpvoid_t buffer_ptr, // ptr into primary ringbuffer
xe::copy_and_swap_32_unaligned(
&fetch, reinterpret_cast<uint32_t*>(fetch_ptr.host_address()), 6);
// Kernel virtual -> GPU physical.
uint32_t frontbuffer_address = fetch.base_address << 12;
assert_true(*frontbuffer_ptr == frontbuffer_address);
frontbuffer_address =
kernel_memory()->GetPhysicalAddress(frontbuffer_address);
assert_true(frontbuffer_address != UINT32_MAX);
if (frontbuffer_address == UINT32_MAX) {
// Xenia-specific safety check.
XELOGE("VdSwap: Invalid front buffer virtual address 0x%.8X",
fetch.base_address << 12);
return;
}
fetch.base_address = frontbuffer_address >> 12;
auto texture_format = gpu::TextureFormat(texture_format_ptr.value());
auto color_space = *color_space_ptr;
assert_true(texture_format == gpu::TextureFormat::k_8_8_8_8 ||
texture_format ==
gpu::TextureFormat::k_2_10_10_10_AS_16_16_16_16);
assert_true(color_space == 0); // RGB(0)
assert_true(*frontbuffer_ptr == fetch.base_address << 12);
assert_true(*width == 1 + fetch.size_2d.width);
assert_true(*height == 1 + fetch.size_2d.height);
@ -379,14 +392,6 @@ void VdSwap(lpvoid_t buffer_ptr, // ptr into primary ringbuffer
// use this method.
buffer_ptr.Zero(64 * 4);
// virtual -> physical
// Doom 3: BFG Edition uses front buffers from the 0xE0000000 range with 4 KB
// offset, so & 0x1FFFF is not enough for this.
fetch.base_address = kernel_memory()
->LookupHeap(fetch.base_address << 12)
->GetPhysicalAddress(fetch.base_address << 12) >>
12;
uint32_t offset = 0;
auto dwords = buffer_ptr.as_array<uint32_t>();
@ -402,9 +407,7 @@ void VdSwap(lpvoid_t buffer_ptr, // ptr into primary ringbuffer
dwords[offset++] = xenos::MakePacketType3(xenos::PM4_XE_SWAP, 4);
dwords[offset++] = 'SWAP';
dwords[offset++] = kernel_memory()
->LookupHeap(*frontbuffer_ptr)
->GetPhysicalAddress(*frontbuffer_ptr);
dwords[offset++] = frontbuffer_address;
dwords[offset++] = *width;
dwords[offset++] = *height;

View File

@ -369,6 +369,14 @@ uint32_t Memory::HostToGuestVirtualThunk(const void* context,
host_address);
}
uint32_t Memory::GetPhysicalAddress(uint32_t address) const {
const BaseHeap* heap = LookupHeap(address);
if (!heap || !heap->IsGuestPhysicalHeap()) {
return UINT32_MAX;
}
return static_cast<const PhysicalHeap*>(heap)->GetPhysicalAddress(address);
}
void Memory::Zero(uint32_t address, uint32_t size) {
std::memset(TranslateVirtual(address), 0, size);
}
@ -440,8 +448,7 @@ bool Memory::AccessViolationCallback(void* host_address, bool is_write) {
}
uint32_t virtual_address = HostToGuestVirtual(host_address);
BaseHeap* heap = LookupHeap(virtual_address);
if (heap == &heaps_.vA0000000 || heap == &heaps_.vC0000000 ||
heap == &heaps_.vE0000000) {
if (heap->IsGuestPhysicalHeap()) {
// Will be rounded to physical page boundaries internally, so just pass 1 as
// the length - guranteed not to cross page boundaries also.
return static_cast<PhysicalHeap*>(heap)->TriggerWatches(virtual_address, 1,
@ -461,8 +468,7 @@ bool Memory::TriggerWatches(uint32_t virtual_address, uint32_t length,
bool is_write, bool unwatch_exact_range,
bool unprotect) {
BaseHeap* heap = LookupHeap(virtual_address);
if (heap == &heaps_.vA0000000 || heap == &heaps_.vC0000000 ||
heap == &heaps_.vE0000000) {
if (heap->IsGuestPhysicalHeap()) {
return static_cast<PhysicalHeap*>(heap)->TriggerWatches(
virtual_address, length, is_write, unwatch_exact_range, unprotect);
}
@ -1274,16 +1280,6 @@ bool BaseHeap::QueryProtect(uint32_t address, uint32_t* out_protect) {
return true;
}
uint32_t BaseHeap::GetPhysicalAddress(uint32_t address) {
// Only valid for memory in this range - will be bogus if the origin was
// outside of it.
uint32_t physical_address = address & 0x1FFFFFFF;
if (address >= 0xE0000000) {
physical_address += 0x1000;
}
return physical_address;
}
VirtualHeap::VirtualHeap() = default;
VirtualHeap::~VirtualHeap() = default;
@ -1724,4 +1720,14 @@ bool PhysicalHeap::TriggerWatches(uint32_t virtual_address, uint32_t length,
return true;
}
uint32_t PhysicalHeap::GetPhysicalAddress(uint32_t address) const {
assert_true(address >= heap_base_);
address -= heap_base_;
assert_true(address <= heap_size_);
if (heap_base_ >= 0xE0000000) {
address += 0x1000;
}
return address;
}
} // namespace xe

View File

@ -171,9 +171,8 @@ class BaseHeap {
// address.
bool QueryProtect(uint32_t address, uint32_t* out_protect);
// Gets the physical address of a virtual address.
// This is only valid if the page is backed by a physical allocation.
uint32_t GetPhysicalAddress(uint32_t address);
// Whether the heap is a guest virtual memory mapping of the physical memory.
virtual bool IsGuestPhysicalHeap() const { return false; }
bool Save(ByteStream* stream);
bool Restore(ByteStream* stream);
@ -244,6 +243,9 @@ class PhysicalHeap : public BaseHeap {
bool TriggerWatches(uint32_t virtual_address, uint32_t length, bool is_write,
bool unwatch_exact_range, bool unprotect = true);
bool IsGuestPhysicalHeap() const override { return true; }
uint32_t GetPhysicalAddress(uint32_t address) const;
protected:
VirtualHeap* parent_heap_;
@ -317,6 +319,10 @@ class Memory {
// Note that the contents at the returned host address are big-endian.
uint32_t HostToGuestVirtual(const void* host_address) const;
// Returns the guest physical address for the guest virtual address, or
// UINT32_MAX if it can't be obtained.
uint32_t GetPhysicalAddress(uint32_t address) const;
// Zeros out a range of memory at the given guest address.
void Zero(uint32_t address, uint32_t size);

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -26,5 +26,5 @@ std::unique_ptr<GraphicsProvider> CreateDemoGraphicsProvider(Window* window) {
} // namespace ui
} // namespace xe
DEFINE_ENTRY_POINT(L"xenia-ui-window-vulkan-demo",
L"xenia-ui-window-vulkan-demo", xe::ui::window_demo_main);
DEFINE_ENTRY_POINT(L"xenia-ui-window-vulkan-demo", xe::ui::window_demo_main,
"");

View File

@ -21,9 +21,15 @@
namespace xe {
namespace vfs {
DEFINE_transient_string(source, "", "Specifies the file to dump from.",
"General");
DEFINE_transient_string(dump_path, "",
"Specifies the directory to dump files to.", "General");
int vfs_dump_main(const std::vector<std::wstring>& args) {
if (args.size() <= 2) {
XELOGE("Usage: %s [source] [dump_path]", args[0].c_str());
XELOGE("Usage: %S [source] [dump_path]", args[0].c_str());
return 1;
}
@ -107,5 +113,5 @@ int vfs_dump_main(const std::vector<std::wstring>& args) {
} // namespace vfs
} // namespace xe
DEFINE_ENTRY_POINT(L"xenia-vfs-dump", L"xenia-vfs-dump",
xe::vfs::vfs_dump_main);
DEFINE_ENTRY_POINT(L"xenia-vfs-dump", xe::vfs::vfs_dump_main,
"[source] [dump_path]", "source", "dump_path");

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -23,7 +23,7 @@ bool has_console_attached() { return true; }
// Used in console mode apps; automatically picked based on subsystem.
int Main(int argc, char* argv[]) {
cvar::ParseLaunchArguments(argc, argv);
cvar::ParseLaunchArguments(argc, argv, "", std::vector<std::string>());
// Run Catch.
int result = Catch::Session().run(argc, argv);

52
xb.bat
View File

@ -1,7 +1,7 @@
@ECHO OFF
REM Copyright 2015 Ben Vanik. All Rights Reserved.
SET DIR=%~dp0
SET "DIR=%~dp0"
REM ============================================================================
REM Environment Validation
@ -20,7 +20,7 @@ REM ============================================================================
REM Trampoline into xenia-build
REM ============================================================================
"%PYTHON_EXE%" xenia-build %*
"%PYTHON_EXE%" "%DIR%\xenia-build" %*
EXIT /b %ERRORLEVEL%
@ -33,19 +33,23 @@ SETLOCAL ENABLEDELAYEDEXPANSION
SET FOUND_PATH=""
SET CANDIDATE_PATHS[0]=C:\python37\python.exe
SET CANDIDATE_PATHS[1]=C:\python36\python.exe
SET CANDIDATE_PATHS[2]=C:\python35\python.exe
SET CANDIDATE_PATHS[3]=C:\python34\python.exe
SET "CANDIDATE_PATHS[0]=C:\python37\python.exe"
SET "CANDIDATE_PATHS[1]=C:\python36\python.exe"
SET "CANDIDATE_PATHS[2]=C:\python35\python.exe"
SET "CANDIDATE_PATHS[3]=C:\python34\python.exe"
SET OUTPUT_INDEX=4
FOR /F "usebackq" %%l IN (`2^>NUL where python3`) DO (
SET CANDIDATE_PATHS[!OUTPUT_INDEX!]=%%l
SET /A OUTPUT_INDEX+=1
FOR /F "usebackq delims=" %%L IN (`2^>NUL where python3`) DO (
IF %%~zL NEQ 0 (
SET "CANDIDATE_PATHS[!OUTPUT_INDEX!]=%%L"
SET /A OUTPUT_INDEX+=1
)
)
FOR /F "usebackq" %%l IN (`2^>NUL where python`) DO (
SET CANDIDATE_PATHS[!OUTPUT_INDEX!]=%%l
SET /A OUTPUT_INDEX+=1
FOR /F "usebackq delims=" %%L IN (`2^>NUL where python`) DO (
IF %%~zL NEQ 0 (
SET "CANDIDATE_PATHS[!OUTPUT_INDEX!]=%%L"
SET /A OUTPUT_INDEX+=1
)
)
SET CANDIDATE_INDEX=0
@ -54,40 +58,30 @@ IF NOT DEFINED CANDIDATE_PATHS[%CANDIDATE_INDEX%] (
GOTO :found_python
)
CALL SET CANDIDATE_PATH=%%CANDIDATE_PATHS[%CANDIDATE_INDEX%]%%
IF NOT EXIST %CANDIDATE_PATH% (
IF NOT EXIST "%CANDIDATE_PATH%" (
SET /A CANDIDATE_INDEX+=1
GOTO :check_candidate_loop
)
CALL :get_size %CANDIDATE_PATH%
IF %_SIZE% NEQ 0 (
SET FOUND_PATH=%CANDIDATE_PATH%
GOTO :found_python
)
SET /A CANDIDATE_INDEX+=1
GOTO :check_candidate_loop
SET "FOUND_PATH=%CANDIDATE_PATH%"
:found_python
IF %FOUND_PATH%=="" (
IF "%FOUND_PATH%"=="" (
ECHO ERROR: no Python executable found on PATH.
ECHO Make sure you can run 'python' or 'python3' in a Command Prompt.
ENDLOCAL & SET _RESULT=1
GOTO :eof
)
CMD /C %FOUND_PATH% -c "import sys; sys.exit(1 if not sys.version_info[:2] >= (3, 4) else 0)"
CMD /C ""%FOUND_PATH%" -c "import sys; sys.exit(1 if not sys.version_info[:2] ^>= (3, 4) else 0)"
IF %ERRORLEVEL% NEQ 0 (
ECHO ERROR: Python version mismatch - not 3.4+
ECHO Found Python executable was '%FOUND_PATH%'.
ECHO ERROR: Python version mismatch, not at least 3.4.
ECHO Found Python executable was "%FOUND_PATH%".
ENDLOCAL & SET _RESULT=1
GOTO :eof
)
ENDLOCAL & (
SET _RESULT=0
SET PYTHON_EXE=%FOUND_PATH%
SET "PYTHON_EXE=%FOUND_PATH%"
)
GOTO :eof
:get_size
SET _SIZE=%~z1
goto :eof