Merge branch 'master' into linux_windowing

This commit is contained in:
Triang3l
2021-08-26 22:58:14 +03:00
813 changed files with 429062 additions and 250262 deletions

View File

@@ -519,7 +519,7 @@ GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() {
}
// X64Emitter handles actually resolving functions.
extern "C" uint64_t ResolveFunction(void* raw_context, uint32_t target_address);
uint64_t ResolveFunction(void* raw_context, uint64_t target_address);
ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() {
// ebx = target PPC address
@@ -548,7 +548,7 @@ ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() {
mov(rcx, rsi); // context
mov(rdx, rbx);
mov(rax, uint64_t(&ResolveFunction));
mov(rax, reinterpret_cast<uint64_t>(&ResolveFunction));
call(rax);
EmitLoadVolatileRegs();

View File

@@ -382,15 +382,14 @@ void X64Emitter::UnimplementedInstr(const hir::Instr* i) {
}
// This is used by the X64ThunkEmitter's ResolveFunctionThunk.
extern "C" uint64_t ResolveFunction(void* raw_context,
uint64_t target_address) {
uint64_t ResolveFunction(void* raw_context, uint64_t target_address) {
auto thread_state = *reinterpret_cast<ThreadState**>(raw_context);
// TODO(benvanik): required?
assert_not_zero(target_address);
auto fn =
thread_state->processor()->ResolveFunction((uint32_t)target_address);
auto fn = thread_state->processor()->ResolveFunction(
static_cast<uint32_t>(target_address));
assert_not_null(fn);
auto x64_fn = static_cast<X64Function*>(fn);
uint64_t addr = reinterpret_cast<uint64_t>(x64_fn->machine_code());

View File

@@ -105,8 +105,7 @@ struct Op : OpBase {
struct VoidOp : Op<VoidOp, KEY_TYPE_X> {
protected:
template <typename T, KeyType KEY_TYPE>
friend struct Op;
friend struct Op<VoidOp, KEY_TYPE_X>;
template <hir::Opcode OPCODE, typename... Ts>
friend struct I;
void Load(const Instr::Op& op) {}
@@ -116,8 +115,7 @@ struct OffsetOp : Op<OffsetOp, KEY_TYPE_O> {
uint64_t value;
protected:
template <typename T, KeyType KEY_TYPE>
friend struct Op;
friend struct Op<OffsetOp, KEY_TYPE_O>;
template <hir::Opcode OPCODE, typename... Ts>
friend struct I;
void Load(const Instr::Op& op) { this->value = op.offset; }
@@ -127,8 +125,7 @@ struct SymbolOp : Op<SymbolOp, KEY_TYPE_S> {
Function* value;
protected:
template <typename T, KeyType KEY_TYPE>
friend struct Op;
friend struct Op<SymbolOp, KEY_TYPE_S>;
template <hir::Opcode OPCODE, typename... Ts>
friend struct I;
bool Load(const Instr::Op& op) {
@@ -141,8 +138,7 @@ struct LabelOp : Op<LabelOp, KEY_TYPE_L> {
hir::Label* value;
protected:
template <typename T, KeyType KEY_TYPE>
friend struct Op;
friend struct Op<LabelOp, KEY_TYPE_L>;
template <hir::Opcode OPCODE, typename... Ts>
friend struct I;
void Load(const Instr::Op& op) { this->value = op.label; }

View File

@@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@@ -73,14 +73,14 @@ void DataFlowAnalysisPass::AnalyzeFlow(HIRBuilder* builder,
// Stash for value map. We may want to maintain this during building.
auto arena = builder->arena();
auto value_map = reinterpret_cast<Value**>(
arena->Alloc(sizeof(Value*) * max_value_estimate));
arena->Alloc(sizeof(Value*) * max_value_estimate, alignof(Value)));
// Allocate incoming bitvectors for use by blocks. We don't need outgoing
// because they are only used during the block iteration.
// Mapped by block ordinal.
// TODO(benvanik): cache this list, grow as needed, etc.
auto incoming_bitvectors =
(llvm::BitVector**)arena->Alloc(sizeof(llvm::BitVector*) * block_count);
auto incoming_bitvectors = (llvm::BitVector**)arena->Alloc(
sizeof(llvm::BitVector*) * block_count, alignof(llvm::BitVector));
for (auto n = 0u; n < block_count; n++) {
incoming_bitvectors[n] = new llvm::BitVector(max_value_estimate);
}

View File

@@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@@ -45,7 +45,7 @@ bool FinalizationPass::Run(HIRBuilder* builder) {
while (label) {
if (!label->name) {
const size_t label_len = 6 + 4;
char* name = reinterpret_cast<char*>(arena->Alloc(label_len + 1));
char* name = reinterpret_cast<char*>(arena->Alloc(label_len + 1, 1));
assert_true(label->id <= 9999);
auto end = fmt::format_to_n(name, label_len, "_label{}", label->id);
name[end.size] = '\0';

View File

@@ -39,7 +39,7 @@ enum class ExportCategory : uint8_t {
};
struct ExportTag {
typedef uint32_t type;
using type = uint32_t;
// packed like so:
// ll...... cccccccc ........ ..bihssi

View File

@@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@@ -739,7 +739,7 @@ void HIRBuilder::Comment(std::string_view value) {
return;
}
auto size = value.size();
auto p = reinterpret_cast<char*>(arena_->Alloc(size + 1));
auto p = reinterpret_cast<char*>(arena_->Alloc(size + 1, 1));
std::memcpy(p, value.data(), size);
p[size] = '\0';
Instr* i = AppendInstr(OPCODE_COMMENT_info, 0);
@@ -752,7 +752,7 @@ void HIRBuilder::Comment(const StringBuffer& value) {
return;
}
auto size = value.length();
auto p = reinterpret_cast<char*>(arena_->Alloc(size + 1));
auto p = reinterpret_cast<char*>(arena_->Alloc(size + 1, 1));
std::memcpy(p, value.buffer(), size);
p[size] = '\0';
Instr* i = AppendInstr(OPCODE_COMMENT_info, 0);

View File

@@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@@ -75,7 +75,7 @@ class HIRBuilder {
template <typename... Args>
void CommentFormat(const std::string_view format, const Args&... args) {
static const uint32_t kMaxCommentSize = 1024;
char* p = reinterpret_cast<char*>(arena_->Alloc(kMaxCommentSize));
char* p = reinterpret_cast<char*>(arena_->Alloc(kMaxCommentSize, 1));
auto result = fmt::format_to_n(p, kMaxCommentSize - 1, format, args...);
p[result.size] = '\0';
size_t rewind = kMaxCommentSize - 1 - result.size;

View File

@@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@@ -245,65 +245,34 @@ void Value::Convert(TypeName target_type, RoundMode round_mode) {
}
}
template <typename T>
T __inline RoundValue(RoundMode round_mode, T value) {
switch (round_mode) {
case ROUND_TO_ZERO:
return std::trunc(value);
case ROUND_TO_NEAREST:
return std::round(value);
case ROUND_TO_MINUS_INFINITY:
return std::floor(value);
case ROUND_TO_POSITIVE_INFINITY:
return std::ceil(value);
default:
assert_unhandled_case(round_mode);
return value;
}
}
void Value::Round(RoundMode round_mode) {
switch (type) {
case FLOAT32_TYPE:
switch (round_mode) {
case ROUND_TO_ZERO:
constant.f32 = std::trunc(constant.f32);
break;
case ROUND_TO_NEAREST:
constant.f32 = std::round(constant.f32);
return;
case ROUND_TO_MINUS_INFINITY:
constant.f32 = std::floor(constant.f32);
break;
case ROUND_TO_POSITIVE_INFINITY:
constant.f32 = std::ceil(constant.f32);
break;
default:
assert_unhandled_case(round_mode);
return;
}
constant.f32 = RoundValue(round_mode, constant.f32);
return;
case FLOAT64_TYPE:
switch (round_mode) {
case ROUND_TO_ZERO:
constant.f64 = std::trunc(constant.f64);
break;
case ROUND_TO_NEAREST:
constant.f64 = std::round(constant.f64);
return;
case ROUND_TO_MINUS_INFINITY:
constant.f64 = std::floor(constant.f64);
break;
case ROUND_TO_POSITIVE_INFINITY:
constant.f64 = std::ceil(constant.f64);
break;
default:
assert_unhandled_case(round_mode);
return;
}
constant.f64 = RoundValue(round_mode, constant.f64);
return;
case VEC128_TYPE:
for (int i = 0; i < 4; i++) {
switch (round_mode) {
case ROUND_TO_ZERO:
constant.v128.f32[i] = std::trunc(constant.v128.f32[i]);
break;
case ROUND_TO_NEAREST:
constant.v128.f32[i] = std::round(constant.v128.f32[i]);
break;
case ROUND_TO_MINUS_INFINITY:
constant.v128.f32[i] = std::floor(constant.v128.f32[i]);
break;
case ROUND_TO_POSITIVE_INFINITY:
constant.v128.f32[i] = std::ceil(constant.v128.f32[i]);
break;
default:
assert_unhandled_case(round_mode);
return;
}
constant.v128.f32[i] = RoundValue(round_mode, constant.v128.f32[i]);
}
return;
default:

View File

@@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@@ -426,6 +426,10 @@ int InstrEmit_sc(PPCHIRBuilder& f, const InstrData& i) {
// Game code should only ever use LEV=0.
// LEV=2 is to signify 'call import' from Xenia.
// TODO(gibbed): syscalls!
if (i.SC.LEV == 0) {
f.CallExtern(f.builtins()->syscall_handler);
return 0;
}
if (i.SC.LEV == 2) {
f.CallExtern(f.function());
return 0;
@@ -807,5 +811,5 @@ void RegisterEmitCategoryControl() {
}
} // namespace cpu
} // namespace xe
} // namespace cpu
} // namespace xe

View File

@@ -10,6 +10,7 @@
#include "xenia/cpu/ppc/ppc_frontend.h"
#include "xenia/base/atomic.h"
#include "xenia/base/logging.h"
#include "xenia/cpu/ppc/ppc_context.h"
#include "xenia/cpu/ppc/ppc_emit.h"
#include "xenia/cpu/ppc/ppc_opcode_info.h"
@@ -78,6 +79,17 @@ void LeaveGlobalLock(PPCContext* ppc_context, void* arg0, void* arg1) {
global_mutex->unlock();
}
void SyscallHandler(PPCContext* ppc_context, void* arg0, void* arg1) {
uint64_t syscall_number = ppc_context->r[0];
switch (syscall_number) {
default:
assert_unhandled_case(syscall_number);
XELOGE("Unhandled syscall {}!", syscall_number);
break;
#pragma warning(suppress : 4065)
}
}
bool PPCFrontend::Initialize() {
void* arg0 = reinterpret_cast<void*>(&xe::global_critical_region::mutex());
void* arg1 = reinterpret_cast<void*>(&builtins_.global_lock_count);
@@ -87,6 +99,8 @@ bool PPCFrontend::Initialize() {
processor_->DefineBuiltin("EnterGlobalLock", EnterGlobalLock, arg0, arg1);
builtins_.leave_global_lock =
processor_->DefineBuiltin("LeaveGlobalLock", LeaveGlobalLock, arg0, arg1);
builtins_.syscall_handler = processor_->DefineBuiltin(
"SyscallHandler", SyscallHandler, nullptr, nullptr);
return true;
}

View File

@@ -33,6 +33,7 @@ struct PPCBuiltins {
Function* check_global_lock;
Function* enter_global_lock;
Function* leave_global_lock;
Function* syscall_handler;
};
class PPCFrontend {

View File

@@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@@ -104,8 +104,8 @@ bool PPCHIRBuilder::Emit(GuestFunction* function, uint32_t flags) {
// instruction may have a label assigned to it if it hasn't been hit
// yet.
size_t list_size = instr_count_ * sizeof(void*);
instr_offset_list_ = (Instr**)arena_->Alloc(list_size);
label_list_ = (Label**)arena_->Alloc(list_size);
instr_offset_list_ = (Instr**)arena_->Alloc(list_size, alignof(void*));
label_list_ = (Label**)arena_->Alloc(list_size, alignof(void*));
std::memset(instr_offset_list_, 0, list_size);
std::memset(label_list_, 0, list_size);
@@ -244,7 +244,7 @@ void PPCHIRBuilder::AnnotateLabel(uint32_t address, Label* label) {
char name_buffer[13];
auto format_result = fmt::format_to_n(name_buffer, 12, "loc_{:08X}", address);
name_buffer[format_result.size] = '\0';
label->name = (char*)arena_->Alloc(sizeof(name_buffer));
label->name = (char*)arena_->Alloc(sizeof(name_buffer), 1);
memcpy(label->name, name_buffer, sizeof(name_buffer));
}

View File

@@ -432,12 +432,12 @@ void Processor::LowerIrql(Irql old_value) {
}
bool Processor::Save(ByteStream* stream) {
stream->Write('PROC');
stream->Write(kProcessorSaveSignature);
return true;
}
bool Processor::Restore(ByteStream* stream) {
if (stream->Read<uint32_t>() != 'PROC') {
if (stream->Read<uint32_t>() != kProcessorSaveSignature) {
XELOGE("Processor::Restore - Invalid magic value!");
return false;
}

View File

@@ -34,6 +34,8 @@ DECLARE_bool(debug);
namespace xe {
namespace cpu {
constexpr fourcc_t kProcessorSaveSignature = make_fourcc("PROC");
class Breakpoint;
class StackWalker;
class XexModule;

View File

@@ -20,7 +20,7 @@
#include "xenia/cpu/processor.h"
#include "xenia/cpu/test_module.h"
#include "third_party/catch/single_include/catch.hpp"
#include "third_party/catch/include/catch.hpp"
#define XENIA_TEST_X64 1

View File

@@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@@ -249,12 +249,11 @@ int XexModule::ApplyPatch(XexModule* module) {
// Patch base XEX header
uint32_t original_image_size = module->image_size();
uint32_t header_target_size = patch_header->delta_headers_target_offset +
patch_header->delta_headers_source_size;
uint32_t header_target_size = patch_header->size_of_target_headers;
if (!header_target_size) {
header_target_size =
patch_header->size_of_target_headers; // unsure which is more correct..
header_target_size = patch_header->delta_headers_target_offset +
patch_header->delta_headers_source_size;
}
size_t mem_size = module->xex_header_mem_.size();
@@ -899,9 +898,9 @@ bool XexModule::Load(const std::string_view name, const std::string_view path,
const void* xex_addr, size_t xex_length) {
auto src_header = reinterpret_cast<const xex2_header*>(xex_addr);
if (src_header->magic == 'XEX1') {
if (src_header->magic == kXEX1Signature) {
xex_format_ = kFormatXex1;
} else if (src_header->magic == 'XEX2') {
} else if (src_header->magic == kXEX2Signature) {
xex_format_ = kFormatXex2;
} else {
return false;
@@ -967,6 +966,16 @@ bool XexModule::LoadContinue() {
return false;
}
// Parse any "unsafe" headers into safer variants
xex2_opt_generic_u32* alternate_titleids;
if (GetOptHeader(xex2_header_keys::XEX_HEADER_ALTERNATE_TITLE_IDS,
&alternate_titleids)) {
auto count = alternate_titleids->count();
for (uint32_t i = 0; i < count; i++) {
opt_alternate_title_ids_.push_back(alternate_titleids->values[i]);
}
}
// Scan and find the low/high addresses.
// All code sections are continuous, so this should be easy.
auto heap = memory()->LookupHeap(base_address_);

View File

@@ -25,6 +25,10 @@ class KernelState;
namespace xe {
namespace cpu {
constexpr fourcc_t kXEX1Signature = make_fourcc("XEX1");
constexpr fourcc_t kXEX2Signature = make_fourcc("XEX2");
constexpr fourcc_t kElfSignature = make_fourcc(0x7F, 'E', 'L', 'F');
class Runtime;
class XexModule : public xe::cpu::Module {
@@ -103,6 +107,10 @@ class XexModule : public xe::cpu::Module {
return retval;
}
std::vector<uint32_t> opt_alternate_title_ids() const {
return opt_alternate_title_ids_;
}
const uint32_t base_address() const { return base_address_; }
const bool is_dev_kit() const { return is_dev_kit_; }
@@ -194,6 +202,9 @@ class XexModule : public xe::cpu::Module {
import_libs_; // pre-loaded import libraries for ease of use
std::vector<PESection> pe_sections_;
// XEX_HEADER_ALTERNATE_TITLE_IDS loaded into a safe std::vector
std::vector<uint32_t> opt_alternate_title_ids_;
uint8_t session_key_[0x10];
bool is_dev_kit_ = false;