diff --git a/src/xenia/app/emulator_window.cc b/src/xenia/app/emulator_window.cc index 0cadca940..74f85078e 100644 --- a/src/xenia/app/emulator_window.cc +++ b/src/xenia/app/emulator_window.cc @@ -850,7 +850,11 @@ void EmulatorWindow::OnKeyDown(ui::KeyEvent& e) { } break; case ui::VirtualKey::kF2: { - ShowBuildCommit(); + if (e.is_ctrl_pressed()) { + emulator()->ClearStickyPersistentFlags(); + } else { + ShowBuildCommit(); + } } break; case ui::VirtualKey::kF9: { diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index ef76bc394..18a883157 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -26,6 +26,7 @@ #include "xenia/base/mapped_memory.h" #include "xenia/base/platform.h" #include "xenia/base/string.h" +#include "xenia/base/system.h" #include "xenia/cpu/backend/code_cache.h" #include "xenia/cpu/backend/null_backend.h" #include "xenia/cpu/cpu_flags.h" @@ -109,7 +110,15 @@ Emulator::Emulator(const std::filesystem::path& command_line, title_id_(std::nullopt), paused_(false), restoring_(false), - restore_fence_() {} + restore_fence_() { + // show the quickstart guide the first time they ever open the emulator + uint64_t persistent_flags = GetPersistentEmulatorFlags(); + if (!(persistent_flags & EmulatorFlagQuickstartShown)) { + LaunchWebBrowser( + "https://github.com/xenia-canary/xenia-canary/wiki/Quickstart"); + SetPersistentEmulatorFlags(persistent_flags | EmulatorFlagQuickstartShown); + } +} Emulator::~Emulator() { // Note that we delete things in the reverse order they were initialized. @@ -280,30 +289,161 @@ X_STATUS Emulator::TerminateTitle() { return X_STATUS_SUCCESS; } +std::string Emulator::CanonicalizeFileExtension( + const std::filesystem::path& path) { + return xe::utf8::lower_ascii(xe::path_to_utf8(path.extension())); +} + const std::unique_ptr Emulator::CreateVfsDeviceBasedOnPath( const std::filesystem::path& path, const std::string_view mount_path) { if (!path.has_extension()) { return std::make_unique(mount_path, path); } - auto extension = xe::utf8::lower_ascii(xe::path_to_utf8(path.extension())); + auto extension = CanonicalizeFileExtension(path); if (extension == ".xex" || extension == ".elf" || extension == ".exe") { auto parent_path = path.parent_path(); return std::make_unique( mount_path, parent_path, !cvars::allow_game_relative_writes); - } else { - return std::make_unique(mount_path, path); + } else if (extension == ".7z" || extension == ".zip" || extension == ".rar") { + xe::ShowSimpleMessageBox( + xe::SimpleMessageBoxType::Error, + fmt::format("Xenia does not support running {} files, the file you " + "actually want to run is inside of this {} file.", + extension, extension)); + // user likely compressed the file themselves, then suffered a traumatic + // brain injury that caused them to forget how archives work + + LaunchWebBrowser(fmt::format( + "https://www.google.com/search?q=how+to+extract+{}+file", extension)); + + xe::FatalError("Terminating due to user's lack of basic computer skills."); + } + return std::make_unique(mount_path, path); +} + +uint64_t Emulator::GetPersistentEmulatorFlags() { +#if XE_PLATFORM_WIN32 == 1 + uint64_t value = 0; + DWORD value_size = sizeof(value); + HKEY xenia_hkey = nullptr; + LSTATUS lstat = + RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Xenia", &xenia_hkey); + if (!xenia_hkey) { + // let the Set function create the key and initialize it to 0 + SetPersistentEmulatorFlags(0ULL); + return 0ULL; + } + + lstat = RegQueryValueExA(xenia_hkey, "XEFLAGS", 0, NULL, + reinterpret_cast(&value), &value_size); + RegCloseKey(xenia_hkey); + if (lstat) { + return 0ULL; + } + return value; +#else + return EmulatorFlagQuickstartShown | EmulatorFlagIsoWarningAcknowledged; +#endif +} +void Emulator::SetPersistentEmulatorFlags(uint64_t new_flags) { +#if XE_PLATFORM_WIN32 == 1 + uint64_t value = new_flags; + DWORD value_size = sizeof(value); + HKEY xenia_hkey = nullptr; + LSTATUS lstat = + RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Xenia", &xenia_hkey); + if (!xenia_hkey) { + lstat = RegCreateKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Xenia", &xenia_hkey); + } + + lstat = RegSetValueExA(xenia_hkey, "XEFLAGS", 0, REG_QWORD, + reinterpret_cast(&value), 8); + RegFlushKey(xenia_hkey); + RegCloseKey(xenia_hkey); +#endif +} + +void Emulator::ClearStickyPersistentFlags() { + SetPersistentEmulatorFlags(GetPersistentEmulatorFlags() & + ~EmulatorFlagIsoWarningSticky); +} + +void Emulator::CheckMountWarning(const std::filesystem::path& path) { + auto extension = CanonicalizeFileExtension(path); + + uint64_t emu_flags = GetPersistentEmulatorFlags(); + + bool moron_flag_set = (emu_flags & EmulatorFlagIsoWarningSticky) != 0ULL; + + if (!(emu_flags & EmulatorFlagIsoWarningAcknowledged) && + extension == ".iso") { + // get their attention, they're more likely to read the message if they're + // worried something is wrong with their computer + + // beep blocks for duration, so run it on another thread + // beep is better than MessageBeep; if the user has disabled all windows + // sounds, MessageBeep doesnt play, but beep does play + + std::thread beep_thread{[]() { + for (uint32_t i = 0; i < 4; ++i) { +#if XE_PLATFORM_WIN32 == 1 + Beep(4096, 500); + Sleep(50); +#endif + } + }}; + + uint64_t time_started_reading = Clock::QueryHostUptimeMillis(); + // this isn't true really, they just won't be able to speak in discussion + // channels, and they can prove they have a physical copy + ShowSimpleMessageBox( + xe::SimpleMessageBoxType::Warning, + "PIRACY IS ILLEGAL, STAY OUT OF OUR DISCORD: ISO files are commonly " + "associated with piracy, which the " + "Xenia team " + "does not support or condone. Any users who come to the Xenia discord " + "for support who are found to be using pirated games will be banned " + "immediately, regardless of whether they own a physical copy."); + uint64_t time_finished_reading = Clock::QueryHostUptimeMillis(); + // join AFTER getting the end time, otherwise the beep duration will knock + // us out of idiot range + beep_thread.join(); + /* + we only show them this warning once. + if they immediately skipped it, assume they're an idiot and force + the warning every time they open the file don't do the check though if + we've already given them the moron flag + */ + if (!moron_flag_set && + (time_finished_reading - time_started_reading) < 2000) { + ShowSimpleMessageBox(xe::SimpleMessageBoxType::Warning, + "You clearly didn't read the warning. It will now " + "show every time you open an ISO file."); + SetPersistentEmulatorFlags(emu_flags | EmulatorFlagIsoWarningSticky); + } else { + // dont set the warning acknowledged bit, ever, if they skipped the first + // warning without reading it + if (!moron_flag_set) { + SetPersistentEmulatorFlags(emu_flags | + EmulatorFlagIsoWarningAcknowledged); + } + } } } X_STATUS Emulator::MountPath(const std::filesystem::path& path, const std::string_view mount_path) { + CheckMountWarning(path); auto device = CreateVfsDeviceBasedOnPath(path, mount_path); if (!device->Initialize()) { - xe::FatalError(fmt::format("Unable to mount {}; file corrupt or not found.", xe::path_to_utf8(path))); + xe::FatalError( + "Unable to mount the selected file, it is an unsupported format or " + "corrupted."); return X_STATUS_NO_SUCH_FILE; } if (!file_system_->RegisterDevice(std::move(device))) { - xe::FatalError(fmt::format("Unable to register {} to {}.", xe::path_to_utf8(path), xe::path_to_utf8(mount_path))); + xe::FatalError(fmt::format("Unable to register the input file to {}.", + xe::path_to_utf8(mount_path))); return X_STATUS_NO_SUCH_FILE; } @@ -634,31 +774,34 @@ bool Emulator::ExceptionCallback(Exception* ex) { current_thread->thread()->system_id(), current_thread->thread_id())); crash_msg.append(fmt::format("Thread Handle: 0x{:08X}\n", current_thread->handle())); crash_msg.append(fmt::format("PC: 0x{:08X}\n", - guest_function->MapMachineCodeToGuestAddress(ex->pc()))); + guest_function->MapMachineCodeToGuestAddress(ex->pc()))); crash_msg.append("Registers:\n"); for (int i = 0; i < 32; i++) { crash_msg.append(fmt::format(" r{:<3} = {:016X}\n", i, context->r[i])); } for (int i = 0; i < 32; i++) { - crash_msg.append(fmt::format(" f{:<3} = {:016X} = (double){} = (float){}\n", i, - *reinterpret_cast(&context->f[i]), context->f[i], - *(float*)&context->f[i])); + crash_msg.append(fmt::format(" f{:<3} = {:016X} = (double){} = (float){}\n", + i, + *reinterpret_cast(&context->f[i]), + context->f[i], *(float*)&context->f[i])); } for (int i = 0; i < 128; i++) { - crash_msg.append(fmt::format(" v{:<3} = [0x{:08X}, 0x{:08X}, 0x{:08X}, 0x{:08X}]\n", i, - context->v[i].u32[0], context->v[i].u32[1], context->v[i].u32[2], - context->v[i].u32[3])); + crash_msg.append( + fmt::format(" v{:<3} = [0x{:08X}, 0x{:08X}, 0x{:08X}, 0x{:08X}]\n", i, + context->v[i].u32[0], context->v[i].u32[1], + context->v[i].u32[2], context->v[i].u32[3])); } XELOGE("{}", crash_msg); std::string crash_dlg = fmt::format( - "The guest has crashed.\n\n" - "Xenia has now paused itself.\n\n" - "{}", crash_msg); + "The guest has crashed.\n\n" + "Xenia has now paused itself.\n\n" + "{}", + crash_msg); // Display a dialog telling the user the guest has crashed. if (display_window_ && imgui_drawer_) { - display_window_->app_context().CallInUIThreadSynchronous([this, &crash_dlg]() { - xe::ui::ImGuiDialog::ShowMessageBox( - imgui_drawer_, "Uh-oh!", crash_dlg); + display_window_->app_context().CallInUIThreadSynchronous([this, + &crash_dlg]() { + xe::ui::ImGuiDialog::ShowMessageBox(imgui_drawer_, "Uh-oh!", crash_dlg); }); } diff --git a/src/xenia/emulator.h b/src/xenia/emulator.h index ff7916ccd..7c8c29326 100644 --- a/src/xenia/emulator.h +++ b/src/xenia/emulator.h @@ -176,7 +176,7 @@ class Emulator { // Terminates the currently running title. X_STATUS TerminateTitle(); -const std::unique_ptr CreateVfsDeviceBasedOnPath( + const std::unique_ptr CreateVfsDeviceBasedOnPath( const std::filesystem::path& path, const std::string_view mount_path); X_STATUS MountPath(const std::filesystem::path& path, @@ -202,7 +202,7 @@ const std::unique_ptr CreateVfsDeviceBasedOnPath( void Pause(); void Resume(); bool is_paused() const { return paused_; } - + void ClearStickyPersistentFlags(); bool SaveToFile(const std::filesystem::path& path); bool RestoreFromFile(const std::filesystem::path& path); @@ -221,6 +221,17 @@ const std::unique_ptr CreateVfsDeviceBasedOnPath( xe::Delegate<> on_exit; private: + enum : uint64_t { + EmulatorFlagQuickstartShown = 1ULL << 0, + EmulatorFlagIsoWarningAcknowledged = 1ULL << 1, + EmulatorFlagIsoWarningSticky = 1ULL<<2, + + }; + static uint64_t GetPersistentEmulatorFlags(); + static void SetPersistentEmulatorFlags(uint64_t new_flags); + static std::string CanonicalizeFileExtension( + const std::filesystem::path& path); + void CheckMountWarning(const std::filesystem::path& path); static bool ExceptionCallbackThunk(Exception* ex, void* data); bool ExceptionCallback(Exception* ex); diff --git a/src/xenia/kernel/xam/xam_info.cc b/src/xenia/kernel/xam/xam_info.cc index c3ff87c33..e3230aea7 100644 --- a/src/xenia/kernel/xam/xam_info.cc +++ b/src/xenia/kernel/xam/xam_info.cc @@ -616,6 +616,55 @@ dword_result_t XamIsCurrentTitleDash_entry(const ppc_context_t& ctx) { } DECLARE_XAM_EXPORT1(XamIsCurrentTitleDash, kNone, kImplemented); +dword_result_t XGetAudioFlags_entry() { return 65537; } +DECLARE_XAM_EXPORT1(XGetAudioFlags, kNone, kStub); + +/* + todo: this table should instead be pointed to by a member of kernel state and initialized along with the process +*/ +static int32_t XamRtlRandomTable[128] = { + 1284227242, 1275210071, 573735546, 790525478, 2139871995, 1547161642, + 179605362, 789336058, 688789844, 1801674531, 1563985344, 1957994488, + 1364589140, 1645522239, 287218729, 606747145, 1972579041, 1085031214, + 1425521274, 1482476501, 1844823847, 57989841, 1897051121, 1935655697, + 1078145449, 1960408961, 1682526488, 842925246, 1500820517, 1214440339, + 1647877149, 682003330, 261478967, 2052111302, 162531612, 583907252, + 1336601894, 1715567821, 413027322, 484763869, 1383384898, 1004336348, + 764733703, 854245398, 651377827, 1614895754, 838170752, 1757981266, + 602609370, 1644491937, 926492609, 220523388, 115176313, 725345543, + 261903793, 746137067, 920026266, 1123561945, 1580818891, 1708537768, + 616249376, 1292428093, 562591055, 343818398, 1788223648, 1659004503, + 2077806209, 299502267, 1604221776, 602162358, 630328440, 1606980848, + 1580436667, 1078081533, 492894223, 839522115, 1979792683, 117609710, + 1767777339, 1454471165, 1965331169, 1844237615, 308236825, 329068152, + 412668190, 796845957, 1303643608, 436374069, 1677128483, 527237240, + 813497703, 1060284298, 1770027372, 1177238915, 884357618, 1409082233, + 1958367476, 448539723, 1592454029, 861567501, 963894560, 73586283, + 362288127, 507921405, 113007714, 823518204, 152049171, 1202660629, + 1326574676, 2025429265, 1035525444, 515967899, 1532298954, 2000478354, + 1450960922, 1417001333, 2049760794, 1229272821, 879983540, 1993962763, + 706699826, 776561741, 2111687655, 1343024091, 1637723038, 1220945662, + 484061587, 1390067357}; + +/* + Follows xam exactly, the updates to the random table are probably racy. +*/ +dword_result_t RtlRandom_entry(lpdword_t seed_out) { + int32_t table_seed_new = (0x7FFFFFED * *seed_out + 0x7FFFFFC3) % 0x7FFFFFFF; + *seed_out = table_seed_new; + uint32_t param_seed_new = + (0x7FFFFFED * table_seed_new + 0x7FFFFFC3) % 0x7FFFFFFFu; + *seed_out = param_seed_new; + + int32_t* update_table_position = &XamRtlRandomTable[param_seed_new & 0x7F]; + + int32_t result = *update_table_position; + *update_table_position = table_seed_new; + return result; +} + +DECLARE_XAM_EXPORT1(RtlRandom, kNone, kImplemented); + } // namespace xam } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xam/xam_voice.cc b/src/xenia/kernel/xam/xam_voice.cc index dbe87db3d..408a47f48 100644 --- a/src/xenia/kernel/xam/xam_voice.cc +++ b/src/xenia/kernel/xam/xam_voice.cc @@ -38,6 +38,13 @@ DECLARE_XAM_EXPORT1(XamVoiceClose, kNone, kStub); dword_result_t XamVoiceHeadsetPresent_entry(lpunknown_t voice_ptr) { return 0; } DECLARE_XAM_EXPORT1(XamVoiceHeadsetPresent, kNone, kStub); +dword_result_t XamVoiceSubmitPacket_entry(lpdword_t unk1, dword_t unk2, + lpdword_t unk3) { + // also may return 0xD000009D + return 0x800700AA; +} +DECLARE_XAM_EXPORT1(XamVoiceSubmitPacket, kNone, kStub); + } // namespace xam } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xbdm/xbdm_misc.cc b/src/xenia/kernel/xbdm/xbdm_misc.cc index 0a168b426..e74b89d99 100644 --- a/src/xenia/kernel/xbdm/xbdm_misc.cc +++ b/src/xenia/kernel/xbdm/xbdm_misc.cc @@ -119,6 +119,22 @@ dword_result_t DmGetConsoleDebugMemoryStatus_entry() { } DECLARE_XBDM_EXPORT1(DmGetConsoleDebugMemoryStatus, kDebug, kStub); +void __CAP_Start_Profiling_entry(dword_t a1, dword_t a2) {} + +DECLARE_XBDM_EXPORT1(__CAP_Start_Profiling, kDebug, kStub); + +void __CAP_End_Profiling_entry() {} + +DECLARE_XBDM_EXPORT1(__CAP_End_Profiling, kDebug, kStub); + +void __CAP_Enter_Function_entry() {} + +DECLARE_XBDM_EXPORT1(__CAP_Enter_Function, kDebug, kStub); + +void __CAP_Exit_Function_entry() {} + +DECLARE_XBDM_EXPORT1(__CAP_Exit_Function, kDebug, kStub); + } // namespace xbdm } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc index c49f9cb1a..636eb4a3e 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc @@ -672,20 +672,17 @@ dword_result_t FscSetCacheElementCount_entry(dword_t unk_0, dword_t unk_1) { return X_STATUS_SUCCESS; } DECLARE_XBOXKRNL_EXPORT1(FscSetCacheElementCount, kFileSystem, kStub); - +// todo: this should fill in the io status block and queue the apc dword_result_t NtDeviceIoControlFile_entry( dword_t handle, dword_t event_handle, dword_t apc_routine, - dword_t apc_context, dword_t io_status_block, dword_t io_control_code, - lpvoid_t input_buffer, dword_t input_buffer_len, lpvoid_t output_buffer, - dword_t output_buffer_len) { + dword_t apc_context, pointer_t io_status_block, + dword_t io_control_code, lpvoid_t input_buffer, dword_t input_buffer_len, + lpvoid_t output_buffer, dword_t output_buffer_len) { // Called by XMountUtilityDrive cache-mounting code // (checks if the returned values look valid, values below seem to pass the // checks) const uint32_t cache_size = 0xFF000; - const uint32_t X_IOCTL_DISK_GET_DRIVE_GEOMETRY = 0x70000; - const uint32_t X_IOCTL_DISK_GET_PARTITION_INFO = 0x74004; - if (io_control_code == X_IOCTL_DISK_GET_DRIVE_GEOMETRY) { if (output_buffer_len < 0x8) { assert_always(); @@ -710,30 +707,89 @@ dword_result_t NtDeviceIoControlFile_entry( return X_STATUS_SUCCESS; } DECLARE_XBOXKRNL_EXPORT1(NtDeviceIoControlFile, kFileSystem, kStub); +// device_extension_size = additional bytes of data (aligned up to 8 byte +// granularity) that will be allocated at the tail of the resulting device +// object. although it is allocated at the tail, it is accessed through a +// pointer at offset 0x18 so in theory a guest could be unaware that its a +// single allocation device_name is optional, extra_device_object_attributes +// gets assigned to the attributes field of the OBJECT_ATTRIBUTES used for +// ObCreateObject -dword_result_t IoCreateDevice_entry(dword_t device_struct, dword_t r4, - dword_t r5, dword_t r6, dword_t r7, - lpdword_t out_struct) { +// todo: need device guest object struct + host object for device +dword_result_t IoCreateDevice_entry(dword_t driver_object, + dword_t device_extension_size, + pointer_t device_name, + dword_t device_type, + dword_t extra_device_object_attributes, + lpdword_t device_object, + const ppc_context_t& ctx) { // Called from XMountUtilityDrive XAM-task code // That code tries writing things to a pointer at out_struct+0x18 // We'll alloc some scratch space for it so it doesn't cause any exceptions // 0x24 is guessed size from accesses to out_struct - likely incorrect - auto out_guest = kernel_memory()->SystemHeapAlloc(0x24); + auto current_kernel = ctx->kernel_state; - auto out = kernel_memory()->TranslateVirtual(out_guest); - memset(out, 0, 0x24); + uint32_t required_size = 80 + xe::align(device_extension_size, 8); - // XMountUtilityDrive writes some kind of header here - // 0x1000 bytes should be enough to store it - auto out_guest2 = kernel_memory()->SystemHeapAlloc(0x1000); - xe::store_and_swap(out + 0x18, out_guest2); + auto kernel_mem = current_kernel->memory(); - *out_struct = out_guest; + auto out_guest = kernel_mem->SystemHeapAlloc(required_size); + + auto out = kernel_mem->TranslateVirtual(out_guest); + + memset(out, 0, required_size); + + xe::store(out, 3); // maybe device object's Ob type? + + // this stores the total object size, without alignment! + + xe::store_and_swap(out + 2, device_extension_size + 80); + + // from 17559 + if (device_type == 7 || device_type == 58 || device_type == 62 || + device_type == 45 || device_type == 2 || device_type == 60 || + device_type == 61 || device_type == 36 || device_type == 64 || + device_type == 65 || device_type == 66 || device_type == 67 || + device_type == 68 || device_type == 69 || device_type == 70 || + device_type == 72 || device_type == 73) { + xe::store_and_swap(out + 0xC, 0); + } else { + // pointer to itself? + xe::store_and_swap(out + 0xC, out_guest); + } + xe::store(out + 0x1C, static_cast(device_type)); + + uint32_t flags_field_value = 16; + if (device_name) { + flags_field_value |= 8; + } + xe::store(out + 0x1e, 1); + xe::store_and_swap(out + 0x14, flags_field_value); + if (device_extension_size != 0) { + // pointer to device specific data + // XMountUtilityDrive writes some kind of header here + xe::store_and_swap(out + 0x18, out_guest + 80); + } + + xe::store_and_swap(out + 8, driver_object); + + *device_object = out_guest; return X_STATUS_SUCCESS; } DECLARE_XBOXKRNL_EXPORT1(IoCreateDevice, kFileSystem, kStub); +//supposed to invoke a callback on the driver object! its some sort of destructor function +//intended to be called for all devices created from the driver +void IoDeleteDevice_entry(dword_t device_ptr, const ppc_context_t& ctx) { + if (device_ptr) { + auto kernel_mem = ctx->kernel_state->memory(); + kernel_mem->SystemHeapFree(device_ptr); + } +} + +DECLARE_XBOXKRNL_EXPORT1(IoDeleteDevice, kFileSystem, kStub); + } // namespace xboxkrnl } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc index 65914b379..607d81c8e 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc @@ -13,6 +13,7 @@ #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/user_module.h" #include "xenia/kernel/util/shim_utils.h" +#include "xenia/kernel/util/xex2_info.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" #include "xenia/xbox.h" @@ -215,6 +216,65 @@ void ExRegisterTitleTerminateNotification_entry( } DECLARE_XBOXKRNL_EXPORT1(ExRegisterTitleTerminateNotification, kModules, kImplemented); +// todo: replace magic numbers +dword_result_t XexLoadImageHeaders_entry(pointer_t path, + pointer_t header, + dword_t buffer_size, + const ppc_context_t& ctx) { + if (buffer_size < 0x800) { + return X_STATUS_BUFFER_TOO_SMALL; + } + auto current_kernel = ctx->kernel_state; + auto target_path = util::TranslateAnsiString(current_kernel->memory(), path); + + vfs::File* vfs_file = nullptr; + vfs::FileAction file_action; + X_STATUS result = current_kernel->file_system()->OpenFile( + nullptr, target_path, vfs::FileDisposition::kOpen, + vfs::FileAccess::kGenericRead, false, true, &vfs_file, &file_action); + + if (!vfs_file) { + return result; + } + size_t bytes_read = 0; + + X_STATUS result_status = vfs_file->ReadSync( + reinterpret_cast(header.host_address()), 2048, 0, &bytes_read); + + if (result_status < 0) { + vfs_file->Destroy(); + return result_status; + } + + if (header->magic != 'XEX2') { + vfs_file->Destroy(); + return X_STATUS_INVALID_IMAGE_FORMAT; + } + unsigned int header_size = header->header_size; + + if (header_size < 0x800 || header_size > 0x10000 || + (header_size & 0x7FF) != 0) { + result_status = X_STATUS_INVALID_IMAGE_FORMAT; + } else if (header_size <= buffer_size) { + if (header_size <= 0x800) { + result_status = X_STATUS_SUCCESS; + } else { + result_status = vfs_file->ReadSync( + reinterpret_cast(header.host_address() + 2048), + header_size - 2048, 2048, &bytes_read); + if (result_status >= X_STATUS_SUCCESS) { + result_status = X_STATUS_SUCCESS; + } + } + + } else { + result_status = X_STATUS_BUFFER_TOO_SMALL; + } + + vfs_file->Destroy(); + return result_status; +} +DECLARE_XBOXKRNL_EXPORT1(XexLoadImageHeaders, kModules, kImplemented); } // namespace xboxkrnl } // namespace kernel diff --git a/src/xenia/vfs/devices/disc_image_device.cc b/src/xenia/vfs/devices/disc_image_device.cc index ce343b43b..69f84a476 100644 --- a/src/xenia/vfs/devices/disc_image_device.cc +++ b/src/xenia/vfs/devices/disc_image_device.cc @@ -30,10 +30,10 @@ DiscImageDevice::~DiscImageDevice() = default; bool DiscImageDevice::Initialize() { mmap_ = MappedMemory::Open(host_path_, MappedMemory::Mode::kRead); if (!mmap_) { - XELOGE("Disc image {} could not be mapped", xe::path_to_utf8(host_path_)); + XELOGE("Disc image could not be mapped"); return false; } else { - XELOGFS("DiscImageDevice::Initialize({})", xe::path_to_utf8(host_path_)); + XELOGFS("DiscImageDevice::Initialize"); } ParseState state = {0}; diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index 5469c86c2..a8cc9414d 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -63,6 +63,7 @@ typedef uint32_t X_STATUS; #define X_STATUS_MUTANT_NOT_OWNED ((X_STATUS)0xC0000046L) #define X_STATUS_THREAD_IS_TERMINATING ((X_STATUS)0xC000004BL) #define X_STATUS_PROCEDURE_NOT_FOUND ((X_STATUS)0xC000007AL) +#define X_STATUS_INVALID_IMAGE_FORMAT ((X_STATUS)0xC000007BL) #define X_STATUS_INSUFFICIENT_RESOURCES ((X_STATUS)0xC000009AL) #define X_STATUS_MEMORY_NOT_ALLOCATED ((X_STATUS)0xC00000A0L) #define X_STATUS_FILE_IS_A_DIRECTORY ((X_STATUS)0xC00000BAL) @@ -123,6 +124,10 @@ typedef uint32_t X_HRESULT; #define X_E_NOTFOUND X_HRESULT_FROM_WIN32(X_ERROR_NOT_FOUND) #define X_E_NO_SUCH_USER X_HRESULT_FROM_WIN32(X_ERROR_NO_SUCH_USER) +//IOCTL_, used by NtDeviceIoControlFile +constexpr uint32_t X_IOCTL_DISK_GET_DRIVE_GEOMETRY = 0x70000; +constexpr uint32_t X_IOCTL_DISK_GET_PARTITION_INFO = 0x74004; + // MEM_*, used by NtAllocateVirtualMemory enum X_MEM : uint32_t { X_MEM_COMMIT = 0x00001000,