mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 05:47:56 -07:00
IOS/ES: Implement basic title installation.
There are several things wrong with this implementation. The first being that since we still don't have a proper ticket/tmd handling library, we hardcode offsets once again to fetch TMD fields. The second being that we don't stream data to the disk and we buffer everything in memory. The third being that we don't properly fetch the content index for decryption, which is prone to breaking. But hey, it works well enough to install the DQX channel!
This commit is contained in:
parent
0a5cfd8946
commit
a8f7012cf7
@ -53,6 +53,7 @@
|
|||||||
#include "Core/HW/DVDInterface.h"
|
#include "Core/HW/DVDInterface.h"
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
#include "Core/HW/Wiimote.h"
|
#include "Core/HW/Wiimote.h"
|
||||||
|
#include "Core/IPC_HLE/ESFormats.h"
|
||||||
#include "Core/IPC_HLE/WII_IPC_HLE_Device_es.h"
|
#include "Core/IPC_HLE/WII_IPC_HLE_Device_es.h"
|
||||||
#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h"
|
#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h"
|
||||||
#include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h"
|
#include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h"
|
||||||
@ -151,6 +152,10 @@ void CWII_IPC_HLE_Device_es::DoState(PointerWrap& p)
|
|||||||
p.Do(m_AccessIdentID);
|
p.Do(m_AccessIdentID);
|
||||||
p.Do(m_TitleIDs);
|
p.Do(m_TitleIDs);
|
||||||
|
|
||||||
|
m_addtitle_tmd.DoState(p);
|
||||||
|
p.Do(m_addtitle_content_id);
|
||||||
|
p.Do(m_addtitle_content_buffer);
|
||||||
|
|
||||||
u32 Count = (u32)(m_ContentAccessMap.size());
|
u32 Count = (u32)(m_ContentAccessMap.size());
|
||||||
p.Do(Count);
|
p.Do(Count);
|
||||||
|
|
||||||
@ -276,6 +281,140 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case IOCTL_ES_ADDTITLESTART:
|
||||||
|
{
|
||||||
|
_dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 4,
|
||||||
|
"IOCTL_ES_ADDTITLESTART wrong number of inputs");
|
||||||
|
|
||||||
|
INFO_LOG(WII_IPC_ES, "IOCTL_ES_ADDTITLESTART");
|
||||||
|
std::vector<u8> tmd(Buffer.InBuffer[0].m_Size);
|
||||||
|
Memory::CopyFromEmu(tmd.data(), Buffer.InBuffer[0].m_Address, Buffer.InBuffer[0].m_Size);
|
||||||
|
|
||||||
|
m_addtitle_tmd.SetBytes(tmd);
|
||||||
|
if (!m_addtitle_tmd.IsValid())
|
||||||
|
{
|
||||||
|
ERROR_LOG(WII_IPC_ES, "Invalid TMD while adding title (size = %zd)", tmd.size());
|
||||||
|
Memory::Write_U32(ES_INVALID_TMD, _CommandAddress + 0x4);
|
||||||
|
return GetDefaultReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the TMD to title storage.
|
||||||
|
std::string tmd_path =
|
||||||
|
Common::GetTMDFileName(m_addtitle_tmd.GetTitleId(), Common::FROM_SESSION_ROOT);
|
||||||
|
File::CreateFullPath(tmd_path);
|
||||||
|
|
||||||
|
File::IOFile fp(tmd_path, "wb");
|
||||||
|
fp.WriteBytes(tmd.data(), tmd.size());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case IOCTL_ES_ADDCONTENTSTART:
|
||||||
|
{
|
||||||
|
_dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2,
|
||||||
|
"IOCTL_ES_ADDCONTENTSTART wrong number of inputs");
|
||||||
|
|
||||||
|
u64 title_id = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
|
||||||
|
u32 content_id = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
|
||||||
|
|
||||||
|
if (m_addtitle_content_id != 0xFFFFFFFF)
|
||||||
|
{
|
||||||
|
ERROR_LOG(WII_IPC_ES, "Trying to add content when we haven't finished adding "
|
||||||
|
"another content. Unsupported.");
|
||||||
|
Memory::Write_U32(ES_WRITE_FAILURE, _CommandAddress + 0x4);
|
||||||
|
return GetDefaultReply();
|
||||||
|
}
|
||||||
|
m_addtitle_content_id = content_id;
|
||||||
|
|
||||||
|
m_addtitle_content_buffer.clear();
|
||||||
|
|
||||||
|
INFO_LOG(WII_IPC_ES, "IOCTL_ES_ADDCONTENTSTART: title id %016" PRIx64 ", "
|
||||||
|
"content id %08x",
|
||||||
|
title_id, m_addtitle_content_id);
|
||||||
|
|
||||||
|
if (title_id != m_addtitle_tmd.GetTitleId())
|
||||||
|
{
|
||||||
|
ERROR_LOG(WII_IPC_ES, "IOCTL_ES_ADDCONTENTSTART: title id %016" PRIx64 " != "
|
||||||
|
"TMD title id %016lx, ignoring",
|
||||||
|
title_id, m_addtitle_tmd.GetTitleId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're supposed to return a "content file descriptor" here, which is
|
||||||
|
// passed to further AddContentData / AddContentFinish. But so far there is
|
||||||
|
// no known content installer which performs content addition concurrently.
|
||||||
|
// Instead we just log an error (see above) if this condition is detected.
|
||||||
|
s32 content_fd = 0;
|
||||||
|
Memory::Write_U32(content_fd, _CommandAddress + 0x4);
|
||||||
|
return GetDefaultReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
case IOCTL_ES_ADDCONTENTDATA:
|
||||||
|
{
|
||||||
|
_dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2,
|
||||||
|
"IOCTL_ES_ADDCONTENTDATA wrong number of inputs");
|
||||||
|
|
||||||
|
u32 content_fd = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
|
||||||
|
INFO_LOG(WII_IPC_ES, "IOCTL_ES_ADDCONTENTDATA: content fd %08x, "
|
||||||
|
"size %d",
|
||||||
|
content_fd, Buffer.InBuffer[1].m_Size);
|
||||||
|
|
||||||
|
u8* data_start = Memory::GetPointer(Buffer.InBuffer[1].m_Address);
|
||||||
|
u8* data_end = data_start + Buffer.InBuffer[1].m_Size;
|
||||||
|
m_addtitle_content_buffer.insert(m_addtitle_content_buffer.end(), data_start, data_end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case IOCTL_ES_ADDCONTENTFINISH:
|
||||||
|
{
|
||||||
|
_dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1,
|
||||||
|
"IOCTL_ES_ADDCONTENTFINISH wrong number of inputs");
|
||||||
|
|
||||||
|
u32 content_fd = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
|
||||||
|
INFO_LOG(WII_IPC_ES, "IOCTL_ES_ADDCONTENTFINISH: content fd %08x", content_fd);
|
||||||
|
|
||||||
|
// Try to find the title key from a pre-installed ticket.
|
||||||
|
std::vector<u8> ticket = DiscIO::FindSignedTicket(m_addtitle_tmd.GetTitleId());
|
||||||
|
if (ticket.size() == 0)
|
||||||
|
{
|
||||||
|
Memory::Write_U32(ES_NO_TICKET_INSTALLED, _CommandAddress + 0x4);
|
||||||
|
return GetDefaultReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_aes_context aes_ctx;
|
||||||
|
mbedtls_aes_setkey_dec(&aes_ctx, DiscIO::GetKeyFromTicket(ticket).data(), 128);
|
||||||
|
|
||||||
|
// The IV for title content decryption is the lower two bytes of the
|
||||||
|
// content index, zero extended.
|
||||||
|
TMDReader::Content content_info;
|
||||||
|
if (!m_addtitle_tmd.FindContentById(m_addtitle_content_id, &content_info))
|
||||||
|
{
|
||||||
|
Memory::Write_U32(ES_INVALID_TMD, _CommandAddress + 0x4);
|
||||||
|
return GetDefaultReply();
|
||||||
|
}
|
||||||
|
u8 iv[16] = {0};
|
||||||
|
iv[0] = (content_info.index >> 8) & 0xFF;
|
||||||
|
iv[1] = content_info.index & 0xFF;
|
||||||
|
std::vector<u8> decrypted_data(m_addtitle_content_buffer.size());
|
||||||
|
mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, m_addtitle_content_buffer.size(), iv,
|
||||||
|
m_addtitle_content_buffer.data(), decrypted_data.data());
|
||||||
|
|
||||||
|
std::string path = StringFromFormat(
|
||||||
|
"%s%08x.app",
|
||||||
|
Common::GetTitleContentPath(m_addtitle_tmd.GetTitleId(), Common::FROM_SESSION_ROOT).c_str(),
|
||||||
|
m_addtitle_content_id);
|
||||||
|
|
||||||
|
File::IOFile fp(path, "wb");
|
||||||
|
fp.WriteBytes(decrypted_data.data(), decrypted_data.size());
|
||||||
|
|
||||||
|
m_addtitle_content_id = 0xFFFFFFFF;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case IOCTL_ES_ADDTITLEFINISH:
|
||||||
|
{
|
||||||
|
INFO_LOG(WII_IPC_ES, "IOCTL_ES_ADDTITLEFINISH");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case IOCTL_ES_GETDEVICEID:
|
case IOCTL_ES_GETDEVICEID:
|
||||||
{
|
{
|
||||||
_dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1,
|
_dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1,
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Core/IPC_HLE/ESFormats.h"
|
||||||
#include "Core/IPC_HLE/WII_IPC_HLE.h"
|
#include "Core/IPC_HLE/WII_IPC_HLE.h"
|
||||||
#include "Core/IPC_HLE/WII_IPC_HLE_Device.h"
|
#include "Core/IPC_HLE/WII_IPC_HLE_Device.h"
|
||||||
|
|
||||||
@ -143,6 +144,11 @@ private:
|
|||||||
|
|
||||||
static u8* keyTable[11];
|
static u8* keyTable[11];
|
||||||
|
|
||||||
|
// For title installation (ioctls IOCTL_ES_ADDTITLE*).
|
||||||
|
TMDReader m_addtitle_tmd;
|
||||||
|
u32 m_addtitle_content_id = 0xFFFFFFFF;
|
||||||
|
std::vector<u8> m_addtitle_content_buffer;
|
||||||
|
|
||||||
const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id);
|
const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id);
|
||||||
u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index);
|
u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user