From 1c08912a59225a0b85e67e3a18df233b7aeb0332 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sat, 8 Jul 2023 19:35:59 +0300 Subject: [PATCH 1/6] [IR:USER] Add empty service --- CMakeLists.txt | 3 ++- include/kernel/handles.hpp | 2 ++ include/logger.hpp | 1 + include/services/ir_user.hpp | 19 +++++++++++++++++++ include/services/service_manager.hpp | 2 ++ src/core/services/ir_user.cpp | 15 +++++++++++++++ src/core/services/service_manager.cpp | 7 ++++++- 7 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 include/services/ir_user.hpp create mode 100644 src/core/services/ir_user.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d446ba7..016b2a59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,7 @@ set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services src/core/services/frd.cpp src/core/services/nim.cpp src/core/services/shared_font.cpp src/core/services/y2r.cpp src/core/services/cam.cpp src/core/services/ldr_ro.cpp src/core/services/act.cpp src/core/services/nfc.cpp src/core/services/dlp_srvr.cpp + src/core/services/ir_user.cpp ) set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA/shader_unit.cpp src/core/PICA/shader_interpreter.cpp src/core/PICA/dynapica/shader_rec.cpp @@ -141,7 +142,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/result/result_common.hpp include/result/result_fs.hpp include/result/result_fnd.hpp include/result/result_gsp.hpp include/result/result_kernel.hpp include/result/result_os.hpp include/crypto/aes_engine.hpp include/metaprogramming.hpp include/PICA/pica_vertex.hpp include/gl_state.hpp - include/config.hpp + include/config.hpp include/services/ir_user.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/kernel/handles.hpp b/include/kernel/handles.hpp index 589b64f5..3656beeb 100644 --- a/include/kernel/handles.hpp +++ b/include/kernel/handles.hpp @@ -21,6 +21,7 @@ namespace KernelHandles { DLP_SRVR, // Download Play: Server. Used for network play. DSP, // DSP service (Used for audio decoding and output) HID, // HID service (Handles everything input-related including gyro) + IR_USER, // One of 3 infrared communication services FRD, // Friend service (Miiverse friend service) FS, // Filesystem service GPU, // GPU service @@ -68,6 +69,7 @@ namespace KernelHandles { case DSP: return "DSP"; case DLP_SRVR: return "DLP::SRVR"; case HID: return "HID"; + case IR_USER: return "IR:USER"; case FRD: return "FRD"; case FS: return "FS"; case GPU: return "GSP::GPU"; diff --git a/include/logger.hpp b/include/logger.hpp index 62129707..e1b425b9 100644 --- a/include/logger.hpp +++ b/include/logger.hpp @@ -42,6 +42,7 @@ namespace Log { static Logger<false> frdLogger; static Logger<false> fsLogger; static Logger<false> hidLogger; + static Logger<false> irUserLogger; static Logger<false> gspGPULogger; static Logger<false> gspLCDLogger; static Logger<false> ldrLogger; diff --git a/include/services/ir_user.hpp b/include/services/ir_user.hpp new file mode 100644 index 00000000..734bec44 --- /dev/null +++ b/include/services/ir_user.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "helpers.hpp" +#include "kernel_types.hpp" +#include "logger.hpp" +#include "memory.hpp" +#include "result/result.hpp" + +class IRUserService { + Handle handle = KernelHandles::IR_USER; + Memory& mem; + MAKE_LOG_FUNCTION(log, irUserLogger) + + // Service commands + + public: + IRUserService(Memory& mem) : mem(mem) {} + void reset(); + void handleSyncRequest(u32 messagePointer); +}; \ No newline at end of file diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index ee2677ad..3136408f 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -21,6 +21,7 @@ #include "services/gsp_gpu.hpp" #include "services/gsp_lcd.hpp" #include "services/hid.hpp" +#include "services/ir_user.hpp" #include "services/ldr_ro.hpp" #include "services/mic.hpp" #include "services/ndm.hpp" @@ -52,6 +53,7 @@ class ServiceManager { DlpSrvrService dlp_srvr; DSPService dsp; HIDService hid; + IRUserService ir_user; FRDService frd; FSService fs; GPUService gsp_gpu; diff --git a/src/core/services/ir_user.cpp b/src/core/services/ir_user.cpp new file mode 100644 index 00000000..6a1a9c11 --- /dev/null +++ b/src/core/services/ir_user.cpp @@ -0,0 +1,15 @@ +#include "ipc.hpp" +#include "services/ir_user.hpp" + +namespace IRUserCommands { + enum : u32 {}; +} + +void IRUserService::reset() {} + +void IRUserService::handleSyncRequest(u32 messagePointer) { + const u32 command = mem.read32(messagePointer); + switch (command) { + default: Helpers::panic("ir:USER service requested. Command: %08X\n", command); + } +} \ No newline at end of file diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index 5f2918de..6ac2478b 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -7,7 +7,7 @@ ServiceManager::ServiceManager(std::span<u32, 16> regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel) : regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), act(mem), apt(mem, kernel), cam(mem), - cecd(mem, kernel), cfg(mem), dlp_srvr(mem), dsp(mem, kernel), hid(mem, kernel), frd(mem), fs(mem, kernel), + cecd(mem, kernel), cfg(mem), dlp_srvr(mem), dsp(mem, kernel), hid(mem, kernel), ir_user(mem), frd(mem), fs(mem, kernel), gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem), mic(mem), nfc(mem, kernel), nim(mem), ndm(mem), ptm(mem), y2r(mem, kernel) {} @@ -26,6 +26,7 @@ void ServiceManager::reset() { dlp_srvr.reset(); dsp.reset(); hid.reset(); + ir_user.reset(); frd.reset(); fs.reset(); gsp_gpu.reset(); @@ -83,6 +84,7 @@ void ServiceManager::registerClient(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +// clang-format off static std::map<std::string, Handle> serviceMap = { { "ac:u", KernelHandles::AC }, { "act:u", KernelHandles::ACT }, @@ -97,6 +99,7 @@ static std::map<std::string, Handle> serviceMap = { { "dlp:SRVR", KernelHandles::DLP_SRVR }, { "dsp::DSP", KernelHandles::DSP }, { "hid:USER", KernelHandles::HID }, + { "ir:USER", KernelHandles::IR_USER }, { "frd:u", KernelHandles::FRD }, { "fs:USER", KernelHandles::FS }, { "gsp::Gpu", KernelHandles::GPU }, @@ -110,6 +113,7 @@ static std::map<std::string, Handle> serviceMap = { { "ptm:sysm", KernelHandles::PTM }, { "y2r:u", KernelHandles::Y2R } }; +// clang-format on // https://www.3dbrew.org/wiki/SRV:GetServiceHandle void ServiceManager::getServiceHandle(u32 messagePointer) { @@ -179,6 +183,7 @@ void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) { case KernelHandles::CFG: cfg.handleSyncRequest(messagePointer); break; case KernelHandles::DLP_SRVR: dlp_srvr.handleSyncRequest(messagePointer); break; case KernelHandles::HID: hid.handleSyncRequest(messagePointer); break; + case KernelHandles::IR_USER: ir_user.handleSyncRequest(messagePointer); break; case KernelHandles::FRD: frd.handleSyncRequest(messagePointer); break; case KernelHandles::LCD: gsp_lcd.handleSyncRequest(messagePointer); break; case KernelHandles::LDR_RO: ldr.handleSyncRequest(messagePointer); break; From b83526378edca4cf22ea853d592b7f185acb092c Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sat, 8 Jul 2023 20:13:20 +0300 Subject: [PATCH 2/6] [IR:USER] Some more stubbing --- include/services/ir_user.hpp | 15 +++++- src/core/services/ir_user.cpp | 69 +++++++++++++++++++++++++-- src/core/services/service_manager.cpp | 7 ++- 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/include/services/ir_user.hpp b/include/services/ir_user.hpp index 734bec44..2c7b1559 100644 --- a/include/services/ir_user.hpp +++ b/include/services/ir_user.hpp @@ -1,19 +1,32 @@ #pragma once +#include <optional> + #include "helpers.hpp" #include "kernel_types.hpp" #include "logger.hpp" #include "memory.hpp" #include "result/result.hpp" +// Circular dependencies in this project? Never +class Kernel; + class IRUserService { Handle handle = KernelHandles::IR_USER; Memory& mem; + Kernel& kernel; MAKE_LOG_FUNCTION(log, irUserLogger) // Service commands + void disconnect(u32 messagePointer); + void finalizeIrnop(u32 messagePointer); + void getConnectionStatusEvent(u32 messagePointer); + void initializeIrnopShared(u32 messagePointer); + void requireConnection(u32 messagePointer); + + std::optional<Handle> connectionStatusEvent = std::nullopt; public: - IRUserService(Memory& mem) : mem(mem) {} + IRUserService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {} void reset(); void handleSyncRequest(u32 messagePointer); }; \ No newline at end of file diff --git a/src/core/services/ir_user.cpp b/src/core/services/ir_user.cpp index 6a1a9c11..c8573182 100644 --- a/src/core/services/ir_user.cpp +++ b/src/core/services/ir_user.cpp @@ -1,15 +1,78 @@ -#include "ipc.hpp" #include "services/ir_user.hpp" +#include "ipc.hpp" +#include "kernel.hpp" + namespace IRUserCommands { - enum : u32 {}; + enum : u32 { + FinalizeIrnop = 0x00020000, + RequireConnection = 0x00060040, + Disconnect = 0x00090000, + GetConnectionStatusEvent = 0x000C0000, + InitializeIrnopShared = 0x00180182 + }; } -void IRUserService::reset() {} +void IRUserService::reset() { connectionStatusEvent = std::nullopt; } void IRUserService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { + case IRUserCommands::Disconnect: disconnect(messagePointer); break; + case IRUserCommands::FinalizeIrnop: finalizeIrnop(messagePointer); break; + case IRUserCommands::GetConnectionStatusEvent: getConnectionStatusEvent(messagePointer); break; + case IRUserCommands::InitializeIrnopShared: initializeIrnopShared(messagePointer); break; + case IRUserCommands::RequireConnection: requireConnection(messagePointer); break; default: Helpers::panic("ir:USER service requested. Command: %08X\n", command); } +} + +void IRUserService::initializeIrnopShared(u32 messagePointer) { + const u32 sharedMemSize = mem.read32(messagePointer + 4); + const u32 receiveBufferSize = mem.read32(messagePointer + 8); + const u32 receiveBufferPackageCount = mem.read32(messagePointer + 12); + const u32 sendBufferSize = mem.read32(messagePointer + 16); + const u32 sendBufferPackageCount = mem.read32(messagePointer + 20); + const u32 bitrate = mem.read32(messagePointer + 24); + const u32 descriptor = mem.read32(messagePointer + 28); + const u32 sharedMemHandle = mem.read32(messagePointer + 32); + + log("IR:USER: InitializeIrnopShared (shared mem size = %08X, sharedMemHandle = %X) (stubbed)\n", sharedMemSize, sharedMemHandle); + mem.write32(messagePointer, IPC::responseHeader(0x18, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void IRUserService::finalizeIrnop(u32 messagePointer) { + log("IR:USER: FinalizeIrnop\n"); + + // This should disconnect any connected device de-initialize the shared memory + mem.write32(messagePointer, IPC::responseHeader(0x2, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void IRUserService::getConnectionStatusEvent(u32 messagePointer) { + log("IR:USER: GetConnectionStatusEvent\n"); + + if (!connectionStatusEvent.has_value()) { + connectionStatusEvent = kernel.makeEvent(ResetType::OneShot); + } + + mem.write32(messagePointer, IPC::responseHeader(0xC, 1, 2)); + mem.write32(messagePointer + 4, Result::Success); + // TOOD: Descriptor here + mem.write32(messagePointer + 12, connectionStatusEvent.value()); +} + +void IRUserService::requireConnection(u32 messagePointer) { + const u8 deviceID = mem.read8(messagePointer + 4); + log("IR:USER: RequireConnection (device: %d)\n", deviceID); + + mem.write32(messagePointer, IPC::responseHeader(0x6, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void IRUserService::disconnect(u32 messagePointer) { + log("IR:USER: Disconnect\n"); + mem.write32(messagePointer, IPC::responseHeader(0x9, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index 6ac2478b..17fdf1da 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -6,10 +6,9 @@ #include "kernel.hpp" ServiceManager::ServiceManager(std::span<u32, 16> regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel) - : regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), act(mem), apt(mem, kernel), cam(mem), - cecd(mem, kernel), cfg(mem), dlp_srvr(mem), dsp(mem, kernel), hid(mem, kernel), ir_user(mem), frd(mem), fs(mem, kernel), - gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem), mic(mem), nfc(mem, kernel), nim(mem), ndm(mem), - ptm(mem), y2r(mem, kernel) {} + : regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), act(mem), apt(mem, kernel), cam(mem), cecd(mem, kernel), cfg(mem), + dlp_srvr(mem), dsp(mem, kernel), hid(mem, kernel), ir_user(mem, kernel), frd(mem), fs(mem, kernel), gsp_gpu(mem, gpu, kernel, currentPID), + gsp_lcd(mem), ldr(mem), mic(mem), nfc(mem, kernel), nim(mem), ndm(mem), ptm(mem), y2r(mem, kernel) {} static constexpr int MAX_NOTIFICATION_COUNT = 16; From 817b3de945162737d1e216a9cd64157f57d520b6 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sat, 8 Jul 2023 20:23:43 +0300 Subject: [PATCH 3/6] [GPU] Implement vertex padding --- src/core/PICA/gpu.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index ed67067c..a2a1f761 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -168,7 +168,15 @@ void GPU::drawArrays() { for (int j = 0; j < attr.componentCount; j++) { uint index = (attrCfg >> (j * 4)) & 0xf; // Get index of attribute in vertexCfg - if (index >= 12) Helpers::panic("[PICA] Vertex attribute used as padding"); + + // Vertex attributes used as padding + // 12, 13, 14 and 15 are equivalent to 4, 8, 12 and 16 bytes of padding respectively + if (index >= 12) [[unlikely]] { + // Align attriubte address up to a 4 byte boundary + attrAddress = (attrAddress + 3) & -4; + attrAddress += (index - 11) << 2; + continue; + } u32 attribInfo = (vertexCfg >> (index * 4)) & 0xf; u32 attribType = attribInfo & 0x3; // Type of attribute(sbyte/ubyte/short/float) From 91bf249cbaaab71a45d08c5166db2f47c0d26f94 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sat, 8 Jul 2023 20:32:21 +0300 Subject: [PATCH 4/6] [BOSS] Stub GetTaskInfo --- include/services/boss.hpp | 1 + src/core/services/boss.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/include/services/boss.hpp b/include/services/boss.hpp index e31018e6..9e6ae27a 100644 --- a/include/services/boss.hpp +++ b/include/services/boss.hpp @@ -16,6 +16,7 @@ class BOSSService { void getOptoutFlag(u32 messagePointer); void getStorageEntryInfo(u32 messagePointer); // Unknown what this is, name taken from Citra void getTaskIdList(u32 messagePointer); + void getTaskInfo(u32 messagePOinter); void getTaskStorageInfo(u32 messagePointer); void receiveProperty(u32 messagePointer); void registerStorageEntry(u32 messagePointer); diff --git a/src/core/services/boss.cpp b/src/core/services/boss.cpp index b7bb0a6b..c535dda2 100644 --- a/src/core/services/boss.cpp +++ b/src/core/services/boss.cpp @@ -11,6 +11,7 @@ namespace BOSSCommands { GetTaskIdList = 0x000E0000, GetNsDataIdList = 0x00100102, ReceiveProperty = 0x00160082, + GetTaskInfo = 0x00250082, RegisterStorageEntry = 0x002F0140, GetStorageEntryInfo = 0x00300000 }; @@ -27,6 +28,7 @@ void BOSSService::handleSyncRequest(u32 messagePointer) { case BOSSCommands::GetOptoutFlag: getOptoutFlag(messagePointer); break; case BOSSCommands::GetStorageEntryInfo: getStorageEntryInfo(messagePointer); break; case BOSSCommands::GetTaskIdList: getTaskIdList(messagePointer); break; + case BOSSCommands::GetTaskInfo: getTaskInfo(messagePointer); break; case BOSSCommands::GetTaskStorageInfo: getTaskStorageInfo(messagePointer); break; case BOSSCommands::InitializeSession: initializeSession(messagePointer); break; case BOSSCommands::ReceiveProperty: receiveProperty(messagePointer); break; @@ -63,6 +65,15 @@ void BOSSService::getTaskIdList(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +// This function is completely undocumented, including on 3DBrew +// The name GetTaskInfo is taken from Citra source and nobody seems to know what exactly it does +// Kid Icarus: Uprising uses it on startup +void BOSSService::getTaskInfo(u32 messagePointer) { + log("BOSS::GetTaskInfo (stubbed and undocumented)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x25, 1, 2)); + mem.write32(messagePointer + 4, Result::Success); +} + void BOSSService::getStorageEntryInfo(u32 messagePointer) { log("BOSS::GetStorageEntryInfo (undocumented)\n"); mem.write32(messagePointer, IPC::responseHeader(0x30, 3, 0)); From 5f2f82d074502c0fbbf88f580be67c3ae1c5b1c5 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sat, 8 Jul 2023 20:43:48 +0300 Subject: [PATCH 5/6] [FS] Implement SdmcIsWritable --- include/services/fs.hpp | 1 + src/core/services/fs.cpp | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/services/fs.hpp b/include/services/fs.hpp index 9220a869..52ac97ad 100644 --- a/include/services/fs.hpp +++ b/include/services/fs.hpp @@ -49,6 +49,7 @@ class FSService { void initialize(u32 messagePointer); void initializeWithSdkVersion(u32 messagePointer); void isSdmcDetected(u32 messagePointer); + void isSdmcWritable(u32 messagePOinter); void openArchive(u32 messagePointer); void openDirectory(u32 messagePointer); void openFile(u32 messagePointer); diff --git a/src/core/services/fs.cpp b/src/core/services/fs.cpp index 06c970f0..2fd3b8e6 100644 --- a/src/core/services/fs.cpp +++ b/src/core/services/fs.cpp @@ -24,6 +24,7 @@ namespace FSCommands { FormatThisUserSaveData = 0x080F0180, GetFreeBytes = 0x08120080, IsSdmcDetected = 0x08170000, + IsSdmcWritable = 0x08180000, GetFormatInfo = 0x084500C2, FormatSaveData = 0x084C0242, InitializeWithSdkVersion = 0x08610042, @@ -155,6 +156,7 @@ void FSService::handleSyncRequest(u32 messagePointer) { case FSCommands::Initialize: initialize(messagePointer); break; case FSCommands::InitializeWithSdkVersion: initializeWithSdkVersion(messagePointer); break; case FSCommands::IsSdmcDetected: isSdmcDetected(messagePointer); break; + case FSCommands::IsSdmcWritable: isSdmcWritable(messagePointer); break; case FSCommands::OpenArchive: openArchive(messagePointer); break; case FSCommands::OpenDirectory: openDirectory(messagePointer); break; case FSCommands::OpenFile: [[likely]] openFile(messagePointer); break; @@ -536,9 +538,22 @@ void FSService::setPriority(u32 messagePointer) { priority = value; } + +// Shows whether an SD card is inserted. At the moment stubbed to no +constexpr bool sdInserted = false; + void FSService::isSdmcDetected(u32 messagePointer) { log("FS::IsSdmcDetected\n"); mem.write32(messagePointer, IPC::responseHeader(0x817, 2, 0)); mem.write32(messagePointer + 4, Result::Success); - mem.write32(messagePointer + 8, 0); // Whether SD is detected. For now we emulate a 3DS without an SD. + mem.write8(messagePointer + 8, sdInserted ? 1 : 0); +} + +// We consider our SD card to always be writable if oen is inserted for now +// So isSdmcWritable returns 1 if an SD card is inserted (because it's always writable) and 0 if not. +void FSService::isSdmcWritable(u32 messagePointer) { + log("FS::isSdmcWritable\n"); + mem.write32(messagePointer, IPC::responseHeader(0x818, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write8(messagePointer + 8, sdInserted ? 1 : 0); } \ No newline at end of file From 7e93d082017b665b1cca016d3bc6d26e8caac0e3 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sat, 8 Jul 2023 20:59:30 +0300 Subject: [PATCH 6/6] Add warning when initializing IR:USER --- src/core/services/ir_user.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/services/ir_user.cpp b/src/core/services/ir_user.cpp index c8573182..a4c98a82 100644 --- a/src/core/services/ir_user.cpp +++ b/src/core/services/ir_user.cpp @@ -38,6 +38,8 @@ void IRUserService::initializeIrnopShared(u32 messagePointer) { const u32 sharedMemHandle = mem.read32(messagePointer + 32); log("IR:USER: InitializeIrnopShared (shared mem size = %08X, sharedMemHandle = %X) (stubbed)\n", sharedMemSize, sharedMemHandle); + Helpers::warn("Game is initializing IR:USER. If it explodes, this is probably why"); + mem.write32(messagePointer, IPC::responseHeader(0x18, 1, 0)); mem.write32(messagePointer + 4, Result::Success); }