mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #3048 from shinyquagsire23/am-patch
Services/AM: Implement GetPatchTitleInfos, Misc Cleanup
This commit is contained in:
		
						commit
						79852d3707
					
				
					 4 changed files with 135 additions and 30 deletions
				
			
		|  | @ -24,6 +24,9 @@ | ||||||
| namespace Service { | namespace Service { | ||||||
| namespace AM { | namespace AM { | ||||||
| 
 | 
 | ||||||
|  | constexpr u32 TID_HIGH_UPDATE = 0x0004000E; | ||||||
|  | constexpr u32 TID_HIGH_DLC = 0x0004008C; | ||||||
|  | 
 | ||||||
| static bool lists_initialized = false; | static bool lists_initialized = false; | ||||||
| static std::array<std::vector<u64_le>, 3> am_title_list; | static std::array<std::vector<u64_le>, 3> am_title_list; | ||||||
| 
 | 
 | ||||||
|  | @ -182,7 +185,7 @@ void GetNumPrograms(Service::Interface* self) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FindContentInfos(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<Service::FS::MediaType>(rp.Pop<u8>()); |     auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); | ||||||
|     u64 title_id = rp.Pop<u64>(); |     u64 title_id = rp.Pop<u64>(); | ||||||
|  | @ -225,7 +228,7 @@ void FindContentInfos(Service::Interface* self) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ListContentInfos(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<u32>(); |     u32 content_count = rp.Pop<u32>(); | ||||||
|     auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); |     auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); | ||||||
|     u64 title_id = rp.Pop<u64>(); |     u64 title_id = rp.Pop<u64>(); | ||||||
|  | @ -264,7 +267,7 @@ void ListContentInfos(Service::Interface* self) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DeleteContents(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<u8>(); |     u8 media_type = rp.Pop<u8>(); | ||||||
|     u64 title_id = rp.Pop<u64>(); |     u64 title_id = rp.Pop<u64>(); | ||||||
|     u32 content_count = rp.Pop<u32>(); |     u32 content_count = rp.Pop<u32>(); | ||||||
|  | @ -278,7 +281,7 @@ void DeleteContents(Service::Interface* self) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetProgramList(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<u32>(); |     u32 count = rp.Pop<u32>(); | ||||||
|     u8 media_type = rp.Pop<u8>(); |     u8 media_type = rp.Pop<u8>(); | ||||||
|  | @ -302,18 +305,9 @@ void GetProgramList(Service::Interface* self) { | ||||||
|     rb.Push(copied); |     rb.Push(copied); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetProgramInfos(Service::Interface* self) { | ResultCode GetTitleInfoFromList(const std::vector<u64>& title_id_list, | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 3, 2, 2); // 0x00030084
 |                                 Service::FS::MediaType media_type, VAddr title_info_out) { | ||||||
| 
 |     for (u32 i = 0; i < title_id_list.size(); i++) { | ||||||
|     auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); |  | ||||||
|     u32 title_count = rp.Pop<u32>(); |  | ||||||
|     VAddr title_id_list_pointer = rp.PopMappedBuffer(); |  | ||||||
|     VAddr title_info_out = rp.PopMappedBuffer(); |  | ||||||
| 
 |  | ||||||
|     std::vector<u64> 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++) { |  | ||||||
|         std::string tmd_path = GetTitleMetadataPath(media_type, title_id_list[i]); |         std::string tmd_path = GetTitleMetadataPath(media_type, title_id_list[i]); | ||||||
| 
 | 
 | ||||||
|         TitleInfo title_info = {}; |         TitleInfo title_info = {}; | ||||||
|  | @ -326,23 +320,113 @@ void GetProgramInfos(Service::Interface* self) { | ||||||
|             title_info.size = tmd.GetContentSizeByIndex(FileSys::TMDContentIndex::Main); |             title_info.size = tmd.GetContentSizeByIndex(FileSys::TMDContentIndex::Main); | ||||||
|             title_info.version = tmd.GetTitleVersion(); |             title_info.version = tmd.GetTitleVersion(); | ||||||
|             title_info.type = tmd.GetTitleType(); |             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)); |         Memory::WriteBlock(title_info_out, &title_info, sizeof(TitleInfo)); | ||||||
|         title_info_out += sizeof(TitleInfo); |         title_info_out += sizeof(TitleInfo); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     return RESULT_SUCCESS; | ||||||
|     rb.Push(RESULT_SUCCESS); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetDataTitleInfos(Service::Interface* self) { | void GetProgramInfos(Service::Interface* self) { | ||||||
|     GetProgramInfos(self); |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 3, 2, 4); // 0x00030084
 | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); |     auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); | ||||||
|  |     u32 title_count = rp.Pop<u32>(); | ||||||
|  | 
 | ||||||
|  |     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<u64> 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<Service::FS::MediaType>(rp.Pop<u8>()); | ||||||
|  |     u32 title_count = rp.Pop<u32>(); | ||||||
|  | 
 | ||||||
|  |     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<u64> 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<u32>(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<Service::FS::MediaType>(rp.Pop<u8>()); | ||||||
|  |     u32 title_count = rp.Pop<u32>(); | ||||||
|  | 
 | ||||||
|  |     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<u64> 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<u32>(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) { | 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<u32>(); |     u32 ticket_count = rp.Pop<u32>(); | ||||||
|     u64 title_id = rp.Pop<u64>(); |     u64 title_id = rp.Pop<u64>(); | ||||||
|     u32 start_index = rp.Pop<u32>(); |     u32 start_index = rp.Pop<u32>(); | ||||||
|  | @ -408,7 +492,7 @@ void GetNumTickets(Service::Interface* self) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetTicketList(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>(); |     u32 ticket_list_count = rp.Pop<u32>(); | ||||||
|     u32 ticket_index = rp.Pop<u32>(); |     u32 ticket_index = rp.Pop<u32>(); | ||||||
|     VAddr ticket_tids_out = rp.PopMappedBuffer(); |     VAddr ticket_tids_out = rp.PopMappedBuffer(); | ||||||
|  |  | ||||||
|  | @ -19,6 +19,12 @@ class Interface; | ||||||
| 
 | 
 | ||||||
| namespace AM { | namespace AM { | ||||||
| 
 | 
 | ||||||
|  | namespace ErrCodes { | ||||||
|  | enum { | ||||||
|  |     InvalidTIDInList = 60, | ||||||
|  | }; | ||||||
|  | } // namespace ErrCodes
 | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Get the .tmd path for a title |  * Get the .tmd path for a title | ||||||
|  * @param media_type the media the title exists on |  * @param media_type the media the title exists on | ||||||
|  | @ -139,8 +145,8 @@ void GetProgramList(Service::Interface* self); | ||||||
| void GetProgramInfos(Service::Interface* self); | void GetProgramInfos(Service::Interface* self); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * AM::GetDataTitleInfos service function |  * AM::GetDLCTitleInfos service function | ||||||
|  * Wrapper for AM::GetProgramInfos |  * Wrapper for AM::GetProgramInfos, explicitly checks that TID high value is 0004008C. | ||||||
|  *  Inputs: |  *  Inputs: | ||||||
|  *      1 : u8 Mediatype |  *      1 : u8 Mediatype | ||||||
|  *      2 : Total titles |  *      2 : Total titles | ||||||
|  | @ -149,7 +155,22 @@ void GetProgramInfos(Service::Interface* self); | ||||||
|  *  Outputs: |  *  Outputs: | ||||||
|  *      1 : Result, 0 on success, otherwise error code |  *      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 |  * AM::ListDataTitleTicketInfos service function | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ const Interface::FunctionInfo FunctionTable[] = { | ||||||
|     {0x10020104, FindContentInfos, "FindContentInfos"}, |     {0x10020104, FindContentInfos, "FindContentInfos"}, | ||||||
|     {0x10030142, ListContentInfos, "ListContentInfos"}, |     {0x10030142, ListContentInfos, "ListContentInfos"}, | ||||||
|     {0x10040102, DeleteContents, "DeleteContents"}, |     {0x10040102, DeleteContents, "DeleteContents"}, | ||||||
|     {0x10050084, GetDataTitleInfos, "GetDataTitleInfos"}, |     {0x10050084, GetDLCTitleInfos, "GetDLCTitleInfos"}, | ||||||
|     {0x10060080, nullptr, "GetNumDataTitleTickets"}, |     {0x10060080, nullptr, "GetNumDataTitleTickets"}, | ||||||
|     {0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"}, |     {0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"}, | ||||||
|     {0x100801C2, nullptr, "GetItemRights"}, |     {0x100801C2, nullptr, "GetItemRights"}, | ||||||
|  | @ -21,7 +21,7 @@ const Interface::FunctionInfo FunctionTable[] = { | ||||||
|     {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, |     {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, | ||||||
|     {0x100B00C0, nullptr, "GetNumExistingContentInfos"}, |     {0x100B00C0, nullptr, "GetNumExistingContentInfos"}, | ||||||
|     {0x100C0142, nullptr, "ListExistingContentInfos"}, |     {0x100C0142, nullptr, "ListExistingContentInfos"}, | ||||||
|     {0x100D0084, nullptr, "GetPatchTitleInfos"}, |     {0x100D0084, GetPatchTitleInfos, "GetPatchTitleInfos"}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| AM_APP_Interface::AM_APP_Interface() { | AM_APP_Interface::AM_APP_Interface() { | ||||||
|  |  | ||||||
|  | @ -58,7 +58,7 @@ const Interface::FunctionInfo FunctionTable[] = { | ||||||
|     {0x10020104, FindContentInfos, "FindContentInfos"}, |     {0x10020104, FindContentInfos, "FindContentInfos"}, | ||||||
|     {0x10030142, ListContentInfos, "ListContentInfos"}, |     {0x10030142, ListContentInfos, "ListContentInfos"}, | ||||||
|     {0x10040102, DeleteContents, "DeleteContents"}, |     {0x10040102, DeleteContents, "DeleteContents"}, | ||||||
|     {0x10050084, GetDataTitleInfos, "GetDataTitleInfos"}, |     {0x10050084, GetDLCTitleInfos, "GetDLCTitleInfos"}, | ||||||
|     {0x10060080, nullptr, "GetNumDataTitleTickets"}, |     {0x10060080, nullptr, "GetNumDataTitleTickets"}, | ||||||
|     {0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"}, |     {0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"}, | ||||||
|     {0x100801C2, nullptr, "GetItemRights"}, |     {0x100801C2, nullptr, "GetItemRights"}, | ||||||
|  | @ -66,7 +66,7 @@ const Interface::FunctionInfo FunctionTable[] = { | ||||||
|     {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, |     {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, | ||||||
|     {0x100B00C0, nullptr, "GetNumExistingContentInfos"}, |     {0x100B00C0, nullptr, "GetNumExistingContentInfos"}, | ||||||
|     {0x100C0142, nullptr, "ListExistingContentInfos"}, |     {0x100C0142, nullptr, "ListExistingContentInfos"}, | ||||||
|     {0x100D0084, nullptr, "GetPatchTitleInfos"}, |     {0x100D0084, GetPatchTitleInfos, "GetPatchTitleInfos"}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| AM_SYS_Interface::AM_SYS_Interface() { | AM_SYS_Interface::AM_SYS_Interface() { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue