From 9489161d0b7109f8d7b956780d59e0299c2f0142 Mon Sep 17 00:00:00 2001 From: Bo Anderson Date: Tue, 6 Dec 2022 15:10:09 +0000 Subject: [PATCH 1/3] kernel: separate host objects from regular handle range Burnout Paradise statically expects certain thread handle values based on how many objects it knows it is allocating ahead of time. From this, it calculates an ID by subtracting the thread handle from a base handle of what it expects the first such thread to be assigned. The value is statically declared in the executable and is not determined automatically. The host objects in the handle range made these thread handles higher than what the game expects. Removing these, and allowing 0xF8000000 to be assigned, allows the thread handles to fit perfectly in the range the game expects. It is not clear what handle range the host objects should be taking. For now though, they're 0-based rather than 0xF8000000-based. --- src/xenia/kernel/kernel_module.cc | 5 +- src/xenia/kernel/util/object_table.cc | 125 +++++++++++++++++++------- src/xenia/kernel/util/object_table.h | 16 ++-- src/xenia/kernel/xmodule.cc | 5 +- src/xenia/kernel/xmodule.h | 3 +- src/xenia/kernel/xobject.cc | 5 +- src/xenia/kernel/xobject.h | 2 +- src/xenia/kernel/xthread.cc | 6 +- 8 files changed, 116 insertions(+), 51 deletions(-) diff --git a/src/xenia/kernel/kernel_module.cc b/src/xenia/kernel/kernel_module.cc index ebf0d64ba..b8bfd6ce4 100644 --- a/src/xenia/kernel/kernel_module.cc +++ b/src/xenia/kernel/kernel_module.cc @@ -21,7 +21,7 @@ namespace kernel { KernelModule::KernelModule(KernelState* kernel_state, const std::string_view path) - : XModule(kernel_state, ModuleType::kKernelModule) { + : XModule(kernel_state, ModuleType::kKernelModule, true) { emulator_ = kernel_state->emulator(); memory_ = emulator_->memory(); export_resolver_ = kernel_state->emulator()->export_resolver(); @@ -29,9 +29,6 @@ KernelModule::KernelModule(KernelState* kernel_state, path_ = path; name_ = utf8::find_base_name_from_guest_path(path); - // Persist this object through reloads. - host_object_ = true; - // HACK: Allocates memory where xboxkrnl.exe would be! // TODO: Need to free this memory when necessary. auto heap = memory()->LookupHeap(0x80040000); diff --git a/src/xenia/kernel/util/object_table.cc b/src/xenia/kernel/util/object_table.cc index d6efa32c4..a95320710 100644 --- a/src/xenia/kernel/util/object_table.cc +++ b/src/xenia/kernel/util/object_table.cc @@ -35,26 +35,37 @@ void ObjectTable::Reset() { entry.object->Release(); } } + for (uint32_t n = 0; n < host_table_capacity_; n++) { + ObjectTableEntry& entry = host_table_[n]; + if (entry.object) { + entry.object->Release(); + } + } table_capacity_ = 0; + host_table_capacity_ = 0; last_free_entry_ = 0; + last_free_host_entry_ = 0; free(table_); table_ = nullptr; + free(host_table_); + host_table_ = nullptr; } -X_STATUS ObjectTable::FindFreeSlot(uint32_t* out_slot) { +X_STATUS ObjectTable::FindFreeSlot(uint32_t* out_slot, bool host) { // Find a free slot. - uint32_t slot = last_free_entry_; + uint32_t slot = host ? last_free_host_entry_ : last_free_entry_; + uint32_t capacity = host ? host_table_capacity_ : table_capacity_; uint32_t scan_count = 0; - while (scan_count < table_capacity_) { - ObjectTableEntry& entry = table_[slot]; + while (scan_count < capacity) { + ObjectTableEntry& entry = host ? host_table_[slot] : table_[slot]; if (!entry.object) { *out_slot = slot; return X_STATUS_SUCCESS; } scan_count++; - slot = (slot + 1) % table_capacity_; - if (slot == 0) { + slot = (slot + 1) % capacity; + if (slot == 0 && host) { // Never allow 0 handles. scan_count++; slot++; @@ -62,23 +73,24 @@ X_STATUS ObjectTable::FindFreeSlot(uint32_t* out_slot) { } // Table out of slots, expand. - uint32_t new_table_capacity = std::max(16 * 1024u, table_capacity_ * 2); - if (!Resize(new_table_capacity)) { + uint32_t new_table_capacity = std::max(16 * 1024u, capacity * 2); + if (!Resize(new_table_capacity, host)) { return X_STATUS_NO_MEMORY; } - // Never allow 0 handles. - slot = ++last_free_entry_; + // Never allow 0 handles on host. + slot = host ? ++last_free_host_entry_ : last_free_entry_++; *out_slot = slot; return X_STATUS_SUCCESS; } -bool ObjectTable::Resize(uint32_t new_capacity) { +bool ObjectTable::Resize(uint32_t new_capacity, bool host) { + uint32_t capacity = host ? host_table_capacity_ : table_capacity_; uint32_t new_size = new_capacity * sizeof(ObjectTableEntry); - uint32_t old_size = table_capacity_ * sizeof(ObjectTableEntry); - auto new_table = - reinterpret_cast(realloc(table_, new_size)); + uint32_t old_size = capacity * sizeof(ObjectTableEntry); + auto new_table = reinterpret_cast( + realloc(host ? host_table_ : table_, new_size)); if (!new_table) { return false; } @@ -89,9 +101,15 @@ bool ObjectTable::Resize(uint32_t new_capacity) { new_size - old_size); } - last_free_entry_ = table_capacity_; - table_capacity_ = new_capacity; - table_ = new_table; + if (host) { + last_free_host_entry_ = capacity; + host_table_capacity_ = new_capacity; + host_table_ = new_table; + } else { + last_free_entry_ = capacity; + table_capacity_ = new_capacity; + table_ = new_table; + } return true; } @@ -105,14 +123,16 @@ X_STATUS ObjectTable::AddHandle(XObject* object, X_HANDLE* out_handle) { // Find a free slot. uint32_t slot = 0; - result = FindFreeSlot(&slot); + bool host_object = object->is_host_object(); + result = FindFreeSlot(&slot, host_object); // Stash. if (XSUCCEEDED(result)) { - ObjectTableEntry& entry = table_[slot]; + ObjectTableEntry& entry = host_object ? host_table_[slot] : table_[slot]; entry.object = object; entry.handle_ref_count = 1; - handle = XObject::kHandleBase + (slot << 2); + handle = slot << 2; + if (!host_object) handle += XObject::kHandleBase; object->handles().push_back(handle); // Retain so long as the object is in the table. @@ -222,6 +242,14 @@ std::vector> ObjectTable::GetAllObjects() { auto lock = global_critical_region_.Acquire(); std::vector> results; + for (uint32_t slot = 0; slot < host_table_capacity_; slot++) { + auto& entry = host_table_[slot]; + if (entry.object && std::find(results.begin(), results.end(), + entry.object) == results.end()) { + entry.object->Retain(); + results.push_back(object_ref(entry.object)); + } + } for (uint32_t slot = 0; slot < table_capacity_; slot++) { auto& entry = table_[slot]; if (entry.object && std::find(results.begin(), results.end(), @@ -238,7 +266,7 @@ void ObjectTable::PurgeAllObjects() { auto lock = global_critical_region_.Acquire(); for (uint32_t slot = 0; slot < table_capacity_; slot++) { auto& entry = table_[slot]; - if (entry.object && !entry.object->is_host_object()) { + if (entry.object) { entry.handle_ref_count = 0; entry.object->Release(); @@ -259,8 +287,13 @@ ObjectTable::ObjectTableEntry* ObjectTable::LookupTableInLock(X_HANDLE handle) { } // Lower 2 bits are ignored. - uint32_t slot = GetHandleSlot(handle); - if (slot <= table_capacity_) { + bool host = (handle < XObject::kHandleBase); + uint32_t slot = GetHandleSlot(handle, host); + if (host) { + if (slot <= host_table_capacity_) { + return &host_table_[slot]; + } + } else if (slot <= table_capacity_) { return &table_[slot]; } @@ -288,10 +321,18 @@ XObject* ObjectTable::LookupObject(X_HANDLE handle, bool already_locked) { } // Lower 2 bits are ignored. - uint32_t slot = GetHandleSlot(handle); + bool host = (handle < XObject::kHandleBase); + uint32_t slot = GetHandleSlot(handle, host); // Verify slot. - if (slot < table_capacity_) { + if (host) { + if (slot < host_table_capacity_) { + ObjectTableEntry& entry = host_table_[slot]; + if (entry.object) { + object = entry.object; + } + } + } else if (slot < table_capacity_) { ObjectTableEntry& entry = table_[slot]; if (entry.object) { object = entry.object; @@ -313,6 +354,15 @@ XObject* ObjectTable::LookupObject(X_HANDLE handle, bool already_locked) { void ObjectTable::GetObjectsByType(XObject::Type type, std::vector>* results) { auto global_lock = global_critical_region_.Acquire(); + for (uint32_t slot = 0; slot < host_table_capacity_; ++slot) { + auto& entry = host_table_[slot]; + if (entry.object) { + if (entry.object->type() == type) { + entry.object->Retain(); + results->push_back(object_ref(entry.object)); + } + } + } for (uint32_t slot = 0; slot < table_capacity_; ++slot) { auto& entry = table_[slot]; if (entry.object) { @@ -377,6 +427,12 @@ X_STATUS ObjectTable::GetObjectByName(const std::string_view name, } bool ObjectTable::Save(ByteStream* stream) { + stream->Write(host_table_capacity_); + for (uint32_t i = 0; i < host_table_capacity_; i++) { + auto& entry = host_table_[i]; + stream->Write(entry.handle_ref_count); + } + stream->Write(table_capacity_); for (uint32_t i = 0; i < table_capacity_; i++) { auto& entry = table_[i]; @@ -387,7 +443,14 @@ bool ObjectTable::Save(ByteStream* stream) { } bool ObjectTable::Restore(ByteStream* stream) { - Resize(stream->Read()); + Resize(stream->Read(), true); + for (uint32_t i = 0; i < host_table_capacity_; i++) { + auto& entry = host_table_[i]; + // entry.object = nullptr; + entry.handle_ref_count = stream->Read(); + } + + Resize(stream->Read(), false); for (uint32_t i = 0; i < table_capacity_; i++) { auto& entry = table_[i]; // entry.object = nullptr; @@ -398,11 +461,13 @@ bool ObjectTable::Restore(ByteStream* stream) { } X_STATUS ObjectTable::RestoreHandle(X_HANDLE handle, XObject* object) { - uint32_t slot = GetHandleSlot(handle); - assert_true(table_capacity_ >= slot); + bool host = (handle < XObject::kHandleBase); + uint32_t slot = GetHandleSlot(handle, host); + uint32_t capacity = host ? host_table_capacity_ : table_capacity_; + assert_true(capacity >= slot); - if (table_capacity_ >= slot) { - auto& entry = table_[slot]; + if (capacity >= slot) { + auto& entry = host ? host_table_[slot] : table_[slot]; entry.object = object; object->Retain(); } diff --git a/src/xenia/kernel/util/object_table.h b/src/xenia/kernel/util/object_table.h index aced0ea60..040d07d4e 100644 --- a/src/xenia/kernel/util/object_table.h +++ b/src/xenia/kernel/util/object_table.h @@ -49,10 +49,10 @@ class ObjectTable { X_STATUS RestoreHandle(X_HANDLE handle, XObject* object); template object_ref LookupObject(X_HANDLE handle, bool already_locked = false) { - auto object = LookupObject(handle, already_locked); if (T::kObjectType == XObject::Type::Socket) { - object = LookupObject((handle | 0xF8000000), false); + handle |= XObject::kHandleBase; } + auto object = LookupObject(handle, already_locked); if (object) { assert_true(object->type() == T::kObjectType); } @@ -95,16 +95,20 @@ class ObjectTable { std::vector>* results); X_HANDLE TranslateHandle(X_HANDLE handle); - static constexpr uint32_t GetHandleSlot(X_HANDLE handle) { - return (handle - XObject::kHandleBase) >> 2; + static constexpr uint32_t GetHandleSlot(X_HANDLE handle, bool host) { + if (!host) handle -= XObject::kHandleBase; + return handle >> 2; } - X_STATUS FindFreeSlot(uint32_t* out_slot); - bool Resize(uint32_t new_capacity); + X_STATUS FindFreeSlot(uint32_t* out_slot, bool host); + bool Resize(uint32_t new_capacity, bool host); xe::global_critical_region global_critical_region_; uint32_t table_capacity_ = 0; + uint32_t host_table_capacity_ = 0; ObjectTableEntry* table_ = nullptr; + ObjectTableEntry* host_table_ = nullptr; uint32_t last_free_entry_ = 0; + uint32_t last_free_host_entry_ = 0; std::unordered_map name_table_; }; diff --git a/src/xenia/kernel/xmodule.cc b/src/xenia/kernel/xmodule.cc index 96880958c..665e5a43e 100644 --- a/src/xenia/kernel/xmodule.cc +++ b/src/xenia/kernel/xmodule.cc @@ -19,8 +19,9 @@ namespace xe { namespace kernel { -XModule::XModule(KernelState* kernel_state, ModuleType module_type) - : XObject(kernel_state, kObjectType), +XModule::XModule(KernelState* kernel_state, ModuleType module_type, + bool host_object) + : XObject(kernel_state, kObjectType, host_object), module_type_(module_type), processor_module_(nullptr), hmodule_ptr_(0) { diff --git a/src/xenia/kernel/xmodule.h b/src/xenia/kernel/xmodule.h index 0a937a73b..28e860da3 100644 --- a/src/xenia/kernel/xmodule.h +++ b/src/xenia/kernel/xmodule.h @@ -61,7 +61,8 @@ class XModule : public XObject { static const XObject::Type kObjectType = XObject::Type::Module; - XModule(KernelState* kernel_state, ModuleType module_type); + XModule(KernelState* kernel_state, ModuleType module_type, + bool host_object = false); virtual ~XModule(); ModuleType module_type() const { return module_type_; } diff --git a/src/xenia/kernel/xobject.cc b/src/xenia/kernel/xobject.cc index bd7374b74..cee06c07a 100644 --- a/src/xenia/kernel/xobject.cc +++ b/src/xenia/kernel/xobject.cc @@ -34,12 +34,13 @@ XObject::XObject(Type type) handles_.reserve(10); } -XObject::XObject(KernelState* kernel_state, Type type) +XObject::XObject(KernelState* kernel_state, Type type, bool host_object) : kernel_state_(kernel_state), type_(type), pointer_ref_count_(1), guest_object_ptr_(0), - allocated_guest_object_(false) { + allocated_guest_object_(false), + host_object_(host_object) { handles_.reserve(10); // TODO: Assert kernel_state != nullptr in this constructor. diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index df067b55d..1647fa193 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -136,7 +136,7 @@ class XObject { }; XObject(Type type); - XObject(KernelState* kernel_state, Type type); + XObject(KernelState* kernel_state, Type type, bool host_object = false); virtual ~XObject(); Emulator* emulator() const; diff --git a/src/xenia/kernel/xthread.cc b/src/xenia/kernel/xthread.cc index df5991d09..63dfc0bd8 100644 --- a/src/xenia/kernel/xthread.cc +++ b/src/xenia/kernel/xthread.cc @@ -60,7 +60,7 @@ XThread::XThread(KernelState* kernel_state, uint32_t stack_size, uint32_t xapi_thread_startup, uint32_t start_address, uint32_t start_context, uint32_t creation_flags, bool guest_thread, bool main_thread) - : XObject(kernel_state, kObjectType), + : XObject(kernel_state, kObjectType, !guest_thread), thread_id_(++next_xthread_id_), guest_thread_(guest_thread), main_thread_(main_thread), @@ -79,10 +79,6 @@ XThread::XThread(KernelState* kernel_state, uint32_t stack_size, creation_params_.stack_size = 16 * 1024; } - if (!guest_thread_) { - host_object_ = true; - } - // The kernel does not take a reference. We must unregister in the dtor. kernel_state_->RegisterThread(this); } From 2a77ed724652923271935eb3dcb25567c73aee2c Mon Sep 17 00:00:00 2001 From: Bo Anderson Date: Tue, 6 Dec 2022 15:59:01 +0000 Subject: [PATCH 2/3] cpu/backend/x64/x64_tracers: fix thread matching --- src/xenia/cpu/backend/x64/x64_tracers.cc | 62 ++++++++++++------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/xenia/cpu/backend/x64/x64_tracers.cc b/src/xenia/cpu/backend/x64/x64_tracers.cc index 404f4ecac..325589bad 100644 --- a/src/xenia/cpu/backend/x64/x64_tracers.cc +++ b/src/xenia/cpu/backend/x64/x64_tracers.cc @@ -30,7 +30,7 @@ namespace x64 { bool trace_enabled = true; #define THREAD_MATCH \ - (!TARGET_THREAD || thread_state->thread_id() == TARGET_THREAD) + (!TARGET_THREAD || ppc_context->thread_id == TARGET_THREAD) #define IFLUSH() #define IPRINT(s) \ if (trace_enabled && THREAD_MATCH) \ @@ -52,41 +52,41 @@ uint32_t GetTracingMode() { } void TraceString(void* raw_context, const char* str) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); IPRINT(str); IFLUSH(); } void TraceContextLoadI8(void* raw_context, uint64_t offset, uint8_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("{} ({:X}) = ctx i8 +{}\n", (int8_t)value, value, offset); } void TraceContextLoadI16(void* raw_context, uint64_t offset, uint16_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("{} ({:X}) = ctx i16 +{}\n", (int16_t)value, value, offset); } void TraceContextLoadI32(void* raw_context, uint64_t offset, uint32_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("{} ({:X}) = ctx i32 +{}\n", (int32_t)value, value, offset); } void TraceContextLoadI64(void* raw_context, uint64_t offset, uint64_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("{} ({:X}) = ctx i64 +{}\n", (int64_t)value, value, offset); } void TraceContextLoadF32(void* raw_context, uint64_t offset, __m128 value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("{} ({:X}) = ctx f32 +{}\n", xe::m128_f32<0>(value), xe::m128_i32<0>(value), offset); } void TraceContextLoadF64(void* raw_context, uint64_t offset, const double* value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); auto v = _mm_loadu_pd(value); DPRINT("{} ({:X}) = ctx f64 +{}\n", xe::m128_f64<0>(v), xe::m128_i64<0>(v), offset); } void TraceContextLoadV128(void* raw_context, uint64_t offset, __m128 value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("[{}, {}, {}, {}] [{:08X}, {:08X}, {:08X}, {:08X}] = ctx v128 +{}\n", xe::m128_f32<0>(value), xe::m128_f32<1>(value), xe::m128_f32<2>(value), xe::m128_f32<3>(value), xe::m128_i32<0>(value), xe::m128_i32<1>(value), @@ -94,35 +94,35 @@ void TraceContextLoadV128(void* raw_context, uint64_t offset, __m128 value) { } void TraceContextStoreI8(void* raw_context, uint64_t offset, uint8_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("ctx i8 +{} = {} ({:X})\n", offset, (int8_t)value, value); } void TraceContextStoreI16(void* raw_context, uint64_t offset, uint16_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("ctx i16 +{} = {} ({:X})\n", offset, (int16_t)value, value); } void TraceContextStoreI32(void* raw_context, uint64_t offset, uint32_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("ctx i32 +{} = {} ({:X})\n", offset, (int32_t)value, value); } void TraceContextStoreI64(void* raw_context, uint64_t offset, uint64_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("ctx i64 +{} = {} ({:X})\n", offset, (int64_t)value, value); } void TraceContextStoreF32(void* raw_context, uint64_t offset, __m128 value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("ctx f32 +{} = {} ({:X})\n", offset, xe::m128_f32<0>(value), xe::m128_i32<0>(value)); } void TraceContextStoreF64(void* raw_context, uint64_t offset, const double* value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); auto v = _mm_loadu_pd(value); DPRINT("ctx f64 +{} = {} ({:X})\n", offset, xe::m128_f64<0>(v), xe::m128_i64<0>(v)); } void TraceContextStoreV128(void* raw_context, uint64_t offset, __m128 value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("ctx v128 +{} = [{}, {}, {}, {}] [{:08X}, {:08X}, {:08X}, {:08X}]\n", offset, xe::m128_f32<0>(value), xe::m128_f32<1>(value), xe::m128_f32<2>(value), xe::m128_f32<3>(value), xe::m128_i32<0>(value), @@ -131,33 +131,33 @@ void TraceContextStoreV128(void* raw_context, uint64_t offset, __m128 value) { } void TraceMemoryLoadI8(void* raw_context, uint32_t address, uint8_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("{} ({:X}) = load.i8 {:08X}\n", (int8_t)value, value, address); } void TraceMemoryLoadI16(void* raw_context, uint32_t address, uint16_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("{} ({:X}) = load.i16 {:08X}\n", (int16_t)value, value, address); } void TraceMemoryLoadI32(void* raw_context, uint32_t address, uint32_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("{} ({:X}) = load.i32 {:08X}\n", (int32_t)value, value, address); } void TraceMemoryLoadI64(void* raw_context, uint32_t address, uint64_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("{} ({:X}) = load.i64 {:08X}\n", (int64_t)value, value, address); } void TraceMemoryLoadF32(void* raw_context, uint32_t address, __m128 value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("{} ({:X}) = load.f32 {:08X}\n", xe::m128_f32<0>(value), xe::m128_i32<0>(value), address); } void TraceMemoryLoadF64(void* raw_context, uint32_t address, __m128 value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("{} ({:X}) = load.f64 {:08X}\n", xe::m128_f64<0>(value), xe::m128_i64<0>(value), address); } void TraceMemoryLoadV128(void* raw_context, uint32_t address, __m128 value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT( "[{}, {}, {}, {}] [{:08X}, {:08X}, {:08X}, {:08X}] = load.v128 {:08X}\n", xe::m128_f32<0>(value), xe::m128_f32<1>(value), xe::m128_f32<2>(value), @@ -166,33 +166,33 @@ void TraceMemoryLoadV128(void* raw_context, uint32_t address, __m128 value) { } void TraceMemoryStoreI8(void* raw_context, uint32_t address, uint8_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("store.i8 {:08X} = {} ({:X})\n", address, (int8_t)value, value); } void TraceMemoryStoreI16(void* raw_context, uint32_t address, uint16_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("store.i16 {:08X} = {} ({:X})\n", address, (int16_t)value, value); } void TraceMemoryStoreI32(void* raw_context, uint32_t address, uint32_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("store.i32 {:08X} = {} ({:X})\n", address, (int32_t)value, value); } void TraceMemoryStoreI64(void* raw_context, uint32_t address, uint64_t value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("store.i64 {:08X} = {} ({:X})\n", address, (int64_t)value, value); } void TraceMemoryStoreF32(void* raw_context, uint32_t address, __m128 value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("store.f32 {:08X} = {} ({:X})\n", address, xe::m128_f32<0>(value), xe::m128_i32<0>(value)); } void TraceMemoryStoreF64(void* raw_context, uint32_t address, __m128 value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("store.f64 {:08X} = {} ({:X})\n", address, xe::m128_f64<0>(value), xe::m128_i64<0>(value)); } void TraceMemoryStoreV128(void* raw_context, uint32_t address, __m128 value) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT( "store.v128 {:08X} = [{}, {}, {}, {}] [{:08X}, {:08X}, {:08X}, {:08X}]\n", address, xe::m128_f32<0>(value), xe::m128_f32<1>(value), @@ -202,7 +202,7 @@ void TraceMemoryStoreV128(void* raw_context, uint32_t address, __m128 value) { void TraceMemset(void* raw_context, uint32_t address, uint8_t value, uint32_t length) { - auto thread_state = *reinterpret_cast(raw_context); + auto ppc_context = reinterpret_cast(raw_context); DPRINT("memset {:08X}-{:08X} ({}) = {:02X}", address, address + length, length, value); } From 422ee1fbdc39a134e491c9f690246fe8246abbad Mon Sep 17 00:00:00 2001 From: Bo Anderson Date: Tue, 6 Dec 2022 21:21:10 +0000 Subject: [PATCH 3/3] kernal/xam/xam_info: base game region on user_country It is debatable whether this is correct in the general case. There's nothing really wrong with 0xFFFF logically. Burnout Paradise however bases its in-game language on this and does not recognise 0xFFFF. The game uses Japanese in the default case. I've avoided the "rest of Asia" code since Burnout Paradise seems to use a different value (0x01F8) for that than what I expected (0x01FC). --- src/xenia/kernel/xam/xam_info.cc | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/xenia/kernel/xam/xam_info.cc b/src/xenia/kernel/xam/xam_info.cc index 9c6dd0611..ec4acc082 100644 --- a/src/xenia/kernel/xam/xam_info.cc +++ b/src/xenia/kernel/xam/xam_info.cc @@ -26,6 +26,7 @@ #include "third_party/fmt/include/fmt/format.h" DEFINE_int32(avpack, 8, "Video modes", "Video"); +DECLARE_int32(user_country); DECLARE_int32(user_language); namespace xe { @@ -206,7 +207,25 @@ dword_result_t XGetAVPack_entry() { } DECLARE_XAM_EXPORT1(XGetAVPack, kNone, kStub); -uint32_t xeXGetGameRegion() { return 0xFFFFu; } +uint32_t xeXGetGameRegion() { + static uint32_t const table[] = { + 0xFFFFu, 0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x02FEu, 0x0201u, 0x03FFu, + 0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu, + 0x00FFu, 0xFFFFu, 0x02FEu, 0x03FFu, 0x0102u, 0x03FFu, 0x03FFu, 0x02FEu, + 0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu, 0x02FEu, + 0x02FEu, 0x02FEu, 0x02FEu, 0x02FEu, 0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu, + 0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu, + 0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu, 0x0101u, 0x03FFu, 0x03FFu, + 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x02FEu, 0x02FEu, 0x02FEu, + 0x03FFu, 0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x0102u, 0x03FFu, 0x00FFu, + 0x03FFu, 0x03FFu, 0x02FEu, 0x02FEu, 0x0201u, 0x03FFu, 0x03FFu, 0x03FFu, + 0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu, 0x02FEu, 0x03FFu, 0x03FFu, 0x02FEu, + 0x02FEu, 0x03FFu, 0x02FEu, 0x03FFu, 0x02FEu, 0x02FEu, 0xFFFFu, 0x03FFu, + 0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu, 0x03FFu, 0x02FEu, 0x00FFu, + 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu}; + auto country = static_cast(cvars::user_country); + return country < xe::countof(table) ? table[country] : 0xFFFFu; +} dword_result_t XGetGameRegion_entry() { return xeXGetGameRegion(); } DECLARE_XAM_EXPORT1(XGetGameRegion, kNone, kStub);