diff --git a/CMakeLists.txt b/CMakeLists.txt index 02617f15..dc529482 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -326,6 +326,7 @@ set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services src/core/services/ir_user.cpp src/core/services/http.cpp src/core/services/soc.cpp src/core/services/ssl.cpp src/core/services/news_u.cpp src/core/services/amiibo_device.cpp src/core/services/csnd.cpp src/core/services/nwm_uds.cpp src/core/services/fonts.cpp + src/core/services/ns.cpp src/core/services/news_s.cpp ) set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA/shader_unit.cpp src/core/PICA/shader_interpreter.cpp src/core/PICA/dynapica/shader_rec.cpp @@ -389,7 +390,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp include/align.hpp include/audio/aac_decoder.hpp include/PICA/pica_simd.hpp include/services/fonts.hpp include/audio/audio_interpolation.hpp include/audio/hle_mixer.hpp include/audio/dsp_simd.hpp include/services/dsp_firmware_db.hpp include/frontend_settings.hpp include/fs/archive_twl_photo.hpp - include/fs/archive_twl_sound.hpp include/fs/archive_card_spi.hpp + include/fs/archive_twl_sound.hpp include/fs/archive_card_spi.hpp include/services/ns.hpp include/services/news_s.hpp ) cmrc_add_resource_library( diff --git a/include/ipc.hpp b/include/ipc.hpp index 67a8897e..204b2e9c 100644 --- a/include/ipc.hpp +++ b/include/ipc.hpp @@ -2,8 +2,19 @@ #include namespace IPC { + namespace BufferType { + enum : std::uint32_t { + Send = 1, + Receive, + }; + } + 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 + + constexpr std::uint32_t pointerHeader(std::uint32_t index, std::uint32_t size, std::uint32_t type) { + return (size << 14) | (index << 10) | (type << 1); + } +} // namespace IPC \ No newline at end of file diff --git a/include/kernel/config_mem.hpp b/include/kernel/config_mem.hpp index 81f0fef1..c06fd8d3 100644 --- a/include/kernel/config_mem.hpp +++ b/include/kernel/config_mem.hpp @@ -8,6 +8,7 @@ namespace ConfigMem { KernelVersionMajor = 0x1FF80003, SyscoreVer = 0x1FF80010, EnvInfo = 0x1FF80014, + PrevFirm = 0x1FF80016, AppMemAlloc = 0x1FF80040, FirmUnknown = 0x1FF80060, FirmRevision = 0x1FF80061, @@ -30,6 +31,12 @@ namespace ConfigMem { // Shows what type of hardware we're running on namespace HardwareCodes { - enum : u8 { Product = 1, Devboard = 2, Debugger = 3, Capture = 4 }; + enum : u8 { + Product = 1, + Devboard = 2, + Debugger = 3, + Capture = 4, + }; } } // namespace ConfigMem + \ No newline at end of file diff --git a/include/kernel/handles.hpp b/include/kernel/handles.hpp index 45400837..5cb7d8a4 100644 --- a/include/kernel/handles.hpp +++ b/include/kernel/handles.hpp @@ -35,14 +35,17 @@ namespace KernelHandles { MCU_HWC, // Used for various MCU hardware-related things like battery control MIC, // MIC service (Controls the microphone) NFC, // NFC (Duh), used for Amiibo - NIM, // Updates, DLC, etc + NIM_AOC, // DLC, etc + NIM_U, // Updates NDM, // ????? NS_S, // Nintendo Shell service NWM_UDS, // Local multiplayer + NEWS_S, // news:u on steroids NEWS_U, // This service literally has 1 command (AddNotification) and I don't even understand what it does PTM_U, // PTM service (Used for accessing various console info, such as battery, shell and pedometer state) PTM_SYSM, // PTM system service PTM_PLAY, // PTM Play service, used for retrieving play history + PTM_GETS, // PTM RTC service (GetSystemTime) SOC, // Socket service SSL, // SSL service (Totally didn't expect that) Y2R, // Also does camera stuff @@ -97,10 +100,12 @@ namespace KernelHandles { case MCU_HWC: return "MCU::HWC"; case MIC: return "MIC"; case NDM: return "NDM"; + case NEWS_S: return "NEWS_S"; case NEWS_U: return "NEWS_U"; case NWM_UDS: return "nwm::UDS"; case NFC: return "NFC"; - case NIM: return "NIM"; + case NIM_AOC: return "NIM:AOC"; + case NIM_U: return "NIM:U"; case PTM_U: return "PTM:U"; case PTM_SYSM: return "PTM:SYSM"; case PTM_PLAY: return "PTM:PLAY"; diff --git a/include/logger.hpp b/include/logger.hpp index 4fc521b6..626025fa 100644 --- a/include/logger.hpp +++ b/include/logger.hpp @@ -65,6 +65,7 @@ namespace Log { static Logger nwmUdsLogger; static Logger nimLogger; static Logger ndmLogger; + static Logger nsLogger; static Logger ptmLogger; static Logger socLogger; static Logger sslLogger; diff --git a/include/services/ac.hpp b/include/services/ac.hpp index 56acd436..02775e18 100644 --- a/include/services/ac.hpp +++ b/include/services/ac.hpp @@ -19,6 +19,7 @@ class ACService { void closeAsync(u32 messagePointer); void createDefaultConfig(u32 messagePointer); void getConnectingInfraPriority(u32 messagePointer); + void getNZoneBeaconNotFoundEvent(u32 messagePointer); void getStatus(u32 messagePointer); void getLastErrorCode(u32 messagePointer); void getWifiStatus(u32 messagePointer); diff --git a/include/services/am.hpp b/include/services/am.hpp index f72a5efc..2bf105c1 100644 --- a/include/services/am.hpp +++ b/include/services/am.hpp @@ -13,9 +13,14 @@ class AMService { MAKE_LOG_FUNCTION(log, amLogger) // Service commands + void checkContentRights(u32 messagePointer); void getDLCTitleInfo(u32 messagePointer); void getPatchTitleInfo(u32 messagePointer); + void getProgramInfos(u32 messagePointer); + void getProgramList(u32 messagePointer); + void getTicketList(u32 messagePointer); void listTitleInfo(u32 messagePointer); + void needsCleanup(u32 messagePointer); public: AMService(Memory& mem) : mem(mem) {} diff --git a/include/services/apt.hpp b/include/services/apt.hpp index 624151c1..ef622266 100644 --- a/include/services/apt.hpp +++ b/include/services/apt.hpp @@ -65,15 +65,18 @@ class APTService { void checkNew3DSApp(u32 messagePointer); void enable(u32 messagePointer); void getAppletInfo(u32 messagePointer); + void getCaptureInfo(u32 messagePointer); void getSharedFont(u32 messagePointer); void getWirelessRebootInfo(u32 messagePointer); void glanceParameter(u32 messagePointer); void initialize(u32 messagePointer); void inquireNotification(u32 messagePointer); void isRegistered(u32 messagePointer); + void loadSysMenuArg(u32 messagePointer); void notifyToWait(u32 messagePointer); void preloadLibraryApplet(u32 messagePointer); void prepareToStartLibraryApplet(u32 messagePointer); + void receiveDeliverArg(u32 messagePointer); void receiveParameter(u32 messagePointer); void replySleepQuery(u32 messagePointer); void setApplicationCpuTimeLimit(u32 messagePointer); diff --git a/include/services/boss.hpp b/include/services/boss.hpp index edc50dee..bf5cd88d 100644 --- a/include/services/boss.hpp +++ b/include/services/boss.hpp @@ -14,10 +14,14 @@ class BOSSService { // Service commands void cancelTask(u32 messagePointer); + void deleteNsData(u32 messagePointer); void initializeSession(u32 messagePointer); + void getAppNewFlag(u32 messagePointer); void getErrorCode(u32 messagePointer); + void getNsDataHeaderInfo(u32 messagePointer); void getNewArrivalFlag(u32 messagePointer); void getNsDataIdList(u32 messagePointer, u32 commandWord); + void getNsDataLastUpdated(u32 messagePointer); void getOptoutFlag(u32 messagePointer); void getStorageEntryInfo(u32 messagePointer); // Unknown what this is, name taken from Citra void getTaskIdList(u32 messagePointer); @@ -26,12 +30,15 @@ class BOSSService { void getTaskState(u32 messagePointer); void getTaskStatus(u32 messagePointer); void getTaskStorageInfo(u32 messagePointer); + void readNsData(u32 messagePointer); void receiveProperty(u32 messagePointer); void registerNewArrivalEvent(u32 messagePointer); void registerStorageEntry(u32 messagePointer); void registerTask(u32 messagePointer); void sendProperty(u32 messagePointer); + void setAppNewFlag(u32 messagePointer); void setOptoutFlag(u32 messagePointer); + void startBgImmediate(u32 messagePointer); void startTask(u32 messagePointer); void unregisterStorage(u32 messagePointer); void unregisterTask(u32 messagePointer); diff --git a/include/services/cfg.hpp b/include/services/cfg.hpp index e2ddffa8..0feb6db3 100644 --- a/include/services/cfg.hpp +++ b/include/services/cfg.hpp @@ -26,6 +26,8 @@ class CFGService { void genUniqueConsoleHash(u32 messagePointer); void secureInfoGetByte101(u32 messagePointer); void secureInfoGetRegion(u32 messagePointer); + void setConfigInfoBlk4(u32 messagePointer); + void updateConfigNANDSavegame(u32 messagePointer); void translateCountryInfo(u32 messagePointer); void getConfigInfo(u32 output, u32 blockID, u32 size, u32 permissionMask); diff --git a/include/services/fs.hpp b/include/services/fs.hpp index 82f07077..1839b181 100644 --- a/include/services/fs.hpp +++ b/include/services/fs.hpp @@ -70,6 +70,7 @@ class FSService { void getArchiveResource(u32 messagePointer); void getFreeBytes(u32 messagePointer); void getFormatInfo(u32 messagePointer); + void getNumSeeds(u32 messagePointer); void getPriority(u32 messagePointer); void getSdmcArchiveResource(u32 messagePointer); void getThisSaveDataSecureValue(u32 messagePointer); diff --git a/include/services/gsp_lcd.hpp b/include/services/gsp_lcd.hpp index f34f59ab..302771ff 100644 --- a/include/services/gsp_lcd.hpp +++ b/include/services/gsp_lcd.hpp @@ -13,8 +13,9 @@ class LCDService { MAKE_LOG_FUNCTION(log, gspLCDLogger) // Service commands + void setLedForceOff(u32 messagePointer); -public: + public: LCDService(Memory& mem) : mem(mem) {} void reset(); void handleSyncRequest(u32 messagePointer); diff --git a/include/services/news_s.hpp b/include/services/news_s.hpp new file mode 100644 index 00000000..a2ed5ba8 --- /dev/null +++ b/include/services/news_s.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "helpers.hpp" +#include "kernel_types.hpp" +#include "logger.hpp" +#include "memory.hpp" + +class NewsSService { + using Handle = HorizonHandle; + + Handle handle = KernelHandles::NEWS_S; + Memory& mem; + MAKE_LOG_FUNCTION(log, newsLogger) + + // Service commands + + public: + NewsSService(Memory& mem) : mem(mem) {} + void reset(); + void handleSyncRequest(u32 messagePointer); +}; diff --git a/include/services/nim.hpp b/include/services/nim.hpp index dbb3bb8b..a8fbf4fd 100644 --- a/include/services/nim.hpp +++ b/include/services/nim.hpp @@ -5,18 +5,31 @@ #include "memory.hpp" #include "result/result.hpp" +class Kernel; + class NIMService { using Handle = HorizonHandle; - Handle handle = KernelHandles::NIM; Memory& mem; + Kernel& kernel; MAKE_LOG_FUNCTION(log, nimLogger) + std::optional backgroundSystemUpdateEvent; + // Service commands + void getAutoTitleDownloadTaskInfos(u32 messagePointer); + void getBackgroundEventForMenu(u32 messagePointer); + void getTaskInfos(u32 messagePointer); void initialize(u32 messagePointer); + void isPendingAutoTitleDownloadTasks(u32 messagePointer); public: - NIMService(Memory& mem) : mem(mem) {} + enum class Type { + AOC, // nim:aoc + U, // nim:u + }; + + NIMService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {} void reset(); - void handleSyncRequest(u32 messagePointer); + void handleSyncRequest(u32 messagePointer, Type type); }; \ No newline at end of file diff --git a/include/services/ns.hpp b/include/services/ns.hpp new file mode 100644 index 00000000..3acf87a0 --- /dev/null +++ b/include/services/ns.hpp @@ -0,0 +1,25 @@ +#pragma once +#include "helpers.hpp" +#include "kernel_types.hpp" +#include "logger.hpp" +#include "memory.hpp" +#include "result/result.hpp" + +class NSService { + Memory& mem; + MAKE_LOG_FUNCTION(log, nsLogger) + + // Service commands + void launchTitle(u32 messagePointer); + +public: + enum class Type { + S, // ns:s + P, // ns:p + C, // ns:c + }; + + NSService(Memory& mem) : mem(mem) {} + void reset(); + void handleSyncRequest(u32 messagePointer, Type type); +}; diff --git a/include/services/ptm.hpp b/include/services/ptm.hpp index 5b797a1d..5480c398 100644 --- a/include/services/ptm.hpp +++ b/include/services/ptm.hpp @@ -13,17 +13,21 @@ class PTMService { const EmulatorConfig& config; // Service commands + void clearSoftwareClosedFlag(u32 messagePointer); void configureNew3DSCPU(u32 messagePointer); void getAdapterState(u32 messagePointer); void getBatteryChargeState(u32 messagePointer); void getBatteryLevel(u32 messagePointer); + void getSoftwareClosedFlag(u32 messagePointer); void getPedometerState(u32 messagePointer); void getStepHistory(u32 messagePointer); void getStepHistoryAll(u32 messagePointer); + void getSystemTime(u32 messagePointer); void getTotalStepCount(u32 messagePointer); public: enum class Type { + GETS, // ptm:gets U, // ptm:u SYSM, // ptm:sysm PLAY, // ptm:play diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index 4fa1e665..60f6fbdc 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -28,10 +28,12 @@ #include "services/mcu/mcu_hwc.hpp" #include "services/mic.hpp" #include "services/ndm.hpp" -#include "services/nwm_uds.hpp" +#include "services/news_s.hpp" #include "services/news_u.hpp" #include "services/nfc.hpp" #include "services/nim.hpp" +#include "services/ns.hpp" +#include "services/nwm_uds.hpp" #include "services/ptm.hpp" #include "services/soc.hpp" #include "services/ssl.hpp" @@ -52,11 +54,11 @@ class ServiceManager { MAKE_LOG_FUNCTION(log, srvLogger) - ACService ac; + ACService ac; ACTService act; - AMService am; + AMService am; APTService apt; - BOSSService boss; + BOSSService boss; CAMService cam; CECDService cecd; CFGService cfg; @@ -73,10 +75,12 @@ class ServiceManager { LDRService ldr; MICService mic; NDMService ndm; + NewsSService news_s; NewsUService news_u; NFCService nfc; NwmUdsService nwm_uds; - NIMService nim; + NIMService nim; + NSService ns; PTMService ptm; SOCService soc; SSLService ssl; diff --git a/src/core/fs/archive_ncch.cpp b/src/core/fs/archive_ncch.cpp index d5a4bab5..6f28ba6f 100644 --- a/src/core/fs/archive_ncch.cpp +++ b/src/core/fs/archive_ncch.cpp @@ -97,8 +97,10 @@ std::optional NCCHArchive::readFile(FileSession* file, u64 offset, u32 size } else if (highProgramID == systemDataArchive && lowProgramID == badWordList) { fileData = std::vector(std::begin(BAD_WORD_LIST_DATA), std::end(BAD_WORD_LIST_DATA)); } else { - Helpers::panic("[NCCH archive] Read from unimplemented NCCH archive file. High program ID: %08X, low ID: %08X", + Helpers::warn("[NCCH archive] Read from unimplemented NCCH archive file. High program ID: %08X, low ID: %08X", highProgramID, lowProgramID); + + return std::nullopt; } if (offset >= fileData.size()) { diff --git a/src/core/kernel/file_operations.cpp b/src/core/kernel/file_operations.cpp index 2b2020d1..fcf84719 100644 --- a/src/core/kernel/file_operations.cpp +++ b/src/core/kernel/file_operations.cpp @@ -111,7 +111,8 @@ void Kernel::readFile(u32 messagePointer, Handle fileHandle) { auto archive = file->archive; std::optional bytesRead = archive->readFile(file, offset, size, dataPointer); if (!bytesRead.has_value()) { - Helpers::panic("Kernel::ReadFile failed"); + Helpers::warn("Kernel::ReadFile failed"); + mem.write32(messagePointer + 4, 0xC8804478); } else { mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, bytesRead.value()); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 57eac8ca..bcf32afa 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -108,6 +108,7 @@ u8 Memory::read8(u32 vaddr) { return getBatteryState(chargerPlugged, charging, batteryLevel); } case ConfigMem::EnvInfo: return envInfo; + case ConfigMem::PrevFirm: return 1; case ConfigMem::HardwareType: return ConfigMem::HardwareCodes::Product; case ConfigMem::KernelVersionMinor: return u8(kernelVersion & 0xff); case ConfigMem::KernelVersionMajor: return u8(kernelVersion >> 8); diff --git a/src/core/services/ac.cpp b/src/core/services/ac.cpp index 8f5545fe..16d0665d 100644 --- a/src/core/services/ac.cpp +++ b/src/core/services/ac.cpp @@ -10,6 +10,7 @@ namespace ACCommands { GetStatus = 0x000C0000, GetWifiStatus = 0x000D0000, GetConnectingInfraPriority = 0x000F0000, + GetNZoneBeaconNotFoundEvent = 0x002F0004, RegisterDisconnectEvent = 0x00300004, IsConnected = 0x003E0042, SetClientVersion = 0x00400042, @@ -29,6 +30,7 @@ void ACService::handleSyncRequest(u32 messagePointer) { case ACCommands::CreateDefaultConfig: createDefaultConfig(messagePointer); break; case ACCommands::GetConnectingInfraPriority: getConnectingInfraPriority(messagePointer); break; case ACCommands::GetLastErrorCode: getLastErrorCode(messagePointer); break; + case ACCommands::GetNZoneBeaconNotFoundEvent: getNZoneBeaconNotFoundEvent(messagePointer); break; case ACCommands::GetStatus: getStatus(messagePointer); break; case ACCommands::GetWifiStatus: getWifiStatus(messagePointer); break; case ACCommands::IsConnected: isConnected(messagePointer); break; @@ -136,4 +138,13 @@ void ACService::registerDisconnectEvent(u32 messagePointer) { mem.write32(messagePointer, IPC::responseHeader(0x30, 1, 0)); mem.write32(messagePointer + 4, Result::Success); +} + +void ACService::getNZoneBeaconNotFoundEvent(u32 messagePointer) { + const u32 processID = mem.read32(messagePointer + 8); + const Handle event = mem.read32(messagePointer + 16); + log("AC::GetNZoneBeaconNotFoundEvent (process ID = %X, event = %X) (stubbed)\n", processID, event); + + mem.write32(messagePointer, IPC::responseHeader(0x2F, 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 32e6a0b3..0426d58a 100644 --- a/src/core/services/am.cpp +++ b/src/core/services/am.cpp @@ -3,6 +3,11 @@ namespace AMCommands { enum : u32 { + GetProgramList = 0x00020082, + GetProgramInfos = 0x00030084, + GetTicketList = 0x00090082, + NeedsCleanup = 0x00130040, + CheckContentRights = 0x002500C0, GetDLCTitleInfo = 0x10050084, ListTitleInfo = 0x10070102, GetPatchTitleInfo = 0x100D0084, @@ -14,9 +19,14 @@ void AMService::reset() {} void AMService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { + case AMCommands::CheckContentRights: checkContentRights(messagePointer); break; case AMCommands::GetPatchTitleInfo: getPatchTitleInfo(messagePointer); break; case AMCommands::GetDLCTitleInfo: getDLCTitleInfo(messagePointer); break; + case AMCommands::GetProgramInfos: getProgramInfos(messagePointer); break; + case AMCommands::GetProgramList: getProgramList(messagePointer); break; + case AMCommands::GetTicketList: getTicketList(messagePointer); break; case AMCommands::ListTitleInfo: listTitleInfo(messagePointer); break; + case AMCommands::NeedsCleanup: needsCleanup(messagePointer); break; default: Helpers::panic("AM service requested. Command: %08X\n", command); } } @@ -56,4 +66,75 @@ void AMService::getPatchTitleInfo(u32 messagePointer) { mem.write32(messagePointer, IPC::responseHeader(0x100D, 1, 4)); mem.write32(messagePointer + 4, Result::FailurePlaceholder); +} + +void AMService::needsCleanup(u32 messagePointer) { + const u32 mediaType = mem.read32(messagePointer + 4); + log("AM::NeedsCleanup (media type = %X)\n", mediaType); + + mem.write32(messagePointer, IPC::responseHeader(0x13, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write8(messagePointer + 8, 0); // Doesn't need cleanup +} + +void AMService::getProgramInfos(u32 messagePointer) { + const u8 mediaType = mem.read8(messagePointer + 4); + const u32 titleCount = mem.read32(messagePointer + 8); + const u32 titleIDs = mem.read32(messagePointer + 16); + const u32 titleInfos = mem.read32(messagePointer + 24); + log("AM::GetProgramInfos (media type = %X, title count = %X, title IDs pointer = %X, title infos pointer = %X) (Stubbed)\n", mediaType, + titleCount, titleIDs, titleInfos); + + for (u32 title = 0; title < titleCount; title++) { + const u64 id = mem.read64(titleIDs + sizeof(u64) * title); + + mem.write64(titleInfos + 0x18 * title, id); // Title ID + mem.write64(titleInfos + 0x18 * title + 8, 0); // Size + mem.write16(titleInfos + 0x18 * title + 16, 0); // Version + mem.write16(titleInfos + 0x18 * title + 18, 0); // Padding + mem.write32(titleInfos + 0x18 * title + 20, 0); // Type + } + + mem.write32(messagePointer, IPC::responseHeader(0x3, 1, 4)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, IPC::pointerHeader(0, sizeof(u64) * titleCount, IPC::BufferType::Send)); + mem.write32(messagePointer + 12, titleIDs); + mem.write32(messagePointer + 16, IPC::pointerHeader(1, sizeof(u32) * titleCount, IPC::BufferType::Receive)); + mem.write32(messagePointer + 20, titleInfos); +} + +void AMService::getProgramList(u32 messagePointer) { + const u32 titleCount = mem.read32(messagePointer + 4); + const u8 mediaType = mem.read8(messagePointer + 8); + const u32 titleIDs = mem.read32(messagePointer + 16); + log("AM::GetProgramList (title count = %X, media type = %X, title ID pointer = %X) (stubbed)\n", titleCount, mediaType, titleIDs); + + mem.write32(messagePointer, IPC::responseHeader(0x2, 2, 2)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 0); // No title IDs read? + mem.write32(messagePointer + 12, IPC::pointerHeader(0, sizeof(u64) * 0, IPC::BufferType::Receive)); + mem.write32(messagePointer + 16, titleIDs); +} + +void AMService::getTicketList(u32 messagePointer) { + const u32 ticketCount = mem.read32(messagePointer + 4); + const u32 numSkips = mem.read32(messagePointer + 8); + const u32 titleIDs = mem.read32(messagePointer + 16); + log("AM::GetTicketList (ticket count = %X, skipped tickets = %X, title ID pointer = %X) (stubbed)\n", ticketCount, numSkips, titleIDs); + + mem.write32(messagePointer, IPC::responseHeader(0x9, 2, 2)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 0); // No tickets read? + mem.write32(messagePointer + 12, IPC::pointerHeader(0, sizeof(u64) * 0, IPC::BufferType::Receive)); + mem.write32(messagePointer + 16, titleIDs); +} + +void AMService::checkContentRights(u32 messagePointer) { + const u64 titleID = mem.read64(messagePointer + 4); + const u16 contentIndex = mem.read16(messagePointer + 12); + log("AM::CheckContentRights (title ID = %llX, content index = %X) (stubbed)\n", titleID, contentIndex); + + mem.write32(messagePointer, IPC::responseHeader(0x25, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write8(messagePointer + 8, 1); // Has content rights } \ No newline at end of file diff --git a/src/core/services/apt.cpp b/src/core/services/apt.cpp index ddeb18de..8b98af4b 100644 --- a/src/core/services/apt.cpp +++ b/src/core/services/apt.cpp @@ -19,10 +19,13 @@ namespace APTCommands { PreloadLibraryApplet = 0x00160040, PrepareToStartLibraryApplet = 0x00180040, StartLibraryApplet = 0x001E0084, + ReceiveDeliverArg = 0x00350080, + LoadSysMenuArg = 0x00360040, ReplySleepQuery = 0x003E0080, NotifyToWait = 0x00430040, GetSharedFont = 0x00440000, GetWirelessRebootInfo = 0x00450040, + GetCaptureInfo = 0x004A0040, AppletUtility = 0x004B00C2, SetApplicationCpuTimeLimit = 0x004F0080, GetApplicationCpuTimeLimit = 0x00500040, @@ -58,12 +61,15 @@ void APTService::handleSyncRequest(u32 messagePointer) { case APTCommands::InquireNotification: [[likely]] inquireNotification(messagePointer); break; case APTCommands::IsRegistered: isRegistered(messagePointer); break; case APTCommands::GetApplicationCpuTimeLimit: getApplicationCpuTimeLimit(messagePointer); break; + case APTCommands::GetCaptureInfo: getCaptureInfo(messagePointer); break; case APTCommands::GetLockHandle: getLockHandle(messagePointer); break; case APTCommands::GetWirelessRebootInfo: getWirelessRebootInfo(messagePointer); break; case APTCommands::GlanceParameter: glanceParameter(messagePointer); break; + case APTCommands::LoadSysMenuArg: loadSysMenuArg(messagePointer); break; case APTCommands::NotifyToWait: notifyToWait(messagePointer); break; case APTCommands::PreloadLibraryApplet: preloadLibraryApplet(messagePointer); break; case APTCommands::PrepareToStartLibraryApplet: prepareToStartLibraryApplet(messagePointer); break; + case APTCommands::ReceiveDeliverArg: receiveDeliverArg(messagePointer); break; case APTCommands::StartLibraryApplet: startLibraryApplet(messagePointer); break; case APTCommands::ReceiveParameter: [[likely]] receiveParameter(messagePointer); break; case APTCommands::ReplySleepQuery: replySleepQuery(messagePointer); break; @@ -421,3 +427,64 @@ void APTService::getWirelessRebootInfo(u32 messagePointer) { mem.write8(messagePointer + 0x104 + i, 0); // Temporarily stub this until we add SetWirelessRebootInfo } } + +void APTService::receiveDeliverArg(u32 messagePointer) { + const u32 parameterSize = mem.read32(messagePointer + 4); + const u32 hmacSize = mem.read32(messagePointer + 8); + const u32 parameter = mem.read32(messagePointer + 0x104); + const u32 hmac = mem.read32(messagePointer + 0x10C); + log("APT::ReceiveDeliverArg (parameter size = %X, HMAC size = %X, parameter pointer = %X, HMAC pointer = %X) (stubbed)\n", parameterSize, + hmacSize, parameter, hmac); + + for (u32 i = 0; i < parameterSize; i += 4) { + mem.write32(parameter + i, 0xDEADC0DE); // Does anything use this + } + + for (u32 i = 0; i < hmacSize; i += 4) { + mem.write32(hmac + i, 0); + } + + mem.write32(messagePointer, IPC::responseHeader(0x35, 4, 4)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 0); // Program ID + mem.write8(messagePointer + 16, 1); // Is valid response + mem.write32(messagePointer + 20, IPC::pointerHeader(0, parameterSize, IPC::BufferType::Send)); + mem.write32(messagePointer + 24, parameter); + mem.write32(messagePointer + 28, IPC::pointerHeader(1, hmacSize, IPC::BufferType::Send)); + mem.write32(messagePointer + 32, hmac); +} + +void APTService::loadSysMenuArg(u32 messagePointer) { + const u32 outputSize = mem.read32(messagePointer + 4); + const u32 output = mem.read32(messagePointer + 0x104); + log("APT::LoadSysMenuArg (output size = %X, output = %X) (stubbed)\n", outputSize, output); + + for (u32 i = 0; i < outputSize; i += 4) { + mem.write32(output + i, 0); + } + + mem.write32(messagePointer, IPC::responseHeader(0x35, 4, 4)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, IPC::pointerHeader(0, outputSize, IPC::BufferType::Send)); + mem.write32(messagePointer + 12, outputSize); +} + +void APTService::getCaptureInfo(u32 messagePointer) { + const u32 size = mem.read32(messagePointer + 4); + const u32 captureBufferInfo = mem.read32(messagePointer + 0x104); + log("APT::GetCaptureInfo (size = %X, capture buffer info pointer = %X) (Stubbed)\n", size, captureBufferInfo); + + mem.write32(captureBufferInfo, 0); // Size (of structure?) + mem.write8(captureBufferInfo + 4, 0); // 1 = is 3D + mem.write32(captureBufferInfo + 8, 0); // Main screen left offset + mem.write32(captureBufferInfo + 12, 0); // Main screen right offset + mem.write32(captureBufferInfo + 16, 0); // Main screen display buffer mode + mem.write32(captureBufferInfo + 20, 0); // Sub screen left offset + mem.write32(captureBufferInfo + 24, 0); // Sub screen right offset + mem.write32(captureBufferInfo + 28, 0); // Sub screen display buffer mode + + mem.write32(messagePointer, IPC::responseHeader(0x4A, 1, 2)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, IPC::pointerHeader(0, size, IPC::BufferType::Send)); + mem.write32(messagePointer + 12, captureBufferInfo); +} \ No newline at end of file diff --git a/src/core/services/boss.cpp b/src/core/services/boss.cpp index cb8fdf81..6e797b2a 100644 --- a/src/core/services/boss.cpp +++ b/src/core/services/boss.cpp @@ -25,9 +25,17 @@ namespace BOSSCommands { GetTaskState = 0x00200082, GetTaskStatus = 0x002300C2, GetTaskInfo = 0x00250082, + DeleteNsData = 0x00260040, + GetNsDataHeaderInfo = 0x002700C2, + ReadNsData = 0x00280102, + GetNsDataLastUpdated = 0x002D0040, GetErrorCode = 0x002E0040, RegisterStorageEntry = 0x002F0140, GetStorageEntryInfo = 0x00300000, + StartBgImmediate = 0x00330042, + InitializeSessionPrivileged = 0x04010082, + GetAppNewFlag = 0x04040080, + SetAppNewFlag = 0x040500C0, // Probably }; } @@ -39,13 +47,16 @@ void BOSSService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { case BOSSCommands::CancelTask: cancelTask(messagePointer); break; + case BOSSCommands::DeleteNsData: deleteNsData(messagePointer); break; + case BOSSCommands::GetAppNewFlag: getAppNewFlag(messagePointer); break; case BOSSCommands::GetErrorCode: getErrorCode(messagePointer); break; + case BOSSCommands::GetNsDataHeaderInfo: getNsDataHeaderInfo(messagePointer); break; case BOSSCommands::GetNewArrivalFlag: getNewArrivalFlag(messagePointer); break; case BOSSCommands::GetNsDataIdList: case BOSSCommands::GetNsDataIdList1: case BOSSCommands::GetNsDataIdList2: - case BOSSCommands::GetNsDataIdList3: - getNsDataIdList(messagePointer, command); break; + case BOSSCommands::GetNsDataIdList3: getNsDataIdList(messagePointer, command); break; + case BOSSCommands::GetNsDataLastUpdated: getNsDataLastUpdated(messagePointer); break; case BOSSCommands::GetOptoutFlag: getOptoutFlag(messagePointer); break; case BOSSCommands::GetStorageEntryInfo: getStorageEntryInfo(messagePointer); break; case BOSSCommands::GetTaskIdList: getTaskIdList(messagePointer); break; @@ -54,16 +65,29 @@ void BOSSService::handleSyncRequest(u32 messagePointer) { case BOSSCommands::GetTaskState: getTaskState(messagePointer); break; case BOSSCommands::GetTaskStatus: getTaskStatus(messagePointer); break; case BOSSCommands::GetTaskStorageInfo: getTaskStorageInfo(messagePointer); break; - case BOSSCommands::InitializeSession: initializeSession(messagePointer); break; + case BOSSCommands::InitializeSession: + case BOSSCommands::InitializeSessionPrivileged: + initializeSession(messagePointer); break; + case BOSSCommands::ReadNsData: readNsData(messagePointer); break; case BOSSCommands::ReceiveProperty: receiveProperty(messagePointer); break; case BOSSCommands::RegisterNewArrivalEvent: registerNewArrivalEvent(messagePointer); break; case BOSSCommands::RegisterStorageEntry: registerStorageEntry(messagePointer); break; case BOSSCommands::RegisterTask: registerTask(messagePointer); break; case BOSSCommands::SendProperty: sendProperty(messagePointer); break; + case BOSSCommands::SetAppNewFlag: setAppNewFlag(messagePointer); break; case BOSSCommands::SetOptoutFlag: setOptoutFlag(messagePointer); break; + case BOSSCommands::StartBgImmediate: startBgImmediate(messagePointer); break; case BOSSCommands::StartTask: startTask(messagePointer); break; case BOSSCommands::UnregisterStorage: unregisterStorage(messagePointer); break; case BOSSCommands::UnregisterTask: unregisterTask(messagePointer); break; + + case 0x04500102: // Home Menu uses this command, what is this? + Helpers::warn("BOSS command 0x04500102"); + + mem.write32(messagePointer, IPC::responseHeader(0x450, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); + break; + default: Helpers::panic("BOSS service requested. Command: %08X\n", command); } } @@ -253,4 +277,91 @@ void BOSSService::getNewArrivalFlag(u32 messagePointer) { mem.write32(messagePointer, IPC::responseHeader(0x7, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write8(messagePointer + 8, 0); // Flag +} + +void BOSSService::startBgImmediate(u32 messagePointer) { + const u32 size = mem.read32(messagePointer + 8); + const u32 taskIDs = mem.read32(messagePointer + 12); + log("BOSS::StartBgImmediate (size = %X, task ID pointer = %X) (stubbed)\n", size, taskIDs); + + mem.write32(messagePointer, IPC::responseHeader(0x33, 1, 2)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, IPC::pointerHeader(0, size, IPC::BufferType::Send)); + mem.write32(messagePointer + 12, taskIDs); +} + +void BOSSService::getAppNewFlag(u32 messagePointer) { + const u64 appID = mem.read64(messagePointer + 4); + log("BOSS::GetAppNewFlag (app ID = %llX)\n", appID); + + mem.write32(messagePointer, IPC::responseHeader(0x404, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write8(messagePointer + 8, 0); // No new content +} + +void BOSSService::getNsDataHeaderInfo(u32 messagePointer) { + const u32 nsDataID = mem.read32(messagePointer + 4); + const u8 type = mem.read8(messagePointer + 8); + const u32 size = mem.read32(messagePointer + 12); + const u32 nsDataHeaderInfo = mem.read32(messagePointer + 20); + log("BOSS::GetNsDataHeaderInfo (NS data ID = %X, type = %X, size = %X, NS data header info pointer = %X) (stubbed)\n", nsDataID, type, size, + nsDataHeaderInfo); + + switch (type) { + case 3: + case 5: mem.write32(nsDataHeaderInfo, 0); break; // ?? + + default: Helpers::panic("Unimplemented NS data header info type %X", type); + } + + mem.write32(messagePointer, IPC::responseHeader(0x27, 1, 2)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, IPC::pointerHeader(0, size, IPC::BufferType::Receive)); + mem.write32(messagePointer + 12, nsDataHeaderInfo); +} + +void BOSSService::getNsDataLastUpdated(u32 messagePointer) { + const u32 nsDataID = mem.read32(messagePointer + 4); + log("BOSS::GetNsDataLastUpdated (NS data ID = %X) (stubbed)\n", nsDataID); + + mem.write32(messagePointer, IPC::responseHeader(0x2D, 3, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write64(messagePointer + 8, 0); // Milliseconds since last update? +} + +void BOSSService::readNsData(u32 messagePointer) { + const u32 nsDataID = mem.read32(messagePointer + 4); + const s64 offset = mem.read64(messagePointer + 8); + const u32 size = mem.read32(messagePointer + 20); + const u32 data = mem.read32(messagePointer + 24); + log("BOSS::ReadNsData (NS data ID = %X, offset = %llX, size = %X, data pointer = %X) (stubbed)\n", nsDataID, offset, size, data); + + for (u32 i = 0; i < size; i++) { + mem.write8(data + i, 0); + } + + mem.write32(messagePointer, IPC::responseHeader(0x28, 3, 2)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, size); // Technically how many bytes have been read + mem.write32(messagePointer + 12, 0); // ?? + mem.write32(messagePointer + 16, IPC::pointerHeader(0, size, IPC::BufferType::Receive)); + mem.write32(messagePointer + 20, data); +} + +void BOSSService::deleteNsData(u32 messagePointer) { + const u32 nsDataID = mem.read32(messagePointer + 4); + log("BOSS::DeleteNsData (NS data ID = %X) (stubbed)\n", nsDataID); + + mem.write32(messagePointer, IPC::responseHeader(0x26, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +// Judging by the inputs and command number, this could very well be a "SetAppNewFlag" +void BOSSService::setAppNewFlag(u32 messagePointer) { + const u64 appID = mem.read64(messagePointer + 4); + const u8 flag = mem.read32(messagePointer + 12); + log("BOSS::SetAppNewFlag (app ID = %llX, flag = %X)\n", appID, flag); + + mem.write32(messagePointer, IPC::responseHeader(0x405, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/cfg.cpp b/src/core/services/cfg.cpp index 0b5f6437..f4f5d1e4 100644 --- a/src/core/services/cfg.cpp +++ b/src/core/services/cfg.cpp @@ -18,6 +18,8 @@ namespace CFGCommands { GetSystemModel = 0x00050000, TranslateCountryInfo = 0x00080080, GetCountryCodeID = 0x000A0040, + SetConfigInfoBlk4 = 0x04020082, + UpdateConfigNANDSavegame = 0x04030000, GetLocalFriendCodeSeed = 0x04050000, SecureInfoGetByte101 = 0x04070000, @@ -44,6 +46,9 @@ void CFGService::handleSyncRequest(u32 messagePointer, CFGService::Type type) { case CFGCommands::GetConfigInfoBlk8: getConfigInfoBlk8(messagePointer); break; case CFGCommands::GetLocalFriendCodeSeed: getLocalFriendCodeSeed(messagePointer); break; case CFGCommands::SecureInfoGetByte101: secureInfoGetByte101(messagePointer); break; + case CFGCommands::SetConfigInfoBlk4: setConfigInfoBlk4(messagePointer); break; + case CFGCommands::UpdateConfigNANDSavegame: updateConfigNANDSavegame(messagePointer); break; + default: Helpers::panic("CFG:S service requested. Command: %08X\n", command); } } else { @@ -76,8 +81,7 @@ 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 - log("CFG::GetConfigInfoBlk2 (size = %X, block ID = %X, output pointer = %08X\n", size, blockID, output); - + 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)); @@ -88,7 +92,7 @@ void CFGService::getConfigInfoBlk8(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 - log("CFG::GetConfigInfoBlk8 (size = %X, block ID = %X, output pointer = %08X\n", size, blockID, output); + log("CFG::GetConfigInfoBlk8 (size = %X, block ID = %X, output pointer = %08X)\n", size, blockID, output); getConfigInfo(output, blockID, size, 0x8); mem.write32(messagePointer, IPC::responseHeader(0x401, 1, 2)); @@ -160,6 +164,18 @@ void CFGService::getConfigInfo(u32 output, u32 blockID, u32 size, u32 permission mem.write32(output, 0); } else if (size == 8 && blockID == 0x00090000) { mem.write64(output, 0); // Some sort of key used with nwm::UDS::InitializeWithVersion + } else if (size == 4 && blockID == 0x110000) { + mem.write32(output, 1); // According to 3Dbrew, 0 means system setup is required + } else if (size == 2 && blockID == 0x50001) { + // Backlight controls. Values taken from Citra + mem.write8(output, 0); + mem.write8(output + 1, 2); + } else if (size == 8 && blockID == 0x50009) { + // N3DS Backlight controls? + mem.write64(output, 0); + } else if (size == 4 && blockID == 0x180000) { + // Infrared LED related? + mem.write32(output, 0); } else { Helpers::panic("Unhandled GetConfigInfoBlk2 configuration. Size = %d, block = %X", size, blockID); } @@ -260,6 +276,25 @@ void CFGService::getLocalFriendCodeSeed(u32 messagePointer) { mem.write64(messagePointer + 8, 0); } +void CFGService::setConfigInfoBlk4(u32 messagePointer) { + u32 blockID = mem.read32(messagePointer + 4); + u32 size = mem.read32(messagePointer + 8); + u32 input = mem.read32(messagePointer + 16); + log("CFG::SetConfigInfoBlk4 (block ID = %X, size = %X, input pointer = %08X)\n", blockID, size, input); + + mem.write32(messagePointer, IPC::responseHeader(0x401, 1, 2)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, IPC::pointerHeader(0, size, IPC::BufferType::Receive)); + mem.write32(messagePointer + 12, input); +} + +void CFGService::updateConfigNANDSavegame(u32 messagePointer) { + log("CFG::UpdateConfigNANDSavegame\n"); + + mem.write32(messagePointer, IPC::responseHeader(0x403, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + // https://www.3dbrew.org/wiki/Cfg:TranslateCountryInfo void CFGService::translateCountryInfo(u32 messagePointer) { const u32 country = mem.read32(messagePointer + 4); diff --git a/src/core/services/fs.cpp b/src/core/services/fs.cpp index 54a4241d..7d0666c5 100644 --- a/src/core/services/fs.cpp +++ b/src/core/services/fs.cpp @@ -44,6 +44,7 @@ namespace FSCommands { SetThisSaveDataSecureValue = 0x086E00C0, GetThisSaveDataSecureValue = 0x086F0040, TheGameboyVCFunction = 0x08750180, + GetNumSeeds = 0x087D0000, }; } @@ -202,6 +203,15 @@ void FSService::handleSyncRequest(u32 messagePointer) { case FSCommands::SetThisSaveDataSecureValue: setThisSaveDataSecureValue(messagePointer); break; case FSCommands::AbnegateAccessRight: abnegateAccessRight(messagePointer); break; case FSCommands::TheGameboyVCFunction: theGameboyVCFunction(messagePointer); break; + case FSCommands::GetNumSeeds: getNumSeeds(messagePointer); break; + case 0x08830000: // Home Menu uses this command, what is this? + Helpers::warn("FS command 0x08830000"); + + mem.write32(messagePointer, IPC::responseHeader(0x883, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 0); + break; + default: Helpers::panic("FS service requested. Command: %08X\n", command); } } @@ -246,6 +256,19 @@ void FSService::openArchive(u32 messagePointer) { auto archivePath = readPath(archivePathType, archivePathPointer, archivePathSize); log("FS::OpenArchive(archive ID = %d, archive path type = %d)\n", archiveID, archivePathType); + // Needed for HOME Menu + if ((archiveID == 7) && (archivePathType == 2)) { + const u32 id = *(u32*)&archivePath.binary[4]; + + if (id == 0xE0000000) { + log("FS::OpenArchive: Failed to open archive\n"); + mem.write32(messagePointer + 4, 0xC8804478); + mem.write64(messagePointer + 8, 0); + + return; + } + } + Rust::Result res = openArchiveHandle(archiveID, archivePath); mem.write32(messagePointer, IPC::responseHeader(0x80C, 3, 0)); if (res.isOk()) { @@ -731,6 +754,14 @@ void FSService::cardSlotIsInserted(u32 messagePointer) { mem.write8(messagePointer + 8, cardInserted ? 1 : 0); } +void FSService::getNumSeeds(u32 messagePointer) { + log("FS::GetNumSeeds (stubbed)"); + + mem.write32(messagePointer, IPC::responseHeader(0x87D, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write8(messagePointer + 8, 0); // Number of seeds? +} + void FSService::renameFile(u32 messagePointer) { log("FS::RenameFile\n"); diff --git a/src/core/services/gsp_lcd.cpp b/src/core/services/gsp_lcd.cpp index d018166b..c8416e03 100644 --- a/src/core/services/gsp_lcd.cpp +++ b/src/core/services/gsp_lcd.cpp @@ -3,6 +3,7 @@ namespace LCDCommands { enum : u32 { + SetLedForceOff = 0x00130040, }; } @@ -11,6 +12,16 @@ void LCDService::reset() {} void LCDService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { + case LCDCommands::SetLedForceOff: setLedForceOff(messagePointer); break; + default: Helpers::panic("LCD service requested. Command: %08X\n", command); } +} + +void LCDService::setLedForceOff(u32 messagePointer) { + const u8 state = mem.read8(messagePointer + 4); + log("LCD::SetLedForceOff (state = %X)\n", state); + + mem.write32(messagePointer, IPC::responseHeader(0x13, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/news_s.cpp b/src/core/services/news_s.cpp new file mode 100644 index 00000000..a9bf4316 --- /dev/null +++ b/src/core/services/news_s.cpp @@ -0,0 +1,16 @@ +#include "services/news_s.hpp" + +#include "ipc.hpp" + +namespace NewsCommands { + enum : u32 {}; +} + +void NewsSService::reset() {} + +void NewsSService::handleSyncRequest(u32 messagePointer) { + const u32 command = mem.read32(messagePointer); + switch (command) { + default: Helpers::panic("news:s service requested. Command: %08X\n", command); + } +} \ No newline at end of file diff --git a/src/core/services/nim.cpp b/src/core/services/nim.cpp index e4e14c1c..b15aba09 100644 --- a/src/core/services/nim.cpp +++ b/src/core/services/nim.cpp @@ -1,19 +1,42 @@ #include "services/nim.hpp" + #include "ipc.hpp" +#include "kernel.hpp" namespace NIMCommands { enum : u32 { - Initialize = 0x00210000 + GetBackgroundEventForMenu = 0x00050000, + GetTaskInfos = 0x000F0042, + IsPendingAutoTitleDownloadTasks = 0x00150000, + GetAutoTitleDownloadTaskInfos = 0x00170042, + Initialize = 0x00210000, }; } -void NIMService::reset() {} +void NIMService::reset() { backgroundSystemUpdateEvent = std::nullopt; } -void NIMService::handleSyncRequest(u32 messagePointer) { +void NIMService::handleSyncRequest(u32 messagePointer, Type type) { const u32 command = mem.read32(messagePointer); switch (command) { - case NIMCommands::Initialize: initialize(messagePointer); break; - default: Helpers::panic("NIM service requested. Command: %08X\n", command); + default: + if (type == Type::AOC) { + switch (command) { + case NIMCommands::Initialize: initialize(messagePointer); break; + + default: Helpers::panic("NIM AOC service requested. Command: %08X\n", command); + } + } else if (type == Type::U) { + switch (command) { + case NIMCommands::GetAutoTitleDownloadTaskInfos: getAutoTitleDownloadTaskInfos(messagePointer); break; + case NIMCommands::GetBackgroundEventForMenu: getBackgroundEventForMenu(messagePointer); break; + case NIMCommands::GetTaskInfos: getTaskInfos(messagePointer); break; + case NIMCommands::IsPendingAutoTitleDownloadTasks: isPendingAutoTitleDownloadTasks(messagePointer); break; + + default: Helpers::panic("NIM U service requested. Command: %08X\n", command); + } + } else { + Helpers::panic("NIM service requested. Command: %08X\n", command); + } } } @@ -21,4 +44,49 @@ void NIMService::initialize(u32 messagePointer) { log("NIM::Initialize\n"); mem.write32(messagePointer, IPC::responseHeader(0x21, 1, 0)); mem.write32(messagePointer + 4, Result::Success); +} + +void NIMService::getTaskInfos(u32 messagePointer) { + const u32 numTaskInfos = mem.read32(messagePointer + 4); + const u32 taskInfos = mem.read32(messagePointer + 12); + log("NIM::GetTaskInfos (num task infos = %X, task infos pointer = %X) (stubbed)\n", numTaskInfos, taskInfos); + + mem.write32(messagePointer, IPC::responseHeader(0xF, 2, 2)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 0); // Read task infos? + mem.write32(messagePointer + 12, IPC::pointerHeader(0, 0, IPC::BufferType::Receive)); + mem.write32(messagePointer + 16, taskInfos); +} + +void NIMService::getAutoTitleDownloadTaskInfos(u32 messagePointer) { + const u32 numTaskInfos = mem.read32(messagePointer + 4); + const u32 taskInfos = mem.read32(messagePointer + 12); + log("NIM::GetAutoTitleDownloadTaskInfos (num task infos = %X, task infos pointer = %X) (stubbed)\n", numTaskInfos, taskInfos); + + mem.write32(messagePointer, IPC::responseHeader(0x17, 2, 2)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 0); // Read task infos? + mem.write32(messagePointer + 12, IPC::pointerHeader(0, 0, IPC::BufferType::Receive)); + mem.write32(messagePointer + 16, taskInfos); +} + +void NIMService::isPendingAutoTitleDownloadTasks(u32 messagePointer) { + log("NIM::IsPendingAutoTitleDownloadTasks\n"); + + mem.write32(messagePointer, IPC::responseHeader(0x15, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write8(messagePointer + 8, 0); // Has pending tasks +} + +void NIMService::getBackgroundEventForMenu(u32 messagePointer) { + log("NIM::GetBackgroundEventForMenu\n"); + + if (!backgroundSystemUpdateEvent.has_value()) { + backgroundSystemUpdateEvent = kernel.makeEvent(ResetType::OneShot); + } + + mem.write32(messagePointer, IPC::responseHeader(0x5, 1, 2)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 0x04000000); + mem.write32(messagePointer + 12, backgroundSystemUpdateEvent.value()); } \ No newline at end of file diff --git a/src/core/services/ns.cpp b/src/core/services/ns.cpp new file mode 100644 index 00000000..9b47b9e4 --- /dev/null +++ b/src/core/services/ns.cpp @@ -0,0 +1,32 @@ +#include "services/ns.hpp" + +#include "ipc.hpp" + +namespace NSCommands { + enum : u32 { + LaunchTitle = 0x000200C0, + }; +} + +void NSService::reset() {} + +void NSService::handleSyncRequest(u32 messagePointer, Type type) { + const u32 command = mem.read32(messagePointer); + + // ns:s commands + switch (command) { + case NSCommands::LaunchTitle: launchTitle(messagePointer); break; + + default: Helpers::panic("NS service requested. Command: %08X\n", command); + } +} + +void NSService::launchTitle(u32 messagePointer) { + const u64 titleID = mem.read64(messagePointer + 4); + const u32 launchFlags = mem.read32(messagePointer + 12); + log("NS::LaunchTitle (title ID = %llX, launch flags = %X) (stubbed)\n", titleID, launchFlags); + + mem.write32(messagePointer, IPC::responseHeader(0x2, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 0); // Process ID +} diff --git a/src/core/services/ptm.cpp b/src/core/services/ptm.cpp index 67451cc2..496ae3a5 100644 --- a/src/core/services/ptm.cpp +++ b/src/core/services/ptm.cpp @@ -12,11 +12,16 @@ namespace PTMCommands { GetStepHistoryAll = 0x000F0084, ConfigureNew3DSCPU = 0x08180040, + // ptm:gets functions + GetSystemTime = 0x04010000, + // ptm:play functions GetPlayHistory = 0x08070082, GetPlayHistoryStart = 0x08080000, GetPlayHistoryLength = 0x08090000, CalcPlayHistoryStart = 0x080B0080, + GetSoftwareClosedFlag = 0x080F0000, + ClearSoftwareClosedFlag = 0x08100000, }; } @@ -50,10 +55,23 @@ void PTMService::handleSyncRequest(u32 messagePointer, PTMService::Type type) { default: Helpers::panic("PTM PLAY service requested. Command: %08X\n", command); break; } + } else if (type == Type::GETS) { + switch (command) { + case PTMCommands::GetSystemTime: getSystemTime(messagePointer); break; + + default: Helpers::panic("PTM GETS service requested. Command: %08X\n", command); break; + } + } else if (type == Type::SYSM) { + switch (command) { + case PTMCommands::GetSoftwareClosedFlag: getSoftwareClosedFlag(messagePointer); break; + case PTMCommands::ClearSoftwareClosedFlag: clearSoftwareClosedFlag(messagePointer); break; + + default: Helpers::panic("PTM SYSM service requested. Command: %08X\n", command); break; + } } else { Helpers::panic("PTM service requested. Command: %08X\n", command); } - } + } } void PTMService::getAdapterState(u32 messagePointer) { @@ -114,4 +132,24 @@ void PTMService::configureNew3DSCPU(u32 messagePointer) { log("PTM::ConfigureNew3DSCPU [stubbed]\n"); mem.write32(messagePointer, IPC::responseHeader(0x818, 1, 0)); mem.write32(messagePointer + 4, Result::Success); +} + +void PTMService::getSystemTime(u32 messagePointer) { + log("PTM::GetSystemTime [stubbed]\n"); + mem.write32(messagePointer, IPC::responseHeader(0x401, 3, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write64(messagePointer + 8, 0); // Milliseconds since 2000? +} + +void PTMService::getSoftwareClosedFlag(u32 messagePointer) { + log("PTM::GetSoftwareClosedFlag\n"); + mem.write32(messagePointer, IPC::responseHeader(0x80F, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write8(messagePointer + 8, 0); // Show software closed dialog +} + +void PTMService::clearSoftwareClosedFlag(u32 messagePointer) { + log("PTM::ClearSoftwareClosedFlag\n"); + mem.write32(messagePointer, IPC::responseHeader(0x810, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index 8fa88a00..e382def7 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -7,9 +7,10 @@ ServiceManager::ServiceManager(std::span regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel, const EmulatorConfig& config) : regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), act(mem), apt(mem, kernel), cam(mem, kernel), cecd(mem, kernel), cfg(mem), - csnd(mem, kernel), dlp_srvr(mem), dsp(mem, kernel, config), hid(mem, kernel), http(mem), ir_user(mem, kernel), frd(mem), fs(mem, kernel, config), - gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem, kernel), mcu_hwc(mem, config), mic(mem, kernel), nfc(mem, kernel), nim(mem), ndm(mem), - news_u(mem), nwm_uds(mem, kernel), ptm(mem, config), soc(mem), ssl(mem), y2r(mem, kernel) {} + csnd(mem, kernel), dlp_srvr(mem), dsp(mem, kernel, config), hid(mem, kernel), http(mem), ir_user(mem, kernel), frd(mem), + fs(mem, kernel, config), gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem, kernel), mcu_hwc(mem, config), mic(mem, kernel), + nfc(mem, kernel), nim(mem, kernel), ndm(mem), news_s(mem), news_u(mem), ns(mem), nwm_uds(mem, kernel), ptm(mem, config), soc(mem), ssl(mem), + y2r(mem, kernel) {} static constexpr int MAX_NOTIFICATION_COUNT = 16; @@ -37,9 +38,11 @@ void ServiceManager::reset() { mcu_hwc.reset(); mic.reset(); ndm.reset(); + news_s.reset(); news_u.reset(); nfc.reset(); nim.reset(); + ns.reset(); ptm.reset(); soc.reset(); ssl.reset(); @@ -102,7 +105,9 @@ static std::map serviceMap = { { "APT:A", KernelHandles::APT }, { "APT:U", KernelHandles::APT }, { "boss:U", KernelHandles::BOSS }, + { "boss:P", KernelHandles::BOSS }, { "cam:u", KernelHandles::CAM }, + { "cecd:s", KernelHandles::CECD }, { "cecd:u", KernelHandles::CECD }, { "cfg:u", KernelHandles::CFG_U }, { "cfg:i", KernelHandles::CFG_I }, @@ -111,6 +116,7 @@ static std::map serviceMap = { { "dlp:SRVR", KernelHandles::DLP_SRVR }, { "dsp::DSP", KernelHandles::DSP }, { "hid:USER", KernelHandles::HID }, + { "hid:SPVR", KernelHandles::HID }, { "http:C", KernelHandles::HTTP }, { "ir:USER", KernelHandles::IR_USER }, { "frd:a", KernelHandles::FRD_A }, @@ -122,14 +128,17 @@ static std::map serviceMap = { { "mcu::HWC", KernelHandles::MCU_HWC }, { "mic:u", KernelHandles::MIC }, { "ndm:u", KernelHandles::NDM }, + { "news:s", KernelHandles::NEWS_S }, { "news:u", KernelHandles::NEWS_U }, { "nfc:u", KernelHandles::NFC }, { "ns:s", KernelHandles::NS_S }, { "nwm::UDS", KernelHandles::NWM_UDS }, - { "nim:aoc", KernelHandles::NIM }, + { "nim:aoc", KernelHandles::NIM_AOC }, + { "nim:u", KernelHandles::NIM_U }, { "ptm:u", KernelHandles::PTM_U }, // TODO: ptm:u and ptm:sysm have very different command sets { "ptm:sysm", KernelHandles::PTM_SYSM }, { "ptm:play", KernelHandles::PTM_PLAY }, + { "ptm:gets", KernelHandles::PTM_GETS }, { "soc:U", KernelHandles::SOC }, { "ssl:C", KernelHandles::SSL }, { "y2r:u", KernelHandles::Y2R }, @@ -224,11 +233,13 @@ void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) { case KernelHandles::MCU_HWC: mcu_hwc.handleSyncRequest(messagePointer); break; case KernelHandles::MIC: mic.handleSyncRequest(messagePointer); break; case KernelHandles::NFC: nfc.handleSyncRequest(messagePointer); break; - case KernelHandles::NIM: nim.handleSyncRequest(messagePointer); break; + case KernelHandles::NIM_AOC: nim.handleSyncRequest(messagePointer, NIMService::Type::AOC); break; + case KernelHandles::NIM_U: nim.handleSyncRequest(messagePointer, NIMService::Type::U); break; case KernelHandles::NDM: ndm.handleSyncRequest(messagePointer); break; case KernelHandles::NEWS_U: news_u.handleSyncRequest(messagePointer); break; - case KernelHandles::NS_S: Helpers::panic("Unimplemented SendSyncRequest to ns:s"); break; + case KernelHandles::NS_S: ns.handleSyncRequest(messagePointer, NSService::Type::S); break; case KernelHandles::NWM_UDS: nwm_uds.handleSyncRequest(messagePointer); break; + case KernelHandles::PTM_GETS: ptm.handleSyncRequest(messagePointer, PTMService::Type::GETS); break; case KernelHandles::PTM_PLAY: ptm.handleSyncRequest(messagePointer, PTMService::Type::PLAY); break; case KernelHandles::PTM_SYSM: ptm.handleSyncRequest(messagePointer, PTMService::Type::SYSM); break; case KernelHandles::PTM_U: ptm.handleSyncRequest(messagePointer, PTMService::Type::U); break;