mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-12 09:09:47 +12:00
Merge 0b41ecaa18
into 54a78902bc
This commit is contained in:
commit
1d66cac12e
8 changed files with 79 additions and 25 deletions
|
@ -48,6 +48,9 @@ struct NCCH {
|
|||
bool seedCrypto = false;
|
||||
u8 secondaryKeySlot = 0;
|
||||
|
||||
// Contains info such as the ideal processor for threads, affinity mask, and how much memory should be reserved for the application
|
||||
u8 flag0 = 0;
|
||||
|
||||
static constexpr u64 mediaUnit = 0x200;
|
||||
u64 size = 0; // Size of NCCH converted to bytes
|
||||
u64 saveDataSize = 0;
|
||||
|
|
|
@ -131,16 +131,21 @@ public:
|
|||
static constexpr u32 pageMask = pageSize - 1;
|
||||
static constexpr u32 totalPageCount = 1 << (32 - pageShift);
|
||||
|
||||
static constexpr u32 FCRAM_SIZE = u32(128_MB);
|
||||
static constexpr u32 FCRAM_APPLICATION_SIZE = u32(64_MB);
|
||||
// TODO: All of these change on N3DS
|
||||
static constexpr u32 FCRAM_SIZE = u32(128_MB); // Total amount of FCRAM
|
||||
static constexpr u32 FCRAM_PAGE_COUNT = FCRAM_SIZE / pageSize;
|
||||
static constexpr u32 FCRAM_APPLICATION_PAGE_COUNT = FCRAM_APPLICATION_SIZE / pageSize;
|
||||
static constexpr u32 FCRAM_MAX_APPLICATION_SIZE = u32(96_MB); // Max amount available for applications
|
||||
static constexpr u32 FCRAM_APPLICATION_MAX_PAGE_COUNT = FCRAM_MAX_APPLICATION_SIZE / pageSize;
|
||||
|
||||
static constexpr u32 DSP_RAM_SIZE = u32(512_KB);
|
||||
static constexpr u32 DSP_CODE_MEMORY_OFFSET = u32(0_KB);
|
||||
static constexpr u32 DSP_DATA_MEMORY_OFFSET = u32(256_KB);
|
||||
|
||||
private:
|
||||
// This will get adjusted based on the cartridge exheader via setFcramApplicationSize, 64MB is just a default
|
||||
u32 fcramApplicationSize = u32(64_MB);
|
||||
u32 fcramApplicationPageCount = u32(64_MB) / pageSize; // Same here
|
||||
|
||||
std::bitset<FCRAM_PAGE_COUNT> usedFCRAMPages;
|
||||
std::optional<u32> findPaddr(u32 size);
|
||||
u64 timeSince3DSEpoch();
|
||||
|
@ -198,9 +203,23 @@ private:
|
|||
u32 getLinearHeapVaddr();
|
||||
u8* getFCRAM() { return fcram; }
|
||||
|
||||
// Set the amount of application FCRAM
|
||||
void setApplicationRamSize(u32 size) {
|
||||
fcramApplicationSize = size;
|
||||
fcramApplicationPageCount = size / pageSize;
|
||||
|
||||
if (usedUserMemory > fcramApplicationSize) {
|
||||
Helpers::panic("Set application FCRAM to a value less than the currently used application memory");
|
||||
}
|
||||
|
||||
if (usedSystemMemory > totalSysFCRAM()) {
|
||||
Helpers::panic("Set system FCRAM to a value less than the currently used system memory");
|
||||
}
|
||||
}
|
||||
|
||||
// Total amount of OS-only FCRAM available (Can vary depending on how much FCRAM the app requests via the cart exheader)
|
||||
u32 totalSysFCRAM() {
|
||||
return FCRAM_SIZE - FCRAM_APPLICATION_SIZE;
|
||||
return FCRAM_SIZE - fcramApplicationSize;
|
||||
}
|
||||
|
||||
// Amount of OS-only FCRAM currently available
|
||||
|
@ -210,10 +229,12 @@ private:
|
|||
|
||||
// Physical FCRAM index to the start of OS FCRAM
|
||||
// We allocate the first part of physical FCRAM for the application, and the rest to the OS. So the index for the OS = application ram size
|
||||
u32 sysFCRAMIndex() {
|
||||
return FCRAM_APPLICATION_SIZE;
|
||||
u32 sysFCRAMStartIndex() {
|
||||
return fcramApplicationSize;
|
||||
}
|
||||
|
||||
u32 getTotalAppFcramSize() { return fcramApplicationSize; }
|
||||
|
||||
enum class BatteryLevel {
|
||||
Empty = 0,
|
||||
AlmostEmpty,
|
||||
|
|
|
@ -89,7 +89,7 @@ s32 Kernel::getCurrentResourceValue(const KernelObject* limit, u32 resourceName)
|
|||
|
||||
u32 Kernel::getMaxForResource(const KernelObject* limit, u32 resourceName) {
|
||||
switch (resourceName) {
|
||||
case ResourceType::Commit: return appResourceLimits.maxCommit;
|
||||
case ResourceType::Commit: return mem.getTotalAppFcramSize();
|
||||
case ResourceType::Thread: return appResourceLimits.maxThreads;
|
||||
default: Helpers::panic("Attempted to get the max of unknown kernel resource: %d\n", resourceName);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@ std::optional<u32> Memory::loadELF(std::ifstream& file) {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Use 64MB of application FCRAM for ELFs by default
|
||||
setApplicationRamSize(64_MB);
|
||||
|
||||
auto segNum = reader.segments.size();
|
||||
printf("Number of segments: %d\n", segNum);
|
||||
printf(" # Perms Vaddr File Size Mem Size\n");
|
||||
|
|
|
@ -184,6 +184,10 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn
|
|||
text.extract(&exheader[0x10]);
|
||||
rodata.extract(&exheader[0x20]);
|
||||
data.extract(&exheader[0x30]);
|
||||
|
||||
// Access Control Info section of the exheader
|
||||
const u8* aci = &exheader[0x200];
|
||||
flag0 = aci[0xE];
|
||||
}
|
||||
|
||||
printf("Stack size: %08X\nBSS size: %08X\n", stackSize, bssSize);
|
||||
|
|
|
@ -13,6 +13,31 @@ bool Memory::mapCXI(NCSD& ncsd, NCCH& cxi) {
|
|||
|
||||
static constexpr std::array<const char*, 7> regionNames = {"Japan", "North America", "Europe", "Australia", "China", "Korea", "Taiwan" };
|
||||
|
||||
// The application RAM sizes for Old 3DS titles, chosen based on flag0 of the exheader
|
||||
static constexpr std::array<u32, 16> applicationRamSizes_O3DS = {
|
||||
64_MB, // Prod
|
||||
64_MB, // Unused
|
||||
96_MB, // Dev1
|
||||
80_MB, // Dev2
|
||||
72_MB, // Dev3
|
||||
32_MB, // Dev4
|
||||
64_MB, 64_MB, 64_MB, 64_MB, 64_MB, 64_MB, 64_MB, 64_MB, 64_MB, 64_MB,
|
||||
};
|
||||
|
||||
// Similar for New 3DS titles chosed based on flag2 from exheader. Index 0 isn't actually used, and denotes that this should use the Old3DS setting
|
||||
[[maybe_unused]] static constexpr std::array<u32, 16> applicationRamSizes_New3DS = {
|
||||
64_MB, // Legacy mode
|
||||
124_MB, // Prod
|
||||
178_MB, // Dev1
|
||||
124_MB, // Dev2
|
||||
124_MB, 124_MB, 124_MB, 124_MB, 124_MB, 124_MB, 124_MB, 124_MB, 124_MB, 124_MB, 124_MB, 124_MB,
|
||||
};
|
||||
|
||||
// TODO: Handle N3DS FCRAM here
|
||||
const u32 memorySize = applicationRamSizes_O3DS[Helpers::getBits<4, 4>(cxi.flag0)];
|
||||
setApplicationRamSize(memorySize);
|
||||
printf("Set application RAM size to %dMB\n", u32(memorySize / 1_MB));
|
||||
|
||||
// Set autodetected 3DS region to one of the values allowed by the CXI's SMDH
|
||||
region = cxi.region.value();
|
||||
printf("Console region autodetected to: %s\n", regionNames[static_cast<size_t>(region)]);
|
||||
|
|
|
@ -34,17 +34,10 @@ void Memory::reset() {
|
|||
writeTable[i] = 0;
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
u32 basePaddrForTLS = tlsBaseOpt.value();
|
||||
for (u32 i = 0; i < appResourceLimits.maxThreads; i++) {
|
||||
u32 index = allocateSysMemory(4_KB);
|
||||
u32 vaddr = VirtualAddrs::TLSBase + i * VirtualAddrs::TLSSize;
|
||||
allocateMemory(vaddr, basePaddrForTLS, VirtualAddrs::TLSSize, true);
|
||||
basePaddrForTLS += VirtualAddrs::TLSSize;
|
||||
allocateMemory(vaddr, index, VirtualAddrs::TLSSize, true, true, true, false, false, true);
|
||||
}
|
||||
|
||||
// Initialize shared memory blocks and reserve memory for them
|
||||
|
@ -301,12 +294,12 @@ std::optional<u32> Memory::allocateMemory(u32 vaddr, u32 paddr, u32 size, bool l
|
|||
// Additionally assert we don't OoM and that we don't try to allocate physical FCRAM past what's available to userland
|
||||
// If we're mapping there's no fear of OoM, because we're not really allocating memory, just binding vaddrs to specific paddrs
|
||||
assert(isAligned(vaddr) && isAligned(paddr) && isAligned(size));
|
||||
assert(size <= FCRAM_APPLICATION_SIZE || isMap);
|
||||
assert(usedUserMemory + size <= FCRAM_APPLICATION_SIZE || isMap);
|
||||
assert(paddr + size <= FCRAM_APPLICATION_SIZE || isMap);
|
||||
assert(size <= fcramApplicationSize || isMap);
|
||||
assert(usedUserMemory + size <= fcramApplicationSize || isMap);
|
||||
assert(paddr + size <= fcramApplicationSize || isMap);
|
||||
|
||||
// Amount of available user FCRAM pages and FCRAM pages to allocate respectively
|
||||
const u32 availablePageCount = (FCRAM_APPLICATION_SIZE - usedUserMemory) / pageSize;
|
||||
const u32 availablePageCount = (fcramApplicationSize - usedUserMemory) / pageSize;
|
||||
const u32 neededPageCount = size / pageSize;
|
||||
|
||||
assert(availablePageCount >= neededPageCount || isMap);
|
||||
|
@ -379,7 +372,7 @@ std::optional<u32> Memory::findPaddr(u32 size) {
|
|||
// If this ends up >= than neededPages then the paddr is good (ie we can use the candidate page as a base address)
|
||||
u32 counter = 0;
|
||||
|
||||
for (u32 i = 0; i < FCRAM_APPLICATION_PAGE_COUNT; i++) {
|
||||
for (u32 i = 0; i < fcramApplicationPageCount; i++) {
|
||||
if (usedFCRAMPages[i]) { // Page is occupied already, go to new candidate
|
||||
candidatePage = i + 1;
|
||||
counter = 0;
|
||||
|
@ -404,19 +397,22 @@ u32 Memory::allocateSysMemory(u32 size) {
|
|||
}
|
||||
|
||||
// We use a pretty dumb allocator for OS memory since this is not really accessible to the app and is only used internally
|
||||
// It works by just allocating memory linearly, starting from index 0 of OS memory and going up
|
||||
// It works by just allocating memory linearly, starting from the end of system memory and going back
|
||||
// This happens in order to allow changing the size of application FCRAM when loading a ROM, and not risking messing up our data
|
||||
// This should also be unreachable in practice and exists as a sanity check
|
||||
if (size > remainingSysFCRAM()) {
|
||||
Helpers::panic("Memory::allocateSysMemory: Overflowed OS FCRAM");
|
||||
}
|
||||
|
||||
const u32 pageCount = size / pageSize; // Number of pages that will be used up
|
||||
const u32 startIndex = sysFCRAMIndex() + usedSystemMemory; // Starting FCRAM index
|
||||
const u32 pageCount = size / pageSize; // Number of pages that will be used up
|
||||
const u32 startIndex = FCRAM_SIZE - usedSystemMemory - size; // Starting FCRAM index
|
||||
const u32 startingPage = startIndex / pageSize;
|
||||
|
||||
for (u32 i = 0; i < pageCount; i++) {
|
||||
if (usedFCRAMPages[startingPage + i]) // Also a theoretically unreachable panic for safety
|
||||
if (usedFCRAMPages[startingPage + i]) { // Also a theoretically unreachable panic for safety
|
||||
Helpers::panic("Memory::reserveMemory: Trying to reserve already reserved memory");
|
||||
}
|
||||
|
||||
usedFCRAMPages[startingPage + i] = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -248,6 +248,8 @@ bool Emulator::loadROM(const std::filesystem::path& path) {
|
|||
}
|
||||
|
||||
kernel.initializeFS();
|
||||
memory.setApplicationRamSize(64_MB); // Set the application RAM size to a default 64MB that loaded apps can override if needed
|
||||
|
||||
auto extension = path.extension();
|
||||
bool success; // Tracks if we loaded the ROM successfully
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue