[Services] Uhh implement IPC result header which apparently libctru's apt code nees

This commit is contained in:
wheremyfoodat 2023-04-20 02:03:05 +03:00
parent fecf038982
commit 2b492a435e
22 changed files with 153 additions and 9 deletions

View file

@ -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

9
include/ipc.hpp Normal file
View file

@ -0,0 +1,9 @@
#pragma once
#include <cstdint>
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;
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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<u32>(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

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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<u32>(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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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> 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> 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> 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<u32>(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<u32>(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.
}

View file

@ -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);
}

View file

@ -1,4 +1,5 @@
#include "services/gsp_lcd.hpp"
#include "ipc.hpp"
namespace LCDCommands {
enum : u32 {

View file

@ -1,4 +1,5 @@
#include "services/hid.hpp"
#include "ipc.hpp"
#include <bit>
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<u32, float>(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

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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
}

View file

@ -1,5 +1,6 @@
#include "services/service_manager.hpp"
#include <map>
#include "ipc.hpp"
#include "kernel.hpp"
ServiceManager::ServiceManager(std::array<u32, 16>& 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);
}

View file

@ -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;
}