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