diff --git a/src/xenia/apu/xma_context.cc b/src/xenia/apu/xma_context.cc index bb615045d..0eeaec4cd 100644 --- a/src/xenia/apu/xma_context.cc +++ b/src/xenia/apu/xma_context.cc @@ -294,6 +294,11 @@ void XmaContext::DecodePackets(XMA_CONTEXT_DATA* data) { return; } + // No available data. + if (!data->input_buffer_0_valid && !data->input_buffer_1_valid) { + return; + } + assert_zero(data->unk_dword_9); // XAudio Loops diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index bb109de09..1609c3577 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -189,6 +189,7 @@ Function* Processor::ResolveFunction(uint32_t address) { // Grab symbol declaration. auto function = LookupFunction(address); if (!function) { + entry->status = Entry::STATUS_FAILED; return nullptr; } @@ -317,10 +318,21 @@ uint64_t Processor::Execute(ThreadState* thread_state, uint32_t address, SCOPE_profile_cpu_f("cpu"); PPCContext* context = thread_state->context(); - assert_true(arg_count <= 5); - for (size_t i = 0; i < arg_count; ++i) { + for (size_t i = 0; i < std::min(arg_count, 8ull); ++i) { context->r[3 + i] = args[i]; } + + if (arg_count > 7) { + // Rest of the arguments go on the stack. + // FIXME: This assumes arguments are 32 bits! + auto stack_arg_base = + memory()->TranslateVirtual((uint32_t)context->r[1] + 0x54 - (64 + 112)); + for (size_t i = 0; i < arg_count - 8; i++) { + xe::store_and_swap(stack_arg_base + (i * 8), + (uint32_t)args[i + 8]); + } + } + if (!Execute(thread_state, address)) { return 0xDEADBABE; } diff --git a/src/xenia/cpu/raw_module.cc b/src/xenia/cpu/raw_module.cc index 02fde0fb3..11dde5213 100644 --- a/src/xenia/cpu/raw_module.cc +++ b/src/xenia/cpu/raw_module.cc @@ -55,6 +55,9 @@ bool RawModule::LoadFile(uint32_t base_address, const std::wstring& path) { low_address_ = base_address; high_address_ = base_address + file_length; + + // Notify backend about executable code. + processor_->backend()->CommitExecutableRange(low_address_, high_address_); return true; } diff --git a/src/xenia/gpu/gl4/command_processor.cc b/src/xenia/gpu/gl4/command_processor.cc index ce487a2e4..7bc8b752d 100644 --- a/src/xenia/gpu/gl4/command_processor.cc +++ b/src/xenia/gpu/gl4/command_processor.cc @@ -24,6 +24,9 @@ #include "third_party/xxhash/xxhash.h" +DEFINE_bool(draw_all_framebuffers, false, + "Copy all render targets to screen on swap"); + namespace xe { namespace gpu { namespace gl4 { @@ -641,6 +644,53 @@ void CommandProcessor::IssueSwap(uint32_t frontbuffer_ptr, swap_state_.back_buffer_texture, dest_rect, GL_LINEAR); + if (FLAGS_draw_all_framebuffers) { + int32_t offsetx = (1280 - (1280 / 5)); + int32_t offsety = 0; + int32_t doffsetx = 0; + for (int i = 0; i < cached_framebuffers_.size(); i++) { + bool has_colortargets = false; + + // Copy color targets to top right corner + for (int j = 0; j < 4; j++) { + GLuint tex = cached_framebuffers_[i].color_targets[j]; + if (!tex) { + continue; + } + has_colortargets = true; + + dest_rect = {offsetx, offsety, 1280 / 5, 720 / 5}; + reinterpret_cast(context_.get()) + ->blitter() + ->CopyColorTexture2D(tex, src_rect, swap_state_.back_buffer_texture, + dest_rect, GL_LINEAR); + + offsety += 720 / 5; + } + + if (has_colortargets) { + offsetx -= 1280 / 5; + } + + offsety = 0; + + GLuint tex = cached_framebuffers_[i].depth_target; + if (!tex) { + continue; + } + + // Copy depth targets to bottom left corner of screen + dest_rect = {doffsetx, (int32_t)swap_state_.height - (720 / 5), 1280 / 5, + 720 / 5}; + reinterpret_cast(context_.get()) + ->blitter() + ->CopyColorTexture2D(tex, src_rect, swap_state_.back_buffer_texture, + dest_rect, GL_LINEAR); + + doffsetx += 1280 / 5; + } + } + // Need to finish to be sure the other context sees the right data. // TODO(benvanik): prevent this? fences? glFinish(); diff --git a/src/xenia/kernel/user_module.cc b/src/xenia/kernel/user_module.cc index 85892e2d8..83b41a882 100644 --- a/src/xenia/kernel/user_module.cc +++ b/src/xenia/kernel/user_module.cc @@ -142,12 +142,12 @@ X_STATUS UserModule::LoadFromMemory(const void* addr, const size_t length) { } X_STATUS UserModule::Unload() { - if (!xex_module()->loaded()) { + if (module_format_ == kModuleFormatXex && !xex_module()->loaded()) { // Quick abort. return X_STATUS_SUCCESS; } - if (xex_module()->Unload()) { + if (module_format_ == kModuleFormatXex && xex_module()->Unload()) { OnUnload(); return X_STATUS_SUCCESS; } @@ -505,7 +505,14 @@ void UserModule::Dump() { sb.AppendFormat(" XEX_HEADER_GAME_RATINGS (TODO):\n"); } break; case XEX_HEADER_LAN_KEY: { - sb.AppendFormat(" XEX_HEADER_LAN_KEY (TODO):\n"); + sb.AppendFormat(" XEX_HEADER_LAN_KEY:"); + auto opt_lan_key = + reinterpret_cast(opt_header_ptr); + + for (int l = 0; l < 16; l++) { + sb.AppendFormat(" %.2X", opt_lan_key->key[l]); + } + sb.Append("\n"); } break; case XEX_HEADER_XBOX360_LOGO: { sb.AppendFormat(" XEX_HEADER_XBOX360_LOGO (TODO):\n"); diff --git a/src/xenia/kernel/util/shim_utils.h b/src/xenia/kernel/util/shim_utils.h index 652801b8a..e7e647426 100644 --- a/src/xenia/kernel/util/shim_utils.h +++ b/src/xenia/kernel/util/shim_utils.h @@ -297,6 +297,7 @@ class Result { } // namespace shim using int_t = const shim::ParamBase&; +using word_t = const shim::ParamBase&; using dword_t = const shim::ParamBase&; using qword_t = const shim::ParamBase&; using float_t = const shim::ParamBase&; @@ -322,6 +323,9 @@ namespace shim { inline void AppendParam(StringBuffer* string_buffer, int_t param) { string_buffer->AppendFormat("%d", int32_t(param)); } +inline void AppendParam(StringBuffer* string_buffer, word_t param) { + string_buffer->AppendFormat("%.4X", uint16_t(param)); +} inline void AppendParam(StringBuffer* string_buffer, dword_t param) { string_buffer->AppendFormat("%.8X", uint32_t(param)); } diff --git a/src/xenia/kernel/util/xex2_info.h b/src/xenia/kernel/util/xex2_info.h index d05f964ee..209aa05d5 100644 --- a/src/xenia/kernel/util/xex2_info.h +++ b/src/xenia/kernel/util/xex2_info.h @@ -468,6 +468,10 @@ union xex2_version { }; }; +struct xex2_opt_lan_key { + uint8_t key[0x10]; +}; + struct xex2_opt_bound_path { xe::be size; char path[1]; diff --git a/src/xenia/kernel/xam/xam_content.cc b/src/xenia/kernel/xam/xam_content.cc index 273f42690..6c453be71 100644 --- a/src/xenia/kernel/xam/xam_content.cc +++ b/src/xenia/kernel/xam/xam_content.cc @@ -333,6 +333,13 @@ SHIM_CALL XamContentCreateEx_shim(PPCContext* ppc_context, cache_size, content_size, overlapped_ptr); } +dword_result_t XamContentOpenFile(dword_t r3, lpstring_t r4, lpstring_t r5, + dword_t r6, dword_t r7, dword_t r8, + dword_t r9) { + return X_ERROR_FILE_NOT_FOUND; +} +DECLARE_XAM_EXPORT(XamContentOpenFile, ExportTag::kStub); + SHIM_CALL XamContentFlush_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t root_name_ptr = SHIM_GET_ARG_32(0); diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc index 1ea023d0a..fa3afcee9 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc @@ -117,6 +117,13 @@ SHIM_CALL NtAllocateVirtualMemory_shim(PPCContext* ppc_context, } uint32_t adjusted_size = xe::round_up(region_size_value, page_size); + // Some games (BF1943) do this, but then if we return an error code it'll + // allocate with a smaller page size. + if (base_addr_value % page_size != 0) { + SHIM_SET_RETURN_32(X_STATUS_MAPPED_ALIGNMENT); + return; + } + // Allocate. uint32_t allocation_type = 0; if (alloc_type & X_MEM_RESERVE) { @@ -480,6 +487,7 @@ SHIM_CALL MmGetPhysicalAddress_shim(PPCContext* ppc_context, // _In_ PVOID BaseAddress // ); // base_address = result of MmAllocatePhysicalMemory. + assert_true(base_address >= 0xA0000000); uint32_t physical_address = base_address & 0x1FFFFFFF; if (base_address >= 0xE0000000) { @@ -514,7 +522,7 @@ SHIM_CALL ExAllocatePoolTypeWithTag_shim(PPCContext* ppc_context, uint32_t tag = SHIM_GET_ARG_32(1); uint32_t zero = SHIM_GET_ARG_32(2); - XELOGD("ExAllocatePoolTypeWithTag(%d, %.8X, %d)", size, tag, zero); + XELOGD("ExAllocatePoolTypeWithTag(%d, %.4s, %d)", size, &tag, zero); uint32_t alignment = 8; uint32_t adjusted_size = size; diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc index fb1128297..344409672 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc @@ -494,33 +494,25 @@ dword_result_t KeResetEvent(pointer_t event_ptr) { DECLARE_XBOXKRNL_EXPORT(KeResetEvent, ExportTag::kImplemented | ExportTag::kThreading); -SHIM_CALL NtCreateEvent_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t handle_ptr = SHIM_GET_ARG_32(0); - uint32_t obj_attributes_ptr = SHIM_GET_ARG_32(1); - uint32_t event_type = SHIM_GET_ARG_32(2); - uint32_t initial_state = SHIM_GET_ARG_32(3); - - XELOGD("NtCreateEvent(%.8X, %.8X, %d, %d)", handle_ptr, obj_attributes_ptr, - event_type, initial_state); - +dword_result_t NtCreateEvent(lpdword_t handle_ptr, + pointer_t obj_attributes_ptr, + dword_t event_type, dword_t initial_state) { // Check for an existing timer with the same name. auto existing_object = - LookupNamedObject(kernel_state, obj_attributes_ptr); + LookupNamedObject(kernel_state(), obj_attributes_ptr); if (existing_object) { if (existing_object->type() == XObject::kTypeEvent) { if (handle_ptr) { existing_object->RetainHandle(); - SHIM_SET_MEM_32(handle_ptr, existing_object->handle()); + *handle_ptr = existing_object->handle(); } - SHIM_SET_RETURN_32(X_STATUS_SUCCESS); + return X_STATUS_SUCCESS; } else { - SHIM_SET_RETURN_32(X_STATUS_INVALID_HANDLE); + return X_STATUS_INVALID_HANDLE; } - return; } - XEvent* ev = new XEvent(kernel_state); + XEvent* ev = new XEvent(kernel_state()); ev->Initialize(!event_type, !!initial_state); // obj_attributes may have a name inside of it, if != NULL. @@ -529,10 +521,12 @@ SHIM_CALL NtCreateEvent_shim(PPCContext* ppc_context, } if (handle_ptr) { - SHIM_SET_MEM_32(handle_ptr, ev->handle()); + *handle_ptr = ev->handle(); } - SHIM_SET_RETURN_32(X_STATUS_SUCCESS); + return X_STATUS_SUCCESS; } +DECLARE_XBOXKRNL_EXPORT(NtCreateEvent, + ExportTag::kImplemented | ExportTag::kThreading); dword_result_t NtSetEvent(dword_t handle, lpdword_t previous_state_ptr) { X_STATUS result = X_STATUS_SUCCESS; @@ -1421,8 +1415,6 @@ void RegisterThreadingExports(xe::cpu::ExportResolver* export_resolver, SHIM_SET_MAPPING("xboxkrnl.exe", KeTlsGetValue, state); SHIM_SET_MAPPING("xboxkrnl.exe", KeTlsSetValue, state); - SHIM_SET_MAPPING("xboxkrnl.exe", NtCreateEvent, state); - SHIM_SET_MAPPING("xboxkrnl.exe", NtCreateSemaphore, state); SHIM_SET_MAPPING("xboxkrnl.exe", NtReleaseSemaphore, state); diff --git a/src/xenia/kernel/xthread.cc b/src/xenia/kernel/xthread.cc index 5b28865c6..261d7913f 100644 --- a/src/xenia/kernel/xthread.cc +++ b/src/xenia/kernel/xthread.cc @@ -107,6 +107,16 @@ uint32_t XThread::GetCurrentThreadId() { return thread->guest_object()->thread_id; } +uint32_t XThread::GetLastError() { + XThread* thread = XThread::GetCurrentThread(); + return thread->last_error(); +} + +void XThread::SetLastError(uint32_t error_code) { + XThread* thread = XThread::GetCurrentThread(); + thread->set_last_error(error_code); +} + uint32_t XThread::last_error() { return guest_object()->last_error; } void XThread::set_last_error(uint32_t error_code) { diff --git a/src/xenia/kernel/xthread.h b/src/xenia/kernel/xthread.h index d6e6af0d9..130f088bc 100644 --- a/src/xenia/kernel/xthread.h +++ b/src/xenia/kernel/xthread.h @@ -122,6 +122,9 @@ class XThread : public XObject { static uint32_t GetCurrentThreadHandle(); static uint32_t GetCurrentThreadId(); + static uint32_t GetLastError(); + static void SetLastError(uint32_t error_code); + const CreationParams* creation_params() const { return &creation_params_; } uint32_t tls_ptr() const { return tls_address_; } uint32_t pcr_ptr() const { return pcr_address_; } diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index b2bc519c6..5e6dfb5d8 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -66,6 +66,7 @@ typedef uint32_t X_STATUS; #define X_STATUS_INVALID_PARAMETER_2 ((X_STATUS)0xC00000F0L) #define X_STATUS_INVALID_PARAMETER_3 ((X_STATUS)0xC00000F1L) #define X_STATUS_DLL_NOT_FOUND ((X_STATUS)0xC0000135L) +#define X_STATUS_MAPPED_ALIGNMENT ((X_STATUS)0xC0000220L) #define X_STATUS_NOT_FOUND ((X_STATUS)0xC0000225L) #define X_STATUS_DRIVER_ORDINAL_NOT_FOUND ((X_STATUS)0xC0000262L) #define X_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND ((X_STATUS)0xC0000263L)