From 2128d5060bfbafa3452f74a802f0fd898abcc17a Mon Sep 17 00:00:00 2001
From: wheremyfoodat <gponiris2004@gmail.com>
Date: Fri, 16 Sep 2022 17:34:03 +0300
Subject: [PATCH] Start implementing ControlMemory

---
 CMakeLists.txt                        |  5 ++-
 include/kernel/kernel.hpp             |  1 +
 src/core/kernel/kernel.cpp            |  1 +
 src/core/kernel/memory_management.cpp | 64 +++++++++++++++++++++++++++
 4 files changed, 70 insertions(+), 1 deletion(-)
 create mode 100644 src/core/kernel/memory_management.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d8fcfba0..35e60fcc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -47,7 +47,10 @@ endif()
 set(SOURCE_FILES src/main.cpp src/emulator.cpp src/core/CPU/cpu_dynarmic.cpp src/core/memory.cpp src/core/elf.cpp
                  
                  )
-set(KERNEL_SOURCE_FILES src/core/kernel/kernel.cpp src/core/kernel/resource_limits.cpp)
+set(KERNEL_SOURCE_FILES src/core/kernel/kernel.cpp src/core/kernel/resource_limits.cpp
+                        src/core/kernel/memory_management.cpp
+)
+
 set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp include/termcolor.hpp
                  include/cpu.hpp include/cpu_dynarmic.hpp include/memory.hpp include/kernel/kernel.hpp
                  include/dynarmic_cp15.hpp include/kernel/resource_limits.hpp include/kernel/kernel_types.hpp
diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp
index 579c8631..e8e5250a 100644
--- a/include/kernel/kernel.hpp
+++ b/include/kernel/kernel.hpp
@@ -53,6 +53,7 @@ class Kernel {
 	std::string getProcessName(u32 pid);
 
 	// SVC implementations
+	void controlMemory();
 	void createAddressArbiter();
 	void getResourceLimit();
 	void getResourceLimitLimitValues();
diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp
index c2f353af..691d26a7 100644
--- a/src/core/kernel/kernel.cpp
+++ b/src/core/kernel/kernel.cpp
@@ -4,6 +4,7 @@
 
 void Kernel::serviceSVC(u32 svc) {
 	switch (svc) {
+		case 0x01: controlMemory(); break;
 		case 0x21: createAddressArbiter(); break;
 		case 0x23: svcCloseHandle(); break;
 		case 0x38: getResourceLimit(); break;
diff --git a/src/core/kernel/memory_management.cpp b/src/core/kernel/memory_management.cpp
new file mode 100644
index 00000000..b86bef74
--- /dev/null
+++ b/src/core/kernel/memory_management.cpp
@@ -0,0 +1,64 @@
+#include "kernel.hpp"
+
+namespace Operation {
+	enum : u32 {
+		Free = 1,
+		Reserve = 2,
+		Commit = 3,
+		Map = 4,
+		Unmap = 5,
+		Protect = 6,
+		AppRegion = 0x100,
+		SysRegion = 0x200,
+		BaseRegion = 0x300,
+		Linear = 0x10000
+	};
+}
+
+// Returns whether "value" is aligned to a page boundary (Ie a boundary of 4096 bytes)
+static constexpr bool isAligned(u32 value) {
+	return (value & 0xFFF) == 0;
+}
+
+// Result ControlMemory(u32* outaddr, u32 addr0, u32 addr1, u32 size, 
+//						MemoryOperation operation, MemoryPermission permissions)
+// This has a weird ABI documented here https://www.3dbrew.org/wiki/Kernel_ABI
+void Kernel::controlMemory() {
+	u32 operation = regs[0]; // The base address is written here
+	u32 addr0 = regs[1];
+	u32 addr1 = regs[2];
+	u32 size = regs[3];
+	u32 perms = regs[4];
+
+	if (perms == 0x10000000) {
+		perms = 3; // We make "don't care" equivalent to read-write
+		Helpers::panic("Unimplemented allocation permission: DONTCARE");
+	}
+
+	// Naturally the bits are in reverse order
+	bool r = perms & 0b001;
+	bool w = perms & 0b010;
+	bool x = perms & 0b100;
+	bool linear = operation & Operation::Linear;
+
+	if (x)
+		Helpers::panic("ControlMemory: attempted to allocate executable memory");
+
+	if (!isAligned(addr0) || !isAligned(addr1) || !isAligned(size)) {
+		Helpers::panic("ControlMemory: Unaligned parameters\nAddr0: %08X\nAddr1: %08X\nSize: %08X", addr0, addr1, size);
+	}
+	
+	printf("ControlMemory(addr0 = %08X, addr1 = %08X, size = %X, operation = %X (%c%c%c)%s\n",
+			addr0, addr1, size, operation, r ? 'r' : '-', w ? 'w' : '-', x ? 'x' : '-', linear ? ", linear" : ""
+	);
+
+	switch (operation & 0xFF) {
+		case Operation::Commit:
+			break;
+
+		default: Helpers::panic("ControlMemory: unknown operation %X\n", operation);
+	}
+
+	regs[0] = SVCResult::Success;
+	regs[1] = 0xF3180131;
+}
\ No newline at end of file