diff --git a/CMakeLists.txt b/CMakeLists.txt index d3ffa15a..401b2494 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,7 +92,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/services/am.hpp include/services/boss.hpp include/services/frd.hpp include/services/nim.hpp include/fs/archive_ext_save_data.hpp include/services/shared_font.hpp include/fs/archive_ncch.hpp include/renderer_gl/textures.hpp include/colour.hpp include/services/y2r.hpp include/services/cam.hpp - include/services/ldr_ro.hpp + include/services/ldr_ro.hpp include/ipc.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/ipc.hpp b/include/ipc.hpp new file mode 100644 index 00000000..67a8897e --- /dev/null +++ b/include/ipc.hpp @@ -0,0 +1,9 @@ +#pragma once +#include + +namespace IPC { + constexpr std::uint32_t responseHeader(std::uint32_t commandID, std::uint32_t normalResponses, std::uint32_t translateResponses) { + // TODO: Maybe validate the response count stuff fits in 6 bits + return (commandID << 16) | (normalResponses << 6) | translateResponses; + } +} \ No newline at end of file diff --git a/src/core/services/ac.cpp b/src/core/services/ac.cpp index cc1e3bd5..66452534 100644 --- a/src/core/services/ac.cpp +++ b/src/core/services/ac.cpp @@ -1,4 +1,5 @@ #include "services/ac.hpp" +#include "ipc.hpp" namespace ACCommands { enum : u32 { @@ -26,5 +27,6 @@ void ACService::setClientVersion(u32 messagePointer) { u32 version = mem.read32(messagePointer + 4); log("AC::SetClientVersion (version = %d)\n", version); + mem.write32(messagePointer, IPC::responseHeader(0x40, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/am.cpp b/src/core/services/am.cpp index 00abb6e2..9db92df5 100644 --- a/src/core/services/am.cpp +++ b/src/core/services/am.cpp @@ -1,4 +1,5 @@ #include "services/am.hpp" +#include "ipc.hpp" namespace AMCommands { enum : u32 { @@ -40,11 +41,14 @@ void AMService::listTitleInfo(u32 messagePointer) { pointer += 24; // = sizeof(TicketInfo) } + mem.write32(messagePointer, IPC::responseHeader(0x1007, 2, 2)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, ticketCount); } void AMService::getDLCTitleInfo(u32 messagePointer) { log("AM::GetDLCTitleInfo (stubbed to fail)\n"); + + mem.write32(messagePointer, IPC::responseHeader(0x1005, 1, 4)); mem.write32(messagePointer + 4, -1); } \ No newline at end of file diff --git a/src/core/services/apt.cpp b/src/core/services/apt.cpp index 93bfc0cf..9eb796d7 100644 --- a/src/core/services/apt.cpp +++ b/src/core/services/apt.cpp @@ -1,4 +1,5 @@ #include "services/apt.hpp" +#include "ipc.hpp" #include "kernel.hpp" namespace APTCommands { @@ -69,11 +70,13 @@ void APTService::appletUtility(u32 messagePointer) { log("APT::AppletUtility(utility = %d, input size = %x, output size = %x, inputPointer = %08X)\n", utility, inputSize, outputSize, inputPointer); + mem.write32(messagePointer, IPC::responseHeader(0x4B, 2, 2)); mem.write32(messagePointer + 4, Result::Success); } void APTService::checkNew3DS(u32 messagePointer) { log("APT::CheckNew3DS\n"); + mem.write32(messagePointer, IPC::responseHeader(0x102, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write8(messagePointer + 8, (model == ConsoleModel::New3DS) ? 1 : 0); // u8, Status (0 = Old 3DS, 1 = New 3DS) } @@ -81,11 +84,14 @@ void APTService::checkNew3DS(u32 messagePointer) { // TODO: Figure out the slight way this differs from APT::CheckNew3DS void APTService::checkNew3DSApp(u32 messagePointer) { log("APT::CheckNew3DSApp\n"); - checkNew3DS(messagePointer); + mem.write32(messagePointer, IPC::responseHeader(0x101, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write8(messagePointer + 8, (model == ConsoleModel::New3DS) ? 1 : 0); // u8, Status (0 = Old 3DS, 1 = New 3DS) } void APTService::enable(u32 messagePointer) { log("APT::Enable\n"); + mem.write32(messagePointer, IPC::responseHeader(0x3, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -97,6 +103,7 @@ void APTService::initialize(u32 messagePointer) { resumeEvent = kernel.makeEvent(ResetType::OneShot); } + mem.write32(messagePointer, IPC::responseHeader(0x2, 1, 3)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, 0x04000000); // Translation descriptor mem.write32(messagePointer + 12, notificationEvent.value()); // Notification Event Handle @@ -106,6 +113,7 @@ void APTService::initialize(u32 messagePointer) { void APTService::inquireNotification(u32 messagePointer) { log("APT::InquireNotification (STUBBED TO RETURN NONE)\n"); + mem.write32(messagePointer, IPC::responseHeader(0xB, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, static_cast(NotificationType::None)); } @@ -118,6 +126,7 @@ void APTService::getLockHandle(u32 messagePointer) { lockHandle = kernel.makeMutex(); } + mem.write32(messagePointer, IPC::responseHeader(0x1, 3, 2)); mem.write32(messagePointer + 4, Result::Success); // Result code mem.write32(messagePointer + 8, 0); // AppletAttr mem.write32(messagePointer + 12, 0); // APT State (bit0 = Power Button State, bit1 = Order To Close State) @@ -128,6 +137,7 @@ void APTService::getLockHandle(u32 messagePointer) { // This apparently does nothing on the original kernel either? void APTService::notifyToWait(u32 messagePointer) { log("APT::NotifyToWait\n"); + mem.write32(messagePointer, IPC::responseHeader(0x43, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -139,6 +149,7 @@ void APTService::receiveParameter(u32 messagePointer) { if (size > 0x1000) Helpers::panic("APT::ReceiveParameter with size > 0x1000"); // TODO: Properly implement this. We currently stub it in the same way as 3dmoo + mem.write32(messagePointer, IPC::responseHeader(0xD, 4, 4)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, 0); // Sender App ID mem.write32(messagePointer + 12, 1); // Signal type (1 = app just started, 0xB = returning to app, 0xC = exiting app) @@ -150,6 +161,7 @@ void APTService::receiveParameter(u32 messagePointer) { void APTService::replySleepQuery(u32 messagePointer) { log("APT::ReplySleepQuery (Stubbed)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x3E, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -161,6 +173,7 @@ void APTService::setApplicationCpuTimeLimit(u32 messagePointer) { if (percentage < 5 || percentage > 89 || fixed != 1) { Helpers::panic("Invalid parameters passed to APT::SetApplicationCpuTimeLimit"); } else { + mem.write32(messagePointer, IPC::responseHeader(0x4F, 1, 0)); mem.write32(messagePointer + 4, Result::Success); cpuTimeLimit = percentage; } @@ -168,6 +181,7 @@ void APTService::setApplicationCpuTimeLimit(u32 messagePointer) { void APTService::getApplicationCpuTimeLimit(u32 messagePointer) { log("APT::GetApplicationCpuTimeLimit\n"); + mem.write32(messagePointer, IPC::responseHeader(0x50, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, cpuTimeLimit); } @@ -176,6 +190,7 @@ void APTService::setScreencapPostPermission(u32 messagePointer) { u32 perm = mem.read32(messagePointer + 4); log("APT::SetScreencapPostPermission (perm = %d)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x55, 1, 0)); // Apparently only 1-3 are valid values, but I see 0 used in some games like Pokemon Rumble mem.write32(messagePointer + 4, Result::Success); screencapPostPermission = perm; @@ -185,6 +200,7 @@ void APTService::getSharedFont(u32 messagePointer) { log("APT::GetSharedFont\n"); constexpr u32 fontVaddr = 0x18000000; + mem.write32(messagePointer, IPC::responseHeader(0x44, 2, 2)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, fontVaddr); mem.write32(messagePointer + 16, KernelHandles::FontSharedMemHandle); @@ -195,6 +211,7 @@ void APTService::getSharedFont(u32 messagePointer) { void APTService::theSmashBrosFunction(u32 messagePointer) { log("APT: Called the elusive Smash Bros function\n"); + mem.write32(messagePointer, IPC::responseHeader(0x103, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, (model == ConsoleModel::New3DS) ? 2 : 1); } @@ -206,6 +223,7 @@ void APTService::getWirelessRebootInfo(u32 messagePointer) { if (size > 0x10) Helpers::panic("APT::GetWirelessInfo with size > 0x10 bytes"); + mem.write32(messagePointer, IPC::responseHeader(0x45, 1, 2)); mem.write32(messagePointer + 4, Result::Success); for (u32 i = 0; i < size; i++) { mem.write8(messagePointer + 0x104 + i, 0); // Temporarily stub this until we add SetWirelessRebootInfo diff --git a/src/core/services/boss.cpp b/src/core/services/boss.cpp index 5c306cc6..f43aa5f3 100644 --- a/src/core/services/boss.cpp +++ b/src/core/services/boss.cpp @@ -1,4 +1,5 @@ #include "services/boss.hpp" +#include "ipc.hpp" namespace BOSSCommands { enum : u32 { @@ -40,22 +41,26 @@ void BOSSService::handleSyncRequest(u32 messagePointer) { void BOSSService::initializeSession(u32 messagePointer) { log("BOSS::InitializeSession (stubbed)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } void BOSSService::getOptoutFlag(u32 messagePointer) { log("BOSS::getOptoutFlag\n"); + mem.write32(messagePointer, IPC::responseHeader(0xA, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write8(messagePointer + 8, optoutFlag); } void BOSSService::getTaskIdList(u32 messagePointer) { log("BOSS::GetTaskIdList (stubbed)\n"); + mem.write32(messagePointer, IPC::responseHeader(0xE, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } void BOSSService::getStorageEntryInfo(u32 messagePointer) { log("BOSS::GetStorageEntryInfo (undocumented)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x30, 3, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, 0); // u32, unknown meaning mem.write16(messagePointer + 12, 0); // s16, unknown meaning @@ -67,21 +72,25 @@ void BOSSService::receiveProperty(u32 messagePointer) { const u32 ptr = mem.read32(messagePointer + 16); log("BOSS::ReceiveProperty(stubbed) (id = %d, size = %08X, ptr = %08X)\n", id, size, ptr); + mem.write32(messagePointer, IPC::responseHeader(0x16, 2, 2)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, 0); // Read size } void BOSSService::unregisterTask(u32 messagePointer) { log("BOSS::UnregisterTask (stubbed)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x0C, 1, 2)); mem.write32(messagePointer + 4, Result::Success); } void BOSSService::registerStorageEntry(u32 messagePointer) { log("BOSS::RegisterStorageEntry (stubbed)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x2F, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } void BOSSService::unregisterStorage(u32 messagePointer) { log("BOSS::UnregisterStorage (stubbed)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x3, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/cam.cpp b/src/core/services/cam.cpp index fc6b27a1..db62aec3 100644 --- a/src/core/services/cam.cpp +++ b/src/core/services/cam.cpp @@ -1,4 +1,5 @@ #include "services/cam.hpp" +#include "ipc.hpp" namespace CAMCommands { enum : u32 { @@ -26,6 +27,7 @@ void CAMService::handleSyncRequest(u32 messagePointer) { void CAMService::driverInitialize(u32 messagePointer) { log("CAM::DriverInitialize\n"); + mem.write32(messagePointer, IPC::responseHeader(0x39, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -55,6 +57,7 @@ void CAMService::getMaxLines(u32 messagePointer) { } } + mem.write32(messagePointer, IPC::responseHeader(0xA, 2, 0)); mem.write32(messagePointer + 4, result); mem.write16(messagePointer + 8, lines); } diff --git a/src/core/services/cecd.cpp b/src/core/services/cecd.cpp index 8fa39d60..cc4bfffb 100644 --- a/src/core/services/cecd.cpp +++ b/src/core/services/cecd.cpp @@ -1,4 +1,5 @@ #include "services/cecd.hpp" +#include "ipc.hpp" namespace CECDCommands { enum : u32 { @@ -26,6 +27,8 @@ void CECDService::getEventHandle(u32 messagePointer) { log("CECD::GetEventHandle (stubbed)\n"); Helpers::panic("TODO: Actually implement CECD::GetEventHandle"); + mem.write32(messagePointer, IPC::responseHeader(0xF, 1, 2)); mem.write32(messagePointer + 4, Result::Success); + // TODO: Translation descriptor here? mem.write32(messagePointer + 12, 0x66666666); } \ No newline at end of file diff --git a/src/core/services/cfg.cpp b/src/core/services/cfg.cpp index 48496a78..f666efab 100644 --- a/src/core/services/cfg.cpp +++ b/src/core/services/cfg.cpp @@ -1,5 +1,6 @@ #include "services/cfg.hpp" #include "services/dsp.hpp" +#include "ipc.hpp" namespace CFGCommands { enum : u32 { @@ -101,12 +102,14 @@ void CFGService::getConfigInfoBlk2(u32 messagePointer) { Helpers::panic("Unhandled GetConfigInfoBlk2 configuration. Size = %d, block = %X", size, blockID); } + mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 2)); mem.write32(messagePointer + 4, Result::Success); } void CFGService::secureInfoGetRegion(u32 messagePointer) { log("CFG::SecureInfoGetRegion\n"); + mem.write32(messagePointer, IPC::responseHeader(0x2, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, static_cast(Regions::USA)); // TODO: Detect the game region and report it } @@ -115,6 +118,7 @@ void CFGService::genUniqueConsoleHash(u32 messagePointer) { log("CFG::GenUniqueConsoleHash (semi-stubbed)\n"); const u32 salt = mem.read32(messagePointer + 4) & 0x000FFFFF; + mem.write32(messagePointer, IPC::responseHeader(0x3, 3, 0)); mem.write32(messagePointer + 4, Result::Success); // We need to implement hash generation & the SHA-256 digest properly later on. We have cryptopp so the hashing isn't too hard to do // Let's stub it for now @@ -128,6 +132,7 @@ void CFGService::getRegionCanadaUSA(u32 messagePointer) { log("CFG::GetRegionCanadaUSA\n"); const u8 ret = (country == CountryCodes::US || country == CountryCodes::CA) ? 1 : 0; + mem.write32(messagePointer, IPC::responseHeader(0x4, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write8(messagePointer + 8, ret); } \ No newline at end of file diff --git a/src/core/services/dsp.cpp b/src/core/services/dsp.cpp index 212e8219..8635f43e 100644 --- a/src/core/services/dsp.cpp +++ b/src/core/services/dsp.cpp @@ -1,4 +1,5 @@ #include "services/dsp.hpp" +#include "ipc.hpp" namespace DSPCommands { enum : u32 { @@ -49,8 +50,9 @@ void DSPService::handleSyncRequest(u32 messagePointer) { void DSPService::convertProcessAddressFromDspDram(u32 messagePointer) { const u32 address = mem.read32(messagePointer + 4); log("DSP::ConvertProcessAddressFromDspDram (address = %08X)\n", address); - const u32 converted = (address << 1) + 0x1FF40000; + + mem.write32(messagePointer, IPC::responseHeader(0xC, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, converted); // Converted address } @@ -61,6 +63,7 @@ void DSPService::loadComponent(u32 messagePointer) { u32 dataMask = mem.read32(messagePointer + 12); log("DSP::LoadComponent (size = %08X, program mask = %X, data mask = %X\n", size, programMask, dataMask); + mem.write32(messagePointer, IPC::responseHeader(0x11, 2, 2)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, 1); // Component loaded mem.write32(messagePointer + 12, (size << 4) | 0xA); @@ -89,6 +92,7 @@ void DSPService::readPipeIfPossible(u32 messagePointer) { mem.write16(buffer + i, pipe.readUnchecked()); } + mem.write32(messagePointer, IPC::responseHeader(0x10, 2, 2)); mem.write32(messagePointer + 4, Result::Success); mem.write16(messagePointer + 8, i); // Number of bytes read } @@ -99,12 +103,14 @@ void DSPService::registerInterruptEvents(u32 messagePointer) { u32 event = mem.read32(messagePointer + 16); log("DSP::RegisterInterruptEvents (interrupt = %d, channel = %d, event = %d)\n", interrupt, channel, event); + mem.write32(messagePointer, IPC::responseHeader(0x15, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } void DSPService::getHeadphoneStatus(u32 messagePointer) { log("DSP::GetHeadphoneStatus\n"); + mem.write32(messagePointer, IPC::responseHeader(0x1F, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, Result::HeadphonesInserted); // This should be toggleable for shits and giggles } @@ -112,7 +118,9 @@ void DSPService::getHeadphoneStatus(u32 messagePointer) { void DSPService::getSemaphoreHandle(u32 messagePointer) { log("DSP::GetSemaphoreHandle\n"); + mem.write32(messagePointer, IPC::responseHeader(0x16, 1, 2)); mem.write32(messagePointer + 4, Result::Success); + // TODO: Translation descriptor here? mem.write32(messagePointer + 12, 0xF9991234); // Semaphore handle (stubbed with random, obvious number) } @@ -120,6 +128,7 @@ void DSPService::setSemaphore(u32 messagePointer) { const u16 value = mem.read16(messagePointer + 4); log("DSP::SetSemaphore(value = %04X)\n", value); + mem.write32(messagePointer, IPC::responseHeader(0x7, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -127,6 +136,7 @@ void DSPService::setSemaphoreMask(u32 messagePointer) { const u16 mask = mem.read16(messagePointer + 4); log("DSP::SetSemaphoreMask(mask = %04X)\n", mask); + mem.write32(messagePointer, IPC::responseHeader(0x17, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -136,6 +146,7 @@ void DSPService::writeProcessPipe(u32 messagePointer) { const u32 buffer = mem.read32(messagePointer + 16); log("DSP::writeProcessPipe (channel = %d, size = %X, buffer = %08X)\n", channel, size, buffer); + mem.write32(messagePointer, IPC::responseHeader(0xD, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -145,6 +156,7 @@ void DSPService::flushDataCache(u32 messagePointer) { const Handle process = mem.read32(messagePointer + 16); log("DSP::FlushDataCache (addr = %08X, size = %08X, process = %X)\n", address, size, process); + mem.write32(messagePointer, IPC::responseHeader(0x13, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -154,5 +166,6 @@ void DSPService::invalidateDCache(u32 messagePointer) { const Handle process = mem.read32(messagePointer + 16); log("DSP::InvalidateDataCache (addr = %08X, size = %08X, process = %X)\n", address, size, process); + mem.write32(messagePointer, IPC::responseHeader(0x14, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/frd.cpp b/src/core/services/frd.cpp index e51bcadf..cbe77ef2 100644 --- a/src/core/services/frd.cpp +++ b/src/core/services/frd.cpp @@ -1,4 +1,5 @@ #include "services/frd.hpp" +#include "ipc.hpp" namespace FRDCommands { enum : u32 { @@ -33,6 +34,7 @@ void FRDService::handleSyncRequest(u32 messagePointer) { void FRDService::getMyFriendKey(u32 messagePointer) { log("FRD::GetMyFriendKey\n"); + mem.write32(messagePointer, IPC::responseHeader(0x5, 5, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, 0); // Principal ID mem.write32(messagePointer + 12, 0); // Padding (?) @@ -46,6 +48,7 @@ void FRDService::getFriendKeyList(u32 messagePointer) { const u32 count = mem.read32(messagePointer + 8); // From what I understand this is a cap on the number of keys to receive? constexpr u32 friendCount = 0; // And this should be the number of friends whose keys were actually received? + mem.write32(messagePointer, IPC::responseHeader(0x11, 2, 2)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, friendCount); @@ -64,6 +67,7 @@ void FRDService::getMyPresence(u32 messagePointer) { mem.write32(buffer + i, 0); } + mem.write32(messagePointer, IPC::responseHeader(0x8, 1, 2)); mem.write32(messagePointer + 4, Result::Success); } @@ -71,10 +75,13 @@ void FRDService::setClientSDKVersion(u32 messagePointer) { u32 version = mem.read32(messagePointer + 4); log("FRD::SetClientSdkVersion (version = %d)\n", version); + mem.write32(messagePointer, IPC::responseHeader(0x32, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } void FRDService::setNotificationMask(u32 messagePointer) { log("FRD::SetNotificationMask (Not documented)\n"); + + mem.write32(messagePointer, IPC::responseHeader(0x21, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/fs.cpp b/src/core/services/fs.cpp index 372110c6..0f421b9d 100644 --- a/src/core/services/fs.cpp +++ b/src/core/services/fs.cpp @@ -1,6 +1,7 @@ #include "services/fs.hpp" #include "kernel/kernel.hpp" #include "io_file.hpp" +#include "ipc.hpp" #ifdef CreateFile // windows.h defines CreateFile & DeleteFile because of course it does. #undef CreateFile @@ -172,6 +173,7 @@ void FSService::handleSyncRequest(u32 messagePointer) { void FSService::initialize(u32 messagePointer) { log("FS::Initialize\n"); + mem.write32(messagePointer, IPC::responseHeader(0x801, 1, 0)); mem.write32(messagePointer + 4, ResultCode::Success); } @@ -180,7 +182,8 @@ void FSService::initializeWithSdkVersion(u32 messagePointer) { const auto version = mem.read32(messagePointer + 4); log("FS::InitializeWithSDKVersion(version = %d)\n", version); - initialize(messagePointer); + mem.write32(messagePointer, IPC::responseHeader(0x861, 1, 0)); + mem.write32(messagePointer + 4, ResultCode::Success); } void FSService::closeArchive(u32 messagePointer) { @@ -188,6 +191,8 @@ void FSService::closeArchive(u32 messagePointer) { const auto object = kernel.getObject(handle, KernelObjectType::Archive); log("FSService::CloseArchive(handle = %X)\n", handle); + mem.write32(messagePointer, IPC::responseHeader(0x80E, 1, 0)); + if (object == nullptr) { log("FSService::CloseArchive: Tried to close invalid archive %X\n", handle); mem.write32(messagePointer + 4, ResultCode::Failure); @@ -207,6 +212,7 @@ void FSService::openArchive(u32 messagePointer) { log("FS::OpenArchive(archive ID = %d, archive path type = %d)\n", archiveID, archivePathType); std::optional handle = openArchiveHandle(archiveID, archivePath); + mem.write32(messagePointer, IPC::responseHeader(0x80C, 3, 0)); if (handle.has_value()) { mem.write32(messagePointer + 4, ResultCode::Success); mem.write64(messagePointer + 8, handle.value()); @@ -240,6 +246,7 @@ void FSService::openFile(u32 messagePointer) { const FilePerms perms(openFlags); std::optional handle = openFileHandle(archive, filePath, archivePath, perms); + mem.write32(messagePointer, IPC::responseHeader(0x802, 1, 2)); if (!handle.has_value()) { printf("OpenFile failed\n"); mem.write32(messagePointer + 4, ResultCode::FileNotFound); @@ -268,6 +275,7 @@ void FSService::openDirectory(u32 messagePointer) { const auto dirPath = readPath(pathType, pathPointer, pathSize); auto dir = openDirectoryHandle(archive, dirPath); + mem.write32(messagePointer, IPC::responseHeader(0x80B, 1, 2)); if (dir.isOk()) { mem.write32(messagePointer + 4, ResultCode::Success); mem.write32(messagePointer + 12, dir.unwrap()); @@ -304,6 +312,7 @@ void FSService::openFileDirectly(u32 messagePointer) { } std::optional handle = openFileHandle(archive, filePath, archivePath, perms); + mem.write32(messagePointer, IPC::responseHeader(0x803, 1, 2)); if (!handle.has_value()) { Helpers::panic("OpenFileDirectly: Failed to open file with given path"); } else { @@ -333,6 +342,7 @@ void FSService::createFile(u32 messagePointer) { auto filePath = readPath(filePathType, filePathPointer, filePathSize); FSResult res = archive->createFile(filePath, size); + mem.write32(messagePointer, IPC::responseHeader(0x808, 1, 0)); mem.write32(messagePointer + 4, static_cast(res)); } @@ -354,6 +364,7 @@ void FSService::deleteFile(u32 messagePointer) { auto filePath = readPath(filePathType, filePathPointer, filePathSize); FSResult res = archive->deleteFile(filePath); + mem.write32(messagePointer, IPC::responseHeader(0x804, 1, 0)); mem.write32(messagePointer + 4, static_cast(res)); } @@ -372,6 +383,7 @@ void FSService::getFormatInfo(u32 messagePointer) { } ArchiveBase::FormatInfo info = archive->getFormatInfo(path); + mem.write32(messagePointer, IPC::responseHeader(0x845, 5, 0)); mem.write32(messagePointer + 4, ResultCode::Success); mem.write32(messagePointer + 8, info.size); mem.write32(messagePointer + 12, info.numOfDirectories); @@ -402,6 +414,8 @@ void FSService::formatSaveData(u32 messagePointer) { const bool duplicateData = mem.read8(messagePointer + 36) != 0; printf("Stubbed FS::FormatSaveData. File num: %d, directory num: %d\n", fileNum, directoryNum); + mem.write32(messagePointer, IPC::responseHeader(0x84C, 1, 0)); + mem.write32(messagePointer + 4, ResultCode::Success); } void FSService::controlArchive(u32 messagePointer) { @@ -415,6 +429,7 @@ void FSService::controlArchive(u32 messagePointer) { log("FS::ControlArchive (action = %X, handle = %X)\n", action, archiveHandle); auto archiveObject = kernel.getObject(archiveHandle, KernelObjectType::Archive); + mem.write32(messagePointer, IPC::responseHeader(0x80D, 1, 0)); if (archiveObject == nullptr) [[unlikely]] { log("FS::ControlArchive: Invalid archive handle %d\n", archiveHandle); mem.write32(messagePointer + 4, ResultCode::Failure); @@ -434,6 +449,7 @@ void FSService::controlArchive(u32 messagePointer) { void FSService::getPriority(u32 messagePointer) { log("FS::GetPriority\n"); + mem.write32(messagePointer, IPC::responseHeader(0x863, 2, 0)); mem.write32(messagePointer + 4, ResultCode::Success); mem.write32(messagePointer + 8, priority); } @@ -441,13 +457,15 @@ void FSService::getPriority(u32 messagePointer) { void FSService::setPriority(u32 messagePointer) { const u32 value = mem.read32(messagePointer + 4); log("FS::SetPriority (priority = %d)\n", value); - + + mem.write32(messagePointer, IPC::responseHeader(0x862, 1, 0)); mem.write32(messagePointer + 4, ResultCode::Success); priority = value; } void FSService::isSdmcDetected(u32 messagePointer) { log("FS::IsSdmcDetected\n"); + mem.write32(messagePointer, IPC::responseHeader(0x817, 2, 0)); mem.write32(messagePointer + 4, ResultCode::Success); mem.write32(messagePointer + 8, 0); // Whether SD is detected. For now we emulate a 3DS without an SD. } \ No newline at end of file diff --git a/src/core/services/gsp_gpu.cpp b/src/core/services/gsp_gpu.cpp index b12adff1..896a4d54 100644 --- a/src/core/services/gsp_gpu.cpp +++ b/src/core/services/gsp_gpu.cpp @@ -1,4 +1,5 @@ #include "services/gsp_gpu.hpp" +#include "ipc.hpp" // Commands used with SendSyncRequest targetted to the GSP::GPU service namespace ServiceCommands { @@ -72,6 +73,7 @@ void GPUService::acquireRight(u32 messagePointer) { privilegedProcess = pid; } + mem.write32(messagePointer, IPC::responseHeader(0x16, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -88,7 +90,8 @@ void GPUService::registerInterruptRelayQueue(u32 messagePointer) { const u32 eventHandle = mem.read32(messagePointer + 12); log("GSP::GPU::RegisterInterruptRelayQueue (flags = %X, event handle = %X)\n", flags, eventHandle); - mem.write32(messagePointer + 4, Result::SuccessRegisterIRQ); + mem.write32(messagePointer, IPC::responseHeader(0x13, 2, 2)); + mem.write32(messagePointer + 4, Result::SuccessRegisterIRQ); // First init returns a unique result mem.write32(messagePointer + 8, 0); // TODO: GSP module thread index mem.write32(messagePointer + 12, 0); // Translation descriptor mem.write32(messagePointer + 16, KernelHandles::GSPSharedMemHandle); @@ -134,6 +137,8 @@ void GPUService::writeHwRegs(u32 messagePointer) { dataPointer += 4; ioAddr += 4; } + + mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -176,6 +181,7 @@ void GPUService::writeHwRegsWithMask(u32 messagePointer) { ioAddr += 4; } + mem.write32(messagePointer, IPC::responseHeader(0x2, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -185,6 +191,7 @@ void GPUService::flushDataCache(u32 messagePointer) { u32 processHandle = handle = mem.read32(messagePointer + 16); log("GSP::GPU::FlushDataCache(address = %08X, size = %X, process = %X\n", address, size, processHandle); + mem.write32(messagePointer, IPC::responseHeader(0x8, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -194,6 +201,7 @@ void GPUService::storeDataCache(u32 messagePointer) { u32 processHandle = handle = mem.read32(messagePointer + 16); log("GSP::GPU::StoreDataCache(address = %08X, size = %X, process = %X\n", address, size, processHandle); + mem.write32(messagePointer, IPC::responseHeader(0x1F, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -205,23 +213,27 @@ void GPUService::setLCDForceBlack(u32 messagePointer) { printf("Filled both LCDs with black\n"); } + mem.write32(messagePointer, IPC::responseHeader(0xB, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } void GPUService::triggerCmdReqQueue(u32 messagePointer) { processCommandBuffer(); + mem.write32(messagePointer, IPC::responseHeader(0xC, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } // Seems to be completely undocumented, probably not very important or useful void GPUService::setAxiConfigQoSMode(u32 messagePointer) { log("GSP::GPU::SetAxiConfigQoSMode\n"); + mem.write32(messagePointer, IPC::responseHeader(0x10, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } // Seems to also be completely undocumented void GPUService::setInternalPriorities(u32 messagePointer) { log("GSP::GPU::SetInternalPriorities\n"); + mem.write32(messagePointer, IPC::responseHeader(0x1E, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } diff --git a/src/core/services/gsp_lcd.cpp b/src/core/services/gsp_lcd.cpp index 21764b31..ff438b56 100644 --- a/src/core/services/gsp_lcd.cpp +++ b/src/core/services/gsp_lcd.cpp @@ -1,4 +1,5 @@ #include "services/gsp_lcd.hpp" +#include "ipc.hpp" namespace LCDCommands { enum : u32 { diff --git a/src/core/services/hid.cpp b/src/core/services/hid.cpp index 27661954..e3056f70 100644 --- a/src/core/services/hid.cpp +++ b/src/core/services/hid.cpp @@ -1,4 +1,5 @@ #include "services/hid.hpp" +#include "ipc.hpp" #include namespace HIDCommands { @@ -38,20 +39,25 @@ void HIDService::handleSyncRequest(u32 messagePointer) { void HIDService::enableAccelerometer(u32 messagePointer) { log("HID::EnableAccelerometer\n"); - mem.write32(messagePointer + 4, Result::Success); accelerometerEnabled = true; + + mem.write32(messagePointer, IPC::responseHeader(0x11, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); } void HIDService::enableGyroscopeLow(u32 messagePointer) { log("HID::EnableGyroscopeLow\n"); - mem.write32(messagePointer + 4, Result::Success); gyroEnabled = true; + + mem.write32(messagePointer, IPC::responseHeader(0x13, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); } void HIDService::getGyroscopeLowCalibrateParam(u32 messagePointer) { log("HID::GetGyroscopeLowCalibrateParam\n"); constexpr s16 unit = 6700; // Approximately from Citra which took it from hardware + mem.write32(messagePointer, IPC::responseHeader(0x16, 6, 0)); mem.write32(messagePointer + 4, Result::Success); // Fill calibration data (for x/y/z depending on i) for (int i = 0; i < 3; i++) { @@ -67,12 +73,14 @@ void HIDService::getGyroscopeCoefficient(u32 messagePointer) { log("HID::GetGyroscopeLowRawToDpsCoefficient\n"); constexpr float gyroscopeCoeff = 14.375f; // Same as retail 3DS + mem.write32(messagePointer, IPC::responseHeader(0x15, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, std::bit_cast(gyroscopeCoeff)); } void HIDService::getIPCHandles(u32 messagePointer) { log("HID::GetIPCHandles\n"); + mem.write32(messagePointer, IPC::responseHeader(0xA, 1, 7)); mem.write32(messagePointer + 4, Result::Success); // Result code mem.write32(messagePointer + 8, 0x14000000); // Translation descriptor mem.write32(messagePointer + 12, KernelHandles::HIDSharedMemHandle); // Shared memory handle diff --git a/src/core/services/ldr_ro.cpp b/src/core/services/ldr_ro.cpp index 9d5d19a8..91ae041d 100644 --- a/src/core/services/ldr_ro.cpp +++ b/src/core/services/ldr_ro.cpp @@ -1,4 +1,5 @@ #include "services/ldr_ro.hpp" +#include "ipc.hpp" namespace LDRCommands { enum : u32 { @@ -31,6 +32,7 @@ void LDRService::initialize(u32 messagePointer) { const Handle process = mem.read32(messagePointer + 20); log("LDR_RO::Initialize (buffer = %08X, size = %08X, vaddr = %08X, process = %X)\n", crsPointer, size, mapVaddr, process); + mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -40,5 +42,6 @@ void LDRService::loadCRR(u32 messagePointer) { const Handle process = mem.read32(messagePointer + 20); log("LDR_RO::LoadCRR (buffer = %08X, size = %08X, process = %X)\n", crrPointer, size, process); + mem.write32(messagePointer, IPC::responseHeader(0x2, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/mic.cpp b/src/core/services/mic.cpp index b69c6b7a..828fb1e4 100644 --- a/src/core/services/mic.cpp +++ b/src/core/services/mic.cpp @@ -1,4 +1,5 @@ #include "services/mic.hpp" +#include "ipc.hpp" namespace MICCommands { enum : u32 { @@ -41,11 +42,13 @@ void MICService::mapSharedMem(u32 messagePointer) { u32 handle = mem.read32(messagePointer + 12); log("MIC::MapSharedMem (size = %08X, handle = %X) (stubbed)\n", size, handle); + mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } void MICService::getGain(u32 messagePointer) { log("MIC::GetGain\n"); + mem.write32(messagePointer, IPC::responseHeader(0x9, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write8(messagePointer + 8, gain); } @@ -54,6 +57,7 @@ void MICService::setGain(u32 messagePointer) { gain = mem.read8(messagePointer + 4); log("MIC::SetGain (value = %d)\n", gain); + mem.write32(messagePointer, IPC::responseHeader(0x8, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -62,6 +66,7 @@ void MICService::setPower(u32 messagePointer) { log("MIC::SetPower (value = %d)\n", val); micEnabled = val != 0; + mem.write32(messagePointer, IPC::responseHeader(0xA, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -70,6 +75,7 @@ void MICService::setClamp(u32 messagePointer) { log("MIC::SetClamp (value = %d)\n", val); shouldClamp = val != 0; + mem.write32(messagePointer, IPC::responseHeader(0xD, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -84,5 +90,6 @@ void MICService::startSampling(u32 messagePointer) { encoding, sampleRate, offset, dataSize, loop ? "yes" : "no" ); + mem.write32(messagePointer, IPC::responseHeader(0x3, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/ndm.cpp b/src/core/services/ndm.cpp index d6c18afe..a9ea9140 100644 --- a/src/core/services/ndm.cpp +++ b/src/core/services/ndm.cpp @@ -1,4 +1,5 @@ #include "services/ndm.hpp" +#include "ipc.hpp" namespace NDMCommands { enum : u32 { @@ -32,25 +33,30 @@ void NDMService::handleSyncRequest(u32 messagePointer) { void NDMService::overrideDefaultDaemons(u32 messagePointer) { log("NDM::OverrideDefaultDaemons(stubbed)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x14, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } void NDMService::resumeDaemons(u32 messagePointer) { log("NDM::resumeDaemons(stubbed)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x7, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } void NDMService::suspendDaemons(u32 messagePointer) { log("NDM::SuspendDaemons(stubbed)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x6, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } void NDMService::resumeScheduler(u32 messagePointer) { log("NDM::ResumeScheduler(stubbed)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x9, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } void NDMService::suspendScheduler(u32 messagePointer) { log("NDM::SuspendScheduler(stubbed)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x8, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/nim.cpp b/src/core/services/nim.cpp index a3c48fb4..df9737f6 100644 --- a/src/core/services/nim.cpp +++ b/src/core/services/nim.cpp @@ -1,4 +1,5 @@ #include "services/nim.hpp" +#include "ipc.hpp" namespace NIMCommands { enum : u32 { @@ -24,5 +25,6 @@ void NIMService::handleSyncRequest(u32 messagePointer) { void NIMService::initialize(u32 messagePointer) { log("NIM::Initialize\n"); + mem.write32(messagePointer, IPC::responseHeader(0x21, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/ptm.cpp b/src/core/services/ptm.cpp index 297f5455..99bfb207 100644 --- a/src/core/services/ptm.cpp +++ b/src/core/services/ptm.cpp @@ -1,4 +1,5 @@ #include "services/ptm.hpp" +#include "ipc.hpp" namespace PTMCommands { enum : u32 { @@ -18,7 +19,7 @@ void PTMService::reset() {} void PTMService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { - case PTMCommands::GetStepHistory: getStepHistory(messagePointer); break; + case PTMCommands::GetStepHistory: getStepHistory(messagePointer); break; case PTMCommands::GetTotalStepCount: getTotalStepCount(messagePointer); break; default: Helpers::panic("PTM service requested. Command: %08X\n", command); } @@ -26,11 +27,13 @@ void PTMService::handleSyncRequest(u32 messagePointer) { void PTMService::getStepHistory(u32 messagePointer) { log("PTM::GetStepHistory [stubbed]\n"); + mem.write32(messagePointer, IPC::responseHeader(0xB, 1, 2)); mem.write32(messagePointer + 4, Result::Success); } void PTMService::getTotalStepCount(u32 messagePointer) { log("PTM::GetTotalStepCount\n"); + mem.write32(messagePointer, IPC::responseHeader(0xC, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, 3); // We walk a lot } \ No newline at end of file diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index 3efdd473..3502b4bb 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -1,5 +1,6 @@ #include "services/service_manager.hpp" #include +#include "ipc.hpp" #include "kernel.hpp" ServiceManager::ServiceManager(std::array& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel) @@ -79,6 +80,7 @@ void ServiceManager::handleSyncRequest(u32 messagePointer) { // https://www.3dbrew.org/wiki/SRV:RegisterClient void ServiceManager::registerClient(u32 messagePointer) { log("srv::registerClient (Stubbed)\n"); + mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -121,6 +123,7 @@ void ServiceManager::getServiceHandle(u32 messagePointer) { else Helpers::panic("srv: GetServiceHandle with unknown service %s", service.c_str()); + mem.write32(messagePointer, IPC::responseHeader(0x5, 1, 2)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 12, handle); } @@ -133,6 +136,7 @@ void ServiceManager::enableNotification(u32 messagePointer) { notificationSemaphore = kernel.makeSemaphore(0, MAX_NOTIFICATION_COUNT); } + mem.write32(messagePointer, IPC::responseHeader(0x2, 1, 2)); mem.write32(messagePointer + 4, Result::Success); // Result code mem.write32(messagePointer + 8, 0); // Translation descriptor // Handle to semaphore signaled on process notification @@ -142,6 +146,7 @@ void ServiceManager::enableNotification(u32 messagePointer) { void ServiceManager::receiveNotification(u32 messagePointer) { log("srv::ReceiveNotification() (STUBBED)\n"); + mem.write32(messagePointer, IPC::responseHeader(0xB, 2, 0)); mem.write32(messagePointer + 4, Result::Success); // Result code mem.write32(messagePointer + 8, 0); // Notification ID } @@ -150,6 +155,7 @@ void ServiceManager::subscribe(u32 messagePointer) { u32 id = mem.read32(messagePointer + 4); log("srv::Subscribe (id = %d) (stubbed)\n", id); + mem.write32(messagePointer, IPC::responseHeader(0x9, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } diff --git a/src/core/services/y2r.cpp b/src/core/services/y2r.cpp index 04f93f2d..3cbd7137 100644 --- a/src/core/services/y2r.cpp +++ b/src/core/services/y2r.cpp @@ -1,4 +1,5 @@ #include "services/y2r.hpp" +#include "ipc.hpp" #include "kernel.hpp" namespace Y2RCommands { @@ -34,12 +35,14 @@ void Y2RService::handleSyncRequest(u32 messagePointer) { void Y2RService::pingProcess(u32 messagePointer) { log("Y2R::PingProcess\n"); + mem.write32(messagePointer, IPC::responseHeader(0x2A, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, 0); // Connected number } void Y2RService::driverInitialize(u32 messagePointer) { log("Y2R::DriverInitialize\n"); + mem.write32(messagePointer, IPC::responseHeader(0x2B, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -48,6 +51,7 @@ void Y2RService::getTransferEndEvent(u32 messagePointer) { if (!transferEndEvent.has_value()) transferEndEvent = kernel.makeEvent(ResetType::OneShot); + mem.write32(messagePointer, IPC::responseHeader(0xF, 1, 2)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 12, transferEndEvent.value()); } @@ -56,6 +60,7 @@ void Y2RService::setTransferEndInterrupt(u32 messagePointer) { const bool enable = mem.read32(messagePointer + 4) != 0; log("Y2R::SetTransferEndInterrupt (enabled: %s)\n", enable ? "yes" : "no"); + mem.write32(messagePointer, IPC::responseHeader(0xD, 1, 0)); mem.write32(messagePointer + 4, Result::Success); transferEndInterruptEnabled = enable; } \ No newline at end of file