diff --git a/docs/modules/loader.md b/docs/modules/loader.md index 5ed0f5162..ca388178c 100644 --- a/docs/modules/loader.md +++ b/docs/modules/loader.md @@ -67,16 +67,35 @@ For example, `override_key=!R` will run the game only while holding down R when When the Stratosphere implementation of loader creates a new process, it notifies [sm](sm.md) through the `AtmosphereAssociatePidTidForMitm` command to notify any MITM services of new processes' identities. -### IPC: AtmosphereSetExternalContentSource +### IPC: AtmosphereSetExternalContentSource and AtmosphereClearExternalContentSource -An additional command is added to the [`ldr:shel`](https://reswitched.github.io/SwIPC/ifaces.html#nn::ro::detail::ILdrShellInterface) interface, called `AtmosphereSetExternalContentSource`. It's command ID is `65000` on all system firmware versions. It takes a `u64 tid` and returns a server-side session handle. The client is expected to implement the `IFileSystem` interface on the returned handle. The next time the title specified by the given title ID is launched, its ExeFS contents will be loaded from the custom `IFileSystem` instead of from SD card or original ExeFS. NSOs loaded from external content source may still be subject to exefs IPS patches. After the title is launched, the `IFileSystem` is closed and the external content source override is removed. If `AtmosphereSetExternalContentSource` is called on a title that already has an external content source set for it, the existing one will be removed and replaced with the new one. It is illegal to call `AtmosphereSetExternalContentSource` while the title is being launched. +Two additional commands are added to the [`ldr:shel`](https://reswitched.github.io/SwIPC/ifaces.html#nn::ro::detail::ILdrShellInterface) interface, called `AtmosphereSetExternalContentSource` and `AtmosphereClearExternalContentSource`. +Their command IDs are `65000` and `65001` on all system firmware versions. -The `IFileSystem` only needs to implement `OpenFile`. The paths received by the `IFileSystem`'s `OpenFile` command begin with slashes, as in `/main`, `/rtld`, and `/main.npdm`. A result code of 0x202 should be returned if the file does not exist. The `IFile`s returned from `OpenFile` only need to implement `Read` and `GetSize`. +`AtmosphereSetExternalContentSource` takes a `u64 tid` and returns a server-side session handle. +The client is expected to implement the `IFileSystem` interface on the returned handle. The next +time the title specified by the given title ID is launched, its ExeFS contents will be loaded from +the custom `IFileSystem` instead of from SD card or original ExeFS. NSOs loaded from external +content source may still be subject to exefs IPS patches. After the title is launched successfuly, +the `IFileSystem` is closed and the external content source override is removed. If +`AtmosphereSetExternalContentSource` is called on a title that already has an external content +source set for it, the existing one will be removed and replaced with the new one. It is illegal to +call `AtmosphereSetExternalContentSource` while the title is being launched. -The SwIPC definition for the `AtmosphereSetExternalContentSource` command follows. +If title launching fails, the external content source remains registered. The +`AtmosphereClearExternalContentSource` command can be used to clear an external content source if +title launch fails. + +The `IFileSystem` only needs to implement `OpenFile` and `GetFileTimeStampRaw`. The paths received +by the `IFileSystem`'s `OpenFile` command begin with slashes, as in `/main`, `/rtld`, and `/main.npdm`. +A result code of 0x202 should be returned if the file does not exist. `GetFileTimeStampRaw` can just +be a stub. The `IFile`s returned from `OpenFile` only need to implement `Read` and `GetSize`. + +The SwIPC definitions for the extension commands follow. ``` interface nn::ldr::detail::IShellInterface is ldr:shel { ... [65000] AtmosphereSetExternalContentSource(u64 tid) -> handle ifilesystem_handle; + [65001] AtmosphereClearExternalContentSource(u64 tid); } ``` diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index 74c4b095e..6253b9bfc 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -214,8 +214,8 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc Registration::AssociatePidTidForMitM(index); rc = 0; -CREATE_PROCESS_END: - /* ECS is a one-shot operation. */ + + /* ECS is a one-shot operation, but we don't clear on failure. */ ContentManagement::ClearExternalContentSource(target_process->tid_sid.title_id); if (mounted_code) { if (R_SUCCEEDED(rc) && target_process->tid_sid.storage_id != FsStorageId_None) { @@ -224,6 +224,8 @@ CREATE_PROCESS_END: ContentManagement::UnmountCode(); } } + +CREATE_PROCESS_END: if (R_SUCCEEDED(rc)) { *out_process_h = process_h; } else { diff --git a/stratosphere/loader/source/ldr_shell.cpp b/stratosphere/loader/source/ldr_shell.cpp index 4574c5af4..a359db5b2 100644 --- a/stratosphere/loader/source/ldr_shell.cpp +++ b/stratosphere/loader/source/ldr_shell.cpp @@ -45,3 +45,7 @@ Result ShellService::SetExternalContentSource(Out out, u64 tid) { out.SetValue(server_h); return 0; } + +void ShellService::ClearExternalContentSource(u64 tid) { + ContentManagement::ClearExternalContentSource(tid); +} diff --git a/stratosphere/loader/source/ldr_shell.hpp b/stratosphere/loader/source/ldr_shell.hpp index 69d6f2107..f51361f5d 100644 --- a/stratosphere/loader/source/ldr_shell.hpp +++ b/stratosphere/loader/source/ldr_shell.hpp @@ -23,6 +23,7 @@ enum ShellServiceCmd { Shell_Cmd_ClearLaunchQueue = 1, Shell_Cmd_AtmosphereSetExternalContentSource = 65000, + Shell_Cmd_AtmosphereClearExternalContentSource = 65001, }; class ShellService final : public IServiceObject { @@ -33,10 +34,12 @@ class ShellService final : public IServiceObject { /* Atmosphere commands. */ Result SetExternalContentSource(Out out, u64 tid); + void ClearExternalContentSource(u64 tid); public: DEFINE_SERVICE_DISPATCH_TABLE { MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), + MakeServiceCommandMeta(), }; };