Memory: Rework FCRAM management entirely

Disables a lot of functionality... but I didn't want to commit too much to this commit
Also reworks virtual memory management somewhat (but needs more work)
This commit is contained in:
PSI-Rockin 2024-05-02 21:40:08 -04:00
parent 8e303d8d08
commit f230384444
16 changed files with 411 additions and 251 deletions

47
include/kernel/fcram.hpp Normal file
View file

@ -0,0 +1,47 @@
#pragma once
#include <list>
#include <memory>
#include "kernel_types.hpp"
class Memory;
typedef std::list<FcramBlock> FcramBlockList;
class KFcram {
struct Region {
struct Block {
s32 pages;
s32 pageOffs;
bool used;
Block(s32 pages, u32 pageOffs) : pages(pages), pageOffs(pageOffs), used(false) {}
};
std::list<Block> blocks;
u32 start;
s32 pages;
s32 freePages;
public:
Region() : start(0), pages(0) {}
void reset(u32 start, size_t size);
void alloc(std::list<FcramBlock>& out, s32 pages, bool linear);
u32 getUsedCount();
u32 getFreeCount();
};
Memory& mem;
Region appRegion, sysRegion, baseRegion;
uint8_t* fcram;
std::unique_ptr<u32> refs;
public:
KFcram(Memory& memory);
void reset(size_t ramSize, size_t appSize, size_t sysSize, size_t baseSize);
void alloc(FcramBlockList& out, s32 pages, FcramRegion region, bool linear);
void incRef(FcramBlockList& list);
void decRef(FcramBlockList& list);
u32 getUsedCount(FcramRegion region);
};

View file

@ -7,6 +7,7 @@
#include <vector>
#include "config.hpp"
#include "fcram.hpp"
#include "helpers.hpp"
#include "kernel_types.hpp"
#include "logger.hpp"
@ -21,6 +22,8 @@ class Kernel {
CPU& cpu;
Memory& mem;
KFcram fcramManager;
// The handle number for the next kernel object to be created
u32 handleCounter;
// A list of our OS threads, the max number of which depends on the resource limit (hardcoded 32 per process on retail it seems).
@ -243,6 +246,7 @@ public:
}
ServiceManager& getServiceManager() { return serviceManager; }
KFcram& getFcramManager() { return fcramManager; }
void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); }
void clearInstructionCache();

View file

@ -44,6 +44,12 @@ enum class ProcessorID : s32 {
New3DSExtra2 = 3
};
enum class FcramRegion {
App = 0x100,
Sys = 0x200,
Base = 0x300
};
struct AddressArbiter {};
struct ResourceLimits {
@ -242,4 +248,11 @@ struct KernelObject {
Helpers::panic("Called GetWaitList on kernel object without a waitlist (Type: %s)", getTypeName());
}
}
};
struct FcramBlock {
u32 paddr;
s32 pages;
FcramBlock(u32 paddr, s32 pages) : paddr(paddr), pages(pages) {}
};

View file

@ -4,14 +4,17 @@
#include <filesystem>
#include <fstream>
#include <optional>
#include <list>
#include <vector>
#include "config.hpp"
#include "crypto/aes_engine.hpp"
#include "handles.hpp"
#include "helpers.hpp"
#include "kernel/kernel_types.hpp"
#include "loader/ncsd.hpp"
#include "loader/3dsx.hpp"
#include "result/result.hpp"
#include "services/region_codes.hpp"
namespace PhysicalAddrs {
@ -45,7 +48,7 @@ namespace VirtualAddrs {
LinearHeapEndNew = 0x40000000,
// Start of TLS for first thread. Next thread's storage will be at TLSBase + 0x1000, and so on
TLSBase = 0xFF400000,
TLSBase = 0x1FF82000,
TLSSize = 0x1000,
VramStart = 0x1F000000,
@ -77,17 +80,15 @@ namespace KernelMemoryTypes {
PERMISSION_X = 1 << 2
};
// I assume this is referring to a single piece of allocated memory? If it's for pages, it makes no sense.
// If it's for multiple allocations, it also makes no sense
struct MemoryInfo {
u32 baseAddr; // Base process virtual address. Used as a paddr in lockedMemoryInfo instead
u32 size; // Of what?
u32 perms; // Is this referring to a single page or?
u32 baseAddr;
u32 pages;
u32 perms;
u32 state;
u32 end() { return baseAddr + size; }
MemoryInfo(u32 baseAddr, u32 size, u32 perms, u32 state) : baseAddr(baseAddr), size(size)
, perms(perms), state(state) {}
u32 end() { return baseAddr + (pages << 12); }
MemoryInfo() : baseAddr(0), pages(0), perms(0), state(0) {}
MemoryInfo(u32 baseAddr, u32 pages, u32 perms, u32 state) : baseAddr(baseAddr), pages(pages), perms(perms), state(state) {}
};
// Shared memory block for HID, GSP:GPU etc
@ -101,6 +102,9 @@ namespace KernelMemoryTypes {
};
}
class KFcram;
enum class FcramRegion;
class Memory {
u8* fcram;
u8* dspRam; // Provided to us by Audio
@ -109,11 +113,17 @@ class Memory {
u64& cpuTicks; // Reference to the CPU tick counter
using SharedMemoryBlock = KernelMemoryTypes::SharedMemoryBlock;
// TODO: remove this reference when Peach's excellent page table code is moved to a better home
KFcram& fcramManager;
// Our dynarmic core uses page tables for reads and writes with 4096 byte pages
std::vector<uintptr_t> readTable, writeTable;
// vaddr->paddr translation table
std::vector<u32> paddrTable;
// This tracks our OS' memory allocations
std::vector<KernelMemoryTypes::MemoryInfo> memoryInfo;
std::list<KernelMemoryTypes::MemoryInfo> memoryInfo;
std::array<SharedMemoryBlock, 5> sharedMemBlocks = {
SharedMemoryBlock(0, 0, KernelHandles::FontSharedMemHandle), // Shared memory for the system font (size is 0 because we read the size from the cmrc filesystem
@ -131,6 +141,9 @@ public:
static constexpr u32 FCRAM_SIZE = u32(128_MB);
static constexpr u32 FCRAM_APPLICATION_SIZE = u32(64_MB);
static constexpr u32 FCRAM_SYSTEM_SIZE = u32(44_MB);
static constexpr u32 FCRAM_BASE_SIZE = u32(20_MB);
static constexpr u32 FCRAM_PAGE_COUNT = FCRAM_SIZE / pageSize;
static constexpr u32 FCRAM_APPLICATION_PAGE_COUNT = FCRAM_APPLICATION_SIZE / pageSize;
@ -139,8 +152,8 @@ public:
static constexpr u32 DSP_DATA_MEMORY_OFFSET = u32(256_KB);
private:
std::bitset<FCRAM_PAGE_COUNT> usedFCRAMPages;
std::optional<u32> findPaddr(u32 size);
//std::bitset<FCRAM_PAGE_COUNT> usedFCRAMPages;
//std::optional<u32> findPaddr(u32 size);
u64 timeSince3DSEpoch();
// https://www.3dbrew.org/wiki/Configuration_Memory#ENVINFO
@ -167,10 +180,8 @@ private:
public:
u16 kernelVersion = 0;
u32 usedUserMemory = u32(0_MB); // How much of the APPLICATION FCRAM range is used (allocated to the appcore)
u32 usedSystemMemory = u32(0_MB); // Similar for the SYSTEM range (reserved for the syscore)
Memory(u64& cpuTicks, const EmulatorConfig& config);
Memory(KFcram& fcramManager, u64& cpuTicks, const EmulatorConfig& config);
void reset();
void* getReadPointer(u32 address);
void* getWritePointer(u32 address);
@ -196,22 +207,6 @@ private:
u32 getLinearHeapVaddr();
u8* getFCRAM() { return fcram; }
// 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;
}
// Amount of OS-only FCRAM currently available
u32 remainingSysFCRAM() {
return totalSysFCRAM() - usedSystemMemory;
}
// 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;
}
enum class BatteryLevel {
Empty = 0, AlmostEmpty, OneBar, TwoBars, ThreeBars, FourBars
};
@ -253,14 +248,16 @@ private:
// isMap: Shows whether this is a reserve operation, that allocates memory and maps it to the addr space, or if it's a map operation,
// which just maps memory from paddr to vaddr without hassle. The latter is useful for shared memory mapping, the "map" ControlMemory, op, etc
// Returns the vaddr the FCRAM was mapped to or nullopt if allocation failed
std::optional<u32> allocateMemory(u32 vaddr, u32 paddr, u32 size, bool linear, bool r = true, bool w = true, bool x = true,
bool adjustsAddrs = false, bool isMap = false);
KernelMemoryTypes::MemoryInfo queryMemory(u32 vaddr);
//std::optional<u32> allocateMemory(u32 vaddr, u32 paddr, u32 size, bool linear, bool r = true, bool w = true, bool x = true,
//bool adjustsAddrs = false, bool isMap = false);
// For internal use
// Allocates a "size"-sized chunk of system FCRAM and returns the index of physical FCRAM used for the allocation
// Used for allocating things like shared memory and the like
u32 allocateSysMemory(u32 size);
bool allocMemory(u32 vaddr, s32 pages, FcramRegion region, bool r, bool w, bool x);
bool allocMemoryLinear(u32& outVaddr, u32 inVaddr, s32 pages, FcramRegion region, bool r, bool w, bool x);
bool mapPhysicalMemory(u32 vaddr, u32 paddr, s32 pages, bool r, bool w, bool x);
bool mapVirtualMemory(u32 dstVaddr, u32 srcVaddr, s32 pages, bool r, bool w, bool x);
Result::HorizonResult queryMemory(KernelMemoryTypes::MemoryInfo& out, u32 vaddr);
void copyToVaddr(u32 dstVaddr, const u8* srcHost, s32 size);
// Map a shared memory block to virtual address vaddr with permissions "myPerms"
// The kernel has a second permission parameter in MapMemoryBlock but not sure what's used for
@ -270,7 +267,7 @@ private:
// Mirrors the page mapping for "size" bytes starting from sourceAddress, to "size" bytes in destAddress
// All of the above must be page-aligned.
void mirrorMapping(u32 destAddress, u32 sourceAddress, u32 size);
// void mirrorMapping(u32 destAddress, u32 sourceAddress, u32 size);
// Backup of the game's CXI partition info, if any
std::optional<NCCH> loadedCXI = std::nullopt;
@ -283,7 +280,6 @@ private:
u8* getDSPMem() { return dspRam; }
u8* getDSPDataMem() { return &dspRam[DSP_DATA_MEMORY_OFFSET]; }
u8* getDSPCodeMem() { return &dspRam[DSP_CODE_MEMORY_OFFSET]; }
u32 getUsedUserMem() { return usedUserMemory; }
void setVRAM(u8* pointer) { vram = pointer; }
void setDSPMem(u8* pointer) { dspRam = pointer; }