diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt
index 9b8d3ba3b2..fbb5961e2e 100644
--- a/Source/Core/Common/CMakeLists.txt
+++ b/Source/Core/Common/CMakeLists.txt
@@ -33,6 +33,7 @@ set(SRCS Analytics.cpp
x64ABI.cpp
x64Emitter.cpp
MD5.cpp
+ Crypto/AES.cpp
Crypto/bn.cpp
Crypto/ec.cpp
Logging/LogManager.cpp)
diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj
index 756c30d473..9f2b64f56d 100644
--- a/Source/Core/Common/Common.vcxproj
+++ b/Source/Core/Common/Common.vcxproj
@@ -143,6 +143,7 @@
+
@@ -195,6 +196,7 @@
+
diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters
index 4ffd6c0575..92d5fb2ae1 100644
--- a/Source/Core/Common/Common.vcxproj.filters
+++ b/Source/Core/Common/Common.vcxproj.filters
@@ -79,6 +79,9 @@
Logging
+
+ Crypto
+
Crypto
@@ -266,6 +269,9 @@
+
+ Crypto
+
Crypto
diff --git a/Source/Core/Common/Crypto/AES.cpp b/Source/Core/Common/Crypto/AES.cpp
new file mode 100644
index 0000000000..e12ba2481c
--- /dev/null
+++ b/Source/Core/Common/Crypto/AES.cpp
@@ -0,0 +1,24 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include
+
+#include "Common/Crypto/AES.h"
+
+namespace Common
+{
+namespace AES
+{
+std::vector Decrypt(const u8* key, u8* iv, const u8* src, size_t size)
+{
+ mbedtls_aes_context aes_ctx;
+ std::vector buffer(size);
+
+ mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
+ mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, size, iv, src, buffer.data());
+
+ return buffer;
+}
+} // namespace AES
+} // namespace Common
diff --git a/Source/Core/Common/Crypto/AES.h b/Source/Core/Common/Crypto/AES.h
new file mode 100644
index 0000000000..54d88727ac
--- /dev/null
+++ b/Source/Core/Common/Crypto/AES.h
@@ -0,0 +1,18 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+#include
+
+#include "Common/CommonTypes.h"
+
+namespace Common
+{
+namespace AES
+{
+std::vector Decrypt(const u8* key, u8* iv, const u8* src, size_t size);
+} // namespace AES
+} // namespace Common
diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp
index 42d3327946..46176ecf5c 100644
--- a/Source/Core/Core/Boot/Boot.cpp
+++ b/Source/Core/Core/Boot/Boot.cpp
@@ -102,7 +102,7 @@ bool CBoot::FindMapFile(std::string* existing_map_file, std::string* writable_ma
DiscIO::CNANDContentManager::Access().GetNANDLoader(_StartupPara.m_strFilename);
if (Loader.IsValid())
{
- u64 TitleID = Loader.GetTitleID();
+ u64 TitleID = Loader.GetTMD().GetTitleId();
title_id_str = StringFromFormat("%08X_%08X", (u32)(TitleID >> 32) & 0xFFFFFFFF,
(u32)TitleID & 0xFFFFFFFF);
}
@@ -278,11 +278,7 @@ bool CBoot::BootUp()
PanicAlertT("Warning - starting ISO in wrong console mode!");
}
- std::vector tmd_buffer = pVolume.GetTMD();
- if (!tmd_buffer.empty())
- {
- IOS::HLE::ES_DIVerify(tmd_buffer);
- }
+ IOS::HLE::ES_DIVerify(pVolume.GetTMD());
_StartupPara.bWii = pVolume.GetVolumeType() == DiscIO::Platform::WII_DISC;
diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp
index a11b1658d5..605579f597 100644
--- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp
+++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp
@@ -346,11 +346,9 @@ bool CBoot::EmulatedBS2_Wii()
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
- std::vector tmd = DVDInterface::GetVolume().GetTMD();
+ IOS::ES::TMDReader tmd = DVDInterface::GetVolume().GetTMD();
- IOS::HLE::TMDReader tmd_reader{std::move(tmd)};
-
- if (!SetupWiiMemory(tmd_reader.GetIOSId()))
+ if (!SetupWiiMemory(tmd.GetIOSId()))
return false;
// Execute the apploader
diff --git a/Source/Core/Core/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Boot/Boot_WiiWAD.cpp
index 2cef0b6ad6..5b3be7c4dc 100644
--- a/Source/Core/Core/Boot/Boot_WiiWAD.cpp
+++ b/Source/Core/Core/Boot/Boot_WiiWAD.cpp
@@ -78,7 +78,7 @@ bool CBoot::Boot_WiiWAD(const std::string& _pFilename)
if (!ContentLoader.IsValid())
return false;
- u64 titleID = ContentLoader.GetTitleID();
+ u64 titleID = ContentLoader.GetTMD().GetTitleId();
// create data directory
File::CreateFullPath(Common::GetTitleDataPath(titleID, Common::FROM_SESSION_ROOT));
@@ -86,12 +86,11 @@ bool CBoot::Boot_WiiWAD(const std::string& _pFilename)
IOS::HLE::CreateVirtualFATFilesystem();
// setup Wii memory
- u64 ios_title_id = 0x0000000100000000ULL | ContentLoader.GetIosVersion();
- if (!SetupWiiMemory(ios_title_id))
+ if (!SetupWiiMemory(ContentLoader.GetTMD().GetIOSId()))
return false;
// DOL
const DiscIO::SNANDContent* pContent =
- ContentLoader.GetContentByIndex(ContentLoader.GetBootIndex());
+ ContentLoader.GetContentByIndex(ContentLoader.GetTMD().GetBootIndex());
if (pContent == nullptr)
return false;
diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp
index 8b64441f7f..bc246bfc20 100644
--- a/Source/Core/Core/ConfigManager.cpp
+++ b/Source/Core/Core/ConfigManager.cpp
@@ -922,7 +922,7 @@ bool SConfig::AutoSetup(EBootBS2 _BootBS2)
const DiscIO::CNANDContentLoader& ContentLoader =
DiscIO::CNANDContentManager::Access().GetNANDLoader(m_strFilename);
- if (ContentLoader.GetContentByIndex(ContentLoader.GetBootIndex()) == nullptr)
+ if (ContentLoader.GetContentByIndex(ContentLoader.GetTMD().GetBootIndex()) == nullptr)
{
// WAD is valid yet cannot be booted. Install instead.
u64 installed = DiscIO::CNANDContentManager::Access().Install_WiiWAD(m_strFilename);
@@ -931,7 +931,7 @@ bool SConfig::AutoSetup(EBootBS2 _BootBS2)
return false; // do not boot
}
- SetRegion(ContentLoader.GetRegion(), &set_region_dir);
+ SetRegion(ContentLoader.GetTMD().GetRegion(), &set_region_dir);
bWii = true;
m_BootType = BOOT_WII_NAND;
diff --git a/Source/Core/Core/IOS/DI/DI.cpp b/Source/Core/Core/IOS/DI/DI.cpp
index f7d3006fff..bd91eb11d5 100644
--- a/Source/Core/Core/IOS/DI/DI.cpp
+++ b/Source/Core/Core/IOS/DI/DI.cpp
@@ -14,6 +14,7 @@
#include "Core/HW/DVDInterface.h"
#include "Core/HW/Memmap.h"
#include "Core/IOS/DI/DI.h"
+#include "Core/IOS/ES/Formats.h"
#include "Core/IOS/IPC.h"
#include "DiscIO/Volume.h"
@@ -105,9 +106,10 @@ IPCCommandResult DI::IOCtlV(const IOCtlVRequest& request)
INFO_LOG(IOS_DI, "DVDLowOpenPartition: partition_offset 0x%016" PRIx64, partition_offset);
// Read TMD to the buffer
- std::vector tmd_buffer = DVDInterface::GetVolume().GetTMD();
- Memory::CopyToEmu(request.io_vectors[0].address, tmd_buffer.data(), tmd_buffer.size());
- ES_DIVerify(tmd_buffer);
+ const ES::TMDReader tmd = DVDInterface::GetVolume().GetTMD();
+ const std::vector raw_tmd = tmd.GetRawTMD();
+ Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size());
+ ES_DIVerify(tmd);
return_value = 1;
break;
diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp
index d0b2c43298..57a430e7a3 100644
--- a/Source/Core/Core/IOS/ES/ES.cpp
+++ b/Source/Core/Core/IOS/ES/ES.cpp
@@ -2,35 +2,6 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
-// =======================================================
-// File description
-// -------------
-/* Here we handle /dev/es requests. We have cases for these functions, the exact
- DevKitPro/libogc name is in parenthesis:
-
- 0x20 GetTitleID (ES_GetTitleID) (Input: none, Output: 8 bytes)
- 0x1d GetDataDir (ES_GetDataDir) (Input: 8 bytes, Output: 30 bytes)
-
- 0x1b DiGetTicketView (Input: none, Output: 216 bytes)
- 0x16 GetConsumption (Input: 8 bytes, Output: 0 bytes, 4 bytes) // there are two output buffers
-
- 0x12 GetNumTicketViews (ES_GetNumTicketViews) (Input: 8 bytes, Output: 4 bytes)
- 0x14 GetTMDViewSize (ES_GetTMDViewSize) (Input: ?, Output: ?) // I don't get this anymore,
- it used to come after 0x12
-
- but only the first two are correctly supported. For the other four we ignore any potential
- input and only write zero to the out buffer. However, most games only use first two,
- but some Nintendo developed games use the other ones to:
-
- 0x1b: Mario Galaxy, Mario Kart, SSBB
- 0x16: Mario Galaxy, Mario Kart, SSBB
- 0x12: Mario Kart
- 0x14: Mario Kart: But only if we don't return a zeroed out buffer for the 0x12 question,
- and instead answer for example 1 will this question appear.
-
-*/
-// =============
-
#include
#include
#include
@@ -115,7 +86,7 @@ void ES::OpenInternal()
// check for cd ...
if (contentLoader.IsValid())
{
- m_TitleID = contentLoader.GetTitleID();
+ m_TitleID = contentLoader.GetTMD().GetTitleId();
m_TitleIDs.clear();
DiscIO::cUIDsys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT};
@@ -215,7 +186,7 @@ u32 ES::OpenTitleContent(u32 CFD, u64 TitleID, u16 Index)
{
const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID);
- if (!Loader.IsValid())
+ if (!Loader.IsValid() || !Loader.GetTicket().IsValid())
{
WARN_LOG(IOS_ES, "ES: loader not valid for %" PRIx64, TitleID);
return 0xffffffff;
@@ -230,8 +201,8 @@ u32 ES::OpenTitleContent(u32 CFD, u64 TitleID, u16 Index)
SContentAccess Access;
Access.m_Position = 0;
- Access.m_Index = pContent->m_Index;
- Access.m_Size = pContent->m_Size;
+ Access.m_Index = pContent->m_metadata.index;
+ Access.m_Size = static_cast(pContent->m_metadata.size);
Access.m_TitleID = TitleID;
pContent->m_Data->Open();
@@ -347,7 +318,8 @@ IPCCommandResult ES::AddTicket(const IOCtlVRequest& request)
INFO_LOG(IOS_ES, "IOCTL_ES_ADDTICKET");
std::vector ticket(request.in_vectors[0].size);
Memory::CopyFromEmu(ticket.data(), request.in_vectors[0].address, request.in_vectors[0].size);
- DiscIO::AddTicket(ticket);
+
+ DiscIO::AddTicket(IOS::ES::TicketReader{std::move(ticket)});
return GetDefaultReply(IPC_SUCCESS);
}
@@ -441,18 +413,18 @@ IPCCommandResult ES::AddContentFinish(const IOCtlVRequest& request)
INFO_LOG(IOS_ES, "IOCTL_ES_ADDCONTENTFINISH: content fd %08x", content_fd);
// Try to find the title key from a pre-installed ticket.
- std::vector ticket = DiscIO::FindSignedTicket(m_addtitle_tmd.GetTitleId());
- if (ticket.size() == 0)
+ IOS::ES::TicketReader ticket = DiscIO::FindSignedTicket(m_addtitle_tmd.GetTitleId());
+ if (!ticket.IsValid())
{
return GetDefaultReply(ES_NO_TICKET_INSTALLED);
}
mbedtls_aes_context aes_ctx;
- mbedtls_aes_setkey_dec(&aes_ctx, DiscIO::GetKeyFromTicket(ticket).data(), 128);
+ mbedtls_aes_setkey_dec(&aes_ctx, ticket.GetTitleKey().data(), 128);
// The IV for title content decryption is the lower two bytes of the
// content index, zero extended.
- TMDReader::Content content_info;
+ IOS::ES::Content content_info;
if (!m_addtitle_tmd.FindContentById(m_addtitle_content_id, &content_info))
{
return GetDefaultReply(ES_INVALID_TMD);
@@ -499,28 +471,21 @@ IPCCommandResult ES::GetTitleContentsCount(const IOCtlVRequest& request)
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
- const DiscIO::CNANDContentLoader& rNANDContent = AccessContentDevice(TitleID);
- u16 NumberOfPrivateContent = 0;
- s32 return_value = IPC_SUCCESS;
- if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check
- {
- NumberOfPrivateContent = rNANDContent.GetNumEntries();
+ const DiscIO::CNANDContentLoader& nand_content = AccessContentDevice(TitleID);
+ if (!nand_content.IsValid())
+ return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
- if ((u32)(TitleID >> 32) == 0x00010000)
- Memory::Write_U32(0, request.io_vectors[0].address);
- else
- Memory::Write_U32(NumberOfPrivateContent, request.io_vectors[0].address);
- }
+ const u16 num_contents = nand_content.GetTMD().GetNumContents();
+
+ if ((u32)(TitleID >> 32) == 0x00010000)
+ Memory::Write_U32(0, request.io_vectors[0].address);
else
- {
- return_value = static_cast(rNANDContent.GetContentSize());
- }
+ Memory::Write_U32(num_contents, request.io_vectors[0].address);
INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i",
- (u32)(TitleID >> 32), (u32)TitleID,
- rNANDContent.IsValid() ? NumberOfPrivateContent : (u32)rNANDContent.GetContentSize());
+ (u32)(TitleID >> 32), (u32)TitleID, num_contents);
- return GetDefaultReply(return_value);
+ return GetDefaultReply(IPC_SUCCESS);
}
IPCCommandResult ES::GetTitleContents(const IOCtlVRequest& request)
@@ -533,25 +498,17 @@ IPCCommandResult ES::GetTitleContents(const IOCtlVRequest& request)
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
const DiscIO::CNANDContentLoader& rNANDContent = AccessContentDevice(TitleID);
- s32 return_value = IPC_SUCCESS;
- if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check
+ if (!rNANDContent.IsValid())
+ return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
+
+ for (const auto& content : rNANDContent.GetTMD().GetContents())
{
- for (u16 i = 0; i < rNANDContent.GetNumEntries(); i++)
- {
- Memory::Write_U32(rNANDContent.GetContentByIndex(i)->m_ContentID,
- request.io_vectors[0].address + i * 4);
- INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", i,
- rNANDContent.GetContentByIndex(i)->m_ContentID);
- }
- }
- else
- {
- return_value = static_cast(rNANDContent.GetContentSize());
- ERROR_LOG(IOS_ES, "IOCTL_ES_GETTITLECONTENTS: Unable to open content %zu",
- rNANDContent.GetContentSize());
+ const u16 index = content.index;
+ Memory::Write_U32(content.id, request.io_vectors[0].address + index * 4);
+ INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", index, content.id);
}
- return GetDefaultReply(return_value);
+ return GetDefaultReply(IPC_SUCCESS);
}
IPCCommandResult ES::OpenTitleContent(const IOCtlVRequest& request)
@@ -611,7 +568,7 @@ IPCCommandResult ES::ReadContent(const IOCtlVRequest& request)
{
const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(rContent.m_TitleID);
// ContentLoader should never be invalid; rContent has been created by it.
- if (ContentLoader.IsValid())
+ if (ContentLoader.IsValid() && ContentLoader.GetTicket().IsValid())
{
const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(rContent.m_Index);
if (!pContent->m_Data->GetRange(rContent.m_Position, Size, pDest))
@@ -777,46 +734,24 @@ IPCCommandResult ES::GetViewCount(const IOCtlVRequest& request)
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
- u32 retVal = 0;
const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID);
- u32 ViewCount =
- static_cast(Loader.GetTicket().size()) / DiscIO::CNANDContentLoader::TICKET_SIZE;
- if (!ViewCount)
+ size_t view_count = 0;
+ if (TitleID >> 32 == 0x00000001 && TitleID != TITLEID_SYSMENU)
{
- std::string TicketFilename = Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT);
- if (File::Exists(TicketFilename))
- {
- u32 FileSize = (u32)File::GetSize(TicketFilename);
- _dbg_assert_msg_(IOS_ES, (FileSize % DiscIO::CNANDContentLoader::TICKET_SIZE) == 0,
- "IOCTL_ES_GETVIEWCNT ticket file size seems to be wrong");
-
- ViewCount = FileSize / DiscIO::CNANDContentLoader::TICKET_SIZE;
- _dbg_assert_msg_(IOS_ES, (ViewCount > 0) && (ViewCount <= 4),
- "IOCTL_ES_GETVIEWCNT ticket count seems to be wrong");
- }
- else if (TitleID >> 32 == 0x00000001)
- {
- // Fake a ticket view to make IOS reload work.
- ViewCount = 1;
- }
- else
- {
- ViewCount = 0;
- if (TitleID == TITLEID_SYSMENU)
- {
- PanicAlertT("There must be a ticket for 00000001/00000002. Your NAND dump is probably "
- "incomplete.");
- }
- // retVal = ES_NO_TICKET_INSTALLED;
- }
+ // Fake a ticket view to make IOS reload work.
+ view_count = 1;
+ }
+ else if (Loader.IsValid() && Loader.GetTicket().IsValid())
+ {
+ view_count = Loader.GetTicket().GetNumberOfTickets();
}
- INFO_LOG(IOS_ES, "IOCTL_ES_GETVIEWCNT for titleID: %08x/%08x (View Count = %i)",
- (u32)(TitleID >> 32), (u32)TitleID, ViewCount);
+ INFO_LOG(IOS_ES, "IOCTL_ES_GETVIEWCNT for titleID: %08x/%08x (View Count = %zu)",
+ static_cast(TitleID >> 32), static_cast(TitleID), view_count);
- Memory::Write_U32(ViewCount, request.io_vectors[0].address);
- return GetDefaultReply(retVal);
+ Memory::Write_U32(static_cast(view_count), request.io_vectors[0].address);
+ return GetDefaultReply(IPC_SUCCESS);
}
IPCCommandResult ES::GetViews(const IOCtlVRequest& request)
@@ -826,70 +761,40 @@ IPCCommandResult ES::GetViews(const IOCtlVRequest& request)
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
u32 maxViews = Memory::Read_U32(request.in_vectors[1].address);
- u32 retVal = 0;
const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID);
- const std::vector& ticket = Loader.GetTicket();
-
- if (ticket.empty())
+ if (TitleID >> 32 == 0x00000001 && TitleID != TITLEID_SYSMENU)
{
- std::string TicketFilename = Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT);
- if (File::Exists(TicketFilename))
- {
- File::IOFile pFile(TicketFilename, "rb");
- if (pFile)
- {
- u8 FileTicket[DiscIO::CNANDContentLoader::TICKET_SIZE];
- for (unsigned int View = 0;
- View != maxViews &&
- pFile.ReadBytes(FileTicket, DiscIO::CNANDContentLoader::TICKET_SIZE);
- ++View)
- {
- Memory::Write_U32(View, request.io_vectors[0].address + View * 0xD8);
- Memory::CopyToEmu(request.io_vectors[0].address + 4 + View * 0xD8, FileTicket + 0x1D0,
- 212);
- }
- }
- }
- else if (TitleID >> 32 == 0x00000001)
- {
- // For IOS titles, the ticket view isn't normally parsed by either the
- // SDK or libogc, just passed to LaunchTitle, so this
- // shouldn't matter at all. Just fill out some fields just
- // to be on the safe side.
- u32 Address = request.io_vectors[0].address;
- Memory::Memset(Address, 0, 0xD8);
- Memory::Write_U64(TitleID, Address + 4 + (0x1dc - 0x1d0)); // title ID
- Memory::Write_U16(0xffff, Address + 4 + (0x1e4 - 0x1d0)); // unnnown
- Memory::Write_U32(0xff00, Address + 4 + (0x1ec - 0x1d0)); // access mask
- Memory::Memset(Address + 4 + (0x222 - 0x1d0), 0xff, 0x20); // content permissions
- }
- else
- {
- // retVal = ES_NO_TICKET_INSTALLED;
- PanicAlertT("IOCTL_ES_GETVIEWS: Tried to get data from an unknown ticket: %08x/%08x",
- (u32)(TitleID >> 32), (u32)TitleID);
- }
+ // For IOS titles, the ticket view isn't normally parsed by either the
+ // SDK or libogc, just passed to LaunchTitle, so this
+ // shouldn't matter at all. Just fill out some fields just
+ // to be on the safe side.
+ u32 Address = request.io_vectors[0].address;
+ Memory::Memset(Address, 0, 0xD8);
+ Memory::Write_U64(TitleID, Address + 4 + (0x1dc - 0x1d0)); // title ID
+ Memory::Write_U16(0xffff, Address + 4 + (0x1e4 - 0x1d0)); // unnnown
+ Memory::Write_U32(0xff00, Address + 4 + (0x1ec - 0x1d0)); // access mask
+ Memory::Memset(Address + 4 + (0x222 - 0x1d0), 0xff, 0x20); // content permissions
}
- else
+ else if (Loader.IsValid() && Loader.GetTicket().IsValid())
{
- u32 view_count =
- static_cast(Loader.GetTicket().size()) / DiscIO::CNANDContentLoader::TICKET_SIZE;
- for (unsigned int view = 0; view != maxViews && view < view_count; ++view)
+ u32 number_of_views = std::min(maxViews, Loader.GetTicket().GetNumberOfTickets());
+ for (u32 view = 0; view < number_of_views; ++view)
{
- Memory::Write_U32(view, request.io_vectors[0].address + view * 0xD8);
- Memory::CopyToEmu(request.io_vectors[0].address + 4 + view * 0xD8,
- &ticket[0x1D0 + (view * DiscIO::CNANDContentLoader::TICKET_SIZE)], 212);
+ const std::vector ticket_view = Loader.GetTicket().GetRawTicketView(view);
+ Memory::CopyToEmu(request.io_vectors[0].address + view * sizeof(IOS::ES::TicketView),
+ ticket_view.data(), ticket_view.size());
}
}
INFO_LOG(IOS_ES, "IOCTL_ES_GETVIEWS for titleID: %08x/%08x (MaxViews = %i)", (u32)(TitleID >> 32),
(u32)TitleID, maxViews);
- return GetDefaultReply(retVal);
+ return GetDefaultReply(IPC_SUCCESS);
}
+// TODO: rename this to GetTMDViewSize. There is only one TMD, so the name doesn't make sense.
IPCCommandResult ES::GetTMDViewCount(const IOCtlVRequest& request)
{
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1, "IOCTL_ES_GETTMDVIEWCNT no in buffer");
@@ -899,18 +804,13 @@ IPCCommandResult ES::GetTMDViewCount(const IOCtlVRequest& request)
const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID);
- u32 TMDViewCnt = 0;
+ u32 view_size = 0;
if (Loader.IsValid())
- {
- TMDViewCnt += DiscIO::CNANDContentLoader::TMD_VIEW_SIZE;
- TMDViewCnt += 2; // title version
- TMDViewCnt += 2; // num entries
- TMDViewCnt += (u32)Loader.GetContentSize() * (4 + 2 + 2 + 8); // content id, index, type, size
- }
- Memory::Write_U32(TMDViewCnt, request.io_vectors[0].address);
+ view_size = static_cast(Loader.GetTMD().GetRawView().size());
+ Memory::Write_U32(view_size, request.io_vectors[0].address);
INFO_LOG(IOS_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x (view size %i)", (u32)(TitleID >> 32),
- (u32)TitleID, TMDViewCnt);
+ (u32)TitleID, view_size);
return GetDefaultReply(IPC_SUCCESS);
}
@@ -929,30 +829,11 @@ IPCCommandResult ES::GetTMDViews(const IOCtlVRequest& request)
if (Loader.IsValid())
{
- u32 Address = request.io_vectors[0].address;
+ const std::vector raw_view = Loader.GetTMD().GetRawView();
+ if (raw_view.size() != request.io_vectors[0].size)
+ return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
- Memory::CopyToEmu(Address, Loader.GetTMDView(), DiscIO::CNANDContentLoader::TMD_VIEW_SIZE);
- Address += DiscIO::CNANDContentLoader::TMD_VIEW_SIZE;
-
- Memory::Write_U16(Loader.GetTitleVersion(), Address);
- Address += 2;
- Memory::Write_U16(Loader.GetNumEntries(), Address);
- Address += 2;
-
- const std::vector& rContent = Loader.GetContent();
- for (size_t i = 0; i < Loader.GetContentSize(); i++)
- {
- Memory::Write_U32(rContent[i].m_ContentID, Address);
- Address += 4;
- Memory::Write_U16(rContent[i].m_Index, Address);
- Address += 2;
- Memory::Write_U16(rContent[i].m_Type, Address);
- Address += 2;
- Memory::Write_U64(rContent[i].m_Size, Address);
- Address += 8;
- }
-
- _dbg_assert_(IOS_ES, (Address - request.io_vectors[0].address) == request.io_vectors[0].size);
+ Memory::CopyToEmu(request.io_vectors[0].address, raw_view.data(), raw_view.size());
}
INFO_LOG(IOS_ES, "IOCTL_ES_GETTMDVIEWS: title: %08x/%08x (buffer size: %i)", (u32)(TitleID >> 32),
@@ -1004,18 +885,15 @@ IPCCommandResult ES::GetStoredTMDSize(const IOCtlVRequest& request)
const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID);
_dbg_assert_(IOS_ES, Loader.IsValid());
- u32 TMDCnt = 0;
+ u32 tmd_size = 0;
if (Loader.IsValid())
- {
- TMDCnt += DiscIO::CNANDContentLoader::TMD_HEADER_SIZE;
- TMDCnt += (u32)Loader.GetContentSize() * DiscIO::CNANDContentLoader::CONTENT_HEADER_SIZE;
- }
+ tmd_size = static_cast(Loader.GetTMD().GetRawTMD().size());
if (request.io_vectors.size())
- Memory::Write_U32(TMDCnt, request.io_vectors[0].address);
+ Memory::Write_U32(tmd_size, request.io_vectors[0].address);
INFO_LOG(IOS_ES, "IOCTL_ES_GETSTOREDTMDSIZE: title: %08x/%08x (view size %i)",
- (u32)(TitleID >> 32), (u32)TitleID, TMDCnt);
+ (u32)(TitleID >> 32), (u32)TitleID, tmd_size);
return GetDefaultReply(IPC_SUCCESS);
}
@@ -1043,20 +921,11 @@ IPCCommandResult ES::GetStoredTMD(const IOCtlVRequest& request)
if (Loader.IsValid() && request.io_vectors.size())
{
- u32 Address = request.io_vectors[0].address;
+ const std::vector raw_tmd = Loader.GetTMD().GetRawTMD();
+ if (raw_tmd.size() != request.io_vectors[0].size)
+ return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
- Memory::CopyToEmu(Address, Loader.GetTMDHeader(), DiscIO::CNANDContentLoader::TMD_HEADER_SIZE);
- Address += DiscIO::CNANDContentLoader::TMD_HEADER_SIZE;
-
- const std::vector& rContent = Loader.GetContent();
- for (size_t i = 0; i < Loader.GetContentSize(); i++)
- {
- Memory::CopyToEmu(Address, rContent[i].m_Header,
- DiscIO::CNANDContentLoader::CONTENT_HEADER_SIZE);
- Address += DiscIO::CNANDContentLoader::CONTENT_HEADER_SIZE;
- }
-
- _dbg_assert_(IOS_ES, (Address - request.io_vectors[0].address) == request.io_vectors[0].size);
+ Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size());
}
INFO_LOG(IOS_ES, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x (buffer size: %i)",
@@ -1131,9 +1000,9 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request)
const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(TitleID);
if (ContentLoader.IsValid())
{
- ios_to_load = 0x0000000100000000ULL | ContentLoader.GetIosVersion();
+ ios_to_load = ContentLoader.GetTMD().GetIOSId();
- u32 bootInd = ContentLoader.GetBootIndex();
+ u32 bootInd = ContentLoader.GetTMD().GetBootIndex();
const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(bootInd);
if (pContent)
{
@@ -1275,10 +1144,13 @@ const DiscIO::CNANDContentLoader& ES::AccessContentDevice(u64 title_id)
return DiscIO::CNANDContentManager::Access().GetNANDLoader(title_id, Common::FROM_SESSION_ROOT);
}
-u32 ES::ES_DIVerify(const std::vector& tmd)
+u32 ES::ES_DIVerify(const IOS::ES::TMDReader& tmd)
{
+ if (!tmd.IsValid())
+ return -1;
+
u64 title_id = 0xDEADBEEFDEADBEEFull;
- u64 tmd_title_id = Common::swap64(&tmd[0x18C]);
+ u64 tmd_title_id = tmd.GetTitleId();
DVDInterface::GetVolume().GetTitleID(&title_id);
if (title_id != tmd_title_id)
@@ -1292,7 +1164,8 @@ u32 ES::ES_DIVerify(const std::vector& tmd)
if (!File::Exists(tmd_path))
{
File::IOFile tmd_file(tmd_path, "wb");
- if (!tmd_file.WriteBytes(tmd.data(), tmd.size()))
+ const std::vector& tmd_bytes = tmd.GetRawTMD();
+ if (!tmd_file.WriteBytes(tmd_bytes.data(), tmd_bytes.size()))
ERROR_LOG(IOS_ES, "DIVerify failed to write disc TMD to NAND.");
}
DiscIO::cUIDsys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT};
diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h
index 86f447e9a0..045fc75f36 100644
--- a/Source/Core/Core/IOS/ES/ES.h
+++ b/Source/Core/Core/IOS/ES/ES.h
@@ -46,7 +46,7 @@ public:
void Close() override;
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
- static u32 ES_DIVerify(const std::vector& tmd);
+ static u32 ES_DIVerify(const IOS::ES::TMDReader& tmd);
// This should only be cleared on power reset
static std::string m_ContentFile;
@@ -203,7 +203,7 @@ private:
u32 m_AccessIdentID = 0;
// For title installation (ioctls IOCTL_ES_ADDTITLE*).
- TMDReader m_addtitle_tmd;
+ IOS::ES::TMDReader m_addtitle_tmd;
u32 m_addtitle_content_id = 0xFFFFFFFF;
std::vector m_addtitle_content_buffer;
};
diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp
index 6a9053fbee..f90bd765b2 100644
--- a/Source/Core/Core/IOS/ES/Formats.cpp
+++ b/Source/Core/Core/IOS/ES/Formats.cpp
@@ -5,17 +5,22 @@
#include "Core/IOS/ES/Formats.h"
#include
+#include
+#include
#include
#include
#include "Common/ChunkFile.h"
#include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h"
+#include "Common/Crypto/AES.h"
namespace IOS
{
-namespace HLE
+namespace ES
{
+constexpr size_t CONTENT_VIEW_SIZE = 0x10;
+
TMDReader::TMDReader(const std::vector& bytes) : m_bytes(bytes)
{
}
@@ -36,13 +41,13 @@ void TMDReader::SetBytes(std::vector&& bytes)
bool TMDReader::IsValid() const
{
- if (m_bytes.size() < 0x1E4)
+ if (m_bytes.size() < sizeof(TMDHeader))
{
// TMD is too small to contain its base fields.
return false;
}
- if (m_bytes.size() < 0x1E4 + GetNumContents() * 36u)
+ if (m_bytes.size() < sizeof(TMDHeader) + GetNumContents() * sizeof(Content))
{
// TMD is too small to contain all its expected content entries.
return false;
@@ -51,19 +56,69 @@ bool TMDReader::IsValid() const
return true;
}
+const std::vector& TMDReader::GetRawTMD() const
+{
+ return m_bytes;
+}
+
+std::vector TMDReader::GetRawHeader() const
+{
+ return std::vector(m_bytes.begin(), m_bytes.begin() + sizeof(TMDHeader));
+}
+
+std::vector TMDReader::GetRawView() const
+{
+ // Base fields
+ std::vector view(m_bytes.cbegin() + offsetof(TMDHeader, tmd_version),
+ m_bytes.cbegin() + offsetof(TMDHeader, access_rights));
+
+ const auto version = m_bytes.cbegin() + offsetof(TMDHeader, title_version);
+ view.insert(view.end(), version, version + sizeof(TMDHeader::title_version));
+
+ const auto num_contents = m_bytes.cbegin() + offsetof(TMDHeader, num_contents);
+ view.insert(view.end(), num_contents, num_contents + sizeof(TMDHeader::num_contents));
+
+ // Content views (same as Content, but without the hash)
+ for (size_t i = 0; i < GetNumContents(); ++i)
+ {
+ const auto content_iterator = m_bytes.cbegin() + sizeof(TMDHeader) + i * sizeof(Content);
+ view.insert(view.end(), content_iterator, content_iterator + CONTENT_VIEW_SIZE);
+ }
+
+ return view;
+}
+
+u16 TMDReader::GetBootIndex() const
+{
+ return Common::swap16(m_bytes.data() + offsetof(TMDHeader, boot_index));
+}
+
u64 TMDReader::GetIOSId() const
{
- return Common::swap64(m_bytes.data() + 0x184);
+ return Common::swap64(m_bytes.data() + offsetof(TMDHeader, ios_id));
+}
+
+DiscIO::Region TMDReader::GetRegion() const
+{
+ if (GetTitleId() == 0x0000000100000002)
+ return DiscIO::RegionSwitchWii(DiscIO::GetSysMenuRegion(GetTitleVersion()));
+
+ return DiscIO::RegionSwitchWii(static_cast(GetTitleId() & 0xff));
}
u64 TMDReader::GetTitleId() const
{
- return Common::swap64(m_bytes.data() + 0x18C);
+ return Common::swap64(m_bytes.data() + offsetof(TMDHeader, title_id));
+}
+
+u16 TMDReader::GetTitleVersion() const
+{
+ return Common::swap16(m_bytes.data() + offsetof(TMDHeader, title_version));
}
u16 TMDReader::GetNumContents() const
{
- return Common::swap16(m_bytes.data() + 0x1DE);
+ return Common::swap16(m_bytes.data() + offsetof(TMDHeader, num_contents));
}
bool TMDReader::GetContent(u16 index, Content* content) const
@@ -73,16 +128,24 @@ bool TMDReader::GetContent(u16 index, Content* content) const
return false;
}
- const u8* content_base = m_bytes.data() + 0x1E4 + index * 36;
- content->id = Common::swap32(content_base);
- content->index = Common::swap16(content_base + 4);
- content->type = Common::swap16(content_base + 6);
- content->size = Common::swap64(content_base + 8);
- std::copy(content_base + 16, content_base + 36, content->sha1.begin());
+ const u8* content_base = m_bytes.data() + sizeof(TMDHeader) + index * sizeof(Content);
+ content->id = Common::swap32(content_base + offsetof(Content, id));
+ content->index = Common::swap16(content_base + offsetof(Content, index));
+ content->type = Common::swap16(content_base + offsetof(Content, type));
+ content->size = Common::swap64(content_base + offsetof(Content, size));
+ std::copy_n(content_base + offsetof(Content, sha1), content->sha1.size(), content->sha1.begin());
return true;
}
+std::vector TMDReader::GetContents() const
+{
+ std::vector contents(GetNumContents());
+ for (size_t i = 0; i < contents.size(); ++i)
+ GetContent(static_cast(i), &contents[i]);
+ return contents;
+}
+
bool TMDReader::FindContentById(u32 id, Content* content) const
{
for (u16 index = 0; index < GetNumContents(); ++index)
@@ -103,5 +166,94 @@ void TMDReader::DoState(PointerWrap& p)
{
p.Do(m_bytes);
}
-} // namespace HLE
+
+TicketReader::TicketReader(const std::vector& bytes) : m_bytes(bytes)
+{
+}
+
+TicketReader::TicketReader(std::vector&& bytes) : m_bytes(std::move(bytes))
+{
+}
+
+void TicketReader::SetBytes(const std::vector& bytes)
+{
+ m_bytes = bytes;
+}
+
+void TicketReader::SetBytes(std::vector&& bytes)
+{
+ m_bytes = std::move(bytes);
+}
+
+bool TicketReader::IsValid() const
+{
+ // Too small for the signature type.
+ if (m_bytes.size() < sizeof(u32))
+ return false;
+
+ u32 ticket_offset = GetOffset();
+ if (ticket_offset == 0)
+ return false;
+
+ // Too small for the ticket itself.
+ if (m_bytes.size() < ticket_offset + sizeof(Ticket))
+ return false;
+
+ return true;
+}
+
+u32 TicketReader::GetNumberOfTickets() const
+{
+ return static_cast(m_bytes.size() / (GetOffset() + sizeof(Ticket)));
+}
+
+u32 TicketReader::GetOffset() const
+{
+ u32 signature_type = Common::swap32(m_bytes.data());
+ if (signature_type == 0x10000) // RSA4096
+ return 576;
+ if (signature_type == 0x10001) // RSA2048
+ return 320;
+ if (signature_type == 0x10002) // ECDSA
+ return 128;
+
+ ERROR_LOG(COMMON, "Invalid ticket signature type: %08x", signature_type);
+ return 0;
+}
+
+const std::vector& TicketReader::GetRawTicket() const
+{
+ return m_bytes;
+}
+
+std::vector TicketReader::GetRawTicketView(u32 ticket_num) const
+{
+ // A ticket view is composed of a view ID + part of a ticket starting from the ticket_id field.
+ std::vector view{sizeof(TicketView)};
+
+ u32 view_id = Common::swap32(ticket_num);
+ std::memcpy(view.data(), &view_id, sizeof(view_id));
+
+ const size_t ticket_start = (GetOffset() + sizeof(Ticket)) * ticket_num;
+ const size_t view_start = ticket_start + offsetof(Ticket, ticket_id);
+ std::memcpy(view.data() + sizeof(view_id), &m_bytes[view_start], sizeof(view) - sizeof(view_id));
+
+ return view;
+}
+
+u64 TicketReader::GetTitleId() const
+{
+ return Common::swap64(m_bytes.data() + GetOffset() + offsetof(Ticket, title_id));
+}
+
+std::vector TicketReader::GetTitleKey() const
+{
+ const u8 common_key[16] = {0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4,
+ 0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7};
+ u8 iv[16] = {};
+ std::copy_n(&m_bytes[GetOffset() + offsetof(Ticket, title_id)], sizeof(Ticket::title_id), iv);
+ return Common::AES::Decrypt(common_key, iv, &m_bytes[GetOffset() + offsetof(Ticket, title_key)],
+ 16);
+}
+} // namespace ES
} // namespace IOS
diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h
index 775f602451..b6d2985cc2 100644
--- a/Source/Core/Core/IOS/ES/Formats.h
+++ b/Source/Core/Core/IOS/ES/Formats.h
@@ -12,11 +12,95 @@
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
+#include "DiscIO/Enums.h"
namespace IOS
{
-namespace HLE
+namespace ES
{
+#pragma pack(push, 4)
+struct TMDHeader
+{
+ u32 signature_type;
+ u8 rsa_2048_signature[256];
+ u8 fill[60];
+ u8 issuer[64];
+ u8 tmd_version;
+ u8 ca_crl_version;
+ u8 signer_crl_version;
+ u64 ios_id;
+ u64 title_id;
+ u32 title_type;
+ u16 group_id;
+ u16 zero;
+ u16 region;
+ u8 ratings[16];
+ u8 reserved[12];
+ u8 ipc_mask[12];
+ u8 reserved2[18];
+ u32 access_rights;
+ u16 title_version;
+ u16 num_contents;
+ u16 boot_index;
+ u16 fill2;
+};
+static_assert(sizeof(TMDHeader) == 0x1e4, "TMDHeader has the wrong size");
+
+struct Content
+{
+ u32 id;
+ u16 index;
+ u16 type;
+ u64 size;
+ std::array sha1;
+};
+static_assert(sizeof(Content) == 36, "Content has the wrong size");
+
+struct TimeLimit
+{
+ u32 enabled;
+ u32 seconds;
+};
+
+struct TicketView
+{
+ u32 view;
+ u64 ticket_id;
+ u32 device_id;
+ u64 title_id;
+ u16 access_mask;
+ u32 permitted_title_id;
+ u32 permitted_title_mask;
+ u8 title_export_allowed;
+ u8 common_key_index;
+ u8 unknown2[0x30];
+ u8 content_access_permissions[0x40];
+ TimeLimit time_limits[8];
+};
+static_assert(sizeof(TicketView) == 0xd8, "TicketView has the wrong size");
+
+struct Ticket
+{
+ u8 signature_issuer[0x40];
+ u8 ecdh_key[0x3c];
+ u8 unknown[0x03];
+ u8 title_key[0x10];
+ u64 ticket_id;
+ u32 device_id;
+ u64 title_id;
+ u16 access_mask;
+ u16 ticket_version;
+ u32 permitted_title_id;
+ u32 permitted_title_mask;
+ u8 title_export_allowed;
+ u8 common_key_index;
+ u8 unknown2[0x30];
+ u8 content_access_permissions[0x40];
+ TimeLimit time_limits[8];
+};
+static_assert(sizeof(Ticket) == 356, "Ticket has the wrong size");
+#pragma pack(pop)
+
class TMDReader final
{
public:
@@ -29,19 +113,20 @@ public:
bool IsValid() const;
- u64 GetIOSId() const;
- u64 GetTitleId() const;
+ // Returns the TMD or parts of it without any kind of parsing. Intended for use by ES.
+ const std::vector& GetRawTMD() const;
+ std::vector GetRawHeader() const;
+ std::vector GetRawView() const;
+
+ u16 GetBootIndex() const;
+ u64 GetIOSId() const;
+ DiscIO::Region GetRegion() const;
+ u64 GetTitleId() const;
+ u16 GetTitleVersion() const;
- struct Content
- {
- u32 id;
- u16 index;
- u16 type;
- u64 size;
- std::array sha1;
- };
u16 GetNumContents() const;
bool GetContent(u16 index, Content* content) const;
+ std::vector GetContents() const;
bool FindContentById(u32 id, Content* content) const;
void DoState(PointerWrap& p);
@@ -49,5 +134,34 @@ public:
private:
std::vector m_bytes;
};
-} // namespace HLE
+
+class TicketReader final
+{
+public:
+ TicketReader() = default;
+ explicit TicketReader(const std::vector& bytes);
+ explicit TicketReader(std::vector&& bytes);
+
+ void SetBytes(const std::vector& bytes);
+ void SetBytes(std::vector&& bytes);
+
+ bool IsValid() const;
+
+ const std::vector& GetRawTicket() const;
+ u32 GetNumberOfTickets() const;
+ u32 GetOffset() const;
+
+ // Returns a "raw" ticket view, without byte swapping. Intended for use from ES.
+ // Theoretically, a ticket file can contain one or more tickets. In practice, most (all?)
+ // official titles only have one ticket, but IOS *does* have code to handle ticket files with
+ // more than just one ticket and generate ticket views for them, so we implement it too.
+ std::vector GetRawTicketView(u32 ticket_num) const;
+
+ u64 GetTitleId() const;
+ std::vector GetTitleKey() const;
+
+private:
+ std::vector m_bytes;
+};
+} // namespace ES
} // namespace IOS
diff --git a/Source/Core/Core/IOS/IPC.cpp b/Source/Core/Core/IOS/IPC.cpp
index 5a334f6c82..b74ed1c996 100644
--- a/Source/Core/Core/IOS/IPC.cpp
+++ b/Source/Core/Core/IOS/IPC.cpp
@@ -658,7 +658,7 @@ void SetDefaultContentFile(const std::string& file_name)
es->LoadWAD(file_name);
}
-void ES_DIVerify(const std::vector& tmd)
+void ES_DIVerify(const ES::TMDReader& tmd)
{
Device::ES::ES_DIVerify(tmd);
}
diff --git a/Source/Core/Core/IOS/IPC.h b/Source/Core/Core/IOS/IPC.h
index 09b3c1179c..5bbd10befd 100644
--- a/Source/Core/Core/IOS/IPC.h
+++ b/Source/Core/Core/IOS/IPC.h
@@ -16,6 +16,11 @@ class PointerWrap;
namespace IOS
{
+namespace ES
+{
+class TMDReader;
+}
+
namespace HLE
{
namespace Device
@@ -61,7 +66,7 @@ void DoState(PointerWrap& p);
// Set default content file
void SetDefaultContentFile(const std::string& file_name);
-void ES_DIVerify(const std::vector& tmd);
+void ES_DIVerify(const ES::TMDReader& tmd);
void SDIO_EventNotify();
diff --git a/Source/Core/Core/IOS/MIOS.cpp b/Source/Core/Core/IOS/MIOS.cpp
index 6fa93f6d68..2a9e55402f 100644
--- a/Source/Core/Core/IOS/MIOS.cpp
+++ b/Source/Core/Core/IOS/MIOS.cpp
@@ -23,6 +23,7 @@
#include "Core/HW/DVDThread.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/SystemTimers.h"
+#include "Core/IOS/ES/Formats.h"
#include "Core/IOS/MIOS.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h"
@@ -97,7 +98,7 @@ static std::vector GetMIOSBinary()
if (!loader.IsValid())
return {};
- const auto* content = loader.GetContentByIndex(loader.GetBootIndex());
+ const auto* content = loader.GetContentByIndex(loader.GetTMD().GetBootIndex());
if (!content)
return {};
diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp
index 5ca881bb28..16e97055d6 100644
--- a/Source/Core/Core/IOS/WFS/WFSI.cpp
+++ b/Source/Core/Core/IOS/WFS/WFSI.cpp
@@ -109,14 +109,14 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
Memory::CopyFromEmu(tmd_bytes.data(), tmd_addr, tmd_size);
m_tmd.SetBytes(std::move(tmd_bytes));
- std::vector ticket = DiscIO::FindSignedTicket(m_tmd.GetTitleId());
- if (ticket.size() == 0)
+ ES::TicketReader ticket = DiscIO::FindSignedTicket(m_tmd.GetTitleId());
+ if (!ticket.IsValid())
{
return_error_code = -11028;
break;
}
- memcpy(m_aes_key, DiscIO::GetKeyFromTicket(ticket).data(), sizeof(m_aes_key));
+ memcpy(m_aes_key, ticket.GetTitleKey().data(), sizeof(m_aes_key));
mbedtls_aes_setkey_dec(&m_aes_ctx, m_aes_key, 128);
break;
@@ -134,7 +134,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
// Initializes the IV from the index of the content in the TMD contents.
u32 content_id = Memory::Read_U32(request.buffer_in + 8);
- TMDReader::Content content_info;
+ ES::Content content_info;
if (!m_tmd.FindContentById(content_id, &content_info))
{
WARN_LOG(IOS, "%s: Content id %08x not found", ioctl_name, content_id);
diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h
index 0c1973184e..82dfded277 100644
--- a/Source/Core/Core/IOS/WFS/WFSI.h
+++ b/Source/Core/Core/IOS/WFS/WFSI.h
@@ -50,7 +50,7 @@ private:
u8 m_aes_key[0x10] = {};
u8 m_aes_iv[0x10] = {};
- TMDReader m_tmd;
+ IOS::ES::TMDReader m_tmd;
std::string m_base_extract_path;
ARCUnpacker m_arc_unpacker;
diff --git a/Source/Core/DiscIO/NANDContentLoader.cpp b/Source/Core/DiscIO/NANDContentLoader.cpp
index fc1f600aa1..1204550fab 100644
--- a/Source/Core/DiscIO/NANDContentLoader.cpp
+++ b/Source/Core/DiscIO/NANDContentLoader.cpp
@@ -4,12 +4,12 @@
#include
#include
+#include
#include
#include
#include
#include
#include