ES: Separate behavior of IOCtlV into separate functions

This function is exceptionally large. Everything within a switch like this
also makes it quite error prone. Separating the functions out makes it
easier to change a certain request implementation as well as improving
code locality.
This commit is contained in:
Lioncash 2017-01-23 22:22:31 -05:00
parent 3c88c248dd
commit ac973e61bb
2 changed files with 1029 additions and 915 deletions

View File

@ -249,15 +249,101 @@ u32 ES::OpenTitleContent(u32 CFD, u64 TitleID, u16 Index)
IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request) IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
{ {
DEBUG_LOG(IOS_ES, "%s (0x%x)", GetDeviceName().c_str(), request.request); DEBUG_LOG(IOS_ES, "%s (0x%x)", GetDeviceName().c_str(), request.request);
// Clear the IO buffers. Note that this is unsafe for other ioctlvs. // Clear the IO buffers. Note that this is unsafe for other ioctlvs.
for (const auto& io_vector : request.io_vectors) for (const auto& io_vector : request.io_vectors)
{ {
if (!request.HasInputVectorWithAddress(io_vector.address)) if (!request.HasInputVectorWithAddress(io_vector.address))
Memory::Memset(io_vector.address, 0, io_vector.size); Memory::Memset(io_vector.address, 0, io_vector.size);
} }
switch (request.request) switch (request.request)
{ {
case IOCTL_ES_ADDTICKET: case IOCTL_ES_ADDTICKET:
return AddTicket(request);
case IOCTL_ES_ADDTITLESTART:
return AddTitleStart(request);
case IOCTL_ES_ADDCONTENTSTART:
return AddContentStart(request);
case IOCTL_ES_ADDCONTENTDATA:
return AddContentData(request);
case IOCTL_ES_ADDCONTENTFINISH:
return AddContentFinish(request);
case IOCTL_ES_ADDTITLEFINISH:
return AddTitleFinish(request);
case IOCTL_ES_GETDEVICEID:
return ESGetDeviceID(request);
case IOCTL_ES_GETTITLECONTENTSCNT:
return GetTitleContentsCount(request);
case IOCTL_ES_GETTITLECONTENTS:
return GetTitleContents(request);
case IOCTL_ES_OPENTITLECONTENT:
return OpenTitleContent(request);
case IOCTL_ES_OPENCONTENT:
return OpenContent(request);
case IOCTL_ES_READCONTENT:
return ReadContent(request);
case IOCTL_ES_CLOSECONTENT:
return CloseContent(request);
case IOCTL_ES_SEEKCONTENT:
return SeekContent(request);
case IOCTL_ES_GETTITLEDIR:
return GetTitleDirectory(request);
case IOCTL_ES_GETTITLEID:
return GetTitleID(request);
case IOCTL_ES_SETUID:
return SetUID(request);
case IOCTL_ES_GETTITLECNT:
return GetTitleCount(request);
case IOCTL_ES_GETTITLES:
return GetTitles(request);
case IOCTL_ES_GETVIEWCNT:
return GetViewCount(request);
case IOCTL_ES_GETVIEWS:
return GetViews(request);
case IOCTL_ES_GETTMDVIEWCNT:
return GetTMDViewCount(request);
case IOCTL_ES_GETTMDVIEWS:
return GetTMDViews(request);
case IOCTL_ES_GETCONSUMPTION:
return GetConsumption(request);
case IOCTL_ES_DELETETICKET:
return DeleteTicket(request);
case IOCTL_ES_DELETETITLECONTENT:
return DeleteTitleContent(request);
case IOCTL_ES_GETSTOREDTMDSIZE:
return GetStoredTMDSize(request);
case IOCTL_ES_GETSTOREDTMD:
return GetStoredTMD(request);
case IOCTL_ES_ENCRYPT:
return Encrypt(request);
case IOCTL_ES_DECRYPT:
return Decrypt(request);
case IOCTL_ES_LAUNCH:
return Launch(request);
case IOCTL_ES_CHECKKOREAREGION:
return CheckKoreaRegion(request);
case IOCTL_ES_GETDEVICECERT:
return GetDeviceCertificate(request);
case IOCTL_ES_SIGN:
return Sign(request);
case IOCTL_ES_GETBOOT2VERSION:
return GetBoot2Version(request);
// Unsupported functions
case IOCTL_ES_DIGETTICKETVIEW:
return DIGetTicketView(request);
case IOCTL_ES_GETOWNEDTITLECNT:
return GetOwnedTitleCount(request);
default:
request.DumpUnknown(GetDeviceName(), LogTypes::IOS);
break;
}
return GetDefaultReply(IPC_SUCCESS);
}
IPCCommandResult ES::AddTicket(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 3, _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 3,
"IOCTL_ES_ADDTICKET wrong number of inputs"); "IOCTL_ES_ADDTICKET wrong number of inputs");
@ -266,10 +352,11 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
std::vector<u8> ticket(request.in_vectors[0].size); std::vector<u8> ticket(request.in_vectors[0].size);
Memory::CopyFromEmu(ticket.data(), request.in_vectors[0].address, request.in_vectors[0].size); Memory::CopyFromEmu(ticket.data(), request.in_vectors[0].address, request.in_vectors[0].size);
DiscIO::AddTicket(ticket); DiscIO::AddTicket(ticket);
break;
return GetDefaultReply(IPC_SUCCESS);
} }
case IOCTL_ES_ADDTITLESTART: IPCCommandResult ES::AddTitleStart(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 4, _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 4,
"IOCTL_ES_ADDTITLESTART wrong number of inputs"); "IOCTL_ES_ADDTITLESTART wrong number of inputs");
@ -292,10 +379,11 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
File::IOFile fp(tmd_path, "wb"); File::IOFile fp(tmd_path, "wb");
fp.WriteBytes(tmd.data(), tmd.size()); fp.WriteBytes(tmd.data(), tmd.size());
break;
return GetDefaultReply(IPC_SUCCESS);
} }
case IOCTL_ES_ADDCONTENTSTART: IPCCommandResult ES::AddContentStart(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 2, _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 2,
"IOCTL_ES_ADDCONTENTSTART wrong number of inputs"); "IOCTL_ES_ADDCONTENTSTART wrong number of inputs");
@ -332,7 +420,7 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
return GetDefaultReply(content_fd); return GetDefaultReply(content_fd);
} }
case IOCTL_ES_ADDCONTENTDATA: IPCCommandResult ES::AddContentData(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 2, _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 2,
"IOCTL_ES_ADDCONTENTDATA wrong number of inputs"); "IOCTL_ES_ADDCONTENTDATA wrong number of inputs");
@ -345,10 +433,10 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
u8* data_start = Memory::GetPointer(request.in_vectors[1].address); u8* data_start = Memory::GetPointer(request.in_vectors[1].address);
u8* data_end = data_start + request.in_vectors[1].size; u8* data_end = data_start + request.in_vectors[1].size;
m_addtitle_content_buffer.insert(m_addtitle_content_buffer.end(), data_start, data_end); m_addtitle_content_buffer.insert(m_addtitle_content_buffer.end(), data_start, data_end);
break; return GetDefaultReply(IPC_SUCCESS);
} }
case IOCTL_ES_ADDCONTENTFINISH: IPCCommandResult ES::AddContentFinish(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1, _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1,
"IOCTL_ES_ADDCONTENTFINISH wrong number of inputs"); "IOCTL_ES_ADDCONTENTFINISH wrong number of inputs");
@ -389,16 +477,16 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
fp.WriteBytes(decrypted_data.data(), decrypted_data.size()); fp.WriteBytes(decrypted_data.data(), decrypted_data.size());
m_addtitle_content_id = 0xFFFFFFFF; m_addtitle_content_id = 0xFFFFFFFF;
break; return GetDefaultReply(IPC_SUCCESS);
} }
case IOCTL_ES_ADDTITLEFINISH: IPCCommandResult ES::AddTitleFinish(const IOCtlVRequest& request)
{ {
INFO_LOG(IOS_ES, "IOCTL_ES_ADDTITLEFINISH"); INFO_LOG(IOS_ES, "IOCTL_ES_ADDTITLEFINISH");
break; return GetDefaultReply(IPC_SUCCESS);
} }
case IOCTL_ES_GETDEVICEID: IPCCommandResult ES::ESGetDeviceID(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_GETDEVICEID no io vectors"); _dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_GETDEVICEID no io vectors");
@ -408,7 +496,7 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
return GetDefaultReply(IPC_SUCCESS); return GetDefaultReply(IPC_SUCCESS);
} }
case IOCTL_ES_GETTITLECONTENTSCNT: IPCCommandResult ES::GetTitleContentsCount(const IOCtlVRequest& request)
{ {
_dbg_assert_(IOS_ES, request.in_vectors.size() == 1); _dbg_assert_(IOS_ES, request.in_vectors.size() == 1);
_dbg_assert_(IOS_ES, request.io_vectors.size() == 1); _dbg_assert_(IOS_ES, request.io_vectors.size() == 1);
@ -438,9 +526,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
return GetDefaultReply(return_value); return GetDefaultReply(return_value);
} }
break;
case IOCTL_ES_GETTITLECONTENTS: IPCCommandResult ES::GetTitleContents(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 2, _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 2,
"IOCTL_ES_GETTITLECONTENTS bad in buffer"); "IOCTL_ES_GETTITLECONTENTS bad in buffer");
@ -470,9 +557,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
return GetDefaultReply(return_value); return GetDefaultReply(return_value);
} }
break;
case IOCTL_ES_OPENTITLECONTENT: IPCCommandResult ES::OpenTitleContent(const IOCtlVRequest& request)
{ {
_dbg_assert_(IOS_ES, request.in_vectors.size() == 3); _dbg_assert_(IOS_ES, request.in_vectors.size() == 3);
_dbg_assert_(IOS_ES, request.io_vectors.size() == 0); _dbg_assert_(IOS_ES, request.io_vectors.size() == 0);
@ -487,9 +573,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
return GetDefaultReply(CFD); return GetDefaultReply(CFD);
} }
break;
case IOCTL_ES_OPENCONTENT: IPCCommandResult ES::OpenContent(const IOCtlVRequest& request)
{ {
_dbg_assert_(IOS_ES, request.in_vectors.size() == 1); _dbg_assert_(IOS_ES, request.in_vectors.size() == 1);
_dbg_assert_(IOS_ES, request.io_vectors.size() == 0); _dbg_assert_(IOS_ES, request.io_vectors.size() == 0);
@ -500,9 +585,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
return GetDefaultReply(CFD); return GetDefaultReply(CFD);
} }
break;
case IOCTL_ES_READCONTENT: IPCCommandResult ES::ReadContent(const IOCtlVRequest& request)
{ {
_dbg_assert_(IOS_ES, request.in_vectors.size() == 1); _dbg_assert_(IOS_ES, request.in_vectors.size() == 1);
_dbg_assert_(IOS_ES, request.io_vectors.size() == 1); _dbg_assert_(IOS_ES, request.io_vectors.size() == 1);
@ -547,14 +631,13 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
} }
DEBUG_LOG(IOS_ES, DEBUG_LOG(IOS_ES,
"IOCTL_ES_READCONTENT: CFD %x, Address 0x%x, Size %i -> stream pos %i (Index %i)", "IOCTL_ES_READCONTENT: CFD %x, Address 0x%x, Size %i -> stream pos %i (Index %i)", CFD,
CFD, Addr, Size, rContent.m_Position, rContent.m_Index); Addr, Size, rContent.m_Position, rContent.m_Index);
return GetDefaultReply(Size); return GetDefaultReply(Size);
} }
break;
case IOCTL_ES_CLOSECONTENT: IPCCommandResult ES::CloseContent(const IOCtlVRequest& request)
{ {
_dbg_assert_(IOS_ES, request.in_vectors.size() == 1); _dbg_assert_(IOS_ES, request.in_vectors.size() == 1);
_dbg_assert_(IOS_ES, request.io_vectors.size() == 0); _dbg_assert_(IOS_ES, request.io_vectors.size() == 0);
@ -581,9 +664,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
return GetDefaultReply(IPC_SUCCESS); return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_SEEKCONTENT: IPCCommandResult ES::SeekContent(const IOCtlVRequest& request)
{ {
_dbg_assert_(IOS_ES, request.in_vectors.size() == 3); _dbg_assert_(IOS_ES, request.in_vectors.size() == 3);
_dbg_assert_(IOS_ES, request.io_vectors.size() == 0); _dbg_assert_(IOS_ES, request.io_vectors.size() == 0);
@ -619,9 +701,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
return GetDefaultReply(rContent.m_Position); return GetDefaultReply(rContent.m_Position);
} }
break;
case IOCTL_ES_GETTITLEDIR: IPCCommandResult ES::GetTitleDirectory(const IOCtlVRequest& request)
{ {
_dbg_assert_(IOS_ES, request.in_vectors.size() == 1); _dbg_assert_(IOS_ES, request.in_vectors.size() == 1);
_dbg_assert_(IOS_ES, request.io_vectors.size() == 1); _dbg_assert_(IOS_ES, request.io_vectors.size() == 1);
@ -632,34 +713,34 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
sprintf(Path, "/title/%08x/%08x/data", (u32)(TitleID >> 32), (u32)TitleID); sprintf(Path, "/title/%08x/%08x/data", (u32)(TitleID >> 32), (u32)TitleID);
INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLEDIR: %s", Path); INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLEDIR: %s", Path);
return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_GETTITLEID: IPCCommandResult ES::GetTitleID(const IOCtlVRequest& request)
{ {
_dbg_assert_(IOS_ES, request.in_vectors.size() == 0); _dbg_assert_(IOS_ES, request.in_vectors.size() == 0);
_dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_GETTITLEID no out buffer"); _dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_GETTITLEID no out buffer");
Memory::Write_U64(m_TitleID, request.io_vectors[0].address); Memory::Write_U64(m_TitleID, request.io_vectors[0].address);
INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLEID: %08x/%08x", (u32)(m_TitleID >> 32), (u32)m_TitleID); INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLEID: %08x/%08x", (u32)(m_TitleID >> 32), (u32)m_TitleID);
return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_SETUID: IPCCommandResult ES::SetUID(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1, "IOCTL_ES_SETUID no in buffer"); _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1, "IOCTL_ES_SETUID no in buffer");
_dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 0, _dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 0,
"IOCTL_ES_SETUID has a payload, it shouldn't"); "IOCTL_ES_SETUID has a payload, it shouldn't");
// TODO: fs permissions based on this // TODO: fs permissions based on this
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
INFO_LOG(IOS_ES, "IOCTL_ES_SETUID titleID: %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID); INFO_LOG(IOS_ES, "IOCTL_ES_SETUID titleID: %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID);
return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_GETTITLECNT: IPCCommandResult ES::GetTitleCount(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 0, _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 0, "IOCTL_ES_GETTITLECNT has an in buffer");
"IOCTL_ES_GETTITLECNT has an in buffer");
_dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, _dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1,
"IOCTL_ES_GETTITLECNT has no out buffer"); "IOCTL_ES_GETTITLECNT has no out buffer");
_dbg_assert_msg_(IOS_ES, request.io_vectors[0].size == 4, _dbg_assert_msg_(IOS_ES, request.io_vectors[0].size == 4,
@ -671,13 +752,11 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
return GetDefaultReply(IPC_SUCCESS); return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_GETTITLES: IPCCommandResult ES::GetTitles(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1, "IOCTL_ES_GETTITLES has an in buffer"); _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1, "IOCTL_ES_GETTITLES has an in buffer");
_dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, _dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_GETTITLES has no out buffer");
"IOCTL_ES_GETTITLES has no out buffer");
u32 MaxCount = Memory::Read_U32(request.in_vectors[0].address); u32 MaxCount = Memory::Read_U32(request.in_vectors[0].address);
u32 Count = 0; u32 Count = 0;
@ -694,9 +773,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLES: Number of titles returned %i", Count); INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLES: Number of titles returned %i", Count);
return GetDefaultReply(IPC_SUCCESS); return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_GETVIEWCNT: IPCCommandResult ES::GetViewCount(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1, "IOCTL_ES_GETVIEWCNT no in buffer"); _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1, "IOCTL_ES_GETVIEWCNT no in buffer");
_dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_GETVIEWCNT no out buffer"); _dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_GETVIEWCNT no out buffer");
@ -744,9 +822,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
Memory::Write_U32(ViewCount, request.io_vectors[0].address); Memory::Write_U32(ViewCount, request.io_vectors[0].address);
return GetDefaultReply(retVal); return GetDefaultReply(retVal);
} }
break;
case IOCTL_ES_GETVIEWS: IPCCommandResult ES::GetViews(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 2, "IOCTL_ES_GETVIEWS no in buffer"); _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 2, "IOCTL_ES_GETVIEWS no in buffer");
_dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_GETVIEWS no out buffer"); _dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_GETVIEWS no out buffer");
@ -811,18 +888,16 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
} }
} }
INFO_LOG(IOS_ES, "IOCTL_ES_GETVIEWS for titleID: %08x/%08x (MaxViews = %i)", INFO_LOG(IOS_ES, "IOCTL_ES_GETVIEWS for titleID: %08x/%08x (MaxViews = %i)", (u32)(TitleID >> 32),
(u32)(TitleID >> 32), (u32)TitleID, maxViews); (u32)TitleID, maxViews);
return GetDefaultReply(retVal); return GetDefaultReply(retVal);
} }
break;
case IOCTL_ES_GETTMDVIEWCNT: IPCCommandResult ES::GetTMDViewCount(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1, "IOCTL_ES_GETTMDVIEWCNT no in buffer"); _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1, "IOCTL_ES_GETTMDVIEWCNT no in buffer");
_dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, _dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_GETTMDVIEWCNT no out buffer");
"IOCTL_ES_GETTMDVIEWCNT no out buffer");
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
@ -834,22 +909,19 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
TMDViewCnt += DiscIO::CNANDContentLoader::TMD_VIEW_SIZE; TMDViewCnt += DiscIO::CNANDContentLoader::TMD_VIEW_SIZE;
TMDViewCnt += 2; // title version TMDViewCnt += 2; // title version
TMDViewCnt += 2; // num entries TMDViewCnt += 2; // num entries
TMDViewCnt += TMDViewCnt += (u32)Loader.GetContentSize() * (4 + 2 + 2 + 8); // content id, index, type, size
(u32)Loader.GetContentSize() * (4 + 2 + 2 + 8); // content id, index, type, size
} }
Memory::Write_U32(TMDViewCnt, request.io_vectors[0].address); Memory::Write_U32(TMDViewCnt, request.io_vectors[0].address);
INFO_LOG(IOS_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x (view size %i)", INFO_LOG(IOS_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x (view size %i)", (u32)(TitleID >> 32),
(u32)(TitleID >> 32), (u32)TitleID, TMDViewCnt); (u32)TitleID, TMDViewCnt);
return GetDefaultReply(IPC_SUCCESS); return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_GETTMDVIEWS: IPCCommandResult ES::GetTMDViews(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 2, "IOCTL_ES_GETTMDVIEWCNT no in buffer"); _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 2, "IOCTL_ES_GETTMDVIEWCNT no in buffer");
_dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, _dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_GETTMDVIEWCNT no out buffer");
"IOCTL_ES_GETTMDVIEWCNT no out buffer");
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
u32 MaxCount = Memory::Read_U32(request.in_vectors[1].address); u32 MaxCount = Memory::Read_U32(request.in_vectors[1].address);
@ -887,44 +959,50 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
_dbg_assert_(IOS_ES, (Address - request.io_vectors[0].address) == request.io_vectors[0].size); _dbg_assert_(IOS_ES, (Address - request.io_vectors[0].address) == request.io_vectors[0].size);
} }
INFO_LOG(IOS_ES, "IOCTL_ES_GETTMDVIEWS: title: %08x/%08x (buffer size: %i)", INFO_LOG(IOS_ES, "IOCTL_ES_GETTMDVIEWS: title: %08x/%08x (buffer size: %i)", (u32)(TitleID >> 32),
(u32)(TitleID >> 32), (u32)TitleID, MaxCount); (u32)TitleID, MaxCount);
return GetDefaultReply(IPC_SUCCESS); return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_GETCONSUMPTION: // This is at least what crediar's ES module does IPCCommandResult ES::GetConsumption(const IOCtlVRequest& request)
{
// This is at least what crediar's ES module does
Memory::Write_U32(0, request.io_vectors[1].address); Memory::Write_U32(0, request.io_vectors[1].address);
INFO_LOG(IOS_ES, "IOCTL_ES_GETCONSUMPTION"); INFO_LOG(IOS_ES, "IOCTL_ES_GETCONSUMPTION");
return GetDefaultReply(IPC_SUCCESS); return GetDefaultReply(IPC_SUCCESS);
}
case IOCTL_ES_DELETETICKET: IPCCommandResult ES::DeleteTicket(const IOCtlVRequest& request)
{ {
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
INFO_LOG(IOS_ES, "IOCTL_ES_DELETETICKET: title: %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID); INFO_LOG(IOS_ES, "IOCTL_ES_DELETETICKET: title: %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID);
// Presumably return -1017 when delete fails // Presumably return -1017 when delete fails
if (!File::Delete(Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT))) if (!File::Delete(Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT)))
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
return GetDefaultReply(IPC_SUCCESS); return GetDefaultReply(IPC_SUCCESS);
} }
case IOCTL_ES_DELETETITLECONTENT: IPCCommandResult ES::DeleteTitleContent(const IOCtlVRequest& request)
{ {
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
INFO_LOG(IOS_ES, "IOCTL_ES_DELETETITLECONTENT: title: %08x/%08x", (u32)(TitleID >> 32), INFO_LOG(IOS_ES, "IOCTL_ES_DELETETITLECONTENT: title: %08x/%08x", (u32)(TitleID >> 32),
(u32)TitleID); (u32)TitleID);
// Presumably return -1017 when title not installed TODO verify // Presumably return -1017 when title not installed TODO verify
if (!DiscIO::CNANDContentManager::Access().RemoveTitle(TitleID, Common::FROM_SESSION_ROOT)) if (!DiscIO::CNANDContentManager::Access().RemoveTitle(TitleID, Common::FROM_SESSION_ROOT))
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
return GetDefaultReply(IPC_SUCCESS); return GetDefaultReply(IPC_SUCCESS);
} }
case IOCTL_ES_GETSTOREDTMDSIZE: IPCCommandResult ES::GetStoredTMDSize(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1, _dbg_assert_msg_(IOS_ES, request.in_vectors.size() == 1,
"IOCTL_ES_GETSTOREDTMDSIZE no in buffer"); "IOCTL_ES_GETSTOREDTMDSIZE no in buffer");
// _dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_ES_GETSTOREDTMDSIZE // _dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1,
// no out buffer"); // "IOCTL_ES_ES_GETSTOREDTMDSIZE no out buffer");
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID);
@ -936,22 +1014,24 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
TMDCnt += DiscIO::CNANDContentLoader::TMD_HEADER_SIZE; TMDCnt += DiscIO::CNANDContentLoader::TMD_HEADER_SIZE;
TMDCnt += (u32)Loader.GetContentSize() * DiscIO::CNANDContentLoader::CONTENT_HEADER_SIZE; TMDCnt += (u32)Loader.GetContentSize() * DiscIO::CNANDContentLoader::CONTENT_HEADER_SIZE;
} }
if (request.io_vectors.size()) if (request.io_vectors.size())
Memory::Write_U32(TMDCnt, request.io_vectors[0].address); Memory::Write_U32(TMDCnt, request.io_vectors[0].address);
INFO_LOG(IOS_ES, "IOCTL_ES_GETSTOREDTMDSIZE: title: %08x/%08x (view size %i)", INFO_LOG(IOS_ES, "IOCTL_ES_GETSTOREDTMDSIZE: title: %08x/%08x (view size %i)",
(u32)(TitleID >> 32), (u32)TitleID, TMDCnt); (u32)(TitleID >> 32), (u32)TitleID, TMDCnt);
return GetDefaultReply(IPC_SUCCESS); return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_GETSTOREDTMD: IPCCommandResult ES::GetStoredTMD(const IOCtlVRequest& request)
{ {
_dbg_assert_msg_(IOS_ES, request.in_vectors.size() > 0, "IOCTL_ES_GETSTOREDTMD no in buffer"); _dbg_assert_msg_(IOS_ES, request.in_vectors.size() > 0, "IOCTL_ES_GETSTOREDTMD no in buffer");
// requires 1 inbuffer and no outbuffer, presumably outbuffer required when second inbuffer is // requires 1 inbuffer and no outbuffer, presumably outbuffer required when second inbuffer is
// used for maxcount (allocated mem?) // used for maxcount (allocated mem?)
// called with 1 inbuffer after deleting a titleid // called with 1 inbuffer after deleting a titleid
//_dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1, "IOCTL_ES_GETSTOREDTMD no out //_dbg_assert_msg_(IOS_ES, request.io_vectors.size() == 1,
// buffer"); // "IOCTL_ES_GETSTOREDTMD no out buffer");
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
u32 MaxCount = 0; u32 MaxCount = 0;
@ -969,8 +1049,7 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
{ {
u32 Address = request.io_vectors[0].address; u32 Address = request.io_vectors[0].address;
Memory::CopyToEmu(Address, Loader.GetTMDHeader(), Memory::CopyToEmu(Address, Loader.GetTMDHeader(), DiscIO::CNANDContentLoader::TMD_HEADER_SIZE);
DiscIO::CNANDContentLoader::TMD_HEADER_SIZE);
Address += DiscIO::CNANDContentLoader::TMD_HEADER_SIZE; Address += DiscIO::CNANDContentLoader::TMD_HEADER_SIZE;
const std::vector<DiscIO::SNANDContent>& rContent = Loader.GetContent(); const std::vector<DiscIO::SNANDContent>& rContent = Loader.GetContent();
@ -988,9 +1067,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
(u32)(TitleID >> 32), (u32)TitleID, MaxCount); (u32)(TitleID >> 32), (u32)TitleID, MaxCount);
return GetDefaultReply(IPC_SUCCESS); return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_ENCRYPT: IPCCommandResult ES::Encrypt(const IOCtlVRequest& request)
{ {
u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address); u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address);
u8* IV = Memory::GetPointer(request.in_vectors[1].address); u8* IV = Memory::GetPointer(request.in_vectors[1].address);
@ -1006,10 +1084,10 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
_dbg_assert_msg_(IOS_ES, keyIndex == 6, _dbg_assert_msg_(IOS_ES, keyIndex == 6,
"IOCTL_ES_ENCRYPT: Key type is not SD, data will be crap"); "IOCTL_ES_ENCRYPT: Key type is not SD, data will be crap");
return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_DECRYPT: IPCCommandResult ES::Decrypt(const IOCtlVRequest& request)
{ {
u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address); u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address);
u8* IV = Memory::GetPointer(request.in_vectors[1].address); u8* IV = Memory::GetPointer(request.in_vectors[1].address);
@ -1022,10 +1100,10 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
_dbg_assert_msg_(IOS_ES, keyIndex == 6, _dbg_assert_msg_(IOS_ES, keyIndex == 6,
"IOCTL_ES_DECRYPT: Key type is not SD, data will be crap"); "IOCTL_ES_DECRYPT: Key type is not SD, data will be crap");
return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_LAUNCH: IPCCommandResult ES::Launch(const IOCtlVRequest& request)
{ {
_dbg_assert_(IOS_ES, request.in_vectors.size() == 2); _dbg_assert_(IOS_ES, request.in_vectors.size() == 2);
bool bSuccess = false; bool bSuccess = false;
@ -1150,28 +1228,30 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
EnqueueCommandAcknowledgement(request.address, 0); EnqueueCommandAcknowledgement(request.address, 0);
return GetNoReply(); return GetNoReply();
} }
break;
case IOCTL_ES_CHECKKOREAREGION: // note by DacoTaco : name is unknown, i just tried to name it IPCCommandResult ES::CheckKoreaRegion(const IOCtlVRequest& request)
// SOMETHING {
// note by DacoTaco : name is unknown, I just tried to name it SOMETHING.
// IOS70 has this to let system menu 4.2 check if the console is region changed. it returns // IOS70 has this to let system menu 4.2 check if the console is region changed. it returns
// -1017 // -1017
// if the IOS didn't find the Korean keys and 0 if it does. 0 leads to a error 003 // if the IOS didn't find the Korean keys and 0 if it does. 0 leads to a error 003
INFO_LOG(IOS_ES, "IOCTL_ES_CHECKKOREAREGION: Title checked for Korean keys."); INFO_LOG(IOS_ES, "IOCTL_ES_CHECKKOREAREGION: Title checked for Korean keys.");
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
}
case IOCTL_ES_GETDEVICECERT: // (Input: none, Output: 384 bytes) IPCCommandResult ES::GetDeviceCertificate(const IOCtlVRequest& request)
{ {
// (Input: none, Output: 384 bytes)
INFO_LOG(IOS_ES, "IOCTL_ES_GETDEVICECERT"); INFO_LOG(IOS_ES, "IOCTL_ES_GETDEVICECERT");
_dbg_assert_(IOS_ES, request.io_vectors.size() == 1); _dbg_assert_(IOS_ES, request.io_vectors.size() == 1);
u8* destination = Memory::GetPointer(request.io_vectors[0].address); u8* destination = Memory::GetPointer(request.io_vectors[0].address);
EcWii& ec = EcWii::GetInstance(); EcWii& ec = EcWii::GetInstance();
get_ng_cert(destination, ec.getNgId(), ec.getNgKeyId(), ec.getNgPriv(), ec.getNgSig()); get_ng_cert(destination, ec.getNgId(), ec.getNgKeyId(), ec.getNgPriv(), ec.getNgSig());
return GetDefaultReply(IPC_SUCCESS);
} }
break;
case IOCTL_ES_SIGN: IPCCommandResult ES::Sign(const IOCtlVRequest& request)
{ {
INFO_LOG(IOS_ES, "IOCTL_ES_SIGN"); INFO_LOG(IOS_ES, "IOCTL_ES_SIGN");
u8* ap_cert_out = Memory::GetPointer(request.io_vectors[1].address); u8* ap_cert_out = Memory::GetPointer(request.io_vectors[1].address);
@ -1182,34 +1262,30 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
EcWii& ec = EcWii::GetInstance(); EcWii& ec = EcWii::GetInstance();
get_ap_sig_and_cert(sig_out, ap_cert_out, m_TitleID, data, data_size, ec.getNgPriv(), get_ap_sig_and_cert(sig_out, ap_cert_out, m_TitleID, data, data_size, ec.getNgPriv(),
ec.getNgId()); ec.getNgId());
}
break;
case IOCTL_ES_GETBOOT2VERSION: return GetDefaultReply(IPC_SUCCESS);
}
IPCCommandResult ES::GetBoot2Version(const IOCtlVRequest& request)
{ {
INFO_LOG(IOS_ES, "IOCTL_ES_GETBOOT2VERSION"); INFO_LOG(IOS_ES, "IOCTL_ES_GETBOOT2VERSION");
Memory::Write_U32( // as of 26/02/2012, this was latest bootmii version
4, request.io_vectors[0].address); // as of 26/02/2012, this was latest bootmii version Memory::Write_U32(4, request.io_vectors[0].address);
return GetDefaultReply(IPC_SUCCESS);
} }
break;
// =============================================================================================== IPCCommandResult ES::DIGetTicketView(const IOCtlVRequest& request)
// unsupported functions {
// =============================================================================================== // (Input: none, Output: 216 bytes) bug crediar :D
case IOCTL_ES_DIGETTICKETVIEW: // (Input: none, Output: 216 bytes) bug crediar :D
WARN_LOG(IOS_ES, "IOCTL_ES_DIGETTICKETVIEW: this looks really wrong..."); WARN_LOG(IOS_ES, "IOCTL_ES_DIGETTICKETVIEW: this looks really wrong...");
break; return GetDefaultReply(IPC_SUCCESS);
}
case IOCTL_ES_GETOWNEDTITLECNT: IPCCommandResult ES::GetOwnedTitleCount(const IOCtlVRequest& request)
{
INFO_LOG(IOS_ES, "IOCTL_ES_GETOWNEDTITLECNT"); INFO_LOG(IOS_ES, "IOCTL_ES_GETOWNEDTITLECNT");
Memory::Write_U32(0, request.io_vectors[0].address); Memory::Write_U32(0, request.io_vectors[0].address);
break;
default:
request.DumpUnknown(GetDeviceName(), LogTypes::IOS);
}
return GetDefaultReply(IPC_SUCCESS); return GetDefaultReply(IPC_SUCCESS);
} }

View File

@ -151,6 +151,44 @@ private:
u8 padding[0x3c]; u8 padding[0x3c];
}; };
IPCCommandResult AddTicket(const IOCtlVRequest& request);
IPCCommandResult AddTitleStart(const IOCtlVRequest& request);
IPCCommandResult AddContentStart(const IOCtlVRequest& request);
IPCCommandResult AddContentData(const IOCtlVRequest& request);
IPCCommandResult AddContentFinish(const IOCtlVRequest& request);
IPCCommandResult AddTitleFinish(const IOCtlVRequest& request);
IPCCommandResult ESGetDeviceID(const IOCtlVRequest& request);
IPCCommandResult GetTitleContentsCount(const IOCtlVRequest& request);
IPCCommandResult GetTitleContents(const IOCtlVRequest& request);
IPCCommandResult OpenTitleContent(const IOCtlVRequest& request);
IPCCommandResult OpenContent(const IOCtlVRequest& request);
IPCCommandResult ReadContent(const IOCtlVRequest& request);
IPCCommandResult CloseContent(const IOCtlVRequest& request);
IPCCommandResult SeekContent(const IOCtlVRequest& request);
IPCCommandResult GetTitleDirectory(const IOCtlVRequest& request);
IPCCommandResult GetTitleID(const IOCtlVRequest& request);
IPCCommandResult SetUID(const IOCtlVRequest& request);
IPCCommandResult GetTitleCount(const IOCtlVRequest& request);
IPCCommandResult GetTitles(const IOCtlVRequest& request);
IPCCommandResult GetViewCount(const IOCtlVRequest& request);
IPCCommandResult GetViews(const IOCtlVRequest& request);
IPCCommandResult GetTMDViewCount(const IOCtlVRequest& request);
IPCCommandResult GetTMDViews(const IOCtlVRequest& request);
IPCCommandResult GetConsumption(const IOCtlVRequest& request);
IPCCommandResult DeleteTicket(const IOCtlVRequest& request);
IPCCommandResult DeleteTitleContent(const IOCtlVRequest& request);
IPCCommandResult GetStoredTMDSize(const IOCtlVRequest& request);
IPCCommandResult GetStoredTMD(const IOCtlVRequest& request);
IPCCommandResult Encrypt(const IOCtlVRequest& request);
IPCCommandResult Decrypt(const IOCtlVRequest& request);
IPCCommandResult Launch(const IOCtlVRequest& request);
IPCCommandResult CheckKoreaRegion(const IOCtlVRequest& request);
IPCCommandResult GetDeviceCertificate(const IOCtlVRequest& request);
IPCCommandResult Sign(const IOCtlVRequest& request);
IPCCommandResult GetBoot2Version(const IOCtlVRequest& request);
IPCCommandResult DIGetTicketView(const IOCtlVRequest& request);
IPCCommandResult GetOwnedTitleCount(const IOCtlVRequest& request);
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);