From db48d08c3452c0e1780bb02cd25371f9ab452792 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Wed, 21 Sep 2022 22:43:43 +0300 Subject: [PATCH] [Kernel, Memory] Add GetProcessInfo, fix memory management bugs --- include/kernel/kernel.hpp | 5 +++++ include/memory.hpp | 12 +++++++++++- src/core/elf.cpp | 5 +++-- src/core/kernel/kernel.cpp | 34 ++++++++++++++++++++++++++++++++++ src/core/memory.cpp | 15 ++++++++++++--- src/core/services/gsp_gpu.cpp | 2 +- 6 files changed, 66 insertions(+), 7 deletions(-) diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index 20a28657..d9b01aee 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -30,6 +30,9 @@ class Kernel { u32 threadCount; ServiceManager serviceManager; + // Top 8 bits are the major version, bottom 8 are the minor version + u16 kernelVersion = 0; + // Get pointer to the object with the specified handle KernelObject* getObject(Handle handle) { // Accessing an object that has not been created @@ -89,6 +92,7 @@ class Kernel { void controlMemory(); void mapMemoryBlock(); void queryMemory(); + void getProcessInfo(); void getResourceLimit(); void getResourceLimitLimitValues(); void getResourceLimitCurrentValues(); @@ -101,6 +105,7 @@ class Kernel { public: Kernel(CPU& cpu, Memory& mem, GPU& gpu); + void setVersion(u8 major, u8 minor); void serviceSVC(u32 svc); void reset(); }; \ No newline at end of file diff --git a/include/memory.hpp b/include/memory.hpp index c5b7330f..1f66b8ff 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -5,6 +5,12 @@ #include #include "helpers.hpp" +namespace PhysicalAddrs { + enum : u32 { + FCRAM = 0x20000000 + }; +} + namespace VirtualAddrs { enum : u32 { ExecutableStart = 0x00100000, @@ -18,7 +24,8 @@ namespace VirtualAddrs { StackSize = 0x4000, NormalHeapStart = 0x08000000, - LinearHeapStart = 0x14000000, + LinearHeapStartOld = 0x14000000, // If kernel version < + LinearHeapStartNew = 0x30000000, // Start of TLS for first thread. Next thread's storage will be at TLSBase + 0x1000, and so on TLSBase = 0xFF400000, @@ -87,6 +94,7 @@ class Memory { std::optional findPaddr(u32 size); public: + u16 kernelVersion = 0; u32 usedUserMemory = 0; std::optional gspMemIndex; // Index of GSP shared mem in lockedMemoryInfo or nullopt if it's already reserved @@ -107,6 +115,8 @@ public: void write32(u32 vaddr, u32 value); void write64(u32 vaddr, u64 value); + u32 getLinearHeapVaddr(); + // Returns whether "addr" is aligned to a page (4096 byte) boundary static constexpr bool isAligned(u32 addr) { return (addr & pageMask) == 0; diff --git a/src/core/elf.cpp b/src/core/elf.cpp index 5f668400..899137c3 100644 --- a/src/core/elf.cpp +++ b/src/core/elf.cpp @@ -35,8 +35,9 @@ std::optional Memory::loadELF(std::ifstream& file) { u64 endAddress = (u64)vaddr + (u64)fileSize; const bool isGood = vaddr >= VirtualAddrs::ExecutableStart && endAddress < VirtualAddrs::ExecutableEnd; if (!isGood) { - Helpers::panic("ELF is loaded at invalid place"); - return std::nullopt; + // We're ignoring this for now because some ELFs define a segment at the vaddr for IPC buffer mapping + // Helpers::panic("ELF is loaded at invalid place"); + // return std::nullopt; } if (memorySize & pageMask) { diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index 74fce4a6..1a475c73 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -12,6 +12,8 @@ Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu) threads[i].tlsBase = VirtualAddrs::TLSBase + i * VirtualAddrs::TLSSize; threads[i].status = ThreadStatus::Dead; } + + setVersion(1, 69); } void Kernel::serviceSVC(u32 svc) { @@ -27,6 +29,7 @@ void Kernel::serviceSVC(u32 svc) { case 0x23: svcCloseHandle(); break; case 0x24: waitSynchronization1(); break; case 0x28: getSystemTick(); break; + case 0x2B: getProcessInfo(); break; case 0x2D: connectToPort(); break; case 0x32: sendSyncRequest(); break; case 0x38: getResourceLimit(); break; @@ -37,6 +40,13 @@ void Kernel::serviceSVC(u32 svc) { } } +void Kernel::setVersion(u8 major, u8 minor) { + u16 descriptor = (u16(major) << 8) | u16(minor); + + kernelVersion = descriptor; + mem.kernelVersion = descriptor; // The memory objects needs a copy because you can read the kernel ver from config mem +} + Handle Kernel::makeProcess() { const Handle processHandle = makeObject(KernelObjectType::Process); const Handle resourceLimitHandle = makeObject(KernelObjectType::ResourceLimit); @@ -129,6 +139,30 @@ void Kernel::outputDebugString() { regs[0] = SVCResult::Success; } +void Kernel::getProcessInfo() { + const auto pid = regs[1]; + const auto type = regs[2]; + const auto process = getProcessFromPID(pid); + printf("GetProcessInfo(process: %s, type = %d)\n", getProcessName(pid).c_str(), type); + + if (process == nullptr) [[unlikely]] { + regs[0] = SVCResult::BadHandle; + return; + } + + switch (type) { + case 20: + regs[1] = PhysicalAddrs::FCRAM - mem.getLinearHeapVaddr(); + regs[2] = 0; + break; + + default: + Helpers::panic("GetProcessInfo: unimplemented type %d", type); + } + + regs[0] = SVCResult::Success; +} + std::string Kernel::getProcessName(u32 pid) { if (pid == KernelHandles::CurrentProcess) { return "current"; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 75978eb6..d16e2808 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -56,7 +56,8 @@ u8 Memory::read8(u32 vaddr) { } else { switch (vaddr) { - case ConfigMem::KernelVersionMinor: return 38; + case ConfigMem::KernelVersionMinor: return u8(kernelVersion & 0xff); + case ConfigMem::KernelVersionMajor: return u8(kernelVersion >> 8); default: Helpers::panic("Unimplemented 8-bit read, addr: %08X", vaddr); } } @@ -169,6 +170,12 @@ std::string Memory::readString(u32 address, u32 maxSize) { return string; } +// Return a pointer to the linear heap vaddr based on the kernel ver, because it needed to be moved +// thanks to the New 3DS having more FCRAM +u32 Memory::getLinearHeapVaddr() { + return (kernelVersion < 0x22C) ? VirtualAddrs::LinearHeapStartOld : VirtualAddrs::LinearHeapStartNew; +} + std::optional Memory::allocateMemory(u32 vaddr, u32 paddr, u32 size, bool linear, bool r, bool w, bool x, bool adjustAddrs) { // Kernel-allocated memory & size must always be aligned to a page boundary @@ -190,7 +197,7 @@ std::optional Memory::allocateMemory(u32 vaddr, u32 paddr, u32 size, bool l // Get the full vaddr. // TODO: Fix this if (vaddr == 0 && adjustAddrs) { - vaddr = usedUserMemory + (linear ? VirtualAddrs::LinearHeapStart : VirtualAddrs::NormalHeapStart); + vaddr = usedUserMemory + (linear ? getLinearHeapVaddr() : VirtualAddrs::NormalHeapStart); } usedUserMemory += size; @@ -234,6 +241,7 @@ std::optional Memory::allocateMemory(u32 vaddr, u32 paddr, u32 size, bool l // Find a paddr which we can use for allocating "size" bytes std::optional Memory::findPaddr(u32 size) { + assert(isAligned(size)); const u32 neededPages = size / pageSize; // The FCRAM page we're testing to see if it's appropriate to use @@ -250,7 +258,8 @@ std::optional Memory::findPaddr(u32 size) { else { // Our candidate page has 1 mor counter++; // Check if there's enough free memory to use this page - if (counter == neededPages) { + // We use == instead of >= because some software does 0-byte allocations + if (counter >= neededPages) { return candidatePage * pageSize; } } diff --git a/src/core/services/gsp_gpu.cpp b/src/core/services/gsp_gpu.cpp index a5d5186e..1d67a3e0 100644 --- a/src/core/services/gsp_gpu.cpp +++ b/src/core/services/gsp_gpu.cpp @@ -251,7 +251,7 @@ void GPUService::memoryFill(u32* cmd) { // Actually send command list (aka display list) to GPU void GPUService::processCommandList(u32* cmd) { - u32 address = cmd[1]; // Buffer address + u32 address = cmd[1] & ~7; // Buffer address u32 size = cmd[2] * 8; // Buffer size in bytes bool updateGas = cmd[3] == 1; // Update gas additive blend results (0 = don't update, 1 = update) bool flushBuffer = cmd[7] == 1; // Flush buffer (0 = don't flush, 1 = flush)