Start handling exheader flag0

This commit is contained in:
wheremyfoodat 2023-08-26 17:01:48 +03:00
parent 902b2032e2
commit fe70616535
7 changed files with 74 additions and 15 deletions

View file

@ -47,6 +47,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
u32 stackSize = 0;

View file

@ -123,16 +123,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();
@ -186,9 +191,23 @@ public:
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
@ -198,8 +217,8 @@ public:
// 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;
}
enum class BatteryLevel {

View file

@ -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");

View file

@ -160,6 +160,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);

View file

@ -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)]);

View file

@ -289,12 +289,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);
@ -367,7 +367,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;
@ -392,19 +392,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;
}

View file

@ -444,6 +444,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