Long overdue clang-format pass on most of the project (#773)
Some checks are pending
Android Build / x64 (release) (push) Waiting to run
Android Build / arm64 (release) (push) Waiting to run
HTTP Server Build / build (push) Waiting to run
Hydra Core Build / Windows (push) Waiting to run
Hydra Core Build / MacOS (push) Waiting to run
Hydra Core Build / Linux (push) Waiting to run
Hydra Core Build / Android-x64 (push) Waiting to run
Hydra Core Build / ARM-Libretro (push) Waiting to run
Linux AppImage Build / build (push) Waiting to run
Linux Build / build (push) Waiting to run
MacOS Build / MacOS-arm64 (push) Waiting to run
MacOS Build / MacOS-x86_64 (push) Waiting to run
MacOS Build / MacOS-Universal (push) Blocked by required conditions
Qt Build / Windows (push) Waiting to run
Qt Build / MacOS-arm64 (push) Waiting to run
Qt Build / MacOS-x86_64 (push) Waiting to run
Qt Build / MacOS-Universal (push) Blocked by required conditions
Qt Build / Linux (push) Waiting to run
Windows Build / build (push) Waiting to run
iOS Simulator Build / build (push) Waiting to run

This commit is contained in:
wheremyfoodat 2025-07-06 18:25:20 +03:00 committed by GitHub
parent d1f4ae2911
commit 8e20bd6220
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
65 changed files with 13445 additions and 26224 deletions

View file

@ -1,4 +1,5 @@
#include "services/act.hpp"
#include "ipc.hpp"
namespace ACTCommands {
@ -33,7 +34,7 @@ void ACTService::initialize(u32 messagePointer) {
void ACTService::generateUUID(u32 messagePointer) {
log("ACT::GenerateUUID (stubbed)\n");
// TODO: The header is probably wrong
mem.write32(messagePointer, IPC::responseHeader(0xD, 1, 0));
mem.write32(messagePointer + 4, Result::Success);

View file

@ -1,4 +1,5 @@
#include "services/am.hpp"
#include "ipc.hpp"
namespace AMCommands {
@ -22,19 +23,19 @@ void AMService::handleSyncRequest(u32 messagePointer) {
}
void AMService::listTitleInfo(u32 messagePointer) {
log("AM::ListDLCOrLicenseTicketInfos\n"); // Yes this is the actual name
log("AM::ListDLCOrLicenseTicketInfos\n"); // Yes this is the actual name
u32 ticketCount = mem.read32(messagePointer + 4);
u64 titleID = mem.read64(messagePointer + 8);
u32 pointer = mem.read32(messagePointer + 24);
for (u32 i = 0; i < ticketCount; i++) {
mem.write64(pointer, titleID); // Title ID
mem.write64(pointer + 8, 0); // Ticket ID
mem.write16(pointer + 16, 0); // Version
mem.write16(pointer + 18, 0); // Padding
mem.write32(pointer + 20, 0); // Size
mem.write64(pointer, titleID); // Title ID
mem.write64(pointer + 8, 0); // Ticket ID
mem.write16(pointer + 16, 0); // Version
mem.write16(pointer + 18, 0); // Padding
mem.write32(pointer + 20, 0); // Size
pointer += 24; // = sizeof(TicketInfo)
pointer += 24; // = sizeof(TicketInfo)
}
mem.write32(messagePointer, IPC::responseHeader(0x1007, 2, 2));

View file

@ -6,6 +6,4 @@ void AmiiboDevice::reset() {
}
// Load amiibo information from our raw 540 byte array
void AmiiboDevice::loadFromRaw() {
}
void AmiiboDevice::loadFromRaw() {}

View file

@ -1,10 +1,11 @@
#include "services/apt.hpp"
#include "ipc.hpp"
#include "kernel.hpp"
#include <algorithm>
#include <vector>
#include "ipc.hpp"
#include "kernel.hpp"
namespace APTCommands {
enum : u32 {
GetLockHandle = 0x00010040,
@ -84,8 +85,7 @@ void APTService::appletUtility(u32 messagePointer) {
u32 outputSize = mem.read32(messagePointer + 12);
u32 inputPointer = mem.read32(messagePointer + 20);
log("APT::AppletUtility(utility = %d, input size = %x, output size = %x, inputPointer = %08X)\n", utility, inputSize, outputSize,
inputPointer);
log("APT::AppletUtility(utility = %d, input size = %x, output size = %x, inputPointer = %08X)\n", utility, inputSize, outputSize, inputPointer);
std::vector<u8> out(outputSize);
const u32 outputBuffer = mem.read32(messagePointer + 0x104);
@ -111,8 +111,9 @@ void APTService::getAppletInfo(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x06, 7, 0));
mem.write32(messagePointer + 4, Result::Success);
mem.write8(messagePointer + 20, 1); // 1 = registered
mem.write8(messagePointer + 24, 1); // 1 = loaded
mem.write8(messagePointer + 20, 1); // 1 = registered
mem.write8(messagePointer + 24, 1); // 1 = loaded
// TODO: The rest of this
}
@ -122,7 +123,7 @@ void APTService::isRegistered(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x09, 2, 0));
mem.write32(messagePointer + 4, Result::Success);
mem.write8(messagePointer + 8, 1); // Return that the app is always registered. This might break with home menu?
mem.write8(messagePointer + 8, 1); // Return that the app is always registered. This might break with home menu?
}
void APTService::preloadLibraryApplet(u32 messagePointer) {
@ -178,7 +179,7 @@ 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)
mem.write8(messagePointer + 8, (model == ConsoleModel::New3DS) ? 1 : 0); // u8, Status (0 = Old 3DS, 1 = New 3DS)
}
// TODO: Figure out the slight way this differs from APT::CheckNew3DS
@ -186,7 +187,7 @@ void APTService::checkNew3DSApp(u32 messagePointer) {
log("APT::CheckNew3DSApp\n");
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)
mem.write8(messagePointer + 8, (model == ConsoleModel::New3DS) ? 1 : 0); // u8, Status (0 = Old 3DS, 1 = New 3DS)
}
void APTService::enable(u32 messagePointer) {
@ -207,14 +208,14 @@ void APTService::initialize(u32 messagePointer) {
notificationEvent = kernel.makeEvent(ResetType::OneShot);
resumeEvent = kernel.makeEvent(ResetType::OneShot);
kernel.signalEvent(resumeEvent.value()); // Seems to be signalled on startup
kernel.signalEvent(resumeEvent.value()); // Seems to be signalled on startup
}
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
mem.write32(messagePointer + 16, resumeEvent.value()); // Resume Event Handle
mem.write32(messagePointer + 8, 0x04000000); // Translation descriptor
mem.write32(messagePointer + 12, notificationEvent.value()); // Notification Event Handle
mem.write32(messagePointer + 16, resumeEvent.value()); // Resume Event Handle
}
void APTService::inquireNotification(u32 messagePointer) {
@ -234,11 +235,11 @@ void APTService::getLockHandle(u32 messagePointer) {
}
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)
mem.write32(messagePointer + 16, 0); // Translation descriptor
mem.write32(messagePointer + 20, lockHandle.value()); // Lock handle
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)
mem.write32(messagePointer + 16, 0); // Translation descriptor
mem.write32(messagePointer + 20, lockHandle.value()); // Lock handle
}
// This apparently does nothing on the original kernel either?
@ -254,7 +255,7 @@ void APTService::sendParameter(u32 messagePointer) {
const u32 cmd = mem.read32(messagePointer + 12);
const u32 paramSize = mem.read32(messagePointer + 16);
const u32 parameterHandle = mem.read32(messagePointer + 24); // What dis?
const u32 parameterHandle = mem.read32(messagePointer + 24); // What dis?
const u32 parameterPointer = mem.read32(messagePointer + 32);
log("APT::SendParameter (source app = %X, dest app = %X, cmd = %X, size = %X)", sourceAppID, destAppID, cmd, paramSize);
@ -298,7 +299,9 @@ void APTService::receiveParameter(u32 messagePointer) {
const u32 buffer = mem.read32(messagePointer + 0x100 + 4);
log("APT::ReceiveParameter(app ID = %X, size = %04X)\n", app, size);
if (size > 0x1000) Helpers::panic("APT::ReceiveParameter with size > 0x1000");
if (size > 0x1000) {
Helpers::panic("APT::ReceiveParameter with size > 0x1000");
}
auto parameter = appletManager.receiveParameter();
mem.write32(messagePointer, IPC::responseHeader(0xD, 4, 4));
@ -326,7 +329,9 @@ void APTService::glanceParameter(u32 messagePointer) {
const u32 buffer = mem.read32(messagePointer + 0x100 + 4);
log("APT::GlanceParameter(app ID = %X, size = %04X)\n", app, size);
if (size > 0x1000) Helpers::panic("APT::GlanceParameter with size > 0x1000");
if (size > 0x1000) {
Helpers::panic("APT::GlanceParameter with size > 0x1000");
}
auto parameter = appletManager.glanceParameter();
// TODO: Properly implement this. We currently stub it similar
@ -355,8 +360,8 @@ void APTService::replySleepQuery(u32 messagePointer) {
}
void APTService::setApplicationCpuTimeLimit(u32 messagePointer) {
u32 fixed = mem.read32(messagePointer + 4); // MUST be 1.
u32 percentage = mem.read32(messagePointer + 8); // CPU time percentage between 5% and 89%
u32 fixed = mem.read32(messagePointer + 4); // MUST be 1.
u32 percentage = mem.read32(messagePointer + 8); // CPU time percentage between 5% and 89%
log("APT::SetApplicationCpuTimeLimit (percentage = %d%%)\n", percentage);
mem.write32(messagePointer, IPC::responseHeader(0x4F, 1, 0));
@ -409,15 +414,16 @@ void APTService::theSmashBrosFunction(u32 messagePointer) {
}
void APTService::getWirelessRebootInfo(u32 messagePointer) {
const u32 size = mem.read32(messagePointer + 4); // Size of data to read
const u32 size = mem.read32(messagePointer + 4); // Size of data to read
log("APT::GetWirelessRebootInfo (size = %X)\n", size);
if (size > 0x10)
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
mem.write8(messagePointer + 0x104 + i, 0); // Temporarily stub this until we add SetWirelessRebootInfo
}
}

View file

@ -194,6 +194,7 @@ void BOSSService::sendProperty(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x14, 1, 2));
mem.write32(messagePointer + 4, Result::Success);
mem.write32(messagePointer + 8, 0); // Read size
// TODO: Should this do anything else?
}

View file

@ -47,5 +47,5 @@ void CECDService::openAndRead(u32 messagePointer) {
// TODO: We should implement this properly the time comes
mem.write32(messagePointer, IPC::responseHeader(0x12, 2, 2));
mem.write32(messagePointer + 4, Result::Success);
mem.write32(messagePointer + 8, 0); // Bytes read
mem.write32(messagePointer + 8, 0); // Bytes read
}

View file

@ -1,13 +1,14 @@
#include "services/cfg.hpp"
#include "services/dsp.hpp"
#include "system_models.hpp"
#include "ipc.hpp"
#include <array>
#include <bit>
#include <string>
#include <unordered_map>
#include "ipc.hpp"
#include "services/dsp.hpp"
#include "system_models.hpp"
namespace CFGCommands {
enum : u32 {
GetConfigInfoBlk2 = 0x00010082,
@ -101,7 +102,7 @@ void CFGService::getSystemModel(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x05, 2, 0));
mem.write32(messagePointer + 4, Result::Success);
mem.write8(messagePointer + 8, SystemModel::Nintendo3DS); // TODO: Make this adjustable via GUI
mem.write8(messagePointer + 8, SystemModel::Nintendo3DS); // TODO: Make this adjustable via GUI
}
// Write a UTF16 string to 3DS memory starting at "pointer". Appends a null terminator.
@ -111,16 +112,15 @@ void CFGService::writeStringU16(u32 pointer, const std::u16string& string) {
pointer += 2;
}
mem.write16(pointer, static_cast<u16>(u'\0')); // Null terminator
mem.write16(pointer, static_cast<u16>(u'\0')); // Null terminator
}
void CFGService::getConfigInfoBlk2(u32 messagePointer) {
u32 size = mem.read32(messagePointer + 4);
u32 blockID = mem.read32(messagePointer + 8);
u32 output = mem.read32(messagePointer + 16); // Pointer to write the output data to
u32 output = mem.read32(messagePointer + 16); // Pointer to write the output data to
log("CFG::GetConfigInfoBlk2 (size = %X, block ID = %X, output pointer = %08X\n", size, blockID, output);
getConfigInfo(output, blockID, size, 0x2);
mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 2));
mem.write32(messagePointer + 4, Result::Success);
@ -254,7 +254,7 @@ void CFGService::genUniqueConsoleHash(u32 messagePointer) {
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
mem.write32(messagePointer + 8, 0x33646D6F ^ salt); // Lower word of hash
mem.write32(messagePointer + 8, 0x33646D6F ^ salt); // Lower word of hash
mem.write32(messagePointer + 12, 0xA3534841 ^ salt); // Upper word of hash
}
@ -303,13 +303,13 @@ void CFGService::getCountryCodeID(u32 messagePointer) {
log("CFG::GetCountryCodeID (code = %04X)\n", characterCode);
mem.write32(messagePointer, IPC::responseHeader(0x0A, 2, 0));
// If the character code is valid, return its table ID and a success code
if (auto search = countryCodeToTableIDMap.find(characterCode); search != countryCodeToTableIDMap.end()) {
mem.write32(messagePointer + 4, Result::Success);
mem.write16(messagePointer + 8, search->second);
}
else {
Helpers::warn("CFG::GetCountryCodeID: Invalid country code %X", characterCode);
mem.write32(messagePointer + 4, Result::CFG::NotFound);
@ -340,7 +340,7 @@ void CFGService::secureInfoGetByte101(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x407, 2, 0));
mem.write32(messagePointer + 4, Result::Success);
mem.write8(messagePointer + 8, 0); // Secure info byte 0x101 is usually 0 according to 3DBrew
mem.write8(messagePointer + 8, 0); // Secure info byte 0x101 is usually 0 according to 3DBrew
}
void CFGService::getLocalFriendCodeSeed(u32 messagePointer) {
@ -379,7 +379,7 @@ void CFGService::translateCountryInfo(u32 messagePointer) {
// By default the translated code is the input
u32 result = country;
if (direction == 0) { // Translate from version B to version A
if (direction == 0) { // Translate from version B to version A
switch (country) {
case 0x6E040000: result = 0x6E030000; break;
case 0x6E050000: result = 0x6E040000; break;
@ -388,7 +388,7 @@ void CFGService::translateCountryInfo(u32 messagePointer) {
case 0x6E030000: result = 0x6E070000; break;
default: break;
}
} else if (direction == 1) { // Translate from version A to version B
} else if (direction == 1) { // Translate from version A to version B
switch (country) {
case 0x6E030000: result = 0x6E040000; break;
case 0x6E040000: result = 0x6E050000; break;
@ -423,7 +423,7 @@ void CFGService::norInitialize(u32 messagePointer) {
void CFGService::norReadData(u32 messagePointer) {
log("CFG::NOR::ReadData\n");
Helpers::warn("Unimplemented CFG::NOR::ReadData");
mem.write32(messagePointer, IPC::responseHeader(0x5, 1, 0));
mem.write32(messagePointer + 4, Result::Success);
}

View file

@ -36,8 +36,8 @@ void CSNDService::handleSyncRequest(u32 messagePointer) {
void CSNDService::acquireSoundChannels(u32 messagePointer) {
log("CSND::AcquireSoundChannels\n");
// The CSND service talks to the DSP using the DSP FIFO to negotiate what CSND channels are allocated to the DSP, and this seems to be channels 0-7 (usually). The rest are dedicated to CSND services.
// https://www.3dbrew.org/wiki/CSND_Services
// The CSND service talks to the DSP using the DSP FIFO to negotiate what CSND channels are allocated to the DSP, and this seems to be channels
// 0-7 (usually). The rest are dedicated to CSND services. https://www.3dbrew.org/wiki/CSND_Services
constexpr u32 csndChannelMask = 0xFFFFFF00;
mem.write32(messagePointer, IPC::responseHeader(0x5, 2, 0));
@ -52,7 +52,8 @@ void CSNDService::initialize(u32 messagePointer) {
const u32 offset2 = mem.read32(messagePointer + 16);
const u32 offset3 = mem.read32(messagePointer + 20);
log("CSND::Initialize (Block size = %08X, offset0 = %X, offset1 = %X, offset2 = %X, offset3 = %X)\n", blockSize, offset0, offset1, offset2, offset3);
log("CSND::Initialize (Block size = %08X, offset0 = %X, offset1 = %X, offset2 = %X, offset3 = %X)\n", blockSize, offset0, offset1, offset2,
offset3);
// Align block size to 4KB. CSND shared memory block is currently stubbed to be 0x3000 == 12KB, so panic if this is more than requested
blockSize = (blockSize + 0xFFF) & ~0xFFF;

View file

@ -1,9 +1,10 @@
#include "services/dlp_srvr.hpp"
#include "ipc.hpp"
namespace DlpSrvrCommands {
enum : u32 {
IsChild = 0x000E0040
IsChild = 0x000E0040,
};
}
@ -22,5 +23,5 @@ void DlpSrvrService::isChild(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x0E, 2, 0));
mem.write32(messagePointer + 4, Result::Success);
mem.write32(messagePointer + 8, 0); // We are responsible adults
mem.write32(messagePointer + 8, 0); // We are responsible adults
}

View file

@ -36,7 +36,7 @@ namespace DSPCommands {
namespace Result {
enum : u32 {
HeadphonesNotInserted = 0,
HeadphonesInserted = 1
HeadphonesInserted = 1,
};
}
@ -85,7 +85,7 @@ void DSPService::convertProcessAddressFromDspDram(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0xC, 2, 0));
mem.write32(messagePointer + 4, Result::Success);
mem.write32(messagePointer + 8, converted); // Converted address
mem.write32(messagePointer + 8, converted); // Converted address
}
void DSPService::loadComponent(u32 messagePointer) {
@ -109,9 +109,9 @@ void DSPService::loadComponent(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x11, 2, 2));
mem.write32(messagePointer + 4, Result::Success);
mem.write32(messagePointer + 8, 1); // Component loaded
mem.write32(messagePointer + 8, 1); // Component loaded
mem.write32(messagePointer + 12, (size << 4) | 0xA);
mem.write32(messagePointer + 16, mem.read32(messagePointer + 20)); // Component buffer
mem.write32(messagePointer + 16, mem.read32(messagePointer + 20)); // Component buffer
}
void DSPService::unloadComponent(u32 messagePointer) {
@ -136,7 +136,7 @@ void DSPService::readPipeIfPossible(u32 messagePointer) {
}
mem.write32(messagePointer + 4, Result::Success);
mem.write16(messagePointer + 8, u16(data.size())); // Number of bytes read
mem.write16(messagePointer + 8, u16(data.size())); // Number of bytes read
}
void DSPService::recvData(u32 messagePointer) {
@ -168,12 +168,10 @@ DSPService::DSPEvent& DSPService::getEventRef(u32 type, u32 pipe) {
case 1: return interrupt1;
case 2:
if (pipe >= pipeCount)
Helpers::panic("Tried to access the event of an invalid pipe");
if (pipe >= pipeCount) Helpers::panic("Tried to access the event of an invalid pipe");
return pipeEvents[pipe];
default:
Helpers::panic("Unknown type for DSP::getEventRef");
default: Helpers::panic("Unknown type for DSP::getEventRef");
}
}
@ -185,8 +183,8 @@ void DSPService::registerInterruptEvents(u32 messagePointer) {
// The event handle being 0 means we're removing an event
if (eventHandle == 0) {
DSPEvent& e = getEventRef(interrupt, channel); // Get event
if (e.has_value()) { // Remove if it exists
DSPEvent& e = getEventRef(interrupt, channel); // Get event
if (e.has_value()) { // Remove if it exists
totalEventCount--;
e = std::nullopt;
}
@ -227,7 +225,7 @@ void DSPService::getSemaphoreEventHandle(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x16, 1, 2));
mem.write32(messagePointer + 4, Result::Success);
// TODO: Translation descriptor here?
mem.write32(messagePointer + 12, semaphoreEvent.value()); // Semaphore event handle
mem.write32(messagePointer + 12, semaphoreEvent.value()); // Semaphore event handle
kernel.signalEvent(semaphoreEvent.value());
}

View file

@ -56,7 +56,7 @@ void FRDService::handleSyncRequest(u32 messagePointer, FRDService::Type type) {
case FRDCommands::SetNotificationMask: setNotificationMask(messagePointer); break;
case FRDCommands::UpdateGameModeDescription: updateGameModeDescription(messagePointer); break;
default:
default:
// FRD:A functions
if (type == Type::A) {
switch (command) {
@ -89,17 +89,17 @@ void FRDService::getMyFriendKey(u32 messagePointer) {
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 (?)
mem.write32(messagePointer + 16, 0); // Local friend code
mem.write32(messagePointer + 8, 0); // Principal ID
mem.write32(messagePointer + 12, 0); // Padding (?)
mem.write32(messagePointer + 16, 0); // Local friend code
mem.write32(messagePointer + 20, 0);
}
void FRDService::getFriendKeyList(u32 messagePointer) {
log("FRD::GetFriendKeyList\n");
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?
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);
@ -147,11 +147,11 @@ void FRDService::getFriendAttributeFlags(u32 messagePointer) {
}
void FRDService::getMyPresence(u32 messagePointer) {
static constexpr u32 presenceSize = 0x12C; // A presence seems to be 12C bytes of data, not sure what it contains
static constexpr u32 presenceSize = 0x12C; // A presence seems to be 12C bytes of data, not sure what it contains
log("FRD::GetMyPresence\n");
u32 buffer = mem.read32(messagePointer + 0x104); // Buffer to write presence info to.
u32 buffer = mem.read32(messagePointer + 0x104); // Buffer to write presence info to.
for (u32 i = 0; i < presenceSize; i += 4) { // Clear presence info with 0s for now
for (u32 i = 0; i < presenceSize; i += 4) { // Clear presence info with 0s for now
mem.write32(buffer + i, 0);
}
@ -168,15 +168,15 @@ void FRDService::getFriendPresence(u32 messagePointer) {
}
void FRDService::getMyProfile(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x7, 3, 0)); // Not sure if the header here has the correct # of responses?
mem.write32(messagePointer, IPC::responseHeader(0x7, 3, 0)); // Not sure if the header here has the correct # of responses?
mem.write32(messagePointer + 4, Result::Success);
// TODO: Should maybe make these user-configurable. Not super important though
mem.write8(messagePointer + 8, static_cast<u8>(Regions::USA)); // Region
mem.write8(messagePointer + 9, static_cast<u8>(CountryCodes::US)); // Country
mem.write8(messagePointer + 10, 2); // Area (this should be Washington)
mem.write8(messagePointer + 11, static_cast<u8>(LanguageCodes::English)); // Language
mem.write8(messagePointer + 12, 2); // Platform (always 2 for CTR)
mem.write8(messagePointer + 8, static_cast<u8>(Regions::USA)); // Region
mem.write8(messagePointer + 9, static_cast<u8>(CountryCodes::US)); // Country
mem.write8(messagePointer + 10, 2); // Area (this should be Washington)
mem.write8(messagePointer + 11, static_cast<u8>(LanguageCodes::English)); // Language
mem.write8(messagePointer + 12, 2); // Platform (always 2 for CTR)
// Padding
mem.write8(messagePointer + 13, 0);
@ -226,7 +226,7 @@ void FRDService::getMyMii(u32 messagePointer) {
void FRDService::getMyFavoriteGame(u32 messagePointer) {
log("FRD::GetMyFavoriteGame (stubbed)\n");
constexpr u64 titleID = 0;
mem.write32(messagePointer, IPC::responseHeader(0xD, 3, 0));
mem.write32(messagePointer + 4, Result::Success);
mem.write64(messagePointer + 8, titleID);

View file

@ -1,10 +1,11 @@
#include "services/fs.hpp"
#include "kernel/kernel.hpp"
#include "io_file.hpp"
#include "ipc.hpp"
#include "kernel/kernel.hpp"
#include "result/result.hpp"
#ifdef CreateFile // windows.h defines CreateFile & DeleteFile because of course it does.
#ifdef CreateFile // windows.h defines CreateFile & DeleteFile because of course it does.
#undef CreateDirectory
#undef CreateFile
#undef DeleteFile
@ -47,21 +48,18 @@ namespace FSCommands {
};
}
void FSService::reset() {
priority = 0;
}
void FSService::reset() { priority = 0; }
// Creates directories for NAND, ExtSaveData, etc if they don't already exist. Should be executed after loading a new ROM.
void FSService::initializeFilesystem() {
const auto sdmcPath = IOFile::getAppData() / "SDMC"; // Create SDMC directory
const auto sdmcPath = IOFile::getAppData() / "SDMC"; // Create SDMC directory
const auto nandSharedpath = IOFile::getAppData() / ".." / "SharedFiles" / "NAND";
const auto savePath = IOFile::getAppData() / "SaveData"; // Create SaveData
const auto formatPath = IOFile::getAppData() / "FormatInfo"; // Create folder for storing archive formatting info
const auto savePath = IOFile::getAppData() / "SaveData"; // Create SaveData
const auto formatPath = IOFile::getAppData() / "FormatInfo"; // Create folder for storing archive formatting info
const auto systemSaveDataPath = IOFile::getAppData() / ".." / "SharedFiles" / "SystemSaveData";
namespace fs = std::filesystem;
if (!fs::is_directory(nandSharedpath)) {
fs::create_directories(nandSharedpath);
}
@ -89,30 +87,26 @@ ArchiveBase* FSService::getArchiveFromID(u32 id, const FSPath& archivePath) {
case ArchiveID::SaveData: return &saveData;
case ArchiveID::UserSaveData2: return &userSaveData2;
case ArchiveID::ExtSaveData:
return &extSaveData_sdmc;
case ArchiveID::ExtSaveData: return &extSaveData_sdmc;
case ArchiveID::SharedExtSaveData:
return &sharedExtSaveData_nand;
case ArchiveID::SharedExtSaveData: return &sharedExtSaveData_nand;
case ArchiveID::SystemSaveData: return &systemSaveData;
case ArchiveID::SDMC: return &sdmc;
case ArchiveID::SDMCWriteOnly: return &sdmcWriteOnly;
case ArchiveID::SavedataAndNcch: return &ncch; // This can only access NCCH outside of FSPXI
case ArchiveID::SavedataAndNcch: return &ncch; // This can only access NCCH outside of FSPXI
case ArchiveID::TwlPhoto: return &twlPhoto;
case ArchiveID::TwlSound: return &twlSound;
case ArchiveID::CardSPI: return &cardSpi;
default:
Helpers::panic("Unknown archive. ID: %d\n", id);
return nullptr;
default: Helpers::panic("Unknown archive. ID: %d\n", id); return nullptr;
}
}
std::optional<HorizonHandle> FSService::openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms) {
FileDescriptor opened = archive->openFile(path, perms);
if (opened.has_value()) { // If opened doesn't have a value, we failed to open the file
if (opened.has_value()) { // If opened doesn't have a value, we failed to open the file
auto handle = kernel.makeObject(KernelObjectType::File);
auto& file = kernel.getObjects()[handle];
@ -126,7 +120,7 @@ std::optional<HorizonHandle> FSService::openFileHandle(ArchiveBase* archive, con
Rust::Result<HorizonHandle, Result::HorizonResult> FSService::openDirectoryHandle(ArchiveBase* archive, const FSPath& path) {
Rust::Result<DirectorySession, Result::HorizonResult> opened = archive->openDirectory(path);
if (opened.isOk()) { // If opened doesn't have a value, we failed to open the directory
if (opened.isOk()) { // If opened doesn't have a value, we failed to open the directory
auto handle = kernel.makeObject(KernelObjectType::Directory);
auto& object = kernel.getObjects()[handle];
object.data = new DirectorySession(opened.unwrap());
@ -152,8 +146,7 @@ Rust::Result<HorizonHandle, Result::HorizonResult> FSService::openArchiveHandle(
archiveObject.data = new ArchiveSession(res.unwrap(), path);
return Ok(handle);
}
else {
} else {
return Err(res.unwrapErr());
}
}
@ -162,8 +155,7 @@ FSPath FSService::readPath(u32 type, u32 pointer, u32 size) {
std::vector<u8> data;
data.resize(size);
for (u32 i = 0; i < size; i++)
data[i] = mem.read8(pointer + i);
for (u32 i = 0; i < size; i++) data[i] = mem.read8(pointer + i);
return FSPath(type, data);
}
@ -222,7 +214,7 @@ void FSService::initializeWithSdkVersion(u32 messagePointer) {
}
void FSService::closeArchive(u32 messagePointer) {
const Handle handle = static_cast<u32>(mem.read64(messagePointer + 4)); // TODO: archive handles should be 64-bit
const Handle handle = static_cast<u32>(mem.read64(messagePointer + 4)); // TODO: archive handles should be 64-bit
const auto object = kernel.getObject(handle, KernelObjectType::Archive);
log("FSService::CloseArchive(handle = %X)\n", handle);
@ -288,7 +280,7 @@ void FSService::openFile(u32 messagePointer) {
mem.write32(messagePointer + 4, Result::FS::FileNotFound);
} else {
mem.write32(messagePointer + 4, Result::Success);
mem.write32(messagePointer + 8, 0x10); // "Move handle descriptor"
mem.write32(messagePointer + 8, 0x10); // "Move handle descriptor"
mem.write32(messagePointer + 12, handle.value());
}
}
@ -475,8 +467,9 @@ void FSService::formatSaveData(u32 messagePointer) {
log("FS::FormatSaveData\n");
const u32 archiveID = mem.read32(messagePointer + 4);
if (archiveID != ArchiveID::SaveData)
if (archiveID != ArchiveID::SaveData) {
Helpers::panic("FS::FormatSaveData: Archive is not SaveData");
}
// Read path and path info
const u32 pathType = mem.read32(messagePointer + 8);
@ -486,24 +479,24 @@ void FSService::formatSaveData(u32 messagePointer) {
// Size of a block. Seems to always be 0x200
const u32 blockSize = mem.read32(messagePointer + 16);
if (blockSize != 0x200 && blockSize != 0x1000)
if (blockSize != 0x200 && blockSize != 0x1000) {
Helpers::panic("FS::FormatSaveData: Invalid SaveData block size");
}
const u32 directoryNum = mem.read32(messagePointer + 20); // Max number of directories
const u32 fileNum = mem.read32(messagePointer + 24); // Max number of files
const u32 directoryBucketNum = mem.read32(messagePointer + 28); // Not sure what a directory bucket is...?
const u32 fileBucketNum = mem.read32(messagePointer + 32); // Same here
const u32 directoryNum = mem.read32(messagePointer + 20); // Max number of directories
const u32 fileNum = mem.read32(messagePointer + 24); // Max number of files
const u32 directoryBucketNum = mem.read32(messagePointer + 28); // Not sure what a directory bucket is...?
const u32 fileBucketNum = mem.read32(messagePointer + 32); // Same here
const bool duplicateData = mem.read8(messagePointer + 36) != 0;
ArchiveBase::FormatInfo info {
ArchiveBase::FormatInfo info{
.size = blockSize * 0x200,
.numOfDirectories = directoryNum,
.numOfFiles = fileNum,
.duplicateData = duplicateData
.duplicateData = duplicateData,
};
saveData.format(path, info);
mem.write32(messagePointer, IPC::responseHeader(0x84C, 1, 0));
mem.write32(messagePointer + 4, Result::Success);
}
@ -517,8 +510,8 @@ void FSService::deleteExtSaveData(u32 messagePointer) {
log("FS::DeleteExtSaveData (media type = %d, saveID = %llx) (stubbed)\n", mediaType, saveID);
mem.write32(messagePointer, IPC::responseHeader(0x0852, 1, 0));
// TODO: We can't properly implement this yet until we properly support title/save IDs. We will stub this and insert a warning for now. Required for Planet Robobot
// When we properly implement it, it will just be a recursive directory deletion
// TODO: We can't properly implement this yet until we properly support title/save IDs. We will stub this and insert a warning for now. Required
// for Planet Robobot When we properly implement it, it will just be a recursive directory deletion
mem.write32(messagePointer + 4, Result::Success);
}
@ -526,7 +519,8 @@ void FSService::createExtSaveData(u32 messagePointer) {
Helpers::warn("Stubbed call to FS::CreateExtSaveData!");
// First 4 words of parameters are the ExtSaveData info
// https://www.3dbrew.org/wiki/Filesystem_services#ExtSaveDataInfo
// This creates the ExtSaveData with the specified saveid in the specified media type. It stores the SMDH as "icon" in the root of the created directory.
// This creates the ExtSaveData with the specified saveid in the specified media type. It stores the SMDH as "icon" in the root of the created
// directory.
const u8 mediaType = mem.read8(messagePointer + 4);
const u64 saveID = mem.read64(messagePointer + 8);
const u32 numOfDirectories = mem.read32(messagePointer + 20);
@ -546,18 +540,13 @@ void FSService::formatThisUserSaveData(u32 messagePointer) {
log("FS::FormatThisUserSaveData\n");
const u32 blockSize = mem.read32(messagePointer + 4);
const u32 directoryNum = mem.read32(messagePointer + 8); // Max number of directories
const u32 fileNum = mem.read32(messagePointer + 12); // Max number of files
const u32 directoryBucketNum = mem.read32(messagePointer + 16); // Not sure what a directory bucket is...?
const u32 fileBucketNum = mem.read32(messagePointer + 20); // Same here
const u32 directoryNum = mem.read32(messagePointer + 8); // Max number of directories
const u32 fileNum = mem.read32(messagePointer + 12); // Max number of files
const u32 directoryBucketNum = mem.read32(messagePointer + 16); // Not sure what a directory bucket is...?
const u32 fileBucketNum = mem.read32(messagePointer + 20); // Same here
const bool duplicateData = mem.read8(messagePointer + 24) != 0;
ArchiveBase::FormatInfo info {
.size = blockSize * 0x200,
.numOfDirectories = directoryNum,
.numOfFiles = fileNum,
.duplicateData = duplicateData
};
ArchiveBase::FormatInfo info{.size = blockSize * 0x200, .numOfDirectories = directoryNum, .numOfFiles = fileNum, .duplicateData = duplicateData};
FSPath emptyPath;
mem.write32(messagePointer, IPC::responseHeader(0x080F, 1, 0));
@ -583,18 +572,16 @@ void FSService::controlArchive(u32 messagePointer) {
}
switch (action) {
case 0: // Commit save data changes. Shouldn't need us to do anything
case 0: // Commit save data changes. Shouldn't need us to do anything
mem.write32(messagePointer + 4, Result::Success);
break;
case 1: // Retrieves a file's last-modified timestamp. Seen in DDLC, stubbed for the moment
case 1: // Retrieves a file's last-modified timestamp. Seen in DDLC, stubbed for the moment
Helpers::warn("FS::ControlArchive: Tried to retrieve a file's last-modified timestamp");
mem.write32(messagePointer + 4, Result::Success);
break;
default:
Helpers::panic("Unimplemented action for ControlArchive (action = %X)\n", action);
break;
default: Helpers::panic("Unimplemented action for ControlArchive (action = %X)\n", action); break;
}
}
@ -678,9 +665,9 @@ void FSService::getThisSaveDataSecureValue(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x86F, 1, 0));
mem.write32(messagePointer + 4, Result::Success);
mem.write8(messagePointer + 8, 0); // Secure value does not exist
mem.write8(messagePointer + 12, 1); // TODO: What is this?
mem.write64(messagePointer + 16, 0); // Secure value
mem.write8(messagePointer + 8, 0); // Secure value does not exist
mem.write8(messagePointer + 12, 1); // TODO: What is this?
mem.write64(messagePointer + 16, 0); // Secure value
}
void FSService::setThisSaveDataSecureValue(u32 messagePointer) {

View file

@ -1,10 +1,11 @@
#include "services/ldr_ro.hpp"
#include "ipc.hpp"
#include "kernel.hpp"
#include <cstdio>
#include <string>
#include "ipc.hpp"
#include "kernel.hpp"
namespace LDRCommands {
enum : u32 {
Initialize = 0x000100C2,
@ -66,10 +67,13 @@ namespace SegmentTable {
namespace SegmentID {
enum : u32 {
TEXT, RODATA, DATA, BSS,
TEXT,
RODATA,
DATA,
BSS,
};
}
}
} // namespace SegmentTable
namespace NamedExportTable {
enum : u32 {
@ -119,8 +123,8 @@ namespace RelocationPatch {
enum : u32 {
SegmentOffset = 0,
PatchType = 4,
IsLastEntry = 5, // For import patches
SegmentIndex = 5, // For relocation patches
IsLastEntry = 5, // For import patches
SegmentIndex = 5, // For relocation patches
IsResolved = 6,
Addend = 8,
};
@ -130,7 +134,7 @@ namespace RelocationPatch {
AbsoluteAddress = 2,
};
};
};
}; // namespace RelocationPatch
struct CROHeaderEntry {
u32 offset, size;
@ -145,12 +149,12 @@ static const std::string CRR_MAGIC("CRR0");
class CRO {
Memory &mem;
u32 croPointer; // Origin address of CRO in RAM
u32 croPointer; // Origin address of CRO in RAM
u32 oldDataSegmentOffset;
bool isCRO; // False if CRS
bool isCRO; // False if CRS
public:
public:
CRO(Memory &mem, u32 croPointer, bool isCRO) : mem(mem), croPointer(croPointer), oldDataSegmentOffset(0), isCRO(isCRO) {}
~CRO() = default;
@ -238,7 +242,7 @@ public:
for (u32 namedExport = 0; namedExport < namedExportTable.size; namedExport++) {
const u32 nameOffset = mem.read32(namedExportTable.offset + 8 * namedExport + NamedExportTable::NameOffset);
const std::string exportSymbolName = mem.readString(nameOffset, exportStringSize);
if (symbolName.compare(exportSymbolName) == 0) {
@ -713,7 +717,7 @@ public:
for (u32 namedImport = 0; namedImport < namedImportTable.size; namedImport++) {
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
const u32 relocationOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::RelocationOffset);
const std::string symbolName = mem.readString(nameOffset, importStringSize);
if (symbolName.compare(std::string("__aeabi_atexit")) == 0) {
@ -725,7 +729,7 @@ public:
const u32 exportSymbolAddr = cro.getNamedExportSymbolAddr(std::string("nnroAeabiAtexit_"));
if (exportSymbolAddr != 0) {
patchBatch(relocationOffset, exportSymbolAddr);
return true;
}
@ -755,7 +759,7 @@ public:
if (isResolved == 0) {
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
const std::string symbolName = mem.readString(nameOffset, importStringSize);
// Check every loaded CRO for the symbol (the pain)
@ -864,7 +868,7 @@ public:
return true;
}
bool clearModules() {
const u32 onUnresolvedAddr = getOnUnresolvedAddr();
@ -879,7 +883,7 @@ public:
if (indexedOffset == 0) {
Helpers::panic("Indexed symbol offset is NULL");
}
const u32 relocationOffset = mem.read32(indexedOffset + 8 * indexedImport + IndexedImportTable::RelocationOffset);
patchBatch(relocationOffset, onUnresolvedAddr, true);
@ -924,7 +928,7 @@ public:
if (isResolved == 0) {
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
const std::string symbolName = mem.readString(nameOffset, importStringSize);
// Check our current CRO for the symbol
@ -988,7 +992,7 @@ public:
u32 currentCROPointer = loadedCRS;
while (currentCROPointer != 0) {
CRO cro(mem, currentCROPointer, true);
const u32 onUnresolvedAddr = cro.getOnUnresolvedAddr();
const u32 importStringSize = mem.read32(currentCROPointer + CROHeader::ImportStringSize);
@ -1003,7 +1007,7 @@ public:
if (isResolved != 0) {
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
const std::string symbolName = mem.readString(nameOffset, importStringSize);
// Check our current CRO for the symbol
@ -1111,7 +1115,7 @@ public:
}
CRO crs(mem, loadedCRS, false);
u32 headAddr = crs.getPrevCRO();
if (autoLink) {
headAddr = crs.getNextCRO();

View file

@ -1,4 +1,5 @@
#include "services/mic.hpp"
#include "ipc.hpp"
#include "kernel/kernel.hpp"
@ -127,9 +128,8 @@ void MICService::startSampling(u32 messagePointer) {
u32 dataSize = mem.read32(messagePointer + 16);
bool loop = mem.read8(messagePointer + 20);
log("MIC::StartSampling (encoding = %d, sample rate = %d, offset = %08X, size = %08X, loop: %s) (stubbed)\n",
encoding, sampleRate, offset, dataSize, loop ? "yes" : "no"
);
log("MIC::StartSampling (encoding = %d, sample rate = %d, offset = %08X, size = %08X, loop: %s) (stubbed)\n", encoding, sampleRate, offset,
dataSize, loop ? "yes" : "no");
currentlySampling = true;
mem.write32(messagePointer, IPC::responseHeader(0x3, 1, 0));
@ -139,7 +139,7 @@ void MICService::startSampling(u32 messagePointer) {
void MICService::stopSampling(u32 messagePointer) {
log("MIC::StopSampling\n");
currentlySampling = false;
mem.write32(messagePointer, IPC::responseHeader(0x5, 1, 0));
mem.write32(messagePointer + 4, Result::Success);
}

View file

@ -1,4 +1,5 @@
#include "services/ndm.hpp"
#include "ipc.hpp"
namespace NDMCommands {

View file

@ -1,6 +1,7 @@
#include "ipc.hpp"
#include "services/news_u.hpp"
#include "ipc.hpp"
namespace NewsCommands {
enum : u32 {};
}

View file

@ -1,4 +1,5 @@
#include "services/nfc.hpp"
#include "io_file.hpp"
#include "ipc.hpp"
#include "kernel.hpp"
@ -166,7 +167,6 @@ void NFCService::communicationGetStatus(u32 messagePointer) {
mem.write8(messagePointer + 8, static_cast<u32>(adapterStatus));
}
void NFCService::communicationGetResult(u32 messagePointer) {
log("NFC::CommunicationGetResult\n");

View file

@ -1,9 +1,10 @@
#include "services/nim.hpp"
#include "ipc.hpp"
namespace NIMCommands {
enum : u32 {
Initialize = 0x00210000
Initialize = 0x00210000,
};
}

View file

@ -1,7 +1,8 @@
#include "services/nwm_uds.hpp"
#include "ipc.hpp"
#include "kernel.hpp"
#include "result/result.hpp"
#include "services/nwm_uds.hpp"
namespace NWMCommands {
enum : u32 {

View file

@ -1,6 +1,7 @@
#include "services/ssl.hpp"
#include "ipc.hpp"
#include "result/result.hpp"
#include "services/ssl.hpp"
namespace SSLCommands {
enum : u32 {
@ -31,10 +32,10 @@ void SSLService::initialize(u32 messagePointer) {
if (initialized) {
Helpers::warn("SSL service initialized twice");
}
}
initialized = true;
rng.seed(std::random_device()()); // Seed rng via std::random_device
rng.seed(std::random_device()()); // Seed rng via std::random_device
mem.write32(messagePointer + 4, Result::Success);
}
@ -48,7 +49,8 @@ void SSLService::generateRandomData(u32 messagePointer) {
u32 data;
for (u32 i = 0; i < size; i++) {
// We don't have an available random value since we're on a multiple of 4 bytes and our Twister is 32-bit, generate a new one from the Mersenne Twister
// We don't have an available random value since we're on a multiple of 4 bytes and our Twister is 32-bit, generate a new one from the
// Mersenne Twister
if ((i & 3) == 0) {
data = rng();
}

View file

@ -337,7 +337,7 @@ void Y2RService::setStandardCoeff(u32 messagePointer) {
log("Y2R::SetStandardCoeff (coefficient = %d)\n", coeff);
mem.write32(messagePointer, IPC::responseHeader(0x20, 1, 0));
if (coeff > 3) { // Invalid coefficient, should have an error code
if (coeff > 3) { // Invalid coefficient, should have an error code
Helpers::panic("Y2R: Invalid standard coefficient (coefficient = %d)\n", coeff);
}
@ -360,7 +360,7 @@ void Y2RService::getStandardCoefficientParams(u32 messagePointer) {
// Write standard coefficient parameters to output buffer
for (int i = 0; i < 8; i++) {
const u32 pointer = messagePointer + 8 + i * sizeof(u16); // Pointer to write parameter to
const u32 pointer = messagePointer + 8 + i * sizeof(u16); // Pointer to write parameter to
mem.write16(pointer, coeff[i]);
}
}
@ -453,7 +453,7 @@ void Y2RService::startConversion(u32 messagePointer) {
void Y2RService::isFinishedSendingYUV(u32 messagePointer) {
log("Y2R::IsFinishedSendingYUV");
constexpr bool finished = true; // For now, Y2R transfers are instant
constexpr bool finished = true; // For now, Y2R transfers are instant
mem.write32(messagePointer, IPC::responseHeader(0x14, 2, 0));
mem.write32(messagePointer + 4, Result::Success);
@ -489,7 +489,7 @@ void Y2RService::isFinishedSendingV(u32 messagePointer) {
void Y2RService::isFinishedReceiving(u32 messagePointer) {
log("Y2R::IsFinishedSendingReceiving");
constexpr bool finished = true; // For now, receiving components is also instant
constexpr bool finished = true; // For now, receiving components is also instant
mem.write32(messagePointer, IPC::responseHeader(0x17, 2, 0));
mem.write32(messagePointer + 4, Result::Success);