Skip to content

Commit

Permalink
Validate the DSi NAND's no$gba footer
Browse files Browse the repository at this point in the history
- Fix #63
  • Loading branch information
JesseTG committed Jun 17, 2024
1 parent a29c415 commit d714a14
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 4 deletions.
51 changes: 48 additions & 3 deletions src/libretro/config/constants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,63 @@ using std::nullopt;
using std::string;
using namespace melonDS;

// We verify the filesize of the NAND image and the presence of the no$gba footer (since melonDS needs it)
bool MelonDsDs::config::IsDsiNandImage(const retro::dirent &file) noexcept {
ZoneScopedN(TracyFunction);
ZoneText(file.path, strnlen(file.path, sizeof(file.path)));

// TODO: Validate the NoCash footer
if (!file.is_regular_file())
return false;

if (find(DSI_NAND_SIZES.begin(), DSI_NAND_SIZES.end(), file.size) == DSI_NAND_SIZES.end())
switch (file.size) {
case DSI_NAND_SIZES_NOFOOTER[0] + NOCASH_FOOTER_SIZE: // 240MB + no$gba footer
case DSI_NAND_SIZES_NOFOOTER[1] + NOCASH_FOOTER_SIZE: // 245.5MB + no$gba footer
case DSI_NAND_SIZES_NOFOOTER[0]: // 240MB
case DSI_NAND_SIZES_NOFOOTER[1]: // 245.5MB
break; // the size is good, let's look for the footer!
default:
return false;
}

RFILE* stream = filestream_open(file.path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!stream)
return false;

return true;
if (filestream_seek(stream, -static_cast<int64_t>(NOCASH_FOOTER_SIZE), RETRO_VFS_SEEK_POSITION_END) < 0) {
filestream_close(stream);
return false;
}

std::array<uint8_t , NOCASH_FOOTER_SIZE> footer;
if (filestream_read(stream, footer.data(), footer.size()) != NOCASH_FOOTER_SIZE) {
filestream_close(stream);
return false;
}

if (filestream_seek(stream, NOCASH_FOOTER_OFFSET, RETRO_VFS_SEEK_POSITION_START) < 0) {
filestream_close(stream);
return false;
}

std::array<uint8_t , NOCASH_FOOTER_SIZE> unusedArea;
if (filestream_read(stream, unusedArea.data(), unusedArea.size()) != NOCASH_FOOTER_SIZE) {
filestream_close(stream);
return false;
}

filestream_close(stream);

if (memcmp(footer.data(), NOCASH_FOOTER_MAGIC, NOCASH_FOOTER_MAGIC_SIZE) == 0) {
// If the no$gba footer is present at the end of the file and correctly starts with the magic bytes...
return true;
}

if (memcmp(unusedArea.data(), NOCASH_FOOTER_MAGIC, NOCASH_FOOTER_MAGIC_SIZE) == 0) {
// If the no$gba footer is present in a normally-unused section of the DSi NAND, and it starts with the magic bytes...
return true;
}

return false;
}

bool MelonDsDs::config::IsFirmwareImage(const retro::dirent& file, Firmware::FirmwareHeader& header) noexcept {
Expand Down
6 changes: 5 additions & 1 deletion src/libretro/config/constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,11 @@ namespace MelonDsDs::config {
static constexpr const char *const UPSIDE_DOWN = "rotate-180";
}

constexpr std::array<size_t, 2> DSI_NAND_SIZES = { 251658304, 257425472 };
constexpr size_t NOCASH_FOOTER_SIZE = 0x40;
constexpr size_t NOCASH_FOOTER_OFFSET = 0xFF800;
constexpr std::array<size_t, 2> DSI_NAND_SIZES_NOFOOTER = { 0xF000000, 0xF580000 }; // Taken from GBATek
constexpr const char *const NOCASH_FOOTER_MAGIC = "DSi eMMC CID/CPU";
constexpr size_t NOCASH_FOOTER_MAGIC_SIZE = 16;
constexpr std::array<size_t, 3> FIRMWARE_SIZES = { 131072, 262144, 524288 };

bool IsDsiNandImage(const retro::dirent &file) noexcept;
Expand Down

0 comments on commit d714a14

Please sign in to comment.