Memory: Implement Protect operation in ControlMemory

This commit is contained in:
PSI-Rockin 2024-05-09 19:10:20 -04:00
parent 1161703ed6
commit c65b91e6f1
3 changed files with 49 additions and 21 deletions

View file

@ -102,6 +102,7 @@ namespace KernelMemoryTypes {
};
}
struct FcramBlock;
class KFcram;
enum class FcramRegion;
@ -187,6 +188,7 @@ private:
static constexpr std::array<u8, 6> MACAddress = {0x40, 0xF4, 0x07, 0xFF, 0xFF, 0xEE};
void changeMemoryState(u32 vaddr, s32 pages, const Operation& op);
void queryPhysicalBlocks(std::list<FcramBlock>& outList, u32 vaddr, s32 pages);
void mapPhysicalMemory(u32 vaddr, u32 paddr, s32 pages, bool r, bool w, bool x);
void unmapPhysicalMemory(u32 vaddr, u32 paddr, s32 pages);
@ -256,6 +258,7 @@ private:
bool mapVirtualMemory(u32 dstVaddr, u32 srcVaddr, s32 pages, bool r, bool w, bool x,
KernelMemoryTypes::MemoryState oldDstState, KernelMemoryTypes::MemoryState oldSrcState,
KernelMemoryTypes::MemoryState newDstState, KernelMemoryTypes::MemoryState newSrcState);
void changePermissions(u32 vaddr, s32 pages, bool r, bool w, bool x);
Result::HorizonResult queryMemory(KernelMemoryTypes::MemoryInfo& out, u32 vaddr);
Result::HorizonResult testMemoryState(u32 vaddr, s32 pages, KernelMemoryTypes::MemoryState desiredState);

View file

@ -94,7 +94,15 @@ void Kernel::controlMemory() {
break;
case Operation::Protect:
Helpers::warn("Ignoring mprotect! Hope nothing goes wrong but if the game accesses invalid memory or crashes then we prolly need to implement this\n");
// Official kernel has an internal state bit to indicate that the region's permissions may be changed
// But this should account for all cases
if (!mem.testMemoryState(addr0, pages, MemoryState::Private) &&
!mem.testMemoryState(addr0, pages, MemoryState::Alias) &&
!mem.testMemoryState(addr0, pages, MemoryState::Aliased) &&
!mem.testMemoryState(addr0, pages, MemoryState::AliasCode)) Helpers::panic("Tried to mprotect invalid region!");
mem.changePermissions(addr0, pages, r, w, false);
regs[1] = addr0;
break;
default: Helpers::warn("ControlMemory: unknown operation %X\n", operation); break;

View file

@ -346,6 +346,28 @@ void Memory::changeMemoryState(u32 vaddr, s32 pages, const Operation& op) {
}
}
void Memory::queryPhysicalBlocks(FcramBlockList& outList, u32 vaddr, s32 pages) {
s32 srcPages = pages;
for (auto& alloc : memoryInfo) {
u32 blockStart = alloc.baseAddr;
u32 blockEnd = alloc.end();
if (!(vaddr >= blockStart && vaddr < blockEnd)) continue;
s32 blockPaddr = paddrTable[vaddr >> 12];
s32 blockPages = alloc.pages - ((vaddr - blockStart) >> 12);
blockPages = std::min(srcPages, blockPages);
FcramBlock physicalBlock(blockPaddr, blockPages);
outList.push_back(physicalBlock);
vaddr += blockPages << 12;
srcPages -= blockPages;
if (srcPages == 0) break;
}
if (srcPages != 0) Helpers::panic("Unable to find virtual pages to map!");
}
void Memory::mapPhysicalMemory(u32 vaddr, u32 paddr, s32 pages, bool r, bool w, bool x) {
assert(!(vaddr & 0xFFF));
assert(!(paddr & 0xFFF));
@ -431,26 +453,7 @@ bool Memory::mapVirtualMemory(u32 dstVaddr, u32 srcVaddr, s32 pages, bool r, boo
// Get a list of physical blocks in the source region
FcramBlockList physicalList;
s32 srcPages = pages;
for (auto& alloc : memoryInfo) {
u32 blockStart = alloc.baseAddr;
u32 blockEnd = alloc.end();
if (!(srcVaddr >= blockStart && srcVaddr < blockEnd)) continue;
s32 blockPaddr = paddrTable[srcVaddr >> 12];
s32 blockPages = alloc.pages - ((srcVaddr - blockStart) >> 12);
blockPages = std::min(srcPages, blockPages);
FcramBlock physicalBlock(blockPaddr, blockPages);
physicalList.push_back(physicalBlock);
srcVaddr += blockPages << 12;
srcPages -= blockPages;
if (srcPages == 0) break;
}
if (srcPages != 0) Helpers::panic("Unable to find virtual pages to map!");
queryPhysicalBlocks(physicalList, srcVaddr, pages);
// Map or unmap each physical block
for (auto& block : physicalList) {
@ -462,6 +465,20 @@ bool Memory::mapVirtualMemory(u32 dstVaddr, u32 srcVaddr, s32 pages, bool r, boo
return true;
}
void Memory::changePermissions(u32 vaddr, s32 pages, bool r, bool w, bool x) {
Operation op{ .r = r, .w = w, .x = x, .changePerms = true };
changeMemoryState(vaddr, pages, op);
// Now that permissions have been changed, update the corresponding host tables
FcramBlockList physicalList;
queryPhysicalBlocks(physicalList, vaddr, pages);
for (auto& block : physicalList) {
mapPhysicalMemory(vaddr, block.paddr, block.pages, r, w, x);
vaddr += block.pages;
}
}
Result::HorizonResult Memory::queryMemory(MemoryInfo& out, u32 vaddr) {
// Check each allocation
for (auto& alloc : memoryInfo) {