diff --git a/include/logger.hpp b/include/logger.hpp index 2ad9e713..82d90410 100644 --- a/include/logger.hpp +++ b/include/logger.hpp @@ -53,6 +53,7 @@ namespace Log { static Logger micLogger; static Logger newsLogger; static Logger nfcLogger; + static Logger nwmUdsLogger; static Logger nimLogger; static Logger ndmLogger; static Logger ptmLogger; diff --git a/include/services/csnd.hpp b/include/services/csnd.hpp index 7b99dee0..8f6d60f8 100644 --- a/include/services/csnd.hpp +++ b/include/services/csnd.hpp @@ -15,15 +15,22 @@ class CSNDService { Kernel& kernel; MAKE_LOG_FUNCTION(log, csndLogger) - bool initialized = false; + u8* sharedMemory = nullptr; std::optional csndMutex = std::nullopt; + size_t sharedMemSize = 0; + bool initialized = false; // Service functions void acquireSoundChannels(u32 messagePointer); + void executeCommands(u32 messagePointer); void initialize(u32 messagePointer); public: CSNDService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {} void reset(); void handleSyncRequest(u32 messagePointer); + + void setSharedMemory(u8* ptr) { + sharedMemory = ptr; + } }; \ No newline at end of file diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index 5d1b37ce..93700498 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -103,6 +103,7 @@ class ServiceManager { void sendGPUInterrupt(GPUInterrupt type) { gsp_gpu.requestInterrupt(type); } void setGSPSharedMem(u8* ptr) { gsp_gpu.setSharedMem(ptr); } void setHIDSharedMem(u8* ptr) { hid.setSharedMem(ptr); } + void setCSNDSharedMem(u8* ptr) { csnd.setSharedMemory(ptr); } void signalDSPEvents() { dsp.signalEvents(); } diff --git a/src/core/kernel/memory_management.cpp b/src/core/kernel/memory_management.cpp index a5557c6d..e90a5697 100644 --- a/src/core/kernel/memory_management.cpp +++ b/src/core/kernel/memory_management.cpp @@ -139,7 +139,10 @@ void Kernel::mapMemoryBlock() { mem.copySharedFont(ptr); break; - case KernelHandles::CSNDSharedMemHandle: printf("Mapping CSND memory block\n"); break; + case KernelHandles::CSNDSharedMemHandle: + serviceManager.setCSNDSharedMem(ptr); + printf("Mapping CSND memory block\n"); + break; default: Helpers::panic("Mapping unknown shared memory block: %X", block); } diff --git a/src/core/services/csnd.cpp b/src/core/services/csnd.cpp index 5f9a950a..4c86c471 100644 --- a/src/core/services/csnd.cpp +++ b/src/core/services/csnd.cpp @@ -7,6 +7,7 @@ namespace CSNDCommands { enum : u32 { Initialize = 0x00010140, + ExecuteCommands = 0x00030040, AcquireSoundChannels = 0x00050000, }; } @@ -14,6 +15,8 @@ namespace CSNDCommands { void CSNDService::reset() { csndMutex = std::nullopt; initialized = false; + sharedMemory = nullptr; + sharedMemSize = 0; } void CSNDService::handleSyncRequest(u32 messagePointer) { @@ -21,6 +24,7 @@ void CSNDService::handleSyncRequest(u32 messagePointer) { switch (command) { case CSNDCommands::AcquireSoundChannels: acquireSoundChannels(messagePointer); break; + case CSNDCommands::ExecuteCommands: executeCommands(messagePointer); break; case CSNDCommands::Initialize: initialize(messagePointer); break; default: @@ -65,10 +69,36 @@ void CSNDService::initialize(u32 messagePointer) { } initialized = true; + sharedMemSize = blockSize; mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 3)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, 0x4000000); mem.write32(messagePointer + 12, csndMutex.value()); mem.write32(messagePointer + 16, KernelHandles::CSNDSharedMemHandle); +} + +void CSNDService::executeCommands(u32 messagePointer) { + const u32 offset = mem.read32(messagePointer + 4); + log("CSND::ExecuteCommands (command offset = %X)\n", offset); + + mem.write32(messagePointer, IPC::responseHeader(0x5, 2, 0)); + + if (!sharedMemory) { + Helpers::warn("CSND::Execute commands without shared memory"); + mem.write32(messagePointer + 4, Result::FailurePlaceholder); + return; + } + + mem.write32(messagePointer + 4, Result::Success); + + // This is initially zero when this command data is written by the user process, once the CSND module finishes processing the command this is set + // to 0x1. This flag is only set to value 1 for the first command(once processing for the entire command chain is finished) at the offset + // specified in the service command, not all type0 commands in the chain. + constexpr u32 commandListDoneOffset = 0x4; + + // Make sure to not access OoB of the shared memory block when marking command list processing as finished + if (offset + commandListDoneOffset < sharedMemSize) { + sharedMemory[offset + commandListDoneOffset] = 1; + } } \ No newline at end of file