From 2e38ea7a333b5a337ddf98989a260028b914b7c8 Mon Sep 17 00:00:00 2001 From: shinyquagsire23 Date: Wed, 25 Oct 2017 11:41:07 -0600 Subject: [PATCH] Services/AM: Implement GetPatchTitleInfos, correct error codes/returns, misc fixes --- src/core/hle/service/am/am.cpp | 130 ++++++++++++++++++++++++----- src/core/hle/service/am/am.h | 27 +++++- src/core/hle/service/am/am_app.cpp | 4 +- src/core/hle/service/am/am_sys.cpp | 4 +- 4 files changed, 135 insertions(+), 30 deletions(-) diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 1d1b57df57..6bbcd96fcc 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -24,6 +24,9 @@ namespace Service { namespace AM { +constexpr u32 TID_HIGH_UPDATE = 0x0004000E; +constexpr u32 TID_HIGH_DLC = 0x0004008C; + static bool lists_initialized = false; static std::array, 3> am_title_list; @@ -182,7 +185,7 @@ void GetNumPrograms(Service::Interface* self) { } void FindContentInfos(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1002, 4, 2); // 0x10020104 + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1002, 4, 4); // 0x10020104 auto media_type = static_cast(rp.Pop()); u64 title_id = rp.Pop(); @@ -225,7 +228,7 @@ void FindContentInfos(Service::Interface* self) { } void ListContentInfos(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1003, 5, 1); // 0x10030142 + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1003, 5, 2); // 0x10030142 u32 content_count = rp.Pop(); auto media_type = static_cast(rp.Pop()); u64 title_id = rp.Pop(); @@ -264,7 +267,7 @@ void ListContentInfos(Service::Interface* self) { } void DeleteContents(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1004, 4, 1); // 0x10040102 + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1004, 4, 2); // 0x10040102 u8 media_type = rp.Pop(); u64 title_id = rp.Pop(); u32 content_count = rp.Pop(); @@ -278,7 +281,7 @@ void DeleteContents(Service::Interface* self) { } void GetProgramList(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 2, 2, 1); // 0x00020082 + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 2, 2, 2); // 0x00020082 u32 count = rp.Pop(); u8 media_type = rp.Pop(); @@ -302,18 +305,9 @@ void GetProgramList(Service::Interface* self) { rb.Push(copied); } -void GetProgramInfos(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 3, 2, 2); // 0x00030084 - - auto media_type = static_cast(rp.Pop()); - u32 title_count = rp.Pop(); - VAddr title_id_list_pointer = rp.PopMappedBuffer(); - VAddr title_info_out = rp.PopMappedBuffer(); - - std::vector title_id_list(title_count); - Memory::ReadBlock(title_id_list_pointer, title_id_list.data(), title_count * sizeof(u64)); - - for (u32 i = 0; i < title_count; i++) { +ResultCode GetTitleInfoFromList(const std::vector& title_id_list, + Service::FS::MediaType media_type, VAddr title_info_out) { + for (u32 i = 0; i < title_id_list.size(); i++) { std::string tmd_path = GetTitleMetadataPath(media_type, title_id_list[i]); TitleInfo title_info = {}; @@ -326,23 +320,113 @@ void GetProgramInfos(Service::Interface* self) { title_info.size = tmd.GetContentSizeByIndex(FileSys::TMDContentIndex::Main); title_info.version = tmd.GetTitleVersion(); title_info.type = tmd.GetTitleType(); + } else { + return ResultCode(ErrorDescription::NotFound, ErrorModule::AM, + ErrorSummary::InvalidState, ErrorLevel::Permanent); } Memory::WriteBlock(title_info_out, &title_info, sizeof(TitleInfo)); title_info_out += sizeof(TitleInfo); } - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RESULT_SUCCESS); + return RESULT_SUCCESS; } -void GetDataTitleInfos(Service::Interface* self) { - GetProgramInfos(self); +void GetProgramInfos(Service::Interface* self) { + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 3, 2, 4); // 0x00030084 - LOG_WARNING(Service_AM, "(STUBBED) called"); + auto media_type = static_cast(rp.Pop()); + u32 title_count = rp.Pop(); + + size_t title_id_list_size, title_info_size; + IPC::MappedBufferPermissions title_id_list_perms, title_info_perms; + VAddr title_id_list_pointer = rp.PopMappedBuffer(&title_id_list_size, &title_id_list_perms); + VAddr title_info_out = rp.PopMappedBuffer(&title_info_size, &title_info_perms); + + std::vector title_id_list(title_count); + Memory::ReadBlock(title_id_list_pointer, title_id_list.data(), title_count * sizeof(u64)); + + ResultCode result = GetTitleInfoFromList(title_id_list, media_type, title_info_out); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); + rb.Push(result); + rb.PushMappedBuffer(title_id_list_pointer, title_id_list_size, title_id_list_perms); + rb.PushMappedBuffer(title_info_out, title_info_size, title_info_perms); +} + +void GetDLCTitleInfos(Service::Interface* self) { + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1005, 2, 4); // 0x10050084 + + auto media_type = static_cast(rp.Pop()); + u32 title_count = rp.Pop(); + + size_t title_id_list_size, title_info_size; + IPC::MappedBufferPermissions title_id_list_perms, title_info_perms; + VAddr title_id_list_pointer = rp.PopMappedBuffer(&title_id_list_size, &title_id_list_perms); + VAddr title_info_out = rp.PopMappedBuffer(&title_info_size, &title_info_perms); + + std::vector title_id_list(title_count); + Memory::ReadBlock(title_id_list_pointer, title_id_list.data(), title_count * sizeof(u64)); + + ResultCode result = RESULT_SUCCESS; + + // Validate that DLC TIDs were passed in + for (u32 i = 0; i < title_count; i++) { + u32 tid_high = static_cast(title_id_list[i] >> 32); + if (tid_high != TID_HIGH_DLC) { + result = ResultCode(ErrCodes::InvalidTIDInList, ErrorModule::AM, + ErrorSummary::InvalidArgument, ErrorLevel::Usage); + break; + } + } + + if (result.IsSuccess()) { + result = GetTitleInfoFromList(title_id_list, media_type, title_info_out); + } + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); + rb.Push(result); + rb.PushMappedBuffer(title_id_list_pointer, title_id_list_size, title_id_list_perms); + rb.PushMappedBuffer(title_info_out, title_info_size, title_info_perms); +} + +void GetPatchTitleInfos(Service::Interface* self) { + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x100D, 2, 4); // 0x100D0084 + + auto media_type = static_cast(rp.Pop()); + u32 title_count = rp.Pop(); + + size_t title_id_list_size, title_info_size; + IPC::MappedBufferPermissions title_id_list_perms, title_info_perms; + VAddr title_id_list_pointer = rp.PopMappedBuffer(&title_id_list_size, &title_id_list_perms); + VAddr title_info_out = rp.PopMappedBuffer(&title_info_size, &title_info_perms); + + std::vector title_id_list(title_count); + Memory::ReadBlock(title_id_list_pointer, title_id_list.data(), title_count * sizeof(u64)); + + ResultCode result = RESULT_SUCCESS; + + // Validate that update TIDs were passed in + for (u32 i = 0; i < title_count; i++) { + u32 tid_high = static_cast(title_id_list[i] >> 32); + if (tid_high != TID_HIGH_UPDATE) { + result = ResultCode(ErrCodes::InvalidTIDInList, ErrorModule::AM, + ErrorSummary::InvalidArgument, ErrorLevel::Usage); + break; + } + } + + if (result.IsSuccess()) { + result = GetTitleInfoFromList(title_id_list, media_type, title_info_out); + } + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); + rb.Push(result); + rb.PushMappedBuffer(title_id_list_pointer, title_id_list_size, title_id_list_perms); + rb.PushMappedBuffer(title_info_out, title_info_size, title_info_perms); } void ListDataTitleTicketInfos(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1007, 4, 1); // 0x10070102 + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1007, 4, 4); // 0x10070102 u32 ticket_count = rp.Pop(); u64 title_id = rp.Pop(); u32 start_index = rp.Pop(); @@ -408,7 +492,7 @@ void GetNumTickets(Service::Interface* self) { } void GetTicketList(Service::Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 9, 2, 1); // 0x00090082 + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 9, 2, 2); // 0x00090082 u32 ticket_list_count = rp.Pop(); u32 ticket_index = rp.Pop(); VAddr ticket_tids_out = rp.PopMappedBuffer(); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 6ee4908b3f..e2270c93c7 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -19,6 +19,12 @@ class Interface; namespace AM { +namespace ErrCodes { +enum { + InvalidTIDInList = 60, +}; +} // namespace ErrCodes + /** * Get the .tmd path for a title * @param media_type the media the title exists on @@ -139,8 +145,8 @@ void GetProgramList(Service::Interface* self); void GetProgramInfos(Service::Interface* self); /** - * AM::GetDataTitleInfos service function - * Wrapper for AM::GetProgramInfos + * AM::GetDLCTitleInfos service function + * Wrapper for AM::GetProgramInfos, explicitly checks that TID high value is 0004008C. * Inputs: * 1 : u8 Mediatype * 2 : Total titles @@ -149,7 +155,22 @@ void GetProgramInfos(Service::Interface* self); * Outputs: * 1 : Result, 0 on success, otherwise error code */ -void GetDataTitleInfos(Service::Interface* self); +void GetDLCTitleInfos(Service::Interface* self); + +/** + * AM::GetPatchTitleInfos service function + * Wrapper for AM::GetProgramInfos, explicitly checks that TID high value is 0004000E. + * Inputs: + * 1 : u8 Mediatype + * 2 : Total titles + * 4 : TitleIDList input pointer + * 6 : TitleList output pointer + * Outputs: + * 1 : Result, 0 on success, otherwise error code + * 2 : TitleIDList input pointer + * 4 : TitleList output pointer + */ +void GetPatchTitleInfos(Service::Interface* self); /** * AM::ListDataTitleTicketInfos service function diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp index 218375c8f9..db85067d02 100644 --- a/src/core/hle/service/am/am_app.cpp +++ b/src/core/hle/service/am/am_app.cpp @@ -13,7 +13,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x10020104, FindContentInfos, "FindContentInfos"}, {0x10030142, ListContentInfos, "ListContentInfos"}, {0x10040102, DeleteContents, "DeleteContents"}, - {0x10050084, GetDataTitleInfos, "GetDataTitleInfos"}, + {0x10050084, GetDLCTitleInfos, "GetDLCTitleInfos"}, {0x10060080, nullptr, "GetNumDataTitleTickets"}, {0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"}, {0x100801C2, nullptr, "GetItemRights"}, @@ -21,7 +21,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, {0x100B00C0, nullptr, "GetNumExistingContentInfos"}, {0x100C0142, nullptr, "ListExistingContentInfos"}, - {0x100D0084, nullptr, "GetPatchTitleInfos"}, + {0x100D0084, GetPatchTitleInfos, "GetPatchTitleInfos"}, }; AM_APP_Interface::AM_APP_Interface() { diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp index 5112a6a0d6..7787fdfedc 100644 --- a/src/core/hle/service/am/am_sys.cpp +++ b/src/core/hle/service/am/am_sys.cpp @@ -58,7 +58,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x10020104, FindContentInfos, "FindContentInfos"}, {0x10030142, ListContentInfos, "ListContentInfos"}, {0x10040102, DeleteContents, "DeleteContents"}, - {0x10050084, GetDataTitleInfos, "GetDataTitleInfos"}, + {0x10050084, GetDLCTitleInfos, "GetDLCTitleInfos"}, {0x10060080, nullptr, "GetNumDataTitleTickets"}, {0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"}, {0x100801C2, nullptr, "GetItemRights"}, @@ -66,7 +66,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, {0x100B00C0, nullptr, "GetNumExistingContentInfos"}, {0x100C0142, nullptr, "ListExistingContentInfos"}, - {0x100D0084, nullptr, "GetPatchTitleInfos"}, + {0x100D0084, GetPatchTitleInfos, "GetPatchTitleInfos"}, }; AM_SYS_Interface::AM_SYS_Interface() {