From 0f6f7cfd954353afd41937ea03640346984acac6 Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 3 Oct 2018 14:48:39 -0500 Subject: [PATCH] Services/AM: Implemented BeginImportProgramTemporarily, EndImportProgramWithoutCommit and CommitImportPrograms. These functions are pretty much identical to BeginImportProgram and EndImportProgram. We don't need to do anything special in EndImportProgramWithoutCommit and CommitImportPrograms because we don't need to implement the two-phase title installation that the 3DS uses to prevent corruption of the title.db. --- src/core/hle/service/am/am.cpp | 56 ++++++++++++++++++++++++++++++++ src/core/hle/service/am/am.h | 37 +++++++++++++++++++++ src/core/hle/service/am/am_u.cpp | 6 ++-- 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 286a40711..05be6ef32 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1038,6 +1038,33 @@ void Module::Interface::BeginImportProgram(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) media_type={}", static_cast(media_type)); } +void Module::Interface::BeginImportProgramTemporarily(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0403, 0, 0); // 0x04030000 + + if (am->cia_installing) { + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrCodes::CIACurrentlyInstalling, ErrorModule::AM, + ErrorSummary::InvalidState, ErrorLevel::Permanent)); + return; + } + + // Note: This function should register the title in the temp_i.db database, but we can get away + // with not doing that because we traverse the file system to detect installed titles. + // Create our CIAFile handle for the app to write to, and while the app writes Citra will store + // contents out to sdmc/nand + const FileSys::Path cia_path = {}; + auto file = std::make_shared(std::make_unique(FS::MediaType::NAND), + cia_path); + + am->cia_installing = true; + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); // No error + rb.PushCopyObjects(file->Connect()); + + LOG_WARNING(Service_AM, "(STUBBED)"); +} + void Module::Interface::EndImportProgram(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0405, 0, 2); // 0x04050002 auto cia = rp.PopObject(); @@ -1049,6 +1076,35 @@ void Module::Interface::EndImportProgram(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } +void Module::Interface::EndImportProgramWithoutCommit(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0406, 0, 2); // 0x04060002 + auto cia = rp.PopObject(); + + // Note: This function is basically a no-op for us since we don't use title.db or ticket.db + // files to keep track of installed titles. + am->ScanForAllTitles(); + + am->cia_installing = false; + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); +} + +void Module::Interface::CommitImportPrograms(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0407, 3, 2); // 0x040700C2 + auto media_type = static_cast(rp.Pop()); + u32 title_count = rp.Pop(); + u8 database = rp.Pop(); + auto buffer = rp.PopMappedBuffer(); + + // Note: This function is basically a no-op for us since we don't use title.db or ticket.db + // files to keep track of installed titles. + am->ScanForAllTitles(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushMappedBuffer(buffer); +} + /// Wraps all File operations to allow adding an offset to them. class AMFileWrapper : public FileSys::FileBackend { public: diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index cb7dff745..dc10af0db 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -384,6 +384,17 @@ public: */ void BeginImportProgram(Kernel::HLERequestContext& ctx); + /** + * AM::BeginImportProgramTemporarily service function + * Begin importing from a CTR Installable Archive into the temporary title database + * Inputs: + * 0 : Command header (0x04030000) + * Outputs: + * 1 : Result, 0 on success, otherwise error code + * 2-3 : CIAFile handle for application to write to + */ + void BeginImportProgramTemporarily(Kernel::HLERequestContext& ctx); + /** * AM::EndImportProgram service function * Finish importing from a CTR Installable Archive @@ -395,6 +406,32 @@ public: */ void EndImportProgram(Kernel::HLERequestContext& ctx); + /** + * AM::EndImportProgramWithoutCommit service function + * Finish importing from a CTR Installable Archive + * Inputs: + * 0 : Command header (0x04060002) + * 1-2 : CIAFile handle application wrote to + * Outputs: + * 1 : Result, 0 on success, otherwise error code + */ + void EndImportProgramWithoutCommit(Kernel::HLERequestContext& ctx); + + /** + * AM::CommitImportPrograms service function + * Commits changes from the temporary title database to the real title database (title.db). + * This is a no-op for us, we don't use title.db + * Inputs: + * 0 : Command header (0x040700C2) + * 1 : Media type + * 2 : Title count + * 3 : Database type + * 4-5 : Title list buffer + * Outputs: + * 1 : Result, 0 on success, otherwise error code + */ + void CommitImportPrograms(Kernel::HLERequestContext& ctx); + /** * AM::GetProgramInfoFromCia service function * Get TitleInfo from a CIA file handle diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp index 7fa4a38c0..840860ec0 100644 --- a/src/core/hle/service/am/am_u.cpp +++ b/src/core/hle/service/am/am_u.cpp @@ -55,11 +55,11 @@ AM_U::AM_U(std::shared_ptr am) : Module::Interface(std::move(am), "am:u" {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"}, {0x04010080, nullptr, "UpdateFirmwareTo"}, {0x04020040, &AM_U::BeginImportProgram, "BeginImportProgram"}, - {0x04030000, nullptr, "BeginImportProgramTemporarily"}, + {0x04030000, &AM_U::BeginImportProgramTemporarily, "BeginImportProgramTemporarily"}, {0x04040002, nullptr, "CancelImportProgram"}, {0x04050002, &AM_U::EndImportProgram, "EndImportProgram"}, - {0x04060002, nullptr, "EndImportProgramWithoutCommit"}, - {0x040700C2, nullptr, "CommitImportPrograms"}, + {0x04060002, &AM_U::EndImportProgramWithoutCommit, "EndImportProgramWithoutCommit"}, + {0x040700C2, &AM_U::CommitImportPrograms, "CommitImportPrograms"}, {0x04080042, &AM_U::GetProgramInfoFromCia, "GetProgramInfoFromCia"}, {0x04090004, &AM_U::GetSystemMenuDataFromCia, "GetSystemMenuDataFromCia"}, {0x040A0002, &AM_U::GetDependencyListFromCia, "GetDependencyListFromCia"},