mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-11 08:39:48 +12:00
Stub GPU DMA, fix up some FS stuff. horribly wrong savedata implementation
This commit is contained in:
parent
b6a1da21a9
commit
5d15efe72c
13 changed files with 169 additions and 35 deletions
|
@ -9,7 +9,7 @@ namespace PathType {
|
|||
Empty = 1,
|
||||
Binary = 2,
|
||||
ASCII = 3,
|
||||
UTF8 = 4,
|
||||
UTF16 = 4,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,6 @@ struct ArchiveSession {
|
|||
|
||||
class ArchiveBase {
|
||||
protected:
|
||||
using Result = u32;
|
||||
using Handle = u32;
|
||||
Memory& mem;
|
||||
|
||||
|
|
|
@ -12,4 +12,10 @@ public:
|
|||
bool openFile(const FSPath& path) override;
|
||||
ArchiveBase* openArchive(const FSPath& path) override;
|
||||
std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override;
|
||||
|
||||
// Returns whether the cart has a RomFS
|
||||
bool hasRomFS() {
|
||||
auto cxi = mem.getCXI();
|
||||
return (cxi != nullptr && cxi->hasRomFS());
|
||||
}
|
||||
};
|
|
@ -12,4 +12,10 @@ public:
|
|||
bool openFile(const FSPath& path) override;
|
||||
ArchiveBase* openArchive(const FSPath& path) override;
|
||||
std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override;
|
||||
|
||||
// Returns whether the cart has save data or not
|
||||
bool cartHasSaveData() {
|
||||
auto cxi = mem.getCXI();
|
||||
return (cxi != nullptr && cxi->hasSaveData()); // We need to have a CXI file with more than 0 bytes of save data
|
||||
}
|
||||
};
|
|
@ -39,25 +39,6 @@ class Kernel {
|
|||
// Top 8 bits are the major version, bottom 8 are the minor version
|
||||
u16 kernelVersion = 0;
|
||||
|
||||
// Get pointer to the object with the specified handle
|
||||
KernelObject* getObject(Handle handle) {
|
||||
// Accessing an object that has not been created
|
||||
if (handle >= objects.size()) [[unlikely]] {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &objects[handle];
|
||||
}
|
||||
|
||||
// Get pointer to the object with the specified handle and type
|
||||
KernelObject* getObject(Handle handle, KernelObjectType type) {
|
||||
if (handle >= objects.size() || objects[handle].type != type) [[unlikely]] {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &objects[handle];
|
||||
}
|
||||
|
||||
Handle makeArbiter();
|
||||
Handle makeEvent(ResetType resetType);
|
||||
Handle makeProcess(u32 id);
|
||||
|
@ -148,5 +129,24 @@ public:
|
|||
return objects;
|
||||
}
|
||||
|
||||
// Get pointer to the object with the specified handle
|
||||
KernelObject* getObject(Handle handle) {
|
||||
// Accessing an object that has not been created
|
||||
if (handle >= objects.size()) [[unlikely]] {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &objects[handle];
|
||||
}
|
||||
|
||||
// Get pointer to the object with the specified handle and type
|
||||
KernelObject* getObject(Handle handle, KernelObjectType type) {
|
||||
if (handle >= objects.size() || objects[handle].type != type) [[unlikely]] {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &objects[handle];
|
||||
}
|
||||
|
||||
void sendGPUInterrupt(GPUInterrupt type) { serviceManager.requestGPUInterrupt(type); }
|
||||
};
|
|
@ -47,6 +47,8 @@ struct NCCH {
|
|||
|
||||
// Contents of the .code file in the ExeFS
|
||||
std::vector<u8> codeFile;
|
||||
// Contains of the cart's save data
|
||||
std::vector<u8> saveData;
|
||||
|
||||
// Header: 0x200 + 0x800 byte NCCH header + exheadr
|
||||
// Returns true on success, false on failure
|
||||
|
@ -57,6 +59,7 @@ struct NCCH {
|
|||
bool hasExeFS() { return exeFS.size != 0; }
|
||||
bool hasRomFS() { return romFS.size != 0; }
|
||||
bool hasCode() { return codeFile.size() != 0; }
|
||||
bool hasSaveData() { return saveData.size() != 0; }
|
||||
|
||||
private:
|
||||
std::array<u8, 16> primaryKey = {}; // For exheader, ExeFS header and icons
|
||||
|
|
|
@ -36,6 +36,8 @@ namespace VirtualAddrs {
|
|||
TLSBase = 0xFF400000,
|
||||
TLSSize = 0x1000,
|
||||
|
||||
VramStart = 0x1F000000,
|
||||
VramSize = 0x00600000,
|
||||
DSPMemStart = 0x1FF00000
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27,8 +27,10 @@ class FSService {
|
|||
std::optional<Handle> openFileHandle(ArchiveBase* archive, const FSPath& path);
|
||||
|
||||
// Service commands
|
||||
void closeArchive(u32 messagePointer);
|
||||
void initialize(u32 messagePointer);
|
||||
void openArchive(u32 messagePointer);
|
||||
void openFile(u32 messagePointer);
|
||||
void openFileDirectly(u32 messagePointer);
|
||||
|
||||
public:
|
||||
|
|
|
@ -44,6 +44,7 @@ class GPUService {
|
|||
void processCommandList(u32* cmd);
|
||||
void memoryFill(u32* cmd);
|
||||
void triggerDisplayTransfer(u32* cmd);
|
||||
void triggerDMARequest(u32* cmd);
|
||||
void flushCacheRegions(u32* cmd);
|
||||
|
||||
public:
|
||||
|
|
|
@ -2,8 +2,13 @@
|
|||
#include <memory>
|
||||
|
||||
bool SelfNCCHArchive::openFile(const FSPath& path) {
|
||||
if (!hasRomFS()) {
|
||||
printf("Tried to open a SelfNCCH file without a RomFS\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (path.type != PathType::Binary) {
|
||||
printf("Invalid SelfNCCH path type");
|
||||
printf("Invalid SelfNCCH path type\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -25,16 +30,17 @@ ArchiveBase* SelfNCCHArchive::openArchive(const FSPath& path) {
|
|||
}
|
||||
|
||||
std::optional<u32> SelfNCCHArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) {
|
||||
auto cxi = mem.getCXI();
|
||||
if (cxi == nullptr) {
|
||||
Helpers::panic("Tried to read file from non-existent CXI");
|
||||
if (!hasRomFS()) {
|
||||
Helpers::panic("Tried to read file from non-existent RomFS");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!cxi->hasRomFS()) {
|
||||
Helpers::panic("Tried to read from CXI without RomFS");
|
||||
if (!file->isOpen) {
|
||||
printf("Tried to read from closed SelfNCCH file session");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto cxi = mem.getCXI();
|
||||
const u32 romFSSize = cxi->romFS.size;
|
||||
const u32 romFSOffset = cxi->romFS.offset;
|
||||
if ((offset >> 32) || (offset >= romFSSize) || (offset + size >= romFSSize)) {
|
||||
|
|
|
@ -1,17 +1,59 @@
|
|||
#include "fs/archive_save_data.hpp"
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
bool SaveDataArchive::openFile(const FSPath& path) {
|
||||
Helpers::panic("SaveDataArchive::OpenFile");
|
||||
return false;
|
||||
if (!cartHasSaveData()) {
|
||||
printf("Tried to read SaveData FS without save data\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (path.type == PathType::UTF16 && mem.readString(path.pointer, path.size) == "/") {
|
||||
printf("Reading root save data dir\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (path.type != PathType::Binary) {
|
||||
printf("Unimplemented SaveData path type: %d\n", path.type);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ArchiveBase* SaveDataArchive::openArchive(const FSPath& path) {
|
||||
Helpers::panic("SaveDataArchive::OpenArchive");
|
||||
return nullptr;
|
||||
if (path.type != PathType::Empty) {
|
||||
Helpers::panic("Unimplemented path type for SaveData archive: %d\n", path.type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
std::optional<u32> SaveDataArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) {
|
||||
Helpers::panic("SaveDataArchive::ReadFile");
|
||||
return std::nullopt;
|
||||
if (!cartHasSaveData()) {
|
||||
printf("Tried to read SaveData FS without save data\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto cxi = mem.getCXI();
|
||||
const u64 saveSize = cxi->saveData.size();
|
||||
|
||||
if (offset >= saveSize) {
|
||||
printf("Tried to read from past the end of save data\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const u64 endOffset = std::min<u64>(saveSize, offset + size); // Don't go past the end of the save file
|
||||
const u32 bytesRead = endOffset - offset;
|
||||
|
||||
if (bytesRead != 0x22) Helpers::panic("Might want to actually implement SaveData");
|
||||
|
||||
static constexpr std::array<u8, 0x22> saveDataStub = { 0x00, 0x23, 0x3C, 0x77, 0x67, 0x28, 0x30, 0x33, 0x58, 0x61, 0x39, 0x61, 0x48, 0x59, 0x36, 0x55, 0x43, 0x76, 0x58, 0x61, 0x6F, 0x65, 0x48, 0x6D, 0x2B, 0x5E, 0x6F, 0x62, 0x3E, 0x6F, 0x34, 0x00, 0x77, 0x09};
|
||||
|
||||
for (u32 i = 0; i < bytesRead; i++) {
|
||||
mem.write8(dataPointer + i, saveDataStub[i]);
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
|
@ -9,6 +9,9 @@ bool NCCH::loadFromHeader(u8* header, IOFile& file) {
|
|||
return false;
|
||||
}
|
||||
|
||||
codeFile.clear();
|
||||
saveData.clear();
|
||||
|
||||
size = u64(*(u32*)&header[0x104]) * mediaUnit; // TODO: Maybe don't type pun because big endian will break
|
||||
exheaderSize = *(u32*)&header[0x180];
|
||||
|
||||
|
@ -46,6 +49,9 @@ bool NCCH::loadFromHeader(u8* header, IOFile& file) {
|
|||
Helpers::panic("Encrypted NCSD file");
|
||||
}
|
||||
|
||||
const u64 saveDataSize = *(u64*)&exheader[0x1C0 + 0x0]; // Size of save data in bytes
|
||||
saveData.resize(saveDataSize, 0xff);
|
||||
|
||||
compressCode = (exheader[0xD] & 1) != 0;
|
||||
stackSize = *(u32*)&exheader[0x1C];
|
||||
bssSize = *(u32*)&exheader[0x3C];
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
namespace FSCommands {
|
||||
enum : u32 {
|
||||
Initialize = 0x08010002,
|
||||
OpenFile = 0x080201C2,
|
||||
OpenFileDirectly = 0x08030204,
|
||||
OpenArchive = 0x080C00C2
|
||||
OpenArchive = 0x080C00C2,
|
||||
CloseArchive = 0x080E0080
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -66,8 +68,10 @@ std::optional<Handle> FSService::openArchiveHandle(u32 archiveID, const FSPath&
|
|||
void FSService::handleSyncRequest(u32 messagePointer) {
|
||||
const u32 command = mem.read32(messagePointer);
|
||||
switch (command) {
|
||||
case FSCommands::CloseArchive: closeArchive(messagePointer); break;
|
||||
case FSCommands::Initialize: initialize(messagePointer); break;
|
||||
case FSCommands::OpenArchive: openArchive(messagePointer); break;
|
||||
case FSCommands::OpenFile: openFile(messagePointer); break;
|
||||
case FSCommands::OpenFileDirectly: openFileDirectly(messagePointer); break;
|
||||
default: Helpers::panic("FS service requested. Command: %08X\n", command);
|
||||
}
|
||||
|
@ -78,6 +82,20 @@ void FSService::initialize(u32 messagePointer) {
|
|||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void FSService::closeArchive(u32 messagePointer) {
|
||||
const Handle handle = static_cast<u32>(mem.read64(messagePointer + 4)); // TODO: archive handles should be 64-bit
|
||||
const auto object = kernel.getObject(handle, KernelObjectType::Archive);
|
||||
log("FSService::CloseArchive(handle = %X)\n", handle);
|
||||
|
||||
if (object == nullptr) {
|
||||
log("FSService::CloseArchive: Tried to close invalid archive %X\n", handle);
|
||||
mem.write32(messagePointer + 4, Result::Failure);
|
||||
} else {
|
||||
object->getData<ArchiveSession>()->isOpen = false;
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
}
|
||||
|
||||
void FSService::openArchive(u32 messagePointer) {
|
||||
const u32 archiveID = mem.read32(messagePointer + 4);
|
||||
const u32 archivePathType = mem.read32(messagePointer + 8);
|
||||
|
@ -85,7 +103,7 @@ void FSService::openArchive(u32 messagePointer) {
|
|||
const u32 archivePathPointer = mem.read32(messagePointer + 20);
|
||||
FSPath archivePath{ .type = archivePathType, .size = archivePathSize, .pointer = archivePathPointer };
|
||||
|
||||
log("FS::OpenArchive (archive ID = %d, archive path type = %d)\n", archiveID, archivePathType);
|
||||
log("FS::OpenArchive(archive ID = %d, archive path type = %d)\n", archiveID, archivePathType);
|
||||
|
||||
std::optional<Handle> handle = openArchiveHandle(archiveID, archivePath);
|
||||
if (handle.has_value()) {
|
||||
|
@ -97,6 +115,37 @@ void FSService::openArchive(u32 messagePointer) {
|
|||
}
|
||||
}
|
||||
|
||||
void FSService::openFile(u32 messagePointer) {
|
||||
const u32 archiveHandle = mem.read64(messagePointer + 8);
|
||||
const u32 filePathType = mem.read32(messagePointer + 16);
|
||||
const u32 filePathSize = mem.read32(messagePointer + 20);
|
||||
const u32 openFlags = mem.read32(messagePointer + 24);
|
||||
const u32 attributes = mem.read32(messagePointer + 28);
|
||||
const u32 filePathPointer = mem.read32(messagePointer + 36);
|
||||
|
||||
log("FS::OpenFile\n");
|
||||
|
||||
auto archiveObject = kernel.getObject(archiveHandle, KernelObjectType::Archive);
|
||||
if (archiveObject == nullptr) [[unlikely]] {
|
||||
log("FS::OpenFile: Invalid archive handle %d\n", archiveHandle);
|
||||
mem.write32(messagePointer + 4, Result::Failure);
|
||||
return;
|
||||
}
|
||||
|
||||
ArchiveBase* archive = archiveObject->getData<ArchiveSession>()->archive;
|
||||
FSPath filePath{ .type = filePathType, .size = filePathSize, .pointer = filePathPointer };
|
||||
|
||||
std::optional<Handle> handle = openFileHandle(archive, filePath);
|
||||
if (!handle.has_value()) {
|
||||
Helpers::panic("OpenFile: Failed to open file with given path");
|
||||
}
|
||||
else {
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write32(messagePointer + 8, 0x10); // "Move handle descriptor"
|
||||
mem.write32(messagePointer + 12, handle.value());
|
||||
}
|
||||
}
|
||||
|
||||
void FSService::openFileDirectly(u32 messagePointer) {
|
||||
const u32 archiveID = mem.read32(messagePointer + 8);
|
||||
const u32 archivePathType = mem.read32(messagePointer + 12);
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace ServiceCommands {
|
|||
// Commands written to shared memory and processed by TriggerCmdReqQueue
|
||||
namespace GXCommands {
|
||||
enum : u32 {
|
||||
TriggerDMARequest = 0,
|
||||
ProcessCommandList = 1,
|
||||
MemoryFill = 2,
|
||||
TriggerDisplayTransfer = 3,
|
||||
|
@ -223,6 +224,7 @@ void GPUService::processCommandBuffer() {
|
|||
case GXCommands::ProcessCommandList: processCommandList(cmd); break;
|
||||
case GXCommands::MemoryFill: memoryFill(cmd); break;
|
||||
case GXCommands::TriggerDisplayTransfer: triggerDisplayTransfer(cmd); break;
|
||||
case GXCommands::TriggerDMARequest: triggerDMARequest(cmd); break;
|
||||
case GXCommands::FlushCacheRegions: flushCacheRegions(cmd); break;
|
||||
default: Helpers::panic("GSP::GPU::ProcessCommands: Unknown cmd ID %d", cmdID);
|
||||
}
|
||||
|
@ -262,6 +264,16 @@ void GPUService::triggerDisplayTransfer(u32* cmd) {
|
|||
requestInterrupt(GPUInterrupt::PPF); // Send "Display transfer finished" interrupt
|
||||
}
|
||||
|
||||
void GPUService::triggerDMARequest(u32* cmd) {
|
||||
u32 source = cmd[1];
|
||||
u32 dest = cmd[2];
|
||||
u32 size = cmd[3];
|
||||
bool flush = cmd[7] == 1;
|
||||
|
||||
log("GSP::GPU::TriggerDMARequest (source = %08X, dest = %08X, size = %08X) (Unimplemented)\n", source, dest, size);
|
||||
requestInterrupt(GPUInterrupt::DMA);
|
||||
}
|
||||
|
||||
void GPUService::flushCacheRegions(u32* cmd) {
|
||||
log("GSP::GPU::FlushCacheRegions (Stubbed)\n");
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue