Changes

3,006 bytes added ,  05:49, 26 February 2023
no edit summary
Line 25: Line 25:  
The first handle is a Process handle, the rest are CodeMemory handles.
 
The first handle is a Process handle, the rest are CodeMemory handles.
   −
This essentially does state/object init and maps the CodeMemory regions in the user-process.
+
This essentially does state/object init and maps the CodeMemory regions in the user-process. The permissions for the first CodeMemory is R-X, for the second CodeMemory it's R--. Both CodeMemory are mapped in the sysmodule with permissions RW-.
 +
 
 +
Both CodeMemory are optional. Handling for size=0 was originally broken, this was [[Switch_System_Flaws|fixed]] with [14.0.0+].
 +
 
 +
This copies the user-process CodeMemory addr/size for each CodeMemory to elsewhere in state, however it uses the first CodeMemory for the second CodeMemory state init as well. This is the same state used by [[#GenerateCode]] and [[#GetCodeAddress]].
    
= IJitEnvironment =
 
= IJitEnvironment =
Line 45: Line 49:  
== GenerateCode ==
 
== GenerateCode ==
 
Takes an u32, an u64, a [[#CodeRange]], a [[#CodeRange]], a [[#Struct32]], a type-0x5 input buffer, a type-0x6 output buffer, and returns an output s32, a [[#CodeRange]], a [[#CodeRange]].
 
Takes an u32, an u64, a [[#CodeRange]], a [[#CodeRange]], a [[#Struct32]], a type-0x5 input buffer, a type-0x6 output buffer, and returns an output s32, a [[#CodeRange]], a [[#CodeRange]].
 +
 +
sdknso copies data from an user-buffer to the tmp [[#Struct32]] which is used with the cmd, the size of that user-buffer is passed as the cmd input u32.
    
An error is thrown if the funcptr in state for the "nnjitpluginGenerateCode" symbol is not set.
 
An error is thrown if the funcptr in state for the "nnjitpluginGenerateCode" symbol is not set.
    
This does a bunch of validation. Then eventually CodeMemory/TransferMemory is mapped, the above symbol funcptr is called, runs more validation, and unmaps CodeMemory/TransferMemory. On success, this runs cache operations. Then this returns.
 
This does a bunch of validation. Then eventually CodeMemory/TransferMemory is mapped, the above symbol funcptr is called, runs more validation, and unmaps CodeMemory/TransferMemory. On success, this runs cache operations. Then this returns.
 +
 +
The funcptr is called with the following params: x0 = s32* out, x1 = {ptr to output [[#CodeRange]] initialized with the input [[#CodeRange]] and with the second u64 cleared}, x2 = {ptr to output [[#CodeRange]] initialized with the input [[#CodeRange]] and with the second u64 cleared}, x3 = {ptr to struct on stack which is the same as the one used for the "nnjitpluginOnPrepared" symbol, except +0x30/+0x38 are set to the sysmodule map-addr for each CodeMemory (addr for the second CodeMemory is set properly)}, x4 = cmd input u64, x5 = InBuffer addr, x6 = InBuffer size, x7 = {ptr to input [[#CodeRange]]}, sp0 = {ptr to input [[#CodeRange]]}, sp8 = {ptr to input [[#Struct32]]}, sp16 = cmd input u32, sp24 = OutBuffer addr, sp32 = OutBuffer size.
 +
 +
The input/output [[#CodeRange]] structs are validated as follows, where stateval is the first/second CodeMemory [[#CreateJitEnvironment|size]] for the first/second [[#CodeRange]]:
 +
* CodeRange.offset must be 0x4-byte aligned.
 +
* CodeRange.offset must be <= stateval-CodeRange.size.
 +
* stateval must be >= CodeRange.size.
 +
* CodeRange.size must be <= ~CodeRange.offset.
 +
* CodeRange.size must be 0x4-byte aligned.
 +
 +
The output [[#CodeRange]] structs are validated the same way as the corresponding input [[#CodeRange]] structs, however in addition the output structs are validated against the input structs:
 +
* out_CodeRange.offset must be >= in_CodeRange.offset.
 +
* in_CodeRange.size must be >= out_CodeRange.size.
 +
* (out_CodeRange.offset-in_CodeRange.offset) must be <= (in_CodeRange.size-out_CodeRange.size).
 +
 +
After using the cmd, sdknso runs cache operations.
    
== Control ==
 
== Control ==
Line 73: Line 95:  
* TransferMemory init is done here. An ASLR'd address for the TransferMemory mapped-address is determined, which will then be reused for all later mappings.
 
* TransferMemory init is done here. An ASLR'd address for the TransferMemory mapped-address is determined, which will then be reused for all later mappings.
 
* CodeMemory init func-calling is done for both regions, where w1={first output from "nnjitpluginConfigure" above}. Likewise with the TransferMemory, with w1={second output from "nnjitpluginConfigure" above}.
 
* CodeMemory init func-calling is done for both regions, where w1={first output from "nnjitpluginConfigure" above}. Likewise with the TransferMemory, with w1={second output from "nnjitpluginConfigure" above}.
* "nnjitpluginOnPrepared", error is handled on failure. Before/after calling this symbol funcptr, the TransferMemory is mapped/unmapped. The symbol funcptr is called with x0 = {ptr to struct on stack}. The struct has following structure: +0 = 0x20-bytes of data from state, +0x20 = TransferMemory map-addr, +0x28 = TransferMemory size, and +0x30 size 0x10-bytes is cleared.
+
* "nnjitpluginOnPrepared", error is handled on failure. Before/after calling this symbol funcptr, the TransferMemory is mapped/unmapped. The symbol funcptr is called with x0 = {ptr to struct on stack}. The struct has following structure: +0 = 0x20-bytes of data from state {user-process map-addr/size for each CodeMemory, used by [[#GetCodeAddress]]}, +0x20 = TransferMemory map-addr, +0x28 = TransferMemory size, and +0x30 size 0x10-bytes is cleared.
 
* Then this does cleanup and returns.
 
* Then this does cleanup and returns.
    
== GetCodeAddress ==
 
== GetCodeAddress ==
 
No input, returns two output u64s which are loaded from state.
 
No input, returns two output u64s which are loaded from state.
 +
 +
These u64s are the user-process map-addrs for each CodeMemory from [[#CreateJitEnvironment|state]]. Originally the second addr was a duplicate of the first addr, this was [[Switch_System_Flaws|fixed]] with [14.0.0+].
    
== CodeRange ==
 
== CodeRange ==
 
This is "nn::jit::CodeRange". This is a 0x10-byte struct. This is 8-byte aligned.
 
This is "nn::jit::CodeRange". This is a 0x10-byte struct. This is 8-byte aligned.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x8 || Offset
 +
|-
 +
| 0x8 || 0x8 || Size
 +
|}
    
== Struct32 ==
 
== Struct32 ==
 
This is "nn::jitsrv::Struct32". This is a 0x20-byte struct. This is 8-byte aligned.
 
This is "nn::jitsrv::Struct32". This is a 0x20-byte struct. This is 8-byte aligned.
 +
 +
This contains arbitrary plugin-specific input data which is passed to the [[#GenerateCode]] funcptr.
 +
 +
= Title usage =
 +
There are no system-titles using jit:u. The only titles using it are the following:
 +
 +
* [[Super Mario 3D All-Stars]] (N64 emulation only)
 +
* [[Nintendo 64 - Nintendo Switch Online]]