- gsv 204: real syncpoint shared page (values mirrored from host1x, armed waits
acknowledged by a 500us poller); first handle is the writable request event.
- syncpt 22/201/202: per-slot events signalled through host1x guest actions.
- nx2:gpu sub 101 memory is identity-mapped (GPU VA == CPU VA) into every
nvhost-as-gpu GMMU via Nx2GpuMemoryRegistry; SMMU physical range widened to
34 bits for the 10/12 GiB layouts.
- Puller runs Ampere 3D/compute/copy classes on the Maxwell engines; class 0 unbinds.
- Turing+ macros are skipped (Eden only has the Fermi macro ISA).
- Submits with increment_value get Eden-side syncpoint increments, since NVN2
signals completion with semaphore releases only.
Once an nx2 NvRm identifies itself (0xD0-byte characteristics), nvhost-gpu and
nvhost-ctrl-gpu answer unknown ioctls with a logged input echo instead of
NotImplemented, ctrl-gpu reports GR + async-copy engines, and Ampere class numbers
(and class 0) map onto Eden's Maxwell object slots. gdbrsp.py gains trace/flow/
breakwhen/fp helpers.
Unknown /dev/nvhost-* nodes (first: /dev/nvhost-tsg-gpu, opened by the
Switch 2 NvRm during NVN device init) open as nx2_stub_device: every
ioctl succeeds with the input echoed and the rest zeroed, and is logged.
With this NVN device init completes and the title reaches
nn::wsi::ounce::native::NativeWindow::Acquire (first frame).
- svc 0x80 (address, size, mask 0x20, attr 0x20) marks memory GPU
accessible for nn::gpu::sdk::CreateGpuAccessibleMemory; accept it.
- gpu 22's sub-session is served by the gpu object; sub 101 registers
memory, sub 211 submits a job whose id event is signalled at once.
- gpu 203 reports [0x8000000, 0xC000000000) as the in-process
VirtualMachine range that serves AllocSpace (NVN reserves fixed VA at
0x8000000 up to 512 GiB).
- Report SM 0x808: NVN2's engine class table is only returned for it.
With this NVN device init allocates its GPU memory and opens
/dev/nvhost-tsg-gpu.
- AllocAsEx from Switch 2 NvRm passes flags 5, no big page size, range
[0x8000000, 0xC000000000) and split 0 (small pages only). Treat split 0
as small pages up to the end, keep a 4 GiB big-page region after it, and
give that allocator an absolute limit (Eden's length-as-limit breaks once
the split is past the region length).
- gpu TIPC 33 returns a count, 203 a kind plus a VA range used by
nn::gpu::sdk::CreateGpuAddressSpace.
- gdbrsp.py: unbreak, step, breaklr, unbreakpc, fp (frame walk), trace.
- gsv 1402's nvsrv session speaks the nvdrv INvDrvServices protocol;
serve it with an NVDRV on the shared module, initialised for the
calling process (Switch 2 doesn't call Initialize).
- GetCharacteristics3 callers asking for the 0xD0-byte Switch 2 layout
get chip 0x17E (Ampere; the Switch 2 NvRm rejects Maxwell for NVN),
Ampere classes, and s16 interface versions at 0x70..0x80.
- After that, unknown nvhost-ctrl-gpu Ioctl3 commands from such callers
return a zeroed success (logged).
ResponseBuilder::Push(Result) writes the CMIF two-word result, so TIPC
data pushed after it landed one word late and outside the copied size;
clients read zeros. TipcReplyWords writes the one-word TIPC result and
the data. vi2 TIPC 5 returns 7 (LayerHistory needs 7 recorders). With
this the title creates its layer and goes on to hid/acc/aoc and RomFS
asset loading.
gsv 305 returns the session nn::vi2::sdk::Initialize keeps. Reply shapes
read from the SDK: TIPC 1 -> u32 < 0x400, 3 -> u32 < 8, 11/31/32 -> one
handle then result (events here). With this nn::vi::Initialize returns and
the title opens the default display and starts creating a layer.
gsv 497 returns the session nn::gpu::sdk::BootWithRemoteMemory keeps.
On it: TIPC 11 returns an id range, 12(id) returns that id's event, 21(id)
starts an operation the SDK then waits for (signalled at once here), 22
returns another session. With this nn::gs::sdk::BootGraphicsSystem
returns and boot moves on to nn::vi.
- gsv 1402 returns an nvsrv session (handle at word 3, result at word 4);
nn::nvsrv::BootWithRemoteMemory keeps it.
- gsv 202 returns a syncpt session; gsv 204 takes two transfer memories
(0x1000 RW, 0x2000 RO) and must leave a header in the RO one (version 1,
count, five region offsets) and return two event handles.
- syncpt TIPC 1 returns a u32 < 0x400 (32 here).
RequestParser doesn't skip TIPC handle words, so 204 reads raw data words.
ISelfController 2000 hands nn::gsv::BootWithRemoteMemory a raw session
handle it then speaks TIPC on (4, 11, 101, 1501, 1502, 1402 during boot).
Return a session to INx2GraphicsSystemSession, which answers every
command with an empty success and logs it. ReturnRawSession creates the
session outside the caller's domain, since gsv wants a real handle.
nn::os::GetRemoteMemoryUsage returns {id 31, id 32}; nn::gsv and
nn::nvsrv BootWithRemoteMemory use it while booting the graphics
system. Return 0 for both for now (logged).
IPC trace logs every dispatched command and non-zero result words.
EDEN_NX2_AUTO_STUB auto-stubs unknown commands without relying on the
use_auto_stub setting, which eden-cli's config rewrite resets.
IApplicationProxy 60 returns the interface nn::oe::GetCurrentGraphicsScale
uses; its command 10 must return 10, 20 or 30, so return 10. Other
commands on it are auto-stubbed (nx2: prefix). IApplicationFunctions 321
is called right after 320; stub it.
The ExeFS directory loader never set its romfs member and, when used on
its own, never registered the process with the FileSystemController, so
fsp-srv SetCurrentProcess failed with ResultTargetNotFound (2002-1002).
Build the RomFS from a romfs/ directory next to exefs/ (or a .romfs file
in exefs/), and register the process when the loader isn't wrapped by
the NCA/NSP loaders.
Switch 2 titles get core mask 0x3f and nn::oe creates a thread on core 5.
Eden emulates four cores, so fold virtual cores 4..7 onto 0..3 in
CreateThread and SetThreadCoreMask (after validating against the real
process mask).
- appletOE command 10 opens the application proxy (same arguments as 0).
- IApplicationProxy commands 40/50/.../90 are new getters; return an
INx2StubInterface (nx2_stub_interface.h). Interfaces whose name starts
with nx2: answer every call with an empty success and log it.
The SDK checks module address/size against (id33 - 1) when initialising
DSOs, so id 33 is a page granule: return 0x1000. Report ids 29/30 as the
upper half of the alias region (a plausible VAMM address-space region,
backed through MapPhysicalMemory) instead of an empty region.
nnosInitialize queries ids 29/30 between the alias (2/3) and ASLR (12/13)
regions and aborts if they fail; report an empty region after the alias
region. VammManager::Initialize (enabled when the system resource size is
non-zero) queries id 33 and passes it to MapPhysicalMemory as a size, so
return 2 MiB. Both are logged as stubs; the real meanings are unknown.
- SDL_AppInit never stored *appstate, so every later callback got null.
- SDL_AppInit/SDL_AppEvent returned SDL_APP_SUCCESS, which tells SDL3 to
quit; they must return SDL_APP_CONTINUE.
- InputSubsystem was a local in SDL_AppInit but the window and its timers
keep a pointer to it; keep it in SdlState, ahead of the window.
- Guard the mouse timer against firing before the mouse driver exists.
Switch 2 ACID blocks have a 0x300-byte signature/key area (Switch 1:
0x200), so the ACID header starts 0x100 bytes later. Without this the
FAC offset was garbage and loading failed with ErrorBadFileAccessControl.
Also read FAC/FAH relative to their ACID/ACI block, as the format (and
the existing KAC read) does.
'main' is also a valid NSO, so IdentifyFile picked the single-NSO loader,
which skips main.npdm, rtld and the sdk modules and then crashes writing
into an uninitialised process. Prefer the ExeFS directory loader when the
file is named main and sits in an ExeFS.
Switch 2 titles are built for a Cortex-A78C class core. Scanning one title's
.text with dynarmic's own decoder table found ~115k RETAB, ~37k LDAPR,
~25k LSE atomics, ~6.6k CAS, ~2.5k SWP plus a few CASP/XPAC/PAC/STG, none of
which dynarmic decoded (only the declarations existed).
- LSE atomics, SWP, CAS, CASP: exclusive load + op + exclusive store; on
store failure no register is written and the instruction is retried
(CheckBit terminal), so it stays atomic across cores.
- LDAPR: ordered load, like LDAR.
- Pointer authentication: identity (nothing is ever signed). RETAA/RETAB,
BRA*/BLRA*, LDRAA/LDRAB, PAC*/AUT*/XPAC*, PACGA.
- MTE: tags are always 0; STG/ST2G only write back, STZG/STZ2G zero the
granules, STGP stores the pair, IRG/GMI/ADDG/SUBG ignore tags.
tools/nx2/a64_coverage.py reports which encodings in an NSO's .text the
decoder table does not match.
- sparse_large_vector: ULONG_PTR -> u64 needs static_cast, not reinterpret_cast
- zbic_compression: silence C4505/C5245 for the amalgamated zstd.c, which
is compiled as project code and hits /we4505
- launch_params: explicit int -> bool (C4800 is an error here)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.
-------------------
Aimed to fix Ender Magnolia missing shader textures. Main example is Yolvan character bullets.
By using windows version of the game, dxvk lib to make it vulkan, and renderdoc, it was possible to capture bullets, and by tracking backward composition and comparing with a similar scene from eden with missing bullets, it was possible to unveil the missing functionality: conditional Phi inputs resolve for bindless handles.
By ignoring the boolean predicate register in the shader, handles for these shaders were resolving to some old value instead of proper live conditional ones.
TESTS:
-Compare Yolvan bullets
-Usual roam on main titles for regression check.
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4551
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.
-------------------
- Add NCZBLOCK (nsz -B / .xcz) reader: each read decodes only the covered blocks and re-encrypts CTR sections, no disk output.
- Allow installing solid .nsz to NAND via DecompressNCZForInstall (lazy, incremental decode with frontier, O(n) instead of O(n^2)).
- Accept BKTR updates with thousands of sections (MaxSectionCount = 0x10000).
- Wire .nsz/.xcz into loader, registered cache, scanner, and NAND install (content_manager.h), and reject solid NCZ from the game list.
- Bump the pinned zstd to 33618c8 in cpmfile.json, which includes the upstream AArch64 revert ([33618c89](33618c89e5)) for a ZSTD_decodeSequence branch optimization that could corrupt data on ARM64; without it, solid NCZ decoding on Android fails with "Data corruption detected".
NCZ format and CTR counter semantics follow the reference nsz tool and its
Rust port:
- https://github.com/nicoboss/nsz (Decompressor.py, BlockDecompressorReader.py)
- https://docs.rs/nsz-rs/0.3.0/src/nsz_rs/decompress.rs.html
The last-block edge case (decompressed size is an exact multiple of block
size) is handled as described in https://github.com/nicoboss/nsz/issues/210
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4552
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>