mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-06 06:05:40 +12:00
Fix typo (#680)
Co-authored-by: Noumi <139501014+noumidev@users.noreply.github.com>
This commit is contained in:
parent
4ce0768ba1
commit
dc80828397
20 changed files with 456 additions and 107 deletions
|
@ -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
|
||||
)
|
||||
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
|
||||
)
|
||||
|
||||
cmrc_add_resource_library(
|
||||
|
|
|
@ -2,8 +2,19 @@
|
|||
#include <cstdint>
|
||||
|
||||
namespace IPC {
|
||||
namespace BufferType {
|
||||
enum : std::uint32_t {
|
||||
Send = 1,
|
||||
Receive = 2,
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
|
@ -8,6 +8,7 @@ namespace ConfigMem {
|
|||
KernelVersionMajor = 0x1FF80003,
|
||||
SyscoreVer = 0x1FF80010,
|
||||
EnvInfo = 0x1FF80014,
|
||||
PrevFirm = 0x1FF80016,
|
||||
AppMemAlloc = 0x1FF80040,
|
||||
FirmUnknown = 0x1FF80060,
|
||||
FirmRevision = 0x1FF80061,
|
||||
|
@ -30,6 +31,11 @@ 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
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace KernelHandles {
|
|||
CFG_U, // CFG service (Console & region info)
|
||||
CFG_I,
|
||||
CFG_S, // Used by most system apps in lieu of cfg:u
|
||||
CFG_NOR, // Used by system settings app
|
||||
CSND, // Plays audio directly from PCM samples
|
||||
DLP_SRVR, // Download Play: Server. Used for network play.
|
||||
DSP, // DSP service (Used for audio decoding and output)
|
||||
|
@ -38,11 +39,14 @@ namespace KernelHandles {
|
|||
NIM, // Updates, DLC, etc
|
||||
NDM, // ?????
|
||||
NS_S, // Nintendo Shell service
|
||||
NWM_EXT, // ?????
|
||||
NWM_UDS, // Local multiplayer
|
||||
NEWS_U, // This service literally has 1 command (AddNotification) and I don't even understand what it does
|
||||
NEWS_S, // news:u on steroids
|
||||
NEWS_U, // This service literally has 1 command (AddNotification)
|
||||
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
|
||||
|
@ -82,6 +86,8 @@ namespace KernelHandles {
|
|||
case CECD: return "CECD";
|
||||
case CFG_U: return "CFG:U";
|
||||
case CFG_I: return "CFG:I";
|
||||
case CFG_S: return "CFG:S";
|
||||
case CFG_NOR: return "CFG:NOR";
|
||||
case CSND: return "CSND";
|
||||
case DSP: return "DSP";
|
||||
case DLP_SRVR: return "DLP::SRVR";
|
||||
|
@ -97,13 +103,16 @@ 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_EXT: return "nwm::EXT";
|
||||
case NWM_UDS: return "nwm::UDS";
|
||||
case NFC: return "NFC";
|
||||
case NIM: return "NIM";
|
||||
case PTM_U: return "PTM:U";
|
||||
case PTM_SYSM: return "PTM:SYSM";
|
||||
case PTM_PLAY: return "PTM:PLAY";
|
||||
case PTM_GETS: return "PTM:GETS";
|
||||
case SOC: return "SOC";
|
||||
case SSL: return "SSL";
|
||||
case Y2R: return "Y2R";
|
||||
|
|
|
@ -65,6 +65,7 @@ namespace Log {
|
|||
static Logger<false> nwmUdsLogger;
|
||||
static Logger<false> nimLogger;
|
||||
static Logger<false> ndmLogger;
|
||||
static Logger<false> nsLogger;
|
||||
static Logger<false> ptmLogger;
|
||||
static Logger<false> socLogger;
|
||||
static Logger<false> sslLogger;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -18,7 +18,7 @@ class CFGService {
|
|||
|
||||
// Service functions
|
||||
void getConfigInfoBlk2(u32 messagePointer);
|
||||
void getConfigInfoBlk8(u32 messagePointer);
|
||||
void getConfigInfoBlk8(u32 messagePointer, u32 commandWord);
|
||||
void getCountryCodeID(u32 messagePointer);
|
||||
void getLocalFriendCodeSeed(u32 messagePointer);
|
||||
void getRegionCanadaUSA(u32 messagePointer);
|
||||
|
@ -26,7 +26,14 @@ 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 isFangateSupported(u32 messagePointer);
|
||||
|
||||
// cfg:nor functions
|
||||
void norInitialize(u32 messagePointer);
|
||||
void norReadData(u32 messagePointer);
|
||||
|
||||
void getConfigInfo(u32 output, u32 blockID, u32 size, u32 permissionMask);
|
||||
|
||||
|
|
|
@ -6,15 +6,13 @@
|
|||
#include "result/result.hpp"
|
||||
|
||||
class LCDService {
|
||||
using Handle = HorizonHandle;
|
||||
|
||||
Handle handle = KernelHandles::LCD;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, gspLCDLogger)
|
||||
|
||||
// Service commands
|
||||
void setLedForceOff(u32 messagePointer);
|
||||
|
||||
public:
|
||||
public:
|
||||
LCDService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
|
|
25
include/services/ns.hpp
Normal file
25
include/services/ns.hpp
Normal file
|
@ -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);
|
||||
};
|
|
@ -24,6 +24,7 @@ class PTMService {
|
|||
|
||||
public:
|
||||
enum class Type {
|
||||
GETS, // ptm:gets
|
||||
U, // ptm:u
|
||||
SYSM, // ptm:sysm
|
||||
PLAY, // ptm:play
|
||||
|
|
|
@ -28,10 +28,11 @@
|
|||
#include "services/mcu/mcu_hwc.hpp"
|
||||
#include "services/mic.hpp"
|
||||
#include "services/ndm.hpp"
|
||||
#include "services/nwm_uds.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 +53,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;
|
||||
|
@ -76,7 +77,8 @@ class ServiceManager {
|
|||
NewsUService news_u;
|
||||
NFCService nfc;
|
||||
NwmUdsService nwm_uds;
|
||||
NIMService nim;
|
||||
NIMService nim;
|
||||
NSService ns;
|
||||
PTMService ptm;
|
||||
SOCService soc;
|
||||
SSLService ssl;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "services/ac.hpp"
|
||||
|
||||
#include "ipc.hpp"
|
||||
|
||||
namespace ACCommands {
|
||||
|
@ -10,6 +11,7 @@ namespace ACCommands {
|
|||
GetStatus = 0x000C0000,
|
||||
GetWifiStatus = 0x000D0000,
|
||||
GetConnectingInfraPriority = 0x000F0000,
|
||||
GetNZoneBeaconNotFoundEvent = 0x002F0004,
|
||||
RegisterDisconnectEvent = 0x00300004,
|
||||
IsConnected = 0x003E0042,
|
||||
SetClientVersion = 0x00400042,
|
||||
|
@ -29,12 +31,17 @@ 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;
|
||||
case ACCommands::RegisterDisconnectEvent: registerDisconnectEvent(messagePointer); break;
|
||||
case ACCommands::SetClientVersion: setClientVersion(messagePointer); break;
|
||||
default: Helpers::panic("AC service requested. Command: %08X\n", command);
|
||||
|
||||
default:
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
Helpers::warn("AC service requested. Command: %08X\n", command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +79,7 @@ void ACService::getLastErrorCode(u32 messagePointer) {
|
|||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0A, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write32(messagePointer + 8, 0); // Hopefully this means no error?
|
||||
mem.write32(messagePointer + 8, 0); // Hopefully this means no error?
|
||||
}
|
||||
|
||||
void ACService::getConnectingInfraPriority(u32 messagePointer) {
|
||||
|
@ -137,3 +144,12 @@ 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);
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include "services/boss.hpp"
|
||||
|
||||
#include "ipc.hpp"
|
||||
|
||||
namespace BOSSCommands {
|
||||
|
@ -25,27 +26,36 @@ 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
|
||||
};
|
||||
}
|
||||
|
||||
void BOSSService::reset() {
|
||||
optoutFlag = 0;
|
||||
}
|
||||
void BOSSService::reset() { optoutFlag = 0; }
|
||||
|
||||
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,17 +64,31 @@ 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;
|
||||
default: Helpers::panic("BOSS service requested. Command: %08X\n", command);
|
||||
|
||||
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:
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
Helpers::warn("BOSS service requested. Command: %08X\n", command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +123,7 @@ void BOSSService::getTaskState(u32 messagePointer) {
|
|||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write8(messagePointer + 8, 0); // TaskStatus: Report the task finished successfully
|
||||
mem.write32(messagePointer + 12, 0); // Current state value for task PropertyID 0x4
|
||||
mem.write8(messagePointer + 16, 0); // TODO: Figure out what this should be
|
||||
mem.write8(messagePointer + 16, 0); // TODO: Figure out what this should be
|
||||
}
|
||||
|
||||
void BOSSService::getTaskStatus(u32 messagePointer) {
|
||||
|
@ -150,15 +174,15 @@ void BOSSService::getErrorCode(u32 messagePointer) {
|
|||
log("BOSS::GetErrorCode (stubbed)\n");
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x2E, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write32(messagePointer + 8, Result::Success); // No error code
|
||||
mem.write32(messagePointer + 8, Result::Success); // No error code
|
||||
}
|
||||
|
||||
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
|
||||
mem.write32(messagePointer + 8, 0); // u32, unknown meaning
|
||||
mem.write16(messagePointer + 12, 0); // s16, unknown meaning
|
||||
}
|
||||
|
||||
void BOSSService::sendProperty(u32 messagePointer) {
|
||||
|
@ -173,7 +197,6 @@ void BOSSService::sendProperty(u32 messagePointer) {
|
|||
// TODO: Should this do anything else?
|
||||
}
|
||||
|
||||
|
||||
void BOSSService::receiveProperty(u32 messagePointer) {
|
||||
const u32 id = mem.read32(messagePointer + 4);
|
||||
const u32 size = mem.read32(messagePointer + 8);
|
||||
|
@ -182,13 +205,13 @@ void BOSSService::receiveProperty(u32 messagePointer) {
|
|||
log("BOSS::ReceiveProperty (id = %d, size = %08X, ptr = %08X) (stubbed)\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
|
||||
mem.write32(messagePointer + 8, 0); // Read size
|
||||
}
|
||||
|
||||
// This seems to accept a KEvent as a parameter and register it for something Spotpass related
|
||||
// I need to update the 3DBrew page when it's known what it does properly
|
||||
void BOSSService::registerNewArrivalEvent(u32 messagePointer) {
|
||||
const Handle eventHandle = mem.read32(messagePointer + 4); // Kernel event handle to register
|
||||
const Handle eventHandle = mem.read32(messagePointer + 4); // Kernel event handle to register
|
||||
log("BOSS::RegisterNewArrivalEvent (handle = %X)\n", eventHandle);
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x8, 1, 0));
|
||||
|
@ -252,5 +275,92 @@ void BOSSService::getNewArrivalFlag(u32 messagePointer) {
|
|||
log("BOSS::GetNewArrivalFlag (stubbed)\n");
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x7, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write8(messagePointer + 8, 0); // Flag
|
||||
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);
|
||||
}
|
|
@ -17,40 +17,80 @@ namespace CFGCommands {
|
|||
GetRegionCanadaUSA = 0x00040000,
|
||||
GetSystemModel = 0x00050000,
|
||||
TranslateCountryInfo = 0x00080080,
|
||||
GetCountryCodeID = 0x000A0040,
|
||||
|
||||
GetCountryCodeID = 0x000A0040,
|
||||
IsFangateSupported = 0x000B0000,
|
||||
SetConfigInfoBlk4 = 0x04020082,
|
||||
UpdateConfigNANDSavegame = 0x04030000,
|
||||
GetLocalFriendCodeSeed = 0x04050000,
|
||||
SecureInfoGetByte101 = 0x04070000,
|
||||
};
|
||||
}
|
||||
|
||||
// cfg:i commands
|
||||
namespace CFGICommands {
|
||||
enum : u32 {
|
||||
GetConfigInfoBlk8 = 0x08010082,
|
||||
};
|
||||
}
|
||||
|
||||
// cfg:nor commands
|
||||
namespace NORCommands {
|
||||
enum : u32 {
|
||||
Initialize = 0x00010040,
|
||||
ReadData = 0x00050082,
|
||||
};
|
||||
}
|
||||
|
||||
void CFGService::reset() {}
|
||||
|
||||
void CFGService::handleSyncRequest(u32 messagePointer, CFGService::Type type) {
|
||||
const u32 command = mem.read32(messagePointer);
|
||||
switch (command) {
|
||||
case CFGCommands::GetConfigInfoBlk2: [[likely]] getConfigInfoBlk2(messagePointer); break;
|
||||
case CFGCommands::GetCountryCodeID: getCountryCodeID(messagePointer); break;
|
||||
case CFGCommands::GetRegionCanadaUSA: getRegionCanadaUSA(messagePointer); break;
|
||||
case CFGCommands::GetSystemModel: getSystemModel(messagePointer); break;
|
||||
case CFGCommands::GenHashConsoleUnique: genUniqueConsoleHash(messagePointer); break;
|
||||
case CFGCommands::SecureInfoGetRegion: secureInfoGetRegion(messagePointer); break;
|
||||
case CFGCommands::TranslateCountryInfo: translateCountryInfo(messagePointer); break;
|
||||
|
||||
default:
|
||||
if (type == Type::S) {
|
||||
// cfg:s-only functions
|
||||
switch (command) {
|
||||
case CFGCommands::GetConfigInfoBlk8: getConfigInfoBlk8(messagePointer); break;
|
||||
case CFGCommands::GetLocalFriendCodeSeed: getLocalFriendCodeSeed(messagePointer); break;
|
||||
case CFGCommands::SecureInfoGetByte101: secureInfoGetByte101(messagePointer); break;
|
||||
default: Helpers::panic("CFG:S service requested. Command: %08X\n", command);
|
||||
if (type != Type::NOR) {
|
||||
switch (command) {
|
||||
case CFGCommands::GetConfigInfoBlk2: [[likely]] getConfigInfoBlk2(messagePointer); break;
|
||||
case CFGCommands::GetCountryCodeID: getCountryCodeID(messagePointer); break;
|
||||
case CFGCommands::GetRegionCanadaUSA: getRegionCanadaUSA(messagePointer); break;
|
||||
case CFGCommands::GetSystemModel: getSystemModel(messagePointer); break;
|
||||
case CFGCommands::GenHashConsoleUnique: genUniqueConsoleHash(messagePointer); break;
|
||||
case CFGCommands::IsFangateSupported: isFangateSupported(messagePointer); break;
|
||||
case CFGCommands::SecureInfoGetRegion: secureInfoGetRegion(messagePointer); break;
|
||||
case CFGCommands::TranslateCountryInfo: translateCountryInfo(messagePointer); break;
|
||||
|
||||
default:
|
||||
if (type == Type::S) {
|
||||
// cfg:s (and cfg:i) functions only functions
|
||||
switch (command) {
|
||||
case CFGCommands::GetConfigInfoBlk8: getConfigInfoBlk8(messagePointer, command); 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 if (type == Type::I) {
|
||||
switch (command) {
|
||||
case CFGCommands::GetConfigInfoBlk8:
|
||||
case CFGICommands::GetConfigInfoBlk8: getConfigInfoBlk8(messagePointer, command); break;
|
||||
|
||||
default: Helpers::panic("CFG:I service requested. Command: %08X\n", command);
|
||||
}
|
||||
} else {
|
||||
Helpers::panic("CFG service requested. Command: %08X\n", command);
|
||||
}
|
||||
} else {
|
||||
Helpers::panic("CFG service requested. Command: %08X\n", command);
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// cfg:nor functions
|
||||
switch (command) {
|
||||
case NORCommands::Initialize: norInitialize(messagePointer); break;
|
||||
case NORCommands::ReadData: norReadData(messagePointer); break;
|
||||
|
||||
default: Helpers::panic("CFG:NOR service requested. Command: %08X\n", command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,14 +124,14 @@ void CFGService::getConfigInfoBlk2(u32 messagePointer) {
|
|||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void CFGService::getConfigInfoBlk8(u32 messagePointer) {
|
||||
void CFGService::getConfigInfoBlk8(u32 messagePointer, u32 commandWord) {
|
||||
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);
|
||||
|
||||
getConfigInfo(output, blockID, size, 0x8);
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x401, 1, 2));
|
||||
mem.write32(messagePointer, IPC::responseHeader(commandWord >> 16, 1, 2));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
|
@ -160,6 +200,37 @@ 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 if (size == 1 && blockID == 0xE0000) {
|
||||
mem.write8(output, 0);
|
||||
} else if ((size == 512 && blockID == 0xC0002) || (size == 148 && blockID == 0x100001)) {
|
||||
// CTR parental controls block (0xC0002) and TWL parental controls block (0x100001)
|
||||
for (u32 i = 0; i < size; i++) {
|
||||
mem.write8(output + i, 0);
|
||||
}
|
||||
} else if (size == 2 && blockID == 0x100000) {
|
||||
// EULA agreed
|
||||
mem.write8(output, 1); // We have agreed to the EULA
|
||||
mem.write8(output + 1, 1); // EULA version = 1
|
||||
} else if (size == 1 && blockID == 0x100002) {
|
||||
Helpers::warn("Unimplemented TWL country code access");
|
||||
mem.write8(output, 0);
|
||||
} else if (size == 24 && blockID == 0x180001) {
|
||||
// QTM calibration data
|
||||
for (u32 i = 0; i < size; i++) {
|
||||
mem.write8(output + i, 0);
|
||||
}
|
||||
} else {
|
||||
Helpers::panic("Unhandled GetConfigInfoBlk2 configuration. Size = %d, block = %X", size, blockID);
|
||||
}
|
||||
|
@ -260,6 +331,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);
|
||||
|
@ -293,3 +383,27 @@ void CFGService::translateCountryInfo(u32 messagePointer) {
|
|||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write32(messagePointer + 8, result);
|
||||
}
|
||||
|
||||
void CFGService::isFangateSupported(u32 messagePointer) {
|
||||
log("CFG::IsFangateSupported\n");
|
||||
|
||||
// TODO: What even is fangate?
|
||||
mem.write32(messagePointer, IPC::responseHeader(0xB, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write32(messagePointer + 8, 1);
|
||||
}
|
||||
|
||||
void CFGService::norInitialize(u32 messagePointer) {
|
||||
log("CFG::NOR::Initialize\n");
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void CFGService::norReadData(u32 messagePointer) {
|
||||
log("CFG::NOR::ReadData\n");
|
||||
Helpers::warn("Unimplemented CFG::NOR::ReadData");
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x5, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include "services/gsp_gpu.hpp"
|
||||
|
||||
#include "PICA/regs.hpp"
|
||||
#include "ipc.hpp"
|
||||
#include "kernel.hpp"
|
||||
|
@ -39,7 +40,7 @@ namespace GXCommands {
|
|||
}
|
||||
|
||||
void GPUService::reset() {
|
||||
privilegedProcess = 0xFFFFFFFF; // Set the privileged process to an invalid handle
|
||||
privilegedProcess = 0xFFFFFFFF; // Set the privileged process to an invalid handle
|
||||
interruptEvent = std::nullopt;
|
||||
gspThreadCount = 0;
|
||||
sharedMem = nullptr;
|
||||
|
@ -113,38 +114,38 @@ void GPUService::registerInterruptRelayQueue(u32 messagePointer) {
|
|||
log("GSP::GPU::RegisterInterruptRelayQueue (flags = %X, event handle = %X)\n", flags, eventHandle);
|
||||
|
||||
const auto event = kernel.getObject(eventHandle, KernelObjectType::Event);
|
||||
if (event == nullptr) { // Check if interrupt event is invalid
|
||||
if (event == nullptr) { // Check if interrupt event is invalid
|
||||
Helpers::panic("Invalid event passed to GSP::GPU::RegisterInterruptRelayQueue");
|
||||
} else {
|
||||
interruptEvent = eventHandle;
|
||||
}
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x13, 2, 2));
|
||||
mem.write32(messagePointer + 4, Result::GSP::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 + 4, Result::GSP::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);
|
||||
}
|
||||
|
||||
void GPUService::requestInterrupt(GPUInterrupt type) {
|
||||
if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet
|
||||
if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Add support for multiple GSP threads
|
||||
u8 index = sharedMem[0]; // The interrupt block is normally located at sharedMem + processGSPIndex*0x40
|
||||
u8 index = sharedMem[0]; // The interrupt block is normally located at sharedMem + processGSPIndex*0x40
|
||||
u8& interruptCount = sharedMem[1];
|
||||
u8 flagIndex = (index + interruptCount) % 0x34;
|
||||
interruptCount++;
|
||||
|
||||
sharedMem[2] = 0; // Set error code to 0
|
||||
sharedMem[0xC + flagIndex] = static_cast<u8>(type); // Write interrupt type to queue
|
||||
sharedMem[2] = 0; // Set error code to 0
|
||||
sharedMem[0xC + flagIndex] = static_cast<u8>(type); // Write interrupt type to queue
|
||||
|
||||
// Update framebuffer info in shared memory
|
||||
// Most new games check to make sure that the "flag" byte of the framebuffer info header is set to 0
|
||||
// Not emulating this causes Yoshi's Wooly World, Captain Toad, Metroid 2 et al to hang
|
||||
if (type == GPUInterrupt::VBlank0 || type == GPUInterrupt::VBlank1) {
|
||||
int screen = static_cast<u32>(type) - static_cast<u32>(GPUInterrupt::VBlank0); // 0 for top screen, 1 for bottom
|
||||
int screen = static_cast<u32>(type) - static_cast<u32>(GPUInterrupt::VBlank0); // 0 for top screen, 1 for bottom
|
||||
FramebufferUpdate* update = getFramebufferInfo(screen);
|
||||
|
||||
if (update->dirtyFlag & 1) {
|
||||
|
@ -166,7 +167,6 @@ void GPUService::readHwRegs(u32 messagePointer) {
|
|||
u32 dataPointer = initialDataPointer;
|
||||
log("GSP::GPU::ReadHwRegs (GPU address = %08X, size = %X, data address = %08X)\n", ioAddr, size, dataPointer);
|
||||
|
||||
|
||||
// Check for alignment
|
||||
if ((size & 3) || (ioAddr & 3) || (dataPointer & 3)) {
|
||||
Helpers::panic("GSP::GPU::ReadHwRegs misalignment");
|
||||
|
@ -197,8 +197,8 @@ void GPUService::readHwRegs(u32 messagePointer) {
|
|||
}
|
||||
|
||||
void GPUService::writeHwRegs(u32 messagePointer) {
|
||||
u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned
|
||||
const u32 size = mem.read32(messagePointer + 8); // Size in bytes
|
||||
u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned
|
||||
const u32 size = mem.read32(messagePointer + 8); // Size in bytes
|
||||
u32 dataPointer = mem.read32(messagePointer + 16);
|
||||
log("GSP::GPU::writeHwRegs (GPU address = %08X, size = %X, data address = %08X)\n", ioAddr, size, dataPointer);
|
||||
|
||||
|
@ -230,14 +230,14 @@ void GPUService::writeHwRegs(u32 messagePointer) {
|
|||
// Update sequential GPU registers using an array of data and mask values using this formula
|
||||
// GPU register = (register & ~mask) | (data & mask).
|
||||
void GPUService::writeHwRegsWithMask(u32 messagePointer) {
|
||||
u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned
|
||||
const u32 size = mem.read32(messagePointer + 8); // Size in bytes
|
||||
u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned
|
||||
const u32 size = mem.read32(messagePointer + 8); // Size in bytes
|
||||
|
||||
u32 dataPointer = mem.read32(messagePointer + 16); // Data pointer
|
||||
u32 maskPointer = mem.read32(messagePointer + 24); // Mask pointer
|
||||
u32 dataPointer = mem.read32(messagePointer + 16); // Data pointer
|
||||
u32 maskPointer = mem.read32(messagePointer + 24); // Mask pointer
|
||||
|
||||
log("GSP::GPU::writeHwRegsWithMask (GPU address = %08X, size = %X, data address = %08X, mask address = %08X)\n",
|
||||
ioAddr, size, dataPointer, maskPointer);
|
||||
log("GSP::GPU::writeHwRegsWithMask (GPU address = %08X, size = %X, data address = %08X, mask address = %08X)\n", ioAddr, size, dataPointer,
|
||||
maskPointer);
|
||||
|
||||
// Check for alignment
|
||||
if ((size & 3) || (ioAddr & 3) || (dataPointer & 3) || (maskPointer & 3)) {
|
||||
|
@ -351,11 +351,11 @@ void GPUService::setInternalPriorities(u32 messagePointer) {
|
|||
}
|
||||
|
||||
void GPUService::processCommandBuffer() {
|
||||
if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet
|
||||
if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr int threadCount = 1; // TODO: More than 1 thread can have GSP commands at a time
|
||||
constexpr int threadCount = 1; // TODO: More than 1 thread can have GSP commands at a time
|
||||
for (int t = 0; t < threadCount; t++) {
|
||||
u8* cmdBuffer = &sharedMem[0x800 + t * 0x200];
|
||||
u8& commandsLeft = cmdBuffer[1];
|
||||
|
@ -408,9 +408,9 @@ void GPUService::memoryFill(u32* cmd) {
|
|||
u32 control = cmd[7];
|
||||
|
||||
// buf0 parameters
|
||||
u32 start0 = cmd[1]; // Start address for the fill. If 0, don't fill anything
|
||||
u32 value0 = cmd[2]; // Value to fill the framebuffer with
|
||||
u32 end0 = cmd[3]; // End address for the fill
|
||||
u32 start0 = cmd[1]; // Start address for the fill. If 0, don't fill anything
|
||||
u32 value0 = cmd[2]; // Value to fill the framebuffer with
|
||||
u32 end0 = cmd[3]; // End address for the fill
|
||||
u32 control0 = control & 0xffff;
|
||||
|
||||
// buf1 parameters
|
||||
|
@ -439,7 +439,7 @@ void GPUService::triggerDisplayTransfer(u32* cmd) {
|
|||
|
||||
log("GSP::GPU::TriggerDisplayTransfer (Stubbed)\n");
|
||||
gpu.displayTransfer(inputAddr, outputAddr, inputSize, outputSize, flags);
|
||||
requestInterrupt(GPUInterrupt::PPF); // Send "Display transfer finished" interrupt
|
||||
requestInterrupt(GPUInterrupt::PPF); // Send "Display transfer finished" interrupt
|
||||
}
|
||||
|
||||
void GPUService::triggerDMARequest(u32* cmd) {
|
||||
|
@ -453,22 +453,14 @@ void GPUService::triggerDMARequest(u32* cmd) {
|
|||
requestInterrupt(GPUInterrupt::DMA);
|
||||
}
|
||||
|
||||
void GPUService::flushCacheRegions(u32* cmd) {
|
||||
log("GSP::GPU::FlushCacheRegions (Stubbed)\n");
|
||||
}
|
||||
void GPUService::flushCacheRegions(u32* cmd) { log("GSP::GPU::FlushCacheRegions (Stubbed)\n"); }
|
||||
|
||||
void GPUService::setBufferSwapImpl(u32 screenId, const FramebufferInfo& info) {
|
||||
using namespace PICA::ExternalRegs;
|
||||
|
||||
static constexpr std::array<u32, 8> fbAddresses = {
|
||||
Framebuffer0AFirstAddr,
|
||||
Framebuffer0BFirstAddr,
|
||||
Framebuffer1AFirstAddr,
|
||||
Framebuffer1BFirstAddr,
|
||||
Framebuffer0ASecondAddr,
|
||||
Framebuffer0BSecondAddr,
|
||||
Framebuffer1ASecondAddr,
|
||||
Framebuffer1BSecondAddr,
|
||||
Framebuffer0AFirstAddr, Framebuffer0BFirstAddr, Framebuffer1AFirstAddr, Framebuffer1BFirstAddr,
|
||||
Framebuffer0ASecondAddr, Framebuffer0BSecondAddr, Framebuffer1ASecondAddr, Framebuffer1BSecondAddr,
|
||||
};
|
||||
|
||||
auto& regs = gpu.getExtRegisters();
|
||||
|
@ -478,12 +470,7 @@ void GPUService::setBufferSwapImpl(u32 screenId, const FramebufferInfo& info) {
|
|||
regs[fbAddresses[fbIndex + 1]] = VaddrToPaddr(info.rightFramebufferVaddr);
|
||||
|
||||
static constexpr std::array<u32, 6> configAddresses = {
|
||||
Framebuffer0Config,
|
||||
Framebuffer0Select,
|
||||
Framebuffer0Stride,
|
||||
Framebuffer1Config,
|
||||
Framebuffer1Select,
|
||||
Framebuffer1Stride,
|
||||
Framebuffer0Config, Framebuffer0Select, Framebuffer0Stride, Framebuffer1Config, Framebuffer1Select, Framebuffer1Stride,
|
||||
};
|
||||
|
||||
const u32 configIndex = screenId * 3;
|
||||
|
@ -494,14 +481,14 @@ void GPUService::setBufferSwapImpl(u32 screenId, const FramebufferInfo& info) {
|
|||
|
||||
// Actually send command list (aka display list) to GPU
|
||||
void GPUService::processCommandList(u32* cmd) {
|
||||
const u32 address = cmd[1] & ~7; // Buffer address
|
||||
const u32 size = cmd[2] & ~3; // Buffer size in bytes
|
||||
[[maybe_unused]] const bool updateGas = cmd[3] == 1; // Update gas additive blend results (0 = don't update, 1 = update)
|
||||
[[maybe_unused]] const bool flushBuffer = cmd[7] == 1; // Flush buffer (0 = don't flush, 1 = flush)
|
||||
const u32 address = cmd[1] & ~7; // Buffer address
|
||||
const u32 size = cmd[2] & ~3; // Buffer size in bytes
|
||||
[[maybe_unused]] const bool updateGas = cmd[3] == 1; // Update gas additive blend results (0 = don't update, 1 = update)
|
||||
[[maybe_unused]] const bool flushBuffer = cmd[7] == 1; // Flush buffer (0 = don't flush, 1 = flush)
|
||||
|
||||
log("GPU::GSP::processCommandList. Address: %08X, size in bytes: %08X\n", address, size);
|
||||
gpu.startCommandList(address, size);
|
||||
requestInterrupt(GPUInterrupt::P3D); // Send an IRQ when command list processing is over
|
||||
requestInterrupt(GPUInterrupt::P3D); // Send an IRQ when command list processing is over
|
||||
}
|
||||
|
||||
// TODO: Emulate the transfer engine & its registers
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include "services/gsp_lcd.hpp"
|
||||
|
||||
#include "ipc.hpp"
|
||||
|
||||
namespace LCDCommands {
|
||||
enum : u32 {
|
||||
SetLedForceOff = 0x00130040,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -11,6 +13,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);
|
||||
}
|
32
src/core/services/ns.cpp
Normal file
32
src/core/services/ns.cpp
Normal file
|
@ -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);
|
||||
Helpers::warn("NS::LaunchTitle (title ID = %llX, launch flags = %X) (stubbed)", titleID, launchFlags);
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x2, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write32(messagePointer + 8, 0); // Process ID
|
||||
}
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
ServiceManager::ServiceManager(std::span<u32, 16> 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), ndm(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;
|
||||
|
||||
|
@ -40,6 +40,7 @@ void ServiceManager::reset() {
|
|||
news_u.reset();
|
||||
nfc.reset();
|
||||
nim.reset();
|
||||
ns.reset();
|
||||
ptm.reset();
|
||||
soc.reset();
|
||||
ssl.reset();
|
||||
|
@ -99,19 +100,23 @@ static std::map<std::string, HorizonHandle> serviceMap = {
|
|||
{ "act:a", KernelHandles::ACT },
|
||||
{ "act:u", KernelHandles::ACT },
|
||||
{ "am:app", KernelHandles::AM },
|
||||
{ "am:sys", KernelHandles::AM },
|
||||
{ "APT:S", KernelHandles::APT }, // TODO: APT:A, APT:S and APT:U are slightly different
|
||||
{ "APT:A", KernelHandles::APT },
|
||||
{ "APT:U", KernelHandles::APT },
|
||||
{ "boss:U", KernelHandles::BOSS },
|
||||
{ "boss:P", KernelHandles::BOSS },
|
||||
{ "cam:u", KernelHandles::CAM },
|
||||
{ "cecd:u", KernelHandles::CECD },
|
||||
{ "cfg:u", KernelHandles::CFG_U },
|
||||
{ "cfg:i", KernelHandles::CFG_I },
|
||||
{ "cfg:s", KernelHandles::CFG_S },
|
||||
{ "cfg:nor", KernelHandles::CFG_NOR },
|
||||
{ "csnd:SND", KernelHandles::CSND },
|
||||
{ "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 },
|
||||
|
@ -126,11 +131,13 @@ static std::map<std::string, HorizonHandle> serviceMap = {
|
|||
{ "news:u", KernelHandles::NEWS_U },
|
||||
{ "nfc:u", KernelHandles::NFC },
|
||||
{ "ns:s", KernelHandles::NS_S },
|
||||
{ "nwm::EXT", KernelHandles::NWM_EXT },
|
||||
{ "nwm::UDS", KernelHandles::NWM_UDS },
|
||||
{ "nim:aoc", KernelHandles::NIM },
|
||||
{ "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 },
|
||||
|
@ -213,6 +220,7 @@ void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) {
|
|||
case KernelHandles::CFG_U: cfg.handleSyncRequest(messagePointer, CFGService::Type::U); break;
|
||||
case KernelHandles::CFG_I: cfg.handleSyncRequest(messagePointer, CFGService::Type::I); break;
|
||||
case KernelHandles::CFG_S: cfg.handleSyncRequest(messagePointer, CFGService::Type::S); break;
|
||||
case KernelHandles::CFG_NOR: cfg.handleSyncRequest(messagePointer, CFGService::Type::NOR); break;
|
||||
case KernelHandles::CSND: csnd.handleSyncRequest(messagePointer); break;
|
||||
case KernelHandles::DLP_SRVR: dlp_srvr.handleSyncRequest(messagePointer); break;
|
||||
case KernelHandles::HID: hid.handleSyncRequest(messagePointer); break;
|
||||
|
@ -228,11 +236,12 @@ void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) {
|
|||
case KernelHandles::NIM: nim.handleSyncRequest(messagePointer); 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_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;
|
||||
case KernelHandles::PTM_GETS: ptm.handleSyncRequest(messagePointer, PTMService::Type::GETS); break;
|
||||
case KernelHandles::SOC: soc.handleSyncRequest(messagePointer); break;
|
||||
case KernelHandles::SSL: ssl.handleSyncRequest(messagePointer); break;
|
||||
case KernelHandles::Y2R: y2r.handleSyncRequest(messagePointer); break;
|
||||
|
|
Loading…
Add table
Reference in a new issue