mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-09 07:35:41 +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;
|
u32 threadCount;
|
||||||
ServiceManager serviceManager;
|
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
|
// Get pointer to the object with the specified handle
|
||||||
KernelObject* getObject(Handle handle) {
|
KernelObject* getObject(Handle handle) {
|
||||||
// Accessing an object that has not been created
|
// Accessing an object that has not been created
|
||||||
|
@ -89,6 +92,7 @@ class Kernel {
|
||||||
void controlMemory();
|
void controlMemory();
|
||||||
void mapMemoryBlock();
|
void mapMemoryBlock();
|
||||||
void queryMemory();
|
void queryMemory();
|
||||||
|
void getProcessInfo();
|
||||||
void getResourceLimit();
|
void getResourceLimit();
|
||||||
void getResourceLimitLimitValues();
|
void getResourceLimitLimitValues();
|
||||||
void getResourceLimitCurrentValues();
|
void getResourceLimitCurrentValues();
|
||||||
|
@ -101,6 +105,7 @@ class Kernel {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Kernel(CPU& cpu, Memory& mem, GPU& gpu);
|
Kernel(CPU& cpu, Memory& mem, GPU& gpu);
|
||||||
|
void setVersion(u8 major, u8 minor);
|
||||||
void serviceSVC(u32 svc);
|
void serviceSVC(u32 svc);
|
||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
|
@ -5,6 +5,12 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
|
||||||
|
namespace PhysicalAddrs {
|
||||||
|
enum : u32 {
|
||||||
|
FCRAM = 0x20000000
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace VirtualAddrs {
|
namespace VirtualAddrs {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
ExecutableStart = 0x00100000,
|
ExecutableStart = 0x00100000,
|
||||||
|
@ -18,7 +24,8 @@ namespace VirtualAddrs {
|
||||||
StackSize = 0x4000,
|
StackSize = 0x4000,
|
||||||
|
|
||||||
NormalHeapStart = 0x08000000,
|
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
|
// Start of TLS for first thread. Next thread's storage will be at TLSBase + 0x1000, and so on
|
||||||
TLSBase = 0xFF400000,
|
TLSBase = 0xFF400000,
|
||||||
|
@ -87,6 +94,7 @@ class Memory {
|
||||||
std::optional<u32> findPaddr(u32 size);
|
std::optional<u32> findPaddr(u32 size);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
u16 kernelVersion = 0;
|
||||||
u32 usedUserMemory = 0;
|
u32 usedUserMemory = 0;
|
||||||
std::optional<int> gspMemIndex; // Index of GSP shared mem in lockedMemoryInfo or nullopt if it's already reserved
|
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 write32(u32 vaddr, u32 value);
|
||||||
void write64(u32 vaddr, u64 value);
|
void write64(u32 vaddr, u64 value);
|
||||||
|
|
||||||
|
u32 getLinearHeapVaddr();
|
||||||
|
|
||||||
// Returns whether "addr" is aligned to a page (4096 byte) boundary
|
// Returns whether "addr" is aligned to a page (4096 byte) boundary
|
||||||
static constexpr bool isAligned(u32 addr) {
|
static constexpr bool isAligned(u32 addr) {
|
||||||
return (addr & pageMask) == 0;
|
return (addr & pageMask) == 0;
|
||||||
|
|
|
@ -35,8 +35,9 @@ std::optional<u32> Memory::loadELF(std::ifstream& file) {
|
||||||
u64 endAddress = (u64)vaddr + (u64)fileSize;
|
u64 endAddress = (u64)vaddr + (u64)fileSize;
|
||||||
const bool isGood = vaddr >= VirtualAddrs::ExecutableStart && endAddress < VirtualAddrs::ExecutableEnd;
|
const bool isGood = vaddr >= VirtualAddrs::ExecutableStart && endAddress < VirtualAddrs::ExecutableEnd;
|
||||||
if (!isGood) {
|
if (!isGood) {
|
||||||
Helpers::panic("ELF is loaded at invalid place");
|
// We're ignoring this for now because some ELFs define a segment at the vaddr for IPC buffer mapping
|
||||||
return std::nullopt;
|
// Helpers::panic("ELF is loaded at invalid place");
|
||||||
|
// return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memorySize & pageMask) {
|
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].tlsBase = VirtualAddrs::TLSBase + i * VirtualAddrs::TLSSize;
|
||||||
threads[i].status = ThreadStatus::Dead;
|
threads[i].status = ThreadStatus::Dead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setVersion(1, 69);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::serviceSVC(u32 svc) {
|
void Kernel::serviceSVC(u32 svc) {
|
||||||
|
@ -27,6 +29,7 @@ void Kernel::serviceSVC(u32 svc) {
|
||||||
case 0x23: svcCloseHandle(); break;
|
case 0x23: svcCloseHandle(); break;
|
||||||
case 0x24: waitSynchronization1(); break;
|
case 0x24: waitSynchronization1(); break;
|
||||||
case 0x28: getSystemTick(); break;
|
case 0x28: getSystemTick(); break;
|
||||||
|
case 0x2B: getProcessInfo(); break;
|
||||||
case 0x2D: connectToPort(); break;
|
case 0x2D: connectToPort(); break;
|
||||||
case 0x32: sendSyncRequest(); break;
|
case 0x32: sendSyncRequest(); break;
|
||||||
case 0x38: getResourceLimit(); 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() {
|
Handle Kernel::makeProcess() {
|
||||||
const Handle processHandle = makeObject(KernelObjectType::Process);
|
const Handle processHandle = makeObject(KernelObjectType::Process);
|
||||||
const Handle resourceLimitHandle = makeObject(KernelObjectType::ResourceLimit);
|
const Handle resourceLimitHandle = makeObject(KernelObjectType::ResourceLimit);
|
||||||
|
@ -129,6 +139,30 @@ void Kernel::outputDebugString() {
|
||||||
regs[0] = SVCResult::Success;
|
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) {
|
std::string Kernel::getProcessName(u32 pid) {
|
||||||
if (pid == KernelHandles::CurrentProcess) {
|
if (pid == KernelHandles::CurrentProcess) {
|
||||||
return "current";
|
return "current";
|
||||||
|
|
|
@ -56,7 +56,8 @@ u8 Memory::read8(u32 vaddr) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
switch (vaddr) {
|
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);
|
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 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,
|
std::optional<u32> Memory::allocateMemory(u32 vaddr, u32 paddr, u32 size, bool linear, bool r, bool w, bool x,
|
||||||
bool adjustAddrs) {
|
bool adjustAddrs) {
|
||||||
// Kernel-allocated memory & size must always be aligned to a page boundary
|
// 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.
|
// Get the full vaddr.
|
||||||
// TODO: Fix this
|
// TODO: Fix this
|
||||||
if (vaddr == 0 && adjustAddrs) {
|
if (vaddr == 0 && adjustAddrs) {
|
||||||
vaddr = usedUserMemory + (linear ? VirtualAddrs::LinearHeapStart : VirtualAddrs::NormalHeapStart);
|
vaddr = usedUserMemory + (linear ? getLinearHeapVaddr() : VirtualAddrs::NormalHeapStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
usedUserMemory += size;
|
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
|
// Find a paddr which we can use for allocating "size" bytes
|
||||||
std::optional<u32> Memory::findPaddr(u32 size) {
|
std::optional<u32> Memory::findPaddr(u32 size) {
|
||||||
|
assert(isAligned(size));
|
||||||
const u32 neededPages = size / pageSize;
|
const u32 neededPages = size / pageSize;
|
||||||
|
|
||||||
// The FCRAM page we're testing to see if it's appropriate to use
|
// 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
|
else { // Our candidate page has 1 mor
|
||||||
counter++;
|
counter++;
|
||||||
// Check if there's enough free memory to use this page
|
// 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;
|
return candidatePage * pageSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,7 +251,7 @@ void GPUService::memoryFill(u32* cmd) {
|
||||||
|
|
||||||
// Actually send command list (aka display list) to GPU
|
// Actually send command list (aka display list) to GPU
|
||||||
void GPUService::processCommandList(u32* cmd) {
|
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
|
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 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)
|
bool flushBuffer = cmd[7] == 1; // Flush buffer (0 = don't flush, 1 = flush)
|
||||||
|
|
Loading…
Add table
Reference in a new issue