Bug Summary

File:Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp
Location:line 561, column 8
Description:Value stored to 'MaxCount' during its initialization is never read

Annotated Source Code

1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5
6
7// =======================================================
8// File description
9// -------------
10/* Here we handle /dev/es requests. We have cases for these functions, the exact
11 DevKitPro/libogc name is in parenthesis:
12
13 0x20 GetTitleID (ES_GetTitleID) (Input: none, Output: 8 bytes)
14 0x1d GetDataDir (ES_GetDataDir) (Input: 8 bytes, Output: 30 bytes)
15
16 0x1b DiGetTicketView (Input: none, Output: 216 bytes)
17 0x16 GetConsumption (Input: 8 bytes, Output: 0 bytes, 4 bytes) // there are two output buffers
18
19 0x12 GetNumTicketViews (ES_GetNumTicketViews) (Input: 8 bytes, Output: 4 bytes)
20 0x14 GetTMDViewSize (ES_GetTMDViewSize) (Input: ?, Output: ?) // I don't get this anymore,
21 it used to come after 0x12
22
23 but only the first two are correctly supported. For the other four we ignore any potential
24 input and only write zero to the out buffer. However, most games only use first two,
25 but some Nintendo developed games use the other ones to:
26
27 0x1b: Mario Galaxy, Mario Kart, SSBB
28 0x16: Mario Galaxy, Mario Kart, SSBB
29 0x12: Mario Kart
30 0x14: Mario Kart: But only if we don't return a zeroed out buffer for the 0x12 question,
31 and instead answer for example 1 will this question appear.
32
33*/
34// =============
35
36#include "WII_IPC_HLE_Device_es.h"
37
38#include "../PowerPC/PowerPC.h"
39#include "../VolumeHandler.h"
40#include "FileUtil.h"
41#include "Crypto/aes.h"
42
43#include "../Boot/Boot_DOL.h"
44#include "NandPaths.h"
45#include "CommonPaths.h"
46#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
47#include "../Movie.h"
48#include "StringUtil.h"
49
50#ifdef _WIN32
51#include <Windows.h>
52#endif
53
54std::string CWII_IPC_HLE_Device_es::m_ContentFile;
55
56CWII_IPC_HLE_Device_es::CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName)
57 : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
58 , m_pContentLoader(NULL__null)
59 , m_TitleID(-1)
60 , AccessIdentID(0x6000000)
61{}
62
63CWII_IPC_HLE_Device_es::~CWII_IPC_HLE_Device_es()
64{}
65
66void CWII_IPC_HLE_Device_es::LoadWAD(const std::string& _rContentFile)
67{
68 m_ContentFile = _rContentFile;
69}
70
71bool CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode)
72{
73 m_pContentLoader = &DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile);
74
75 // check for cd ...
76 if (m_pContentLoader->IsValid())
77 {
78 m_TitleID = m_pContentLoader->GetTitleID();
79
80 m_TitleIDs.clear();
81 DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDs);
82 // uncomment if ES_GetOwnedTitlesCount / ES_GetOwnedTitles is implemented
83 // m_TitleIDsOwned.clear();
84 // DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDsOwned, true);
85 }
86 else if (VolumeHandler::IsValid())
87 {
88 // blindly grab the titleID from the disc - it's unencrypted at:
89 // offset 0x0F8001DC and 0x0F80044C
90 VolumeHandler::GetVolume()->GetTitleID((u8*)&m_TitleID);
91 m_TitleID = Common::swap64(m_TitleID);
92 }
93 else
94 {
95 m_TitleID = ((u64)0x00010000 << 32) | 0xF00DBEEF;
96 }
97
98 INFO_LOG(WII_IPC_ES, "Set default title to %08x/%08x", (u32)(m_TitleID>>32), (u32)m_TitleID)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 98, "Set default title to %08x/%08x", (u32)(m_TitleID>>
32), (u32)m_TitleID); } } while (0)
;
99
100 Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
101 if (m_Active)
102 INFO_LOG(WII_IPC_ES, "Device was re-opened.")do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 102, "Device was re-opened."); } } while (0)
;
103 m_Active = true;
104 return true;
105}
106
107bool CWII_IPC_HLE_Device_es::Close(u32 _CommandAddress, bool _bForce)
108{
109 // Leave deletion of the INANDContentLoader objects to CNANDContentManager, don't do it here!
110 m_NANDContent.clear();
111 m_ContentAccessMap.clear();
112 m_pContentLoader = NULL__null;
113 m_TitleIDs.clear();
114 m_TitleID = -1;
115 AccessIdentID = 0x6000000;
116
117 INFO_LOG(WII_IPC_ES, "ES: Close")do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 117, "ES: Close"); } } while (0)
;
118 if (!_bForce)
119 Memory::Write_U32(0, _CommandAddress + 4);
120 m_Active = false;
121 return true;
122}
123
124bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
125{
126 SIOCtlVBuffer Buffer(_CommandAddress);
127
128 DEBUG_LOG(WII_IPC_ES, "%s (0x%x)", GetDeviceName().c_str(), Buffer.Parameter)do { { if (LogTypes::LDEBUG <= 3) GenericLog(LogTypes::LDEBUG
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 128, "%s (0x%x)", GetDeviceName().c_str(), Buffer.Parameter
); } } while (0)
;
129
130 // Prepare the out buffer(s) with zeroes as a safety precaution
131 // to avoid returning bad values
132 for (u32 i = 0; i < Buffer.NumberPayloadBuffer; i++)
133 {
134 Memory::Memset(Buffer.PayloadBuffer[i].m_Address, 0,
135 Buffer.PayloadBuffer[i].m_Size);
136 }
137
138 // Uhh just put this here for now
139 u8 keyTable[11][16] = {
140 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // ECC Private Key
141 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // Console ID
142 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // NAND AES Key
143 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // NAND HMAC
144 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // Common Key
145 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // PRNG seed
146 {0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08, 0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d,}, // SD Key
147 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // Unknown
148 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // Unknown
149 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // Unknown
150 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // Unknown
151 };
152
153 switch (Buffer.Parameter)
154 {
155 case IOCTL_ES_GETDEVICEID:
156 {
157 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETDEVICEID no out buffer"){};
158
159 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETDEVICEID")do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 159, "IOCTL_ES_GETDEVICEID"); } } while (0)
;
160 // Return arbitrary device ID - TODO allow user to set value?
161 Memory::Write_U32(0x31337f11, Buffer.PayloadBuffer[0].m_Address);
162 Memory::Write_U32(0, _CommandAddress + 0x4);
163 return true;
164 }
165 break;
166
167 case IOCTL_ES_GETTITLECONTENTSCNT:
168 {
169 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1){};
170 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1){};
171
172 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
173
174 const DiscIO::INANDContentLoader& rNANDContent = AccessContentDevice(TitleID);
175 u16 NumberOfPrivateContent = 0;
176 if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check
177 {
178 NumberOfPrivateContent = rNANDContent.GetNumEntries();
179
180 if ((u32)(TitleID>>32) == 0x00010000)
181 Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address);
182 else
183 Memory::Write_U32(NumberOfPrivateContent, Buffer.PayloadBuffer[0].m_Address);
184
185 Memory::Write_U32(0, _CommandAddress + 0x4);
186 }
187 else
188 Memory::Write_U32((u32)rNANDContent.GetContentSize(), _CommandAddress + 0x4);
189
190 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i",do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 191, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i"
, (u32)(TitleID>>32), (u32)TitleID, rNANDContent.IsValid
() ? NumberOfPrivateContent : (u32)rNANDContent.GetContentSize
()); } } while (0)
191 (u32)(TitleID>>32), (u32)TitleID, rNANDContent.IsValid() ? NumberOfPrivateContent : (u32)rNANDContent.GetContentSize())do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 191, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i"
, (u32)(TitleID>>32), (u32)TitleID, rNANDContent.IsValid
() ? NumberOfPrivateContent : (u32)rNANDContent.GetContentSize
()); } } while (0)
;
192
193 return true;
194 }
195 break;
196
197 case IOCTL_ES_GETTITLECONTENTS:
198 {
199 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETTITLECONTENTS bad in buffer"){};
200 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLECONTENTS bad out buffer"){};
201
202 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
203
204 const DiscIO::INANDContentLoader& rNANDCOntent = AccessContentDevice(TitleID);
205 if (rNANDCOntent.IsValid()) // Not sure if dolphin will ever fail this check
206 {
207 for (u16 i = 0; i < rNANDCOntent.GetNumEntries(); i++)
208 {
209 Memory::Write_U32(rNANDCOntent.GetContentByIndex(i)->m_ContentID, Buffer.PayloadBuffer[0].m_Address + i*4);
210 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", i, rNANDCOntent.GetContentByIndex(i)->m_ContentID)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 210, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", i, rNANDCOntent
.GetContentByIndex(i)->m_ContentID); } } while (0)
;
211 }
212 Memory::Write_U32(0, _CommandAddress + 0x4);
213 }
214 else
215 {
216 Memory::Write_U32((u32)rNANDCOntent.GetContentSize(), _CommandAddress + 0x4);
217 INFO_LOG(WII_IPC_ES,do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 221, "IOCTL_ES_GETTITLECONTENTS: " "Unable to open content %lu"
, (unsigned long)rNANDCOntent. GetContentSize()); } } while (
0)
218 "IOCTL_ES_GETTITLECONTENTS: "do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 221, "IOCTL_ES_GETTITLECONTENTS: " "Unable to open content %lu"
, (unsigned long)rNANDCOntent. GetContentSize()); } } while (
0)
219 "Unable to open content %lu",do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 221, "IOCTL_ES_GETTITLECONTENTS: " "Unable to open content %lu"
, (unsigned long)rNANDCOntent. GetContentSize()); } } while (
0)
220 (unsigned long)rNANDCOntent.\do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 221, "IOCTL_ES_GETTITLECONTENTS: " "Unable to open content %lu"
, (unsigned long)rNANDCOntent. GetContentSize()); } } while (
0)
221 GetContentSize())do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 221, "IOCTL_ES_GETTITLECONTENTS: " "Unable to open content %lu"
, (unsigned long)rNANDCOntent. GetContentSize()); } } while (
0)
;
222 }
223
224 return true;
225 }
226 break;
227
228
229 case IOCTL_ES_OPENTITLECONTENT:
230 {
231 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 3){};
232 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0){};
233
234 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
235 u32 Index = Memory::Read_U32(Buffer.InBuffer[2].m_Address);
236
237 u32 CFD = AccessIdentID++;
238 m_ContentAccessMap[CFD].m_Position = 0;
239 m_ContentAccessMap[CFD].m_pContent = AccessContentDevice(TitleID).GetContentByIndex(Index);
240 _dbg_assert_msg_(WII_IPC_ES, m_ContentAccessMap[CFD].m_pContent != NULL, "No Content for TitleID: %08x/%08x at Index %x", (u32)(TitleID>>32), (u32)TitleID, Index){};
241 // Fix for DLC by itsnotmailmail
242 if (m_ContentAccessMap[CFD].m_pContent == NULL__null)
243 CFD = 0xffffffff; //TODO: what is the correct error value here?
244 Memory::Write_U32(CFD, _CommandAddress + 0x4);
245
246 INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENTITLECONTENT: TitleID: %08x/%08x Index %i -> got CFD %x", (u32)(TitleID>>32), (u32)TitleID, Index, CFD)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 246, "IOCTL_ES_OPENTITLECONTENT: TitleID: %08x/%08x Index %i -> got CFD %x"
, (u32)(TitleID>>32), (u32)TitleID, Index, CFD); } } while
(0)
;
247 return true;
248 }
249 break;
250
251 case IOCTL_ES_OPENCONTENT:
252 {
253 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1){};
254 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0){};
255
256 u32 CFD = AccessIdentID++;
257 u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
258
259 m_ContentAccessMap[CFD].m_Position = 0;
260 m_ContentAccessMap[CFD].m_pContent = AccessContentDevice(m_TitleID).GetContentByIndex(Index);
261
262 if (m_ContentAccessMap[CFD].m_pContent == NULL__null)
263 CFD = 0xffffffff; //TODO: what is the correct error value here?
264
265 Memory::Write_U32(CFD, _CommandAddress + 0x4);
266
267 INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 267, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index
, CFD); } } while (0)
;
268 return true;
269 }
270 break;
271
272 case IOCTL_ES_READCONTENT:
273 {
274 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1){};
275 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1){};
276
277 u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
278 u32 Size = Buffer.PayloadBuffer[0].m_Size;
279 u32 Addr = Buffer.PayloadBuffer[0].m_Address;
280
281 _dbg_assert_(WII_IPC_ES, m_ContentAccessMap.find(CFD) != m_ContentAccessMap.end()){};
282 SContentAccess& rContent = m_ContentAccessMap[CFD];
283
284 _dbg_assert_(WII_IPC_ES, rContent.m_pContent->m_pData != NULL){};
285
286 u8* pSrc = &rContent.m_pContent->m_pData[rContent.m_Position];
287 u8* pDest = Memory::GetPointer(Addr);
288
289 if (rContent.m_Position + Size > rContent.m_pContent->m_Size)
290 {
291 Size = rContent.m_pContent->m_Size-rContent.m_Position;
292 }
293
294 if (Size > 0)
295 {
296 if (pDest) {
297 memcpy(pDest, pSrc, Size);
298 rContent.m_Position += Size;
299 } else {
300 PanicAlertT("IOCTL_ES_READCONTENT - bad destination")MsgAlert(false, WARNING, "IOCTL_ES_READCONTENT - bad destination"
)
;
301 }
302 }
303
304 INFO_LOG(WII_IPC_ES, "IOCTL_ES_READCONTENT: CFD %x, Address 0x%x, Size %i -> stream pos %i (Index %i)", CFD, Addr, Size, rContent.m_Position, rContent.m_pContent->m_Index)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 304, "IOCTL_ES_READCONTENT: CFD %x, Address 0x%x, Size %i -> stream pos %i (Index %i)"
, CFD, Addr, Size, rContent.m_Position, rContent.m_pContent->
m_Index); } } while (0)
;
305
306 Memory::Write_U32(Size, _CommandAddress + 0x4);
307 return true;
308 }
309 break;
310
311 case IOCTL_ES_CLOSECONTENT:
312 {
313 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1){};
314 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0){};
315
316 u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
317
318 CContentAccessMap::iterator itr = m_ContentAccessMap.find(CFD);
319 m_ContentAccessMap.erase(itr);
320
321 INFO_LOG(WII_IPC_ES, "IOCTL_ES_CLOSECONTENT: CFD %x", CFD)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 321, "IOCTL_ES_CLOSECONTENT: CFD %x", CFD); } } while (0)
;
322
323 Memory::Write_U32(0, _CommandAddress + 0x4);
324 return true;
325 }
326 break;
327
328 case IOCTL_ES_SEEKCONTENT:
329 {
330 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 3){};
331 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0){};
332
333 u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
334 u32 Addr = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
335 u32 Mode = Memory::Read_U32(Buffer.InBuffer[2].m_Address);
336
337 _dbg_assert_(WII_IPC_ES, m_ContentAccessMap.find(CFD) != m_ContentAccessMap.end()){};
338 SContentAccess& rContent = m_ContentAccessMap[CFD];
339
340 switch (Mode)
341 {
342 case 0: // SET
343 rContent.m_Position = Addr;
344 break;
345
346 case 1: // CUR
347 rContent.m_Position += Addr;
348 break;
349
350 case 2: // END
351 rContent.m_Position = rContent.m_pContent->m_Size + Addr;
352 break;
353 }
354
355 INFO_LOG(WII_IPC_ES, "IOCTL_ES_SEEKCONTENT: CFD %x, Address 0x%x, Mode %i -> Pos %i", CFD, Addr, Mode, rContent.m_Position)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 355, "IOCTL_ES_SEEKCONTENT: CFD %x, Address 0x%x, Mode %i -> Pos %i"
, CFD, Addr, Mode, rContent.m_Position); } } while (0)
;
356
357 Memory::Write_U32(rContent.m_Position, _CommandAddress + 0x4);
358 return true;
359 }
360 break;
361
362 case IOCTL_ES_GETTITLEDIR:
363 {
364 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1){};
365 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1){};
366
367 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
368
369 char* Path = (char*)Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
370 sprintf(Path, "/title/%08x/%08x/data", (u32)(TitleID >> 32), (u32)TitleID);
371
372 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLEDIR: %s", Path)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 372, "IOCTL_ES_GETTITLEDIR: %s", Path); } } while (0)
;
373 }
374 break;
375
376 case IOCTL_ES_GETTITLEID:
377 {
378 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 0){};
379 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLEID no out buffer"){};
380
381 Memory::Write_U64(m_TitleID, Buffer.PayloadBuffer[0].m_Address);
382 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLEID: %08x/%08x", (u32)(m_TitleID>>32), (u32)m_TitleID)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 382, "IOCTL_ES_GETTITLEID: %08x/%08x", (u32)(m_TitleID>>
32), (u32)m_TitleID); } } while (0)
;
383 }
384 break;
385
386 case IOCTL_ES_SETUID:
387 {
388 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_SETUID no in buffer"){};
389 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0){};
390 // TODO: fs permissions based on this
391 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
392 INFO_LOG(WII_IPC_ES, "IOCTL_ES_SETUID titleID: %08x/%08x", (u32)(TitleID>>32), (u32)TitleID)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 392, "IOCTL_ES_SETUID titleID: %08x/%08x", (u32)(TitleID>>
32), (u32)TitleID); } } while (0)
;
393 }
394 break;
395
396 case IOCTL_ES_GETTITLECNT:
397 {
398 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 0, "IOCTL_ES_GETTITLECNT has an in buffer"){};
399 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLECNT has no out buffer"){};
400 _dbg_assert_msg_(WII_IPC_ES, Buffer.PayloadBuffer[0].m_Size == 4, "IOCTL_ES_GETTITLECNT payload[0].size != 4"){};
401
402 Memory::Write_U32((u32)m_TitleIDs.size(), Buffer.PayloadBuffer[0].m_Address);
403
404 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECNT: Number of Titles %lu",do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 405, "IOCTL_ES_GETTITLECNT: Number of Titles %lu", (unsigned
long)m_TitleIDs.size()); } } while (0)
405 (unsigned long)m_TitleIDs.size())do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 405, "IOCTL_ES_GETTITLECNT: Number of Titles %lu", (unsigned
long)m_TitleIDs.size()); } } while (0)
;
406
407 Memory::Write_U32(0, _CommandAddress + 0x4);
408
409 return true;
410 }
411 break;
412
413
414 case IOCTL_ES_GETTITLES:
415 {
416 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETTITLES has an in buffer"){};
417 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLES has no out buffer"){};
418
419 u32 MaxCount = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
420 u32 Count = 0;
421 for (int i = 0; i < (int)m_TitleIDs.size(); i++)
422 {
423 Memory::Write_U64(m_TitleIDs[i], Buffer.PayloadBuffer[0].m_Address + i*8);
424 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLES: %08x/%08x", (u32)(m_TitleIDs[i] >> 32), (u32)m_TitleIDs[i])do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 424, "IOCTL_ES_GETTITLES: %08x/%08x", (u32)(m_TitleIDs[i] >>
32), (u32)m_TitleIDs[i]); } } while (0)
;
425 Count++;
426 if (Count >= MaxCount)
427 break;
428 }
429
430 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLES: Number of titles returned %i", Count)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 430, "IOCTL_ES_GETTITLES: Number of titles returned %i", Count
); } } while (0)
;
431 Memory::Write_U32(0, _CommandAddress + 0x4);
432 return true;
433 }
434 break;
435
436
437 case IOCTL_ES_GETVIEWCNT:
438 {
439 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETVIEWCNT no in buffer"){};
440 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETVIEWCNT no out buffer"){};
441
442 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
443
444 u32 retVal = 0;
445 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
446 u32 ViewCount = Loader.GetTIKSize() / DiscIO::INANDContentLoader::TICKET_SIZE;
447
448 if (!ViewCount)
449 {
450 std::string TicketFilename = Common::GetTicketFileName(TitleID);
451 if (File::Exists(TicketFilename))
452 {
453 u32 FileSize = (u32)File::GetSize(TicketFilename);
454 _dbg_assert_msg_(WII_IPC_ES, (FileSize % DiscIO::INANDContentLoader::TICKET_SIZE) == 0, "IOCTL_ES_GETVIEWCNT ticket file size seems to be wrong"){};
455
456 ViewCount = FileSize / DiscIO::INANDContentLoader::TICKET_SIZE;
457 _dbg_assert_msg_(WII_IPC_ES, (ViewCount>0) && (ViewCount<=4), "IOCTL_ES_GETVIEWCNT ticket count seems to be wrong"){};
458 }
459 else
460 {
461 if (TitleID == TITLEID_SYSMENU0x0000000100000002ull)
462 {
463 PanicAlertT("There must be a ticket for 00000001/00000002. Your NAND dump is probably incomplete.")MsgAlert(false, WARNING, "There must be a ticket for 00000001/00000002. Your NAND dump is probably incomplete."
)
;
464 }
465 ViewCount = 0;
466 //retVal = ES_NO_TICKET_INSTALLED;
467 }
468 }
469
470 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETVIEWCNT for titleID: %08x/%08x (View Count = %i)", (u32)(TitleID>>32), (u32)TitleID, ViewCount)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 470, "IOCTL_ES_GETVIEWCNT for titleID: %08x/%08x (View Count = %i)"
, (u32)(TitleID>>32), (u32)TitleID, ViewCount); } } while
(0)
;
471
472 Memory::Write_U32(ViewCount, Buffer.PayloadBuffer[0].m_Address);
473 Memory::Write_U32(retVal, _CommandAddress + 0x4);
474 return true;
475 }
476 break;
477
478 case IOCTL_ES_GETVIEWS:
479 {
480 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETVIEWS no in buffer"){};
481 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETVIEWS no out buffer"){};
482
483 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
484 u32 maxViews = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
485 u32 retVal = 0;
486
487 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
488
489 const u8 *Ticket = Loader.GetTIK();
490 if (Ticket)
491 {
492 u32 viewCnt = Loader.GetTIKSize() / DiscIO::INANDContentLoader::TICKET_SIZE;
493 for (unsigned int View = 0; View != maxViews && View < viewCnt; ++View)
494 {
495 Memory::Write_U32(View, Buffer.PayloadBuffer[0].m_Address + View * 0xD8);
496 Memory::WriteBigEData(Ticket + 0x1D0 + (View * DiscIO::INANDContentLoader::TICKET_SIZE),
497 Buffer.PayloadBuffer[0].m_Address + 4 + View * 0xD8, 212);
498 }
499 }
500 else
501 {
502 std::string TicketFilename = Common::GetTicketFileName(TitleID);
503 if (File::Exists(TicketFilename))
504 {
505 File::IOFile pFile(TicketFilename, "rb");
506 if (pFile)
507 {
508 u8 FileTicket[DiscIO::INANDContentLoader::TICKET_SIZE];
509 for (unsigned int View = 0; View != maxViews && pFile.ReadBytes(FileTicket, DiscIO::INANDContentLoader::TICKET_SIZE); ++View)
510 {
511 Memory::Write_U32(View, Buffer.PayloadBuffer[0].m_Address + View * 0xD8);
512 Memory::WriteBigEData(FileTicket+0x1D0, Buffer.PayloadBuffer[0].m_Address + 4 + View * 0xD8, 212);
513 }
514 }
515 }
516 else
517 {
518 //retVal = ES_NO_TICKET_INSTALLED;
519 PanicAlertT("IOCTL_ES_GETVIEWS: Tried to get data from an unknown ticket: %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID)MsgAlert(false, WARNING, "IOCTL_ES_GETVIEWS: Tried to get data from an unknown ticket: %08x/%08x"
, (u32)(TitleID >> 32), (u32)TitleID)
;
520 }
521 }
522 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETVIEWS for titleID: %08x/%08x (MaxViews = %i)", (u32)(TitleID >> 32), (u32)TitleID, maxViews)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 522, "IOCTL_ES_GETVIEWS for titleID: %08x/%08x (MaxViews = %i)"
, (u32)(TitleID >> 32), (u32)TitleID, maxViews); } } while
(0)
;
523
524 Memory::Write_U32(retVal, _CommandAddress + 0x4);
525 return true;
526 }
527 break;
528
529 case IOCTL_ES_GETTMDVIEWCNT:
530 {
531 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no in buffer"){};
532 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no out buffer"){};
533
534 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
535
536 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
537
538 u32 TMDViewCnt = 0;
539 if (Loader.IsValid())
540 {
541 TMDViewCnt += DiscIO::INANDContentLoader::TMD_VIEW_SIZE;
542 TMDViewCnt += 2; // title version
543 TMDViewCnt += 2; // num entries
544 TMDViewCnt += (u32)Loader.GetContentSize() * (4+2+2+8); // content id, index, type, size
545 }
546 Memory::Write_U32(TMDViewCnt, Buffer.PayloadBuffer[0].m_Address);
547
548 Memory::Write_U32(0, _CommandAddress + 0x4);
549
550 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x (view size %i)", (u32)(TitleID >> 32), (u32)TitleID, TMDViewCnt)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 550, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x (view size %i)"
, (u32)(TitleID >> 32), (u32)TitleID, TMDViewCnt); } } while
(0)
;
551 return true;
552 }
553 break;
554
555 case IOCTL_ES_GETTMDVIEWS:
556 {
557 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETTMDVIEWCNT no in buffer"){};
558 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no out buffer"){};
559
560 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
561 u32 MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
Value stored to 'MaxCount' during its initialization is never read
562
563 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
564
565 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x buffer size: %i", (u32)(TitleID >> 32), (u32)TitleID, MaxCount)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 565, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x buffer size: %i"
, (u32)(TitleID >> 32), (u32)TitleID, MaxCount); } } while
(0)
;
566
567 if (Loader.IsValid())
568 {
569 u32 Address = Buffer.PayloadBuffer[0].m_Address;
570
571 Memory::WriteBigEData(Loader.GetTMDView(), Address, DiscIO::INANDContentLoader::TMD_VIEW_SIZE);
572 Address += DiscIO::INANDContentLoader::TMD_VIEW_SIZE;
573
574 Memory::Write_U16(Loader.GetTitleVersion(), Address); Address += 2;
575 Memory::Write_U16(Loader.GetNumEntries(), Address); Address += 2;
576
577 const std::vector<DiscIO::SNANDContent>& rContent = Loader.GetContent();
578 for (size_t i=0; i<Loader.GetContentSize(); i++)
579 {
580 Memory::Write_U32(rContent[i].m_ContentID, Address); Address += 4;
581 Memory::Write_U16(rContent[i].m_Index, Address); Address += 2;
582 Memory::Write_U16(rContent[i].m_Type, Address); Address += 2;
583 Memory::Write_U64(rContent[i].m_Size, Address); Address += 8;
584 }
585
586 _dbg_assert_(WII_IPC_ES, (Address-Buffer.PayloadBuffer[0].m_Address) == Buffer.PayloadBuffer[0].m_Size){};
587 }
588 Memory::Write_U32(0, _CommandAddress + 0x4);
589
590 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTMDVIEWS: title: %08x/%08x (buffer size: %i)", (u32)(TitleID >> 32), (u32)TitleID, MaxCount)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 590, "IOCTL_ES_GETTMDVIEWS: title: %08x/%08x (buffer size: %i)"
, (u32)(TitleID >> 32), (u32)TitleID, MaxCount); } } while
(0)
;
591 return true;
592 }
593 break;
594
595 case IOCTL_ES_GETCONSUMPTION: // This is at least what crediar's ES module does
596 Memory::Write_U32(0, Buffer.PayloadBuffer[1].m_Address);
597 Memory::Write_U32(0, _CommandAddress + 0x4);
598 WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETCONSUMPTION:%d", Memory::Read_U32(_CommandAddress+4))do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 598, "IOCTL_ES_GETCONSUMPTION:%d", Memory::Read_U32(_CommandAddress
+4)); } } while (0)
;
599 return true;
600
601 case IOCTL_ES_DELETETICKET:
602 {
603 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
604 INFO_LOG(WII_IPC_ES, "IOCTL_ES_DELETETICKET: title: %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 604, "IOCTL_ES_DELETETICKET: title: %08x/%08x", (u32)(TitleID
>> 32), (u32)TitleID); } } while (0)
;
605 if (File::Delete(Common::GetTicketFileName(TitleID)))
606 {
607 Memory::Write_U32(0, _CommandAddress + 0x4);
608 }
609 else
610 {
611 // Presumably return -1017 when delete fails
612 Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT, _CommandAddress + 0x4);
613 }
614 }
615 break;
616 case IOCTL_ES_DELETETITLECONTENT:
617 {
618 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
619 INFO_LOG(WII_IPC_ES, "IOCTL_ES_DELETETITLECONTENT: title: %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 619, "IOCTL_ES_DELETETITLECONTENT: title: %08x/%08x", (u32)
(TitleID >> 32), (u32)TitleID); } } while (0)
;
620 if (DiscIO::CNANDContentManager::Access().RemoveTitle(TitleID))
621 {
622 Memory::Write_U32(0, _CommandAddress + 0x4);
623 }
624 else
625 {
626 // Presumably return -1017 when title not installed TODO verify
627 Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT, _CommandAddress + 0x4);
628 }
629
630 }
631 case IOCTL_ES_GETSTOREDTMDSIZE:
632 {
633 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETSTOREDTMDSIZE no in buffer"){};
634 // _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_ES_GETSTOREDTMDSIZE no out buffer");
635
636 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
637 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
638
639 _dbg_assert_(WII_IPC_ES, Loader.IsValid()){};
640 u32 TMDCnt = 0;
641 if (Loader.IsValid())
642 {
643 TMDCnt += DiscIO::INANDContentLoader::TMD_HEADER_SIZE;
644 TMDCnt += (u32)Loader.GetContentSize() * DiscIO::INANDContentLoader::CONTENT_HEADER_SIZE;
645 }
646 if(Buffer.NumberPayloadBuffer)
647 Memory::Write_U32(TMDCnt, Buffer.PayloadBuffer[0].m_Address);
648
649 Memory::Write_U32(0, _CommandAddress + 0x4);
650
651 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMDSIZE: title: %08x/%08x (view size %i)", (u32)(TitleID >> 32), (u32)TitleID, TMDCnt)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 651, "IOCTL_ES_GETSTOREDTMDSIZE: title: %08x/%08x (view size %i)"
, (u32)(TitleID >> 32), (u32)TitleID, TMDCnt); } } while
(0)
;
652 return true;
653 }
654 break;
655 case IOCTL_ES_GETSTOREDTMD:
656 {
657 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer > 0, "IOCTL_ES_GETSTOREDTMD no in buffer"){};
658 // requires 1 inbuffer and no outbuffer, presumably outbuffer required when second inbuffer is used for maxcount (allocated mem?)
659 // called with 1 inbuffer after deleting a titleid
660 //_dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETSTOREDTMD no out buffer");
661
662 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
663 u32 MaxCount = 0;
664 if (Buffer.NumberInBuffer > 1)
665 {
666 // TODO: actually use this param in when writing to the outbuffer :/
667 MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
668 }
669 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
670
671
672 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x buffer size: %i", (u32)(TitleID >> 32), (u32)TitleID, MaxCount)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 672, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x buffer size: %i"
, (u32)(TitleID >> 32), (u32)TitleID, MaxCount); } } while
(0)
;
673
674 if (Loader.IsValid() && Buffer.NumberPayloadBuffer)
675 {
676 u32 Address = Buffer.PayloadBuffer[0].m_Address;
677
678 Memory::WriteBigEData(Loader.GetTMDHeader(), Address, DiscIO::INANDContentLoader::TMD_HEADER_SIZE);
679 Address += DiscIO::INANDContentLoader::TMD_HEADER_SIZE;
680
681 const std::vector<DiscIO::SNANDContent>& rContent = Loader.GetContent();
682 for (size_t i=0; i<Loader.GetContentSize(); i++)
683 {
684 Memory::WriteBigEData(rContent[i].m_Header, Address, DiscIO::INANDContentLoader::CONTENT_HEADER_SIZE);
685 Address += DiscIO::INANDContentLoader::CONTENT_HEADER_SIZE;
686 }
687
688 _dbg_assert_(WII_IPC_ES, (Address-Buffer.PayloadBuffer[0].m_Address) == Buffer.PayloadBuffer[0].m_Size){};
689 }
690 Memory::Write_U32(0, _CommandAddress + 0x4);
691
692 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x (buffer size: %i)", (u32)(TitleID >> 32), (u32)TitleID, MaxCount)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 692, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x (buffer size: %i)"
, (u32)(TitleID >> 32), (u32)TitleID, MaxCount); } } while
(0)
;
693 return true;
694 }
695 break;
696
697 case IOCTL_ES_ENCRYPT:
698 {
699 u32 keyIndex = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
700 u8* IV = Memory::GetPointer(Buffer.InBuffer[1].m_Address);
701 u8* source = Memory::GetPointer(Buffer.InBuffer[2].m_Address);
702 u32 size = Buffer.InBuffer[2].m_Size;
703 u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address);
704
705 AES_KEY AESKey;
706 AES_set_encrypt_key(keyTable[keyIndex], 128, &AESKey);
707 AES_cbc_encrypt(source, destination, size, &AESKey, IV, AES_ENCRYPT1);
708
709 _dbg_assert_msg_(WII_IPC_ES, keyIndex == 6, "IOCTL_ES_ENCRYPT: Key type is not SD, data will be crap"){};
710 }
711 break;
712
713 case IOCTL_ES_DECRYPT:
714 {
715 u32 keyIndex = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
716 u8* IV = Memory::GetPointer(Buffer.InBuffer[1].m_Address);
717 u8* source = Memory::GetPointer(Buffer.InBuffer[2].m_Address);
718 u32 size = Buffer.InBuffer[2].m_Size;
719 u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address);
720
721 AES_KEY AESKey;
722 AES_set_decrypt_key(keyTable[keyIndex], 128, &AESKey);
723 AES_cbc_encrypt(source, destination, size, &AESKey, IV, AES_DECRYPT0);
724
725 _dbg_assert_msg_(WII_IPC_ES, keyIndex == 6, "IOCTL_ES_DECRYPT: Key type is not SD, data will be crap"){};
726 }
727 break;
728
729
730 case IOCTL_ES_LAUNCH:
731 {
732 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 2){};
733 bool bSuccess = false;
734 u16 IOSv = 0xffff;
735
736 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
737 u32 view = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
738 u64 ticketid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+4);
739 u32 devicetype = Memory::Read_U32(Buffer.InBuffer[1].m_Address+12);
740 u64 titleid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+16);
741 u16 access = Memory::Read_U16(Buffer.InBuffer[1].m_Address+24);
742
743
744 if ((u32)(TitleID>>32) != 0x00000001 || TitleID == TITLEID_SYSMENU0x0000000100000002ull)
745 {
746 const DiscIO::INANDContentLoader& ContentLoader = AccessContentDevice(TitleID);
747 if (ContentLoader.IsValid())
748 {
749 u32 bootInd = ContentLoader.GetBootIndex();
750 const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(bootInd);
751 if (pContent)
752 {
753 LoadWAD(Common::GetTitleContentPath(TitleID));
754 CDolLoader DolLoader(pContent->m_pData, pContent->m_Size);
755 DolLoader.Load(); // TODO: Check why sysmenu does not load the DOL correctly
756 PCPowerPC::ppcState.pc = DolLoader.GetEntryPoint() | 0x80000000;
757 IOSv = ContentLoader.GetIosVersion();
758 bSuccess = true;
759
760 }
761 }
762 }
763 else // IOS, MIOS, BC etc
764 {
765 //TODO: fixme
766 // The following is obviously a hack
767 // Lie to mem about loading a different IOS
768 // someone with an affected game should test
769 IOSv = TitleID & 0xffff;
770 }
771 if (!bSuccess && IOSv >= 30 && IOSv != 0xffff)
772 {
773 PanicAlertT("IOCTL_ES_LAUNCH: Game tried to reload an IOS or a title that is not available in your NAND dump\n"MsgAlert(false, WARNING, "IOCTL_ES_LAUNCH: Game tried to reload an IOS or a title that is not available in your NAND dump\n"
"TitleID %016llx.\n Dolphin will likely hang now.", TitleID)
774 "TitleID %016llx.\n Dolphin will likely hang now.", TitleID)MsgAlert(false, WARNING, "IOCTL_ES_LAUNCH: Game tried to reload an IOS or a title that is not available in your NAND dump\n"
"TitleID %016llx.\n Dolphin will likely hang now.", TitleID)
;
775 }
776 else
777 {
778 CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer();
779 size_t size = s_Usb->m_WiiMotes.size();
780 bool* wiiMoteConnected = new bool[size];
781 for (unsigned int i = 0; i < size; i++)
782 wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected();
783
784 std::string tContentFile(m_ContentFile.c_str());
785
786 WII_IPC_HLE_Interface::Reset(true);
787 WII_IPC_HLE_Interface::Init();
788 s_Usb = GetUsbPointer();
789 for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++)
790 {
791 if (wiiMoteConnected[i])
792 {
793 s_Usb->m_WiiMotes[i].Activate(false);
794 s_Usb->m_WiiMotes[i].Activate(true);
795 }
796 else
797 {
798 s_Usb->m_WiiMotes[i].Activate(false);
799 }
800 }
801
802 delete[] wiiMoteConnected;
803 WII_IPC_HLE_Interface::SetDefaultContentFile(tContentFile);
804 }
805 // Pass the "#002 check"
806 // Apploader should write the IOS version and revision to 0x3140, and compare it
807 // to 0x3188 to pass the check, but we don't do it, and i don't know where to read the IOS rev...
808 // Currently we just write 0xFFFF for the revision, copy manually and it works fine :p
809 // TODO : figure it correctly : where should we read the IOS rev that the wad "needs" ?
810 Memory::Write_U16(IOSv, 0x00003140);
811 Memory::Write_U16(0xFFFF, 0x00003142);
812 Memory::Write_U32(Memory::Read_U32(0x00003140), 0x00003188);
813
814 //TODO: provide correct return code when bSuccess= false
815 Memory::Write_U32(0, _CommandAddress + 0x4);
816
817 ERROR_LOG(WII_IPC_ES, "IOCTL_ES_LAUNCH %016llx %08x %016llx %08x %016llx %04x", TitleID,view,ticketid,devicetype,titleid,access)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 817, "IOCTL_ES_LAUNCH %016llx %08x %016llx %08x %016llx %04x"
, TitleID,view,ticketid,devicetype,titleid,access); } } while
(0)
;
818 // IOCTL_ES_LAUNCH 0001000248414341 00000001 0001c0fef3df2cfa 00000000 0001000248414341 ffff
819
820 //We have to handle the reply ourselves as this handle is not valid anymore
821
822
823 // It seems that the original hardware overwrites the command after it has been
824 // executed. We write 8 which is not any valid command, and what IOS does
825 Memory::Write_U32(8, _CommandAddress);
826 // IOS seems to write back the command that was responded to
827 Memory::Write_U32(6, _CommandAddress + 8);
828
829 // Generate a reply to the IPC command
830 WII_IPC_HLE_Interface::EnqReply(_CommandAddress, 0);
831
832 return false;
833 }
834 break;
835
836 case IOCTL_ES_CHECKKOREAREGION: //note by DacoTaco : name is unknown, i just tried to name it SOMETHING
837 //IOS70 has this to let system menu 4.2 check if the console is region changed. it returns -1017
838 //if the IOS didn't find the Korean keys and 0 if it does. 0 leads to a error 003
839 WARN_LOG(WII_IPC_ES,"IOCTL_ES_CHECKKOREAREGION: Title checked for Korean keys.")do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 839, "IOCTL_ES_CHECKKOREAREGION: Title checked for Korean keys."
); } } while (0)
;
840 Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT , _CommandAddress + 0x4);
841 return true;
842
843 // ===============================================================================================
844 // unsupported functions
845 // ===============================================================================================
846 case IOCTL_ES_DIGETTICKETVIEW: // (Input: none, Output: 216 bytes) bug crediar :D
847 WARN_LOG(WII_IPC_ES, "IOCTL_ES_DIGETTICKETVIEW: this looks really wrong...")do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 847, "IOCTL_ES_DIGETTICKETVIEW: this looks really wrong..."
); } } while (0)
;
848 break;
849
850 case IOCTL_ES_GETDEVICECERT: // (Input: none, Output: 384 bytes)
851 WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETDEVICECERT: this looks really wrong...")do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 851, "IOCTL_ES_GETDEVICECERT: this looks really wrong...");
} } while (0)
;
852 break;
853
854 default:
855 WARN_LOG(WII_IPC_ES, "CWII_IPC_HLE_Device_es: 0x%x", Buffer.Parameter)do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 855, "CWII_IPC_HLE_Device_es: 0x%x", Buffer.Parameter); } }
while (0)
;
856
857 DumpCommands(_CommandAddress, 8, LogTypes::WII_IPC_ES);
858 INFO_LOG(WII_IPC_ES, "command.Parameter: 0x%08x", Buffer.Parameter)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 858, "command.Parameter: 0x%08x", Buffer.Parameter); } } while
(0)
;
859 break;
860 }
861
862 // Write return value (0 means OK)
863 Memory::Write_U32(0, _CommandAddress + 0x4);
864
865 return true;
866}
867
868const DiscIO::INANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice(u64 _TitleID)
869{
870 if (m_pContentLoader->IsValid() && m_pContentLoader->GetTitleID() == _TitleID)
871 return* m_pContentLoader;
872
873 CTitleToContentMap::iterator itr = m_NANDContent.find(_TitleID);
874 if (itr != m_NANDContent.end())
875 return *itr->second;
876
877 m_NANDContent[_TitleID] = &DiscIO::CNANDContentManager::Access().GetNANDLoader(_TitleID);
878
879 _dbg_assert_msg_(WII_IPC_ES, ((u32)(_TitleID >> 32) == 0x00010000) || m_NANDContent[_TitleID]->IsValid(), "NandContent not valid for TitleID %08x/%08x", (u32)(_TitleID >> 32), (u32)_TitleID){};
880 return *m_NANDContent[_TitleID];
881}
882
883bool CWII_IPC_HLE_Device_es::IsValid(u64 _TitleID) const
884{
885 if (m_pContentLoader->IsValid() && m_pContentLoader->GetTitleID() == _TitleID)
886 return true;
887
888 return false;
889}
890
891
892u32 CWII_IPC_HLE_Device_es::ES_DIVerify(u8* _pTMD, u32 _sz)
893{
894 u64 titleID = 0xDEADBEEFDEADBEEFull;
895 u64 tmdTitleID = Common::swap64(*(u64*)(_pTMD+0x18c));
896 VolumeHandler::GetVolume()->GetTitleID((u8*)&titleID);
897 if (Common::swap64(titleID) != tmdTitleID)
898 {
899 return -1;
900 }
901 std::string tmdPath = Common::GetTMDFileName(tmdTitleID);
902
903 File::CreateFullPath(tmdPath);
904 File::CreateFullPath(Common::GetTitleDataPath(tmdTitleID));
905
906 Movie::g_titleID = tmdTitleID;
907 std::string savePath = Common::GetTitleDataPath(tmdTitleID);
908 if (Movie::IsRecordingInput())
909 {
910 // TODO: Check for the actual save data
911 if (File::Exists((savePath + "banner.bin").c_str()))
912 Movie::g_bClearSave = false;
913 else
914 Movie::g_bClearSave = true;
915 }
916
917 // TODO: Force the game to save to another location, instead of moving the user's save.
918 if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsStartingFromClearSave())
919 {
920 if (File::Exists((savePath + "banner.bin").c_str()))
921 {
922 if (File::Exists((savePath + "../backup/").c_str()))
923 {
924 // The last run of this game must have been to play back a movie, so their save is already backed up.
925 File::DeleteDirRecursively(savePath.c_str());
926 }
927 else
928 {
929 #ifdef _WIN32
930 MoveFile(UTF8ToTStr(savePath).c_str(), UTF8ToTStr(savePath + "../backup/").c_str());
931 #else
932 File::CopyDir(savePath.c_str(),(savePath + "../backup/").c_str());
933 File::DeleteDirRecursively(savePath.c_str());
934 #endif
935 }
936 }
937 }
938 else if (File::Exists((savePath + "../backup/").c_str()))
939 {
940 // Delete the save made by a previous movie, and copy back the user's save.
941 if (File::Exists((savePath + "banner.bin").c_str()))
942 File::DeleteDirRecursively(savePath);
943 #ifdef _WIN32
944 MoveFile(UTF8ToTStr(savePath + "../backup/").c_str(), UTF8ToTStr(savePath).c_str());
945 #else
946 File::CopyDir((savePath + "../backup/").c_str(), savePath.c_str());
947 File::DeleteDirRecursively((savePath + "../backup/").c_str());
948 #endif
949 }
950
951 if(!File::Exists(tmdPath))
952 {
953 File::IOFile _pTMDFile(tmdPath, "wb");
954 if (!_pTMDFile.WriteBytes(_pTMD, _sz))
955 ERROR_LOG(WII_IPC_ES, "DIVerify failed to write disc TMD to NAND.")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::WII_IPC_ES, "/home/anal/dolphin-emu/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp"
, 955, "DIVerify failed to write disc TMD to NAND."); } } while
(0)
;
956 }
957 DiscIO::cUIDsys::AccessInstance().AddTitle(tmdTitleID);
958 return 0;
959}