(Switch 2) Compatibility Mode: Difference between revisions
Created page with "When a Switch 1 game is running on the Switch 2, it is loaded together with 3 new modules: * nnCompatTrampoline * nnCompatThin * nnCompat These binaries are compiled with PAC enabled. = Hooking = Backwards-compatibility is achieved by (ab)using dynamic linking to selectively hook API functions. Three compatibility libraries are mapped into the game process. They provide symbols which override the original sdk co..." |
|||
Line 18: | Line 18: | ||
== CompatibilityParameter == | == CompatibilityParameter == | ||
The system puts an additional information block in the ProgramArgument parameter | The system puts an additional information block in the ProgramArgument parameter for the process. This block contains certain extra information and overrides, which allows customization of the compatibility hooks depending on the game. | ||
To retrieve this pointer, [[#nnCompatThin|nnCompatThin]] intercepts the nnosInitialize function and retrieves it from there. Normally, a game doesn't use the ProgramParameter so it doesn't care this parameter was passed. | To retrieve this pointer, [[#nnCompatThin|nnCompatThin]] intercepts the nnosInitialize function and retrieves it from there. Normally, a game doesn't use the ProgramParameter so it doesn't care this parameter was passed. | ||
= nnCompatTrampoline = | = nnCompatTrampoline = |
Revision as of 09:03, 6 June 2025
When a Switch 1 game is running on the Switch 2, it is loaded together with 3 new modules:
These binaries are compiled with PAC enabled.
Hooking
Backwards-compatibility is achieved by (ab)using dynamic linking to selectively hook API functions. Three compatibility libraries are mapped into the game process. They provide symbols which override the original sdk codebin implementation, wherein a translation layer for Switch 2 is provided.
Most of these end up doing small tweaks to the parameters, and then calling into the original function implementation.
Switch 2 is mostly backwards-compatible, so most sdk codebin symbols remain unchanged and execute their original code. The overrides are mostly related to Graphics (i.e. translating to the new GPU), but there are also plenty other function overrides to deal with various system differences.
Below is a breakdown what some of the hooks and what their purpose is.
CompatibilityParameter
The system puts an additional information block in the ProgramArgument parameter for the process. This block contains certain extra information and overrides, which allows customization of the compatibility hooks depending on the game.
To retrieve this pointer, nnCompatThin intercepts the nnosInitialize function and retrieves it from there. Normally, a game doesn't use the ProgramParameter so it doesn't care this parameter was passed.
nnCompatTrampoline
nnCompatThin
Hooked Symbol | Difference |
---|---|
nnosInitialize | Captures the ProgramArgument parameter where the #CompatibilityParameter is stored. |
nn::os::CreateThread | No change. |
nn::os::SetThreadCoreMask | No change. |
nn::os::GetThreadAvailableCoreMask | Returns actual core mask masked with 0x7, effectively pretending that there are only 3 CPU cores available. |
nn::audio::GetAudioInName | If the primary audio in name is "XUac", it returns the secondary device name instead. Presumably, the "XUac" device has been removed in Switch 2. |
nn::audio::GetReleasedWaveBuffer | Now returns NULL under certain circumstances. |
nnCompat
Hooked Symbol | Difference |
---|---|
nn::os::GetSystemTickFrequency | Returns 31250000 instead of 19200000. |
nn::os::ConvertToTick | Uses conversion ratio 31250000 instead of 19200000. |