Difference between revisions of "Homebrew ABI"
m (Reverted edits by Qlutoo (talk) to last revision by Misson20000) |
|||
Line 10: | Line 10: | ||
* Resetting MemoryState | * Resetting MemoryState | ||
* No leftover threads running in the background | * No leftover threads running in the background | ||
− | |||
− | |||
=== Entrypoint Arguments === | === Entrypoint Arguments === | ||
Line 35: | Line 33: | ||
enum LoaderConfigFlags { | enum LoaderConfigFlags { | ||
− | + | IsRecognitionMandatory = BIT(0), | |
}; | }; | ||
=== Loader Config Keys === | === Loader Config Keys === | ||
− | A loader key can be marked as mandatory or not in its <code>Flags</code> field. | + | A loader key can be marked as recognition-mandatory or not recognition-mandatory in its <code>Flags</code> field. |
− | + | The presence-mandatory field is part of the specification and does not go in the <code>Flags</code> field, but any complying loader must pass all fields specified to be presence-mandatory. | |
− | |||
− | + | If a key is marked as recognition-mandatory and is not recognized by the application, the program should jump to [[#LoaderReturnAddr]] with <code>result_code=346 | ((100 + key) << 9);</code>, as the default behaviour may be unsafe. | |
− | If a key that is | + | If a key that is presence-mandatory is not found (for example with an outdated loader), use <code>result_code=346 | ((200 + key) << 9);</code>. |
If there is some error encountered while validating an entry's values, use <code>result_code = 346 | ((300 + key) << 9);</code>. | If there is some error encountered while validating an entry's values, use <code>result_code = 346 | ((300 + key) << 9);</code>. | ||
− | * 0: [[#EndOfList]] | + | * 0: [[#EndOfList]] [RECOGNITION-MANDATORY] [PRESENCE-MANDATORY] |
− | * 1: [[#MainThreadHandle]] | + | * 1: [[#MainThreadHandle]] [RECOGNITION-MANDATORY] [PRESENCE-MANDATORY in some cases] |
− | * 2: [[# | + | * 2: [[#LoaderReturnAddr]] [RECOGNITION-MANDATORY] |
− | * 3: [[#OverrideHeap]] | + | * 3: [[#OverrideHeap]] [RECOGNITION-MANDATORY] |
* 4: [[#OverrideService]] | * 4: [[#OverrideService]] | ||
Line 63: | Line 60: | ||
* 6: [[#SyscallAvailableHint]] | * 6: [[#SyscallAvailableHint]] | ||
− | * 7: [[#AppletType]] | + | * 7: [[#AppletType]] [PRESENCE-MANDATORY in some cases] |
− | * 8: [[#AppletWorkaround]] | + | * 8: [[#AppletWorkaround]] [RECOGNITION-MANDATORY] |
* 9: [[#StdioSockets]] | * 9: [[#StdioSockets]] | ||
Line 75: | Line 72: | ||
* '''Key:''' 0 | * '''Key:''' 0 | ||
+ | * '''IsRecognitionMandatory:''' True, because not recognizing this tag would send the loader off the end of the list. | ||
+ | * '''IsPresenceMandatory:''' True, because the list must be terminated. | ||
* '''Value[0]:''' Ignored. | * '''Value[0]:''' Ignored. | ||
* '''Value[1]:''' Ignored. | * '''Value[1]:''' Ignored. | ||
Line 82: | Line 81: | ||
* '''Key:''' 1 | * '''Key:''' 1 | ||
+ | * '''IsRecognitionMandatory:''' True. | ||
+ | * '''IsPresenceMandatory:''' True if entry function was called with INVALID_HANDLE. | ||
* '''Value[0]:''' Handle to the main thread. | * '''Value[0]:''' Handle to the main thread. | ||
* '''Value[1]:''' Ignored. | * '''Value[1]:''' Ignored. | ||
* '''DefaultBehavior:''' Use main thread handle from entry function arguments. | * '''DefaultBehavior:''' Use main thread handle from entry function arguments. | ||
− | ==== | + | ==== LoaderReturnAddr ==== |
− | + | When the homebrew has finished executing, it shall jump to this address to return to the homebrew menu. | |
* '''Key:''' 2 | * '''Key:''' 2 | ||
− | * '''Value[0]:''' | + | * '''IsRecognitionMandatory:''' True, because the default behaviour may be unsafe if this key is not handled correctly. |
− | * '''Value[1]:''' | + | * '''IsPresenceMandatory:''' False. |
+ | * '''Value[0]:''' Function pointer with type <code>void __noreturn (*)(int result_code);</code> | ||
+ | * '''Value[1]:''' Ignored. | ||
+ | * '''DefaultBehavior:''' Returns back to where LR was when the program entered, or exits process using svcExitProcess if LR was NULL. | ||
==== OverrideHeap ==== | ==== OverrideHeap ==== | ||
Line 97: | Line 101: | ||
* '''Key:''' 3 | * '''Key:''' 3 | ||
+ | * '''IsRecognitionMandatory:''' True, because the default behaviour may be unsafe if this key is not handled correctly. | ||
+ | * '''IsPresenceMandatory:''' False. | ||
* '''Value[0]:''' Base address of heap. Must be MemoryType 4, 5, or 9 with all reference counts being zero. | * '''Value[0]:''' Base address of heap. Must be MemoryType 4, 5, or 9 with all reference counts being zero. | ||
* '''Value[1]:''' Size of heap. | * '''Value[1]:''' Size of heap. | ||
Line 113: | Line 119: | ||
* '''Key:''' 4 | * '''Key:''' 4 | ||
+ | * '''IsRecognitionMandatory:''' False. | ||
+ | * '''IsPresenceMandatory:''' False. | ||
* '''Value[0]:''' Name of service, same format as for sm. | * '''Value[0]:''' Name of service, same format as for sm. | ||
* '''Value[1]:''' Service handle. | * '''Value[1]:''' Service handle. | ||
Line 121: | Line 129: | ||
* '''Key:''' 5 | * '''Key:''' 5 | ||
− | * '''Value[0]:''' | + | * '''IsRecognitionMandatory:''' False. |
+ | * '''IsPresenceMandatory:''' False. | ||
+ | * '''Value[0]:''' Argc. | ||
* '''Value[1]:''' Argv string pointer. | * '''Value[1]:''' Argv string pointer. | ||
− | * '''DefaultBehavior:''' Setting (argc == 1, argv[0] == "", argv[1] == NULL), or argv parsed in NSO0 fashion. | + | * '''DefaultBehavior:''' Setting (argc == 1, argv[0] == "unknown", argv[1] == NULL), or argv parsed in NSO0 fashion. |
==== SyscallAvailableHint ==== | ==== SyscallAvailableHint ==== | ||
Line 131: | Line 141: | ||
* '''Key:''' 6 | * '''Key:''' 6 | ||
+ | * '''IsRecognitionMandatory:''' False. | ||
+ | * '''IsPresenceMandatory:''' False. | ||
* '''Value[0]:''' 64-bit mask for the 0-0x3F SVC range. n:th bit set means SVC is accessible. | * '''Value[0]:''' 64-bit mask for the 0-0x3F SVC range. n:th bit set means SVC is accessible. | ||
* '''Value[1]:''' 64-bit mask for the 0x40-0x7F SVC range. | * '''Value[1]:''' 64-bit mask for the 0x40-0x7F SVC range. | ||
Line 139: | Line 151: | ||
* '''Key:''' 7 | * '''Key:''' 7 | ||
+ | * '''IsRecognitionMandatory:''' False. | ||
+ | * '''IsPresenceMandatory:''' Application-defined. Depends on whether the application is using any applet services or not. | ||
* '''Value[0]:''' AppletType | * '''Value[0]:''' AppletType | ||
* '''Value[1]:''' Ignored. | * '''Value[1]:''' Ignored. | ||
Line 154: | Line 168: | ||
* '''Key:''' 8 | * '''Key:''' 8 | ||
+ | * '''IsRecognitionMandatory:''' True, because the default behaviour (using applet services) is unsafe if this tag is passed. | ||
+ | * '''IsPresenceMandatory:''' False. | ||
* '''Value[0]:''' AppletResourceUserId | * '''Value[0]:''' AppletResourceUserId | ||
* '''Value[1]:''' Ignored. | * '''Value[1]:''' Ignored. | ||
Line 161: | Line 177: | ||
* '''Key:''' 9 | * '''Key:''' 9 | ||
+ | * '''IsRecognitionMandatory:''' False. | ||
+ | * '''IsPresenceMandatory:''' False. | ||
* '''Value[0]:''' First word: stdout file descriptor, second word: stdin file descriptor | * '''Value[0]:''' First word: stdout file descriptor, second word: stdin file descriptor | ||
* '''Value[1]:''' Third word: stderr file descriptor, fourth word: SocketService | * '''Value[1]:''' Third word: stderr file descriptor, fourth word: SocketService | ||
Line 173: | Line 191: | ||
* '''Key:''' 10 | * '''Key:''' 10 | ||
+ | * '''IsRecognitionMandatory:''' False. | ||
+ | * '''IsPresenceMandatory:''' False. | ||
* '''Value[0]:''' Process handle. | * '''Value[0]:''' Process handle. | ||
* '''Value[1]:''' Ignored. | * '''Value[1]:''' Ignored. |
Revision as of 19:08, 17 January 2018
DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT
Entrypoint
Entrypoint is at binary_ptr+0. At this offset, there is a branch instruction that jumps past the NRO0 header. This is for (.text) file format polyglot compatibility with NSO0.
Every application should clean itself up before returning to loader.
This includes tasks like:
- Not leaking handles
- Resetting MemoryState
- No leftover threads running in the background
Entrypoint Arguments
NSO0: the system executes binary_ptr+0 with X0=NULL, X1=main_thread_handle.
NRO0: the homebrew loader puts X0=loader_config_ptr, X1=0xFFFFFFFFFFFFFFFF [INVALID_HANDLE].
Loader Config
Loader config allows overriding functionality to workaround limitations in a limited homebrew environment.
It is an array of tuples:
struct LoaderConfig { LoaderConfigEntry Entries[]; };
Each entry is key-value pair:
struct LoaderConfigEntry { u32 Key; u32 Flags; u64 Value[2]; };
enum LoaderConfigFlags { IsRecognitionMandatory = BIT(0), };
Loader Config Keys
A loader key can be marked as recognition-mandatory or not recognition-mandatory in its Flags
field.
The presence-mandatory field is part of the specification and does not go in the Flags
field, but any complying loader must pass all fields specified to be presence-mandatory.
If a key is marked as recognition-mandatory and is not recognized by the application, the program should jump to #LoaderReturnAddr with result_code=346 | ((100 + key) << 9);
, as the default behaviour may be unsafe.
If a key that is presence-mandatory is not found (for example with an outdated loader), use result_code=346 | ((200 + key) << 9);
.
If there is some error encountered while validating an entry's values, use result_code = 346 | ((300 + key) << 9);
.
- 0: #EndOfList [RECOGNITION-MANDATORY] [PRESENCE-MANDATORY]
- 1: #MainThreadHandle [RECOGNITION-MANDATORY] [PRESENCE-MANDATORY in some cases]
- 2: #LoaderReturnAddr [RECOGNITION-MANDATORY]
- 3: #OverrideHeap [RECOGNITION-MANDATORY]
- 5: #Argv
- 7: #AppletType [PRESENCE-MANDATORY in some cases]
- 8: #AppletWorkaround [RECOGNITION-MANDATORY]
- 10: #ProcessHandle
EndOfList
EndOfList is the final entry in the LoaderConfig.
- Key: 0
- IsRecognitionMandatory: True, because not recognizing this tag would send the loader off the end of the list.
- IsPresenceMandatory: True, because the list must be terminated.
- Value[0]: Ignored.
- Value[1]: Ignored.
MainThreadHandle
This is the handle to the thread that is executing the entrypoint. Required for mutex to function.
- Key: 1
- IsRecognitionMandatory: True.
- IsPresenceMandatory: True if entry function was called with INVALID_HANDLE.
- Value[0]: Handle to the main thread.
- Value[1]: Ignored.
- DefaultBehavior: Use main thread handle from entry function arguments.
LoaderReturnAddr
When the homebrew has finished executing, it shall jump to this address to return to the homebrew menu.
- Key: 2
- IsRecognitionMandatory: True, because the default behaviour may be unsafe if this key is not handled correctly.
- IsPresenceMandatory: False.
- Value[0]: Function pointer with type
void __noreturn (*)(int result_code);
- Value[1]: Ignored.
- DefaultBehavior: Returns back to where LR was when the program entered, or exits process using svcExitProcess if LR was NULL.
OverrideHeap
If the NRO loader has reserved some space in the heap for itself, the application must not manipulate the heap.
- Key: 3
- IsRecognitionMandatory: True, because the default behaviour may be unsafe if this key is not handled correctly.
- IsPresenceMandatory: False.
- Value[0]: Base address of heap. Must be MemoryType 4, 5, or 9 with all reference counts being zero.
- Value[1]: Size of heap.
- DefaultBehavior: Allocates heap using svcSetHeapSize instead.
OverrideService
The NRO loader should be able to steal handles from more priliveged processes. In this case, the homebrew should use this handle instead of the normal one.
Homebrew should allow up to 32 service overrides.
Note: Overridden service handles should not be converted to domains or closed.
Note: For services that authenticate with pid, the app should not attempt re-authentication with an overridden handle.
Note: There needs be special handling for the file system service. If the original fsp-srv handle doesn't allow MountSdcard, it shall fallback to the stolen one, etc etc.
- Key: 4
- IsRecognitionMandatory: False.
- IsPresenceMandatory: False.
- Value[0]: Name of service, same format as for sm.
- Value[1]: Service handle.
- DefaultBehavior: Fetches service from "sm:" named port.
Argv
The NRO loader should be able to send argv.
- Key: 5
- IsRecognitionMandatory: False.
- IsPresenceMandatory: False.
- Value[0]: Argc.
- Value[1]: Argv string pointer.
- DefaultBehavior: Setting (argc == 1, argv[0] == "unknown", argv[1] == NULL), or argv parsed in NSO0 fashion.
SyscallAvailableHint
Homebrew doesn't know if any privileged syscalls are available.
This entry allows loader to give hints about having access to rare syscalls (such as JIT).
- Key: 6
- IsRecognitionMandatory: False.
- IsPresenceMandatory: False.
- Value[0]: 64-bit mask for the 0-0x3F SVC range. n:th bit set means SVC is accessible.
- Value[1]: 64-bit mask for the 0x40-0x7F SVC range.
- DefaultBehavior: If NSO0, assume kernelhax thus all rare syscalls are allowed. If NRO0, assume all rare syscalls are inaccessible.
AppletType
Specifies the AM AppletType, used for selecting which Open*Proxy command to use.
- Key: 7
- IsRecognitionMandatory: False.
- IsPresenceMandatory: Application-defined. Depends on whether the application is using any applet services or not.
- Value[0]: AppletType
- Value[1]: Ignored.
enum LoaderConfigAppletType { LoaderConfigAppletType_Application = 0, LoaderConfigAppletType_SystemApplet = 1, LoaderConfigAppletType_LibraryApplet = 2, LoaderConfigAppletType_OverlayApplet = 3, LoaderConfigAppletType_SystemApplication = 4, };
AppletWorkaround
This flag means that AM services is broken, and must not be used.
- Key: 8
- IsRecognitionMandatory: True, because the default behaviour (using applet services) is unsafe if this tag is passed.
- IsPresenceMandatory: False.
- Value[0]: AppletResourceUserId
- Value[1]: Ignored.
StdioSockets
Use these sockets for standard input/output/error. There must be an #OverrideService key present for either bsd:u
or bsd:s
, depending on which is indicated.
- Key: 9
- IsRecognitionMandatory: False.
- IsPresenceMandatory: False.
- Value[0]: First word: stdout file descriptor, second word: stdin file descriptor
- Value[1]: Third word: stderr file descriptor, fourth word: SocketService
enum LoaderConfigSocketService { LoaderConfigSocketService_BsdU = 0, LoaderConfigSocketService_BsdS = 1, };
ProcessHandle
Handle to self process.
- Key: 10
- IsRecognitionMandatory: False.
- IsPresenceMandatory: False.
- Value[0]: Process handle.
- Value[1]: Ignored.