mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-07 06:35:40 +12:00
[Kernel, Memory] Add GetProcessInfo, fix memory management bugs
This commit is contained in:
parent
71ca62e2cc
commit
db48d08c34
6 changed files with 66 additions and 7 deletions
|
@ -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();
|
||||
};
|
|
@ -5,6 +5,12 @@
|
|||
#include <vector>
|
||||
#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<u32> findPaddr(u32 size);
|
||||
|
||||
public:
|
||||
u16 kernelVersion = 0;
|
||||
u32 usedUserMemory = 0;
|
||||
std::optional<int> 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;
|
||||
|
|
|
@ -35,8 +35,9 @@ std::optional<u32> 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) {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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<u32> 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<u32> 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<u32> Memory::allocateMemory(u32 vaddr, u32 paddr, u32 size, bool l
|
|||
|
||||
// Find a paddr which we can use for allocating "size" bytes
|
||||
std::optional<u32> 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<u32> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue