Process Manager services: Difference between revisions
No edit summary |
|||
| (73 intermediate revisions by 6 users not shown) | |||
| Line 1: | Line 1: | ||
= | = pm:bm = | ||
This is "nn::pm::detail::IBootModeInterface". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 0 || GetBootMode | |||
|- | |||
| 1 || SetMaintenanceBoot | |||
|- | |||
| 2 || [19.0.0+] | |||
|- | |||
| 3 || [19.0.0+] | |||
|} | |||
= pm:dmnt = | |||
This is "nn::pm::detail::IDebugMonitorInterface". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 0 || [5.0.0+] [[#GetExceptionProcessIdList]] ([1.0.0-4.1.0] [[#GetModuleIdList]]) | |||
|- | |||
| 1 || [5.0.0+] [[#StartProcess]] ([1.0.0-4.1.0] [[#GetExceptionProcessIdList]]) | |||
|- | |||
| 2 || [5.0.0+] [[#GetProcessId]] ([1.0.0-4.1.0] [[#StartProcess]]) | |||
|- | |||
| 3 || [5.0.0+] [[#HookToCreateProcess]] ([1.0.0-4.1.0] [[#GetProcessId]]) | |||
|- | |||
| 4 || [5.0.0+] [[#GetApplicationProcessId]] ([1.0.0-4.1.0] [[#HookToCreateProcess]]) | |||
|- | |||
| 5 || [5.0.0+] [[#HookToCreateApplicationProcess]] ([1.0.0-4.1.0] [[#GetApplicationProcessId]]) | |||
|- | |||
| 6 || [6.0.0+] [[#ClearHook]] | |||
|- | |||
| 7 || [14.0.0+] GetProgramIdDebug | |||
|} | |||
== GetModuleIdList== | |||
Stubbed in all versions of retail firmware (just returns 0). | |||
[2.0.0+] When output buffer size is > INT_MAX, returns ResultInvalidSize. | |||
== GetExceptionProcessIdList == | |||
Returns an array of pids of all processes that have mask 4 set in process flags. | |||
[2.0.0+] When output buffer size is > INT_MAX, returns ResultInvalidSize. | |||
== StartProcess == | |||
Takes a pid. Last process event must be ProcessEvent_Created or ProcessEvent_DebugAttached. | |||
Then it uses svcStartProcess(process_handle, u8, u8, u32) with args coming from ldr:pm GetProgramInfo. | |||
After that, it sets last process state to ProcessEvent_DebugDetached. | |||
== GetProcessId == | |||
Takes a title-id and returns the pid. | |||
== HookToCreateProcess == | |||
Takes a title-id of the program to debug. Sets this to a global field. | |||
Next time it gets launched it will be handled differently. | |||
Returns an event handle that is signaled when the requested title is about to be launched. | |||
== GetApplicationProcessId == | |||
Returns the pid of the application process. | |||
== HookToCreateApplicationProcess == | |||
Does *not* take a specific title-id as input. | |||
Returns an event handle that is triggered for application titles. | |||
== ClearHook == | |||
Takes in a u32 of bitflags. | |||
Disables debugging/clears the globally specified tid if bit 0 is set, disables debugging/clears the next application if bit 1 is set. | |||
= pm:info = | |||
This is "nn::pm::detail::IInformationInterface". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 0 || [[#GetProgramId]] | |||
|- | |||
| 1 || [14.0.0+] GetAppletResourceLimitCurrentValue | |||
|- | |||
| 2 || [14.0.0+] GetAppletResourceLimitPeakValue | |||
|} | |||
== GetProgramId == | |||
Takes a pid and returns the title-id associated with the process. | |||
= pm:shell = | = pm:shell = | ||
This is "nn::pm::detail::IShellInterface". | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
! Cmd || Name | ! Cmd || Name | ||
|- | |- | ||
| 0 || | | 0 || [[#LaunchProgram]] | ||
|- | |- | ||
| 1 || TerminateProcess | | 1 || TerminateProcess | ||
|- | |- | ||
| 2 || | | 2 || TerminateProgram | ||
|- | |||
| 3 || GetProcessEventEvent | |||
|- | |||
| 4 || [[#GetProcessEventInfo]] | |||
|- | |||
| 5 || [5.0.0+] [[#NotifyBootFinished]] ([1.0.0-4.1.0] [[#CleanupProcess]]) | |||
|- | |||
| 6 || [5.0.0+] [[#GetApplicationProcessIdForShell]] ([1.0.0-4.1.0] [[#ClearJitDebugOccured]]) | |||
|- | |||
| 7 || [4.0.0+] [[#BoostSystemMemoryResourceLimit]] | |||
|- | |||
| 8 || [7.0.0+] [[#BoostApplicationThreadResourceLimit]] | |||
|- | |- | ||
| | | 9 || [8.0.0+] [[#GetBootFinishedEvent]] | ||
|- | |- | ||
| | | 10 || [14.0.0+] BoostSystemThreadResourceLimit | ||
|- | |- | ||
| 5 || | | 12 || [19.0.0+] GetProcessId | ||
|} | |||
== LaunchProgram == | |||
Takes an u32 launch_flags and [[NCM_services#ProgramLocation|ProgramLocation]]. Returns the u64 title PID. | |||
See [[#Process launch]]. | |||
== GetProcessEventInfo == | |||
Returns 1 if flags has mask 2 set. | |||
Returns 2 if flags has mask 1 set and state is 6. | |||
Returns 3 if flags has mask 0x10 set and not 0x20. | |||
Returns 4 if flags has mask 0x30 set. | |||
[2.0.0+] returns 5 if state >= 2 and flags has mask 0x100 set. | |||
Returns 0 if process is not found. | |||
== CleanupProcess == | |||
Takes a pid as input. If the process with pid has the state "dead", it unregisters the pid in fsp:pr, sm:m, and ldr:pm. | |||
Then it removes the process from PMs internal linked-list of active processes. | |||
[5.0.0+] This command was removed. | |||
== ClearJitDebugOccured == | |||
Takes a pid as input. Clears 0x10 from process flags. | |||
[5.0.0+] This command was removed. | |||
== NotifyBootFinished == | |||
This [[#LaunchProgram|launches]] the [[boot2]] title with launch_flags=0. | |||
[10.0.0+] The functionality described [[SMC#DisableProgramVerification|here]] was added, prior to title-launching. | |||
[4.0.0+] When booting from SafeMode Firmware, instead of [[boot2]], this launches the following titles in order (launch_flags=0): | |||
* 0100000000000009 (settings) | |||
* 0100000000000006 (usb) | |||
* 010000000000001D (pcie) | |||
* 0100000000000007 (tma) | |||
* 0100000000000042 (pgl) [10.0.0+] | |||
* 010000000000001F (ns) | |||
* 0100000000000015 (lm) | |||
* 0100000000000010 (ptm) | |||
* 0100000000000016 (wlan) | |||
* 0100000000000012 (bsdsockets) | |||
* 0100000000000046 (eth) [15.0.0+] | |||
* 010000000000000F (nifm) | |||
* 0100000000000024 (ssl) | |||
* 0100000000000025 (nim) | |||
* 0100000000000031 (glue) | |||
* 010000000000003D (safemode) | |||
== GetApplicationProcessIdForShell == | |||
Loops through the internal linked-list of processes, looks for mask 0x40 set in process flags. Returns pid of first such entry. | |||
== BoostSystemMemoryResourceLimit == | |||
Takes an u64 '''mem_size''' as input. If the desired memory size doesn't exceed an internal limit (imposed by PM by looking at the [[SPL_services#MemoryArrange|MemoryArrange]] ConfigItem), PM calls svcSetResourceLimitLimitValue to set the new [[SVC#LimitableResource|LimitableResource_Memory]] value. | |||
This is used directly by [[NS_Services#IApplicationManagerInterface|ns:am2 BoostSystemMemoryResourceLimit]]. | |||
== BoostApplicationThreadResourceLimit == | |||
Calls svcSetResourceLimitLimitValue to increase the limit on application threads by an amount calculated dynamically during setup. | |||
This function can only increase the limit once, on further calls it will call svcSetResourceLimitLimitValue with the same value it called the first time. | |||
On normal [[7.0.0]] retail firmware, this will double the limit on application threads from 0x60 to 0xC0. | |||
== GetBootFinishedEvent == | |||
This function returns a handle to an event that is signaled when [[#NotifyBootFinished]] is called. | |||
However, this is only used/available in safe mode; in normal, non-safe FIRM, the implementation for this command just does "abort();". | |||
= BootMode = | |||
This is "nn::pm::BootMode". | |||
{| class="wikitable" border="1" | |||
! Value | |||
! Description | |||
|- | |- | ||
| | | 0 || Normal | ||
|- | |- | ||
| | | 1 || Maintenance | ||
|- | |||
| 2 || SafeMode | |||
|} | |||
= HookType = | |||
This is "nn::pm::HookType". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Bit | |||
! Description | |||
|- | |||
| 0 | |||
| ProgramId | |||
|- | |||
| 1 | |||
| Application | |||
|} | |||
= LaunchProgramFlags = | |||
This is "nn::pm::LaunchProgramFlags". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Bit | |||
! Description | |||
|- | |||
| 0 | |||
| NotifyExit | |||
|- | |||
| 1 | |||
| [5.0.0+] NotifyStart ([1.0.0-4.1.0] NotStart) | |||
|- | |||
| 2 | |||
| NotifyException | |||
|- | |||
| 3 | |||
| [5.0.0+] NotifyDebug ([1.0.0-4.1.0] DisableAslr) | |||
|- | |||
| 4 | |||
| [5.0.0+] NotStart ([1.0.0-4.1.0] NotifyDebug) | |||
|- | |||
| 5 | |||
| [5.0.0+] DisableAslr ([2.0.0-4.1.0] NotifyStart) | |||
|} | |||
= ProcessEvent = | |||
This is "nn::pm::ProcessEvent". | |||
{| class="wikitable" border="1" | |||
! Value | |||
! Description | |||
|- | |||
| 0 || None | |||
|- | |||
| 1 || Exit | |||
|- | |||
| 2 || Started | |||
|- | |||
| 3 || Exception | |||
|- | |||
| 4 || DebugRunning | |||
|- | |||
| 5 || DebugBreaked | |||
|} | |||
= ProcessEventInfo = | |||
This is "nn::pm::ProcessEventInfo". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset | |||
! Size | |||
! Description | |||
|- | |||
| 0x0 | |||
| 0x4 | |||
| [[#ProcessEvent|Event]] | |||
|- | |||
| 0x4 | |||
| 0x4 | |||
| Reserved | |||
|- | |||
| 0x8 | |||
| 0x8 | |||
| ProcessId | |||
|} | |||
= ProcessEnvironment = | |||
This is "nn::pm::ProcessEnvironment". | |||
{| class="wikitable" border="1" | |||
! Value | |||
! Description | |||
|- | |- | ||
| | | 0 || | ||
|} | |} | ||
= Notes = | |||
PM has a separate thread that is waiting for synchronization on process handles. | |||
== State changes == | |||
When the kernel signals a process handle, it uses svcResetSignal on the process handle and then it uses svcGetProcessInfo to read out the ProcessEvent. | |||
If the process moved from non-crashed -> ProcessEvent_Crashed it clears 4 in process flags. | |||
If process flags has mask 8 set: | |||
* If event is ProcessEvent_Running or ProcessEvent_DebugDetached, it clears 0x20 and sets 0x10 in process flags, and signals the ProcessEventWaiter handle. | |||
* If event is ProcessEvent_DebugSuspended, it sets 0x20 and 0x10 in process flags, and signals the ProcessEventWaiter handle. | |||
[2.0.0+] If new state is ProcessEvent_DebugDetached, and process flags has 0x80 set, it sets mask 0x100 and signals the ProcessEventWaiter handle. | |||
If process flags has mask 1 set: | |||
* If new state is ProcessEvent_Exited, it signals the ProcessEventWaiter handle. | |||
If mask 1 is not set, it immediately does what is otherwise done by the [[#FinalizeDeadProcess]] command. | |||
== Process launch == | |||
This thread can also be triggered by the pm:shell [[#LaunchProcess]] cmd. | |||
It uses [[Loader_services|ldr:pm]] GetProgramInfo with the supplied title-id. | |||
If ApplicationType == Application, it goes through the process list and errors if any has mask 0x40 set. Thus you can only run one Application at a time. | |||
Resource limits for the process is selected by ApplicationType. | |||
It calls [[Loader_services|ldr:pm]] RegisterTitle, then [[Loader_services|ldr:pm]] CreateProcess, then [[Filesystem_services|fsp-pr]] RegisterTitle, then [[Services_API|sm:m]] RegisterTitle. | |||
[1.0.0] The second input argument for [[Loader_services|ldr:pm]] CreateProcess is (launch_flags >> 2) & 3. | |||
[2.0.0+] The second input argument for [[Loader_services|ldr:pm]] CreateProcess is ((launch_flags >> 2) & 2) | ((launch_flags >> 1) != 1). | |||
If launch_flags has mask 1 set, it sets mask 1 in process flags. | |||
If launch_flags has mask 0x10 set, it sets mask 8 in process flags. | |||
[2.0.0+] If launch_flags has mask 0x20 set, it sets mask 0x80 in process flags. | |||
[2.0.0+] The launch_flags mask 0x10 and 0x20 will be ignored unless ((*(u8*) (info_output+2)) & 4) is set. | |||
If ApplicationType == Application, it sets 0x40 in the process flags, and signals the event returned by [[#EnableDebugForApplication]]. svcStartProcess is not called in this case, it has to be done manually by the [[#StartProcess]] command. | |||
If the title-id matches the title-id given in [[#EnableDebugForTitleId]], then svcStartProcess is not called. Instead process remains in suspended state, and has to be done manually by the [[#StartProcess]] command. | |||
If launch_flags has mask 2 set, svcStartProcess is skipped. | |||
Finally it does svcStartProcess on the process handle that was returned by [[Loader_services|ldr:pm]] CreateProcess, and sets process state to 2. | |||
The arguments for svcStartProcess are process_handle, *(u8*)info_output, *(u8*)(info_output+1), *(u32*)(info_output+4). | |||
Thus at the point of launch, the pid is already registered in ldr, fs, sm, and pm. | |||
[[Category:Services]] | |||