Skip to content

core: add NUP v2 container, writer and loader - #771

Open
Hinkiii wants to merge 1 commit into
Eglantine-Community:nx2-experimentalfrom
Hinkiii:nupv2
Open

Hinkiii wants to merge 1 commit into
Eglantine-Community:nx2-experimentalfrom
Hinkiii:nupv2

Conversation

@Hinkiii

@Hinkiii Hinkiii commented Nov 8, 2026 •

Copy link
Copy Markdown

Sorry for taking so long to get this PR set up, I did my best to add hash support for both the main file and romfs regions to help combat some possible mismatch/corruption confusions.

Tests were ran on Windows 11 Pro with a Ryzen 7 3700x 32gb RAM and a RTX 4060ti 8gb

We don't save on space vs the original NUP format but make up for it by matching the romfs data location to that of the table that is read within the main executable.

With my experience testing this format I've seen between 23% and 45% and seems to benefit both SATA and NVMe interfaces, more testing should be done on more hardware but I think it's at least a good starting point as the previous format has some inherent issues in my opinion between recompressed files and lack of hashing.

NUP v2 stores a program's RomFS raw and byte-identical at a 64 KiB-aligned offset, with the ExeFS members 4 KiB-aligned behind a 4096-byte superblock, so a read at X of the game's storage is a read at RomFsOffset + X of the file.

  • Nup2Container parses and validates the header; the superblock records an optional SHA-256 of the RomFS.

  • Nup2 writer packs from files, converts from NUP v1 or a dump folder, writes slices in parallel while hashing in order, and verifies a file against its recorded hash (with a read-ahead thread) or against a NUP v1 file.

  • MappedVfsFile memory-maps the container. IStorage::Read skips the SD card throttle for Switch 2 programs.

  • Loader::VerifyNSOSegmentHashes checks each NSO segment against the header hashes; the packer warns on a mismatch.

  • Qt: open, convert and verify NUP v2 from the UI. eden-cli: --convert-nup, --convert-nup-dump, --pack-nup2, --verify-nup2, --check-nup2.

  • Tests in src/tests/core/nup2.cpp.

  • [✓ ] I have read and followed the Contribution Guidelines.

  • [✓ ] I have read and followed the AI Policy.

  • [ ✓] I have read and followed the Coding Guidelines to the best of my ability.

  • [✓ ] I have put [HUMANMADE] in the title if the pr was human-mande


Summary

What does this PR change and why?

Type of change

  • Bug fix
  • Game compatibility / game-support
  • Performance
  • [✓ ] New feature
  • Refactor / cleanup
  • CI / build
  • Documentation

Related issues

e.g. Fixes #123

Testing

  • [ ✓] Tested on Windows
  • Tested on Linux
  • Tested on macOS
  • [✓ ] Tested on NVIDIA
  • Tested on AMD
  • Tested on Intel

Games tested:

E.g. OOT / FEFW

Checklist

  • [ ✓] I built it locally and it compiles without new warnings
  • [✓ ] I did not add any copyrighted game data, keys or firmware
  • [ ✓] Docs updated if needed
  • [✓ ] I added AI Disclosure if one was used

Screenshots / logs

Before/After

Boot time in seconds (lower is better)

FEFW, SATA, cold
v1 ████████████████████ 9.8
v2 ███████████ 5.6 -43%
FEFW, NVMe, cold
v1 ██████████████████ 9.0
v2 ██████████ 5.1 -43%
OoT, SATA, cold
v1 █████████████████████████████ 14.6
v2 █████████████████████ 10.6 -27%
OoT, NVMe, cold
v1 ████████████████████████████ 13.9
v2 █████████████████████ 10.6 -24%

FEFW, SATA, warm
v1 ███████████████████ 9.4
v2 ██████████ 5.2 -45%
FEFW, NVMe, warm
v1 █████████████████ 8.3
v2 ██████████ 5.1 -39%
OoT, SATA, warm
v1 ███████████████████████████████ 15.6
v2 ██████████████████████ 10.9 -30%
OoT, NVMe, warm
v1 █████████████████████████████ 14.5
v2 ██████████████████████ 11.1 -23%

NUP v2 stores a program's RomFS raw and byte-identical at a 64 KiB-aligned
offset, with the ExeFS members 4 KiB-aligned behind a 4096-byte superblock, so
a read at X of the game's storage is a read at RomFsOffset + X of the file.

- Nup2Container parses and validates the header; the superblock records an
  optional SHA-256 of the RomFS.
- Nup2 writer packs from files, converts from NUP v1 or a dump folder, writes
  slices in parallel while hashing in order, and verifies a file against its
  recorded hash (with a read-ahead thread) or against a NUP v1 file.
- MappedVfsFile memory-maps the container. IStorage::Read skips the SD card
  throttle for Switch 2 programs.
- Loader::VerifyNSOSegmentHashes checks each NSO segment against the header
  hashes; the packer warns on a mismatch.
- Qt: open, convert and verify NUP v2 from the UI. eden-cli: --convert-nup,
  --convert-nup-dump, --pack-nup2, --verify-nup2, --check-nup2.
- Tests in src/tests/core/nup2.cpp.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions
github-actions Bot changed the base branch from nx2 to nx2-experimental November 8, 2026 10:08
@github-actions

github-actions Bot commented Nov 8, 2026

Copy link
Copy Markdown

Retargeted to nx2-experimental for pre-build testing. It will be promoted to nx2 after validation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant