mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-07 14:45:41 +12:00
Merge pull request #79 from wheremyfoodat/stacc-the-raccs
Better ROM management sorta, implement NCSD/CXI main thread stack properly
This commit is contained in:
commit
4d3625b7bb
6 changed files with 76 additions and 15 deletions
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
|
||||
#include "PICA/gpu.hpp"
|
||||
#include "cpu.hpp"
|
||||
|
@ -25,7 +26,7 @@ class Emulator {
|
|||
GLStateManager gl;
|
||||
SDL_Window* window;
|
||||
SDL_GLContext glContext;
|
||||
SDL_GameController* gameController;
|
||||
SDL_GameController* gameController = nullptr;
|
||||
int gameControllerID;
|
||||
|
||||
// Variables to keep track of whether the user is controlling the 3DS analog stick with their keyboard
|
||||
|
@ -44,6 +45,8 @@ class Emulator {
|
|||
std::ifstream loadedELF;
|
||||
NCSD loadedNCSD;
|
||||
|
||||
std::optional<std::filesystem::path> romPath = std::nullopt;
|
||||
|
||||
public:
|
||||
Emulator();
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ namespace VirtualAddrs {
|
|||
// Stack for main ARM11 thread.
|
||||
// Typically 0x4000 bytes, determined by exheader
|
||||
StackTop = 0x10000000,
|
||||
StackBottom = 0x0FFFC000,
|
||||
DefaultStackSize = 0x4000,
|
||||
|
||||
NormalHeapStart = 0x08000000,
|
||||
|
@ -248,4 +247,5 @@ public:
|
|||
u32 getUsedUserMem() { return usedUserMemory; }
|
||||
|
||||
void setVRAM(u8* pointer) { vram = pointer; }
|
||||
bool allocateMainThreadStack(u32 size);
|
||||
};
|
|
@ -14,6 +14,13 @@ std::optional<u32> Memory::loadELF(std::ifstream& file) {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Allocate stack space. For ELFs we use the default stack size, which is 16KB
|
||||
if (!allocateMainThreadStack(VirtualAddrs::DefaultStackSize)) {
|
||||
// Should be unreachable
|
||||
printf("Failed to allocate stack space for ELF file\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto segNum = reader.segments.size();
|
||||
printf("Number of segments: %d\n", segNum);
|
||||
printf(" # Perms Vaddr File Size Mem Size\n");
|
||||
|
|
|
@ -9,6 +9,27 @@ bool Memory::mapCXI(NCSD& ncsd, NCCH& cxi) {
|
|||
printf("Text address = %08X, size = %08X\n", cxi.text.address, cxi.text.size);
|
||||
printf("Rodata address = %08X, size = %08X\n", cxi.rodata.address, cxi.rodata.size);
|
||||
printf("Data address = %08X, size = %08X\n", cxi.data.address, cxi.data.size);
|
||||
printf("Stack size: %08X\n", cxi.stackSize);
|
||||
|
||||
if (!isAligned(cxi.stackSize)) {
|
||||
Helpers::warn("CXI has a suspicious stack size of %08X which is not a multiple of 4KB", cxi.stackSize);
|
||||
}
|
||||
|
||||
// Round up the size of the CXI stack size to a page (4KB) boundary, as the OS can only allocate memory this way
|
||||
u32 stackSize = (cxi.stackSize + pageSize - 1) & -pageSize;
|
||||
|
||||
if (stackSize > 512_KB) {
|
||||
// TODO: Figure out the actual max stack size
|
||||
Helpers::warn("CXI stack size is %08X which seems way too big. Clamping to 512KB", stackSize);
|
||||
stackSize = 512_KB;
|
||||
}
|
||||
|
||||
// Allocate stack
|
||||
if (!allocateMainThreadStack(stackSize)) {
|
||||
// Should be unreachable
|
||||
printf("Failed to allocate stack for CXI partition. Requested stack size: %08X\n", stackSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map code file to memory
|
||||
auto& code = cxi.codeFile;
|
||||
|
|
|
@ -28,16 +28,16 @@ void Memory::reset() {
|
|||
writeTable[i] = 0;
|
||||
}
|
||||
|
||||
// Map stack pages as R/W
|
||||
// We have 16KB for the stack, so we allocate the last 16KB of APPLICATION FCRAM for the stack
|
||||
u32 basePaddrForStack = FCRAM_APPLICATION_SIZE - VirtualAddrs::DefaultStackSize;
|
||||
allocateMemory(VirtualAddrs::StackBottom, basePaddrForStack, VirtualAddrs::DefaultStackSize, true);
|
||||
// Map (32 * 4) KB of FCRAM before the stack for the TLS of each thread
|
||||
std::optional<u32> tlsBaseOpt = findPaddr(32 * 4_KB);
|
||||
if (!tlsBaseOpt.has_value()) { // Should be unreachable but still good to have
|
||||
Helpers::panic("Failed to allocate memory for thread-local storage");
|
||||
}
|
||||
|
||||
// And map (4 * 32)KB of FCRAM before the stack for the TLS of each thread
|
||||
u32 basePaddrForTLS = basePaddrForStack;
|
||||
u32 basePaddrForTLS = tlsBaseOpt.value();
|
||||
for (int i = 0; i < appResourceLimits.maxThreads; i++) {
|
||||
u32 vaddr = VirtualAddrs::TLSBase + i * VirtualAddrs::TLSSize;
|
||||
basePaddrForTLS -= VirtualAddrs::TLSSize;
|
||||
basePaddrForTLS += VirtualAddrs::TLSSize;
|
||||
allocateMemory(vaddr, basePaddrForTLS, VirtualAddrs::TLSSize, true);
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,18 @@ void Memory::reset() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Memory::allocateMainThreadStack(u32 size) {
|
||||
// Map stack pages as R/W
|
||||
std::optional<u32> basePaddr = findPaddr(size);
|
||||
if (!basePaddr.has_value()) { // Should also be unreachable but still good to have
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 stackBottom = VirtualAddrs::StackTop - size;
|
||||
std::optional<u32> result = allocateMemory(stackBottom, basePaddr.value(), size, true); // Should never be nullopt
|
||||
return result.has_value();
|
||||
}
|
||||
|
||||
u8 Memory::read8(u32 vaddr) {
|
||||
const u32 page = vaddr >> pageShift;
|
||||
const u32 offset = vaddr & pageMask;
|
||||
|
|
|
@ -63,8 +63,16 @@ void Emulator::reset() {
|
|||
// Reloading r13 and r15 needs to happen after everything has been reset
|
||||
// Otherwise resetting the kernel or cpu might nuke them
|
||||
cpu.setReg(13, VirtualAddrs::StackTop); // Set initial SP
|
||||
if (romType == ROMType::ELF) { // Reload ELF if we're using one
|
||||
loadELF(loadedELF);
|
||||
|
||||
// If a ROM is active and we reset, reload it. This is necessary to set up stack, executable memory, .data/.rodata/.bss all over again
|
||||
if (romType != ROMType::None && romPath.has_value()) {
|
||||
bool success = loadROM(romPath.value());
|
||||
if (!success) {
|
||||
romType = ROMType::None;
|
||||
romPath = std::nullopt;
|
||||
|
||||
Helpers::panic("Failed to reload ROM. This should pause the emulator in the future GUI");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,17 +292,27 @@ bool Emulator::loadROM(const std::filesystem::path& path) {
|
|||
|
||||
kernel.initializeFS();
|
||||
auto extension = path.extension();
|
||||
bool success; // Tracks if we loaded the ROM successfully
|
||||
|
||||
if (extension == ".elf" || extension == ".axf")
|
||||
return loadELF(path);
|
||||
success = loadELF(path);
|
||||
else if (extension == ".3ds")
|
||||
return loadNCSD(path, ROMType::NCSD);
|
||||
success = loadNCSD(path, ROMType::NCSD);
|
||||
else if (extension == ".cxi" || extension == ".app")
|
||||
return loadNCSD(path, ROMType::CXI);
|
||||
success = loadNCSD(path, ROMType::CXI);
|
||||
else {
|
||||
printf("Unknown file type\n");
|
||||
return false;
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
romPath = path;
|
||||
} else {
|
||||
romPath = std::nullopt;
|
||||
romType = ROMType::None;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Used for loading both CXI and NCSD files since they are both so similar and use the same interface
|
||||
|
|
Loading…
Add table
Reference in a new issue