From 46cf049e3bc6b36d7101de6b53c1c09df2826527 Mon Sep 17 00:00:00 2001
From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com>
Date: Sun, 10 Sep 2023 23:00:26 +0300
Subject: [PATCH] Add CSND::ExecuteCommands

---
 include/logger.hpp                    |  1 +
 include/services/csnd.hpp             |  9 +++++++-
 include/services/service_manager.hpp  |  1 +
 src/core/kernel/memory_management.cpp |  5 ++++-
 src/core/services/csnd.cpp            | 30 +++++++++++++++++++++++++++
 5 files changed, 44 insertions(+), 2 deletions(-)

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<false> micLogger;
 	static Logger<false> newsLogger;
 	static Logger<false> nfcLogger;
+	static Logger<false> nwmUdsLogger;
 	static Logger<false> nimLogger;
 	static Logger<false> ndmLogger;
 	static Logger<false> 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<Handle> 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