Bug Summary

File:Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp
Location:line 529, column 8
Description:Value stored to 'TitleID' 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#include "ConfigManager.h"
43
44#include "../Boot/Boot_DOL.h"
45#include "NandPaths.h"
46#include "CommonPaths.h"
47#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
48#include "../Movie.h"
49#include "StringUtil.h"
50
51#include "ec_wii.h"
52
53#ifdef _WIN32
54#include <Windows.h>
55#endif
56
57std::string CWII_IPC_HLE_Device_es::m_ContentFile;
58
59CWII_IPC_HLE_Device_es::CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName)
60 : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
61 , m_pContentLoader(NULL__null)
62 , m_TitleID(-1)
63 , m_AccessIdentID(0x6000000)
64{
65}
66
67static u8 key_sd [0x10] = {0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08, 0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d};
68static u8 key_ecc [0x1e] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
69static u8 key_empty[0x10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
70
71// default key table
72u8* CWII_IPC_HLE_Device_es::keyTable[11] = {
73 key_ecc, // ECC Private Key
74 key_empty, // Console ID
75 key_empty, // NAND AES Key
76 key_empty, // NAND HMAC
77 key_empty, // Common Key
78 key_empty, // PRNG seed
79 key_sd, // SD Key
80 key_empty, // Unknown
81 key_empty, // Unknown
82 key_empty, // Unknown
83 key_empty, // Unknown
84};
85
86CWII_IPC_HLE_Device_es::~CWII_IPC_HLE_Device_es()
87{}
88
89void CWII_IPC_HLE_Device_es::LoadWAD(const std::string& _rContentFile)
90{
91 m_ContentFile = _rContentFile;
92}
93
94void CWII_IPC_HLE_Device_es::OpenInternal()
95{
96 m_pContentLoader = &DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile);
97
98 // check for cd ...
99 if (m_pContentLoader->IsValid())
100 {
101 m_TitleID = m_pContentLoader->GetTitleID();
102
103 m_TitleIDs.clear();
104 DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDs);
105 // uncomment if ES_GetOwnedTitlesCount / ES_GetOwnedTitles is implemented
106 // m_TitleIDsOwned.clear();
107 // DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDsOwned, true);
108 }
109 else if (VolumeHandler::IsValid())
110 {
111 // blindly grab the titleID from the disc - it's unencrypted at:
112 // offset 0x0F8001DC and 0x0F80044C
113 VolumeHandler::GetVolume()->GetTitleID((u8*)&m_TitleID);
114 m_TitleID = Common::swap64(m_TitleID);
115 }
116 else
117 {
118 m_TitleID = ((u64)0x00010000 << 32) | 0xF00DBEEF;
119 }
120
121 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"
, 121, "Set default title to %08x/%08x", (u32)(m_TitleID>>
32), (u32)m_TitleID); } } while (0)
;
122}
123
124void CWII_IPC_HLE_Device_es::DoState(PointerWrap& p)
125{
126 IWII_IPC_HLE_Device::DoState(p);
127 p.Do(m_ContentFile);
128 OpenInternal();
129 p.Do(m_AccessIdentID);
130 p.Do(m_TitleIDs);
131
132 u32 Count = m_ContentAccessMap.size();
133 p.Do(Count);
134
135 u32 CFD, Position;
136 u64 TitleID;
137 u16 Index;
138 if (p.GetMode() == PointerWrap::MODE_READ)
139 {
140 for (u32 i = 0; i < Count; i++)
141 {
142 p.Do(CFD);
143 p.Do(Position);
144 p.Do(TitleID);
145 p.Do(Index);
146 CFD = OpenTitleContent(CFD, TitleID, Index);
147 if (CFD != 0xffffffff)
148 {
149 m_ContentAccessMap[CFD].m_Position = Position;
150 }
151 }
152 }
153 else
154 {
155 for (auto itr = m_ContentAccessMap.begin(); itr != m_ContentAccessMap.end(); ++itr)
156 {
157 CFD = itr->first;
158 SContentAccess& Access = itr->second;
159 Position = Access.m_Position;
160 TitleID = Access.m_TitleID;
161 Index = Access.m_pContent->m_Index;
162 p.Do(CFD);
163 p.Do(Position);
164 p.Do(TitleID);
165 p.Do(Index);
166 }
167 }
168}
169
170bool CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode)
171{
172 OpenInternal();
173
174 Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
175 if (m_Active)
176 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"
, 176, "Device was re-opened."); } } while (0)
;
177 m_Active = true;
178 return true;
179}
180
181bool CWII_IPC_HLE_Device_es::Close(u32 _CommandAddress, bool _bForce)
182{
183 // Leave deletion of the INANDContentLoader objects to CNANDContentManager, don't do it here!
184 m_NANDContent.clear();
185 for (auto itr = m_ContentAccessMap.begin(); itr != m_ContentAccessMap.end(); ++itr)
186 {
187 delete itr->second.m_pFile;
188 }
189 m_ContentAccessMap.clear();
190 m_pContentLoader = NULL__null;
191 m_TitleIDs.clear();
192 m_TitleID = -1;
193 m_AccessIdentID = 0x6000000;
194
195 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"
, 195, "ES: Close"); } } while (0)
;
196 if (!_bForce)
197 Memory::Write_U32(0, _CommandAddress + 4);
198 m_Active = false;
199 return true;
200}
201
202u32 CWII_IPC_HLE_Device_es::OpenTitleContent(u32 CFD, u64 TitleID, u16 Index)
203{
204 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
205
206 if (!Loader.IsValid())
207 {
208 WARN_LOG(WII_IPC_ES, "ES: loader not valid for %llx", TitleID)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"
, 208, "ES: loader not valid for %llx", TitleID); } } while (
0)
;
209 return 0xffffffff;
210 }
211
212 const DiscIO::SNANDContent* pContent = Loader.GetContentByIndex(Index);
213
214 if (pContent == NULL__null)
215 {
216 return 0xffffffff; //TODO: what is the correct error value here?
217 }
218
219 SContentAccess Access;
220 Access.m_Position = 0;
221 Access.m_pContent = pContent;
222 Access.m_TitleID = TitleID;
223 Access.m_pFile = NULL__null;
224
225 if (!pContent->m_pData)
226 {
227 std::string Filename = pContent->m_Filename;
228 INFO_LOG(WII_IPC_ES, "ES: load %s", Filename.c_str())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"
, 228, "ES: load %s", Filename.c_str()); } } while (0)
;
229
230 Access.m_pFile = new File::IOFile(Filename, "rb");
231 if (!Access.m_pFile->IsGood())
232 {
233 WARN_LOG(WII_IPC_ES, "ES: couldn't load %s", Filename.c_str())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"
, 233, "ES: couldn't load %s", Filename.c_str()); } } while (
0)
;
234 return 0xffffffff;
235 }
236 }
237
238 m_ContentAccessMap[CFD] = Access;
239 return CFD;
240}
241
242bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
243{
244 SIOCtlVBuffer Buffer(_CommandAddress);
245
246 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"
, 246, "%s (0x%x)", GetDeviceName().c_str(), Buffer.Parameter
); } } while (0)
;
247
248 // Prepare the out buffer(s) with zeroes as a safety precaution
249 // to avoid returning bad values
250 // XXX: is this still necessary?
251 for (u32 i = 0; i < Buffer.NumberPayloadBuffer; i++)
252 {
253 u32 j;
254 for (j = 0; j < Buffer.NumberInBuffer; j++)
255 {
256 if (Buffer.InBuffer[j].m_Address == Buffer.PayloadBuffer[i].m_Address)
257 {
258 // The out buffer is the same as one of the in buffers. Don't zero it.
259 break;
260 }
261 }
262 if (j == Buffer.NumberInBuffer)
263 {
264 Memory::Memset(Buffer.PayloadBuffer[i].m_Address, 0,
265 Buffer.PayloadBuffer[i].m_Size);
266 }
267 }
268
269 switch (Buffer.Parameter)
270 {
271 case IOCTL_ES_GETDEVICEID:
272 {
273 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETDEVICEID no out buffer"){};
274
275 EcWii &ec = EcWii::GetInstance();
276 INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETDEVICEID %08X", ec.getNgId())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"
, 276, "IOCTL_ES_GETDEVICEID %08X", ec.getNgId()); } } while (
0)
;
277 Memory::Write_U32(ec.getNgId(), Buffer.PayloadBuffer[0].m_Address);
278 Memory::Write_U32(0, _CommandAddress + 0x4);
279 return true;
280 }
281 break;
282
283 case IOCTL_ES_GETTITLECONTENTSCNT:
284 {
285 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1){};
286 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1){};
287
288 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
289
290 const DiscIO::INANDContentLoader& rNANDContent = AccessContentDevice(TitleID);
291 u16 NumberOfPrivateContent = 0;
292 if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check
293 {
294 NumberOfPrivateContent = rNANDContent.GetNumEntries();
295
296 if ((u32)(TitleID>>32) == 0x00010000)
297 Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address);
298 else
299 Memory::Write_U32(NumberOfPrivateContent, Buffer.PayloadBuffer[0].m_Address);
300
301 Memory::Write_U32(0, _CommandAddress + 0x4);
302 }
303 else
304 Memory::Write_U32((u32)rNANDContent.GetContentSize(), _CommandAddress + 0x4);
305
306 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"
, 307, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i"
, (u32)(TitleID>>32), (u32)TitleID, rNANDContent.IsValid
() ? NumberOfPrivateContent : (u32)rNANDContent.GetContentSize
()); } } while (0)
307 (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"
, 307, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i"
, (u32)(TitleID>>32), (u32)TitleID, rNANDContent.IsValid
() ? NumberOfPrivateContent : (u32)rNANDContent.GetContentSize
()); } } while (0)
;
308
309 return true;
310 }
311 break;
312
313 case IOCTL_ES_GETTITLECONTENTS:
314 {
315 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETTITLECONTENTS bad in buffer"){};
316 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLECONTENTS bad out buffer"){};
317
318 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
319
320 const DiscIO::INANDContentLoader& rNANDCOntent = AccessContentDevice(TitleID);
321 if (rNANDCOntent.IsValid()) // Not sure if dolphin will ever fail this check
322 {
323 for (u16 i = 0; i < rNANDCOntent.GetNumEntries(); i++)
324 {
325 Memory::Write_U32(rNANDCOntent.GetContentByIndex(i)->m_ContentID, Buffer.PayloadBuffer[0].m_Address + i*4);
326 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"
, 326, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", i, rNANDCOntent
.GetContentByIndex(i)->m_ContentID); } } while (0)
;
327 }
328 Memory::Write_U32(0, _CommandAddress + 0x4);
329 }
330 else
331 {
332 Memory::Write_U32((u32)rNANDCOntent.GetContentSize(), _CommandAddress + 0x4);
333 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"
, 337, "IOCTL_ES_GETTITLECONTENTS: " "Unable to open content %lu"
, (unsigned long)rNANDCOntent. GetContentSize()); } } while (
0)
334 "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"
, 337, "IOCTL_ES_GETTITLECONTENTS: " "Unable to open content %lu"
, (unsigned long)rNANDCOntent. GetContentSize()); } } while (
0)
335 "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"
, 337, "IOCTL_ES_GETTITLECONTENTS: " "Unable to open content %lu"
, (unsigned long)rNANDCOntent. GetContentSize()); } } while (
0)
336 (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"
, 337, "IOCTL_ES_GETTITLECONTENTS: " "Unable to open content %lu"
, (unsigned long)rNANDCOntent. GetContentSize()); } } while (
0)
337 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"
, 337, "IOCTL_ES_GETTITLECONTENTS: " "Unable to open content %lu"
, (unsigned long)rNANDCOntent. GetContentSize()); } } while (
0)
;
338 }
339
340 return true;
341 }
342 break;
343
344
345 case IOCTL_ES_OPENTITLECONTENT:
346 {
347 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 3){};
348 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0){};
349
350 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
351 u32 Index = Memory::Read_U32(Buffer.InBuffer[2].m_Address);
352
353 u32 CFD = OpenTitleContent(m_AccessIdentID++, TitleID, Index);
354 Memory::Write_U32(CFD, _CommandAddress + 0x4);
355
356 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"
, 356, "IOCTL_ES_OPENTITLECONTENT: TitleID: %08x/%08x Index %i -> got CFD %x"
, (u32)(TitleID>>32), (u32)TitleID, Index, CFD); } } while
(0)
;
357
358 return true;
359 }
360 break;
361
362 case IOCTL_ES_OPENCONTENT:
363 {
364 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1){};
365 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0){};
366 u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
367
368 u32 CFD = OpenTitleContent(m_AccessIdentID++, m_TitleID, Index);
369 Memory::Write_U32(CFD, _CommandAddress + 0x4);
370 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"
, 370, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index
, CFD); } } while (0)
;
371
372 return true;
373 }
374 break;
375
376 case IOCTL_ES_READCONTENT:
377 {
378 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1){};
379 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1){};
380
381 u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
382 u32 Size = Buffer.PayloadBuffer[0].m_Size;
383 u32 Addr = Buffer.PayloadBuffer[0].m_Address;
384
385 auto itr = m_ContentAccessMap.find(CFD);
386 if (itr == m_ContentAccessMap.end())
387 {
388 Memory::Write_U32(-1, _CommandAddress + 0x4);
389 return true;
390 }
391 SContentAccess& rContent = itr->second;
392
393 _dbg_assert_(WII_IPC_ES, rContent.m_pContent->m_pData != NULL){};
394
395 u8* pDest = Memory::GetPointer(Addr);
396
397 if (rContent.m_Position + Size > rContent.m_pContent->m_Size)
398 {
399 Size = rContent.m_pContent->m_Size-rContent.m_Position;
400 }
401
402 if (Size > 0)
403 {
404 if (pDest)
405 {
406 if (rContent.m_pContent->m_pData)
407 {
408 u8* pSrc = &rContent.m_pContent->m_pData[rContent.m_Position];
409 memcpy(pDest, pSrc, Size);
410 }
411 else
412 {
413 auto& pFile = rContent.m_pFile;
414 if (!pFile->Seek(rContent.m_Position, SEEK_SET0))
415 {
416 ERROR_LOG(WII_IPC_ES, "ES: couldn't seek!")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"
, 416, "ES: couldn't seek!"); } } while (0)
;
417 }
418 WARN_LOG(WII_IPC_ES, "2 %p", pFile->GetHandle())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"
, 418, "2 %p", pFile->GetHandle()); } } while (0)
;
419 if (!pFile->ReadBytes(pDest, Size))
420 {
421 ERROR_LOG(WII_IPC_ES, "ES: short read; returning uninitialized data!")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"
, 421, "ES: short read; returning uninitialized data!"); } } while
(0)
;
422 }
423 }
424 rContent.m_Position += Size;
425 } else {
426 PanicAlertT("IOCTL_ES_READCONTENT - bad destination")MsgAlert(false, WARNING, "IOCTL_ES_READCONTENT - bad destination"
)
;
427 }
428 }
429
430 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"
, 430, "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)
;
431
432 Memory::Write_U32(Size, _CommandAddress + 0x4);
433 return true;
434 }
435 break;
436
437 case IOCTL_ES_CLOSECONTENT:
438 {
439 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1){};
440 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0){};
441
442 u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
443
444 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"
, 444, "IOCTL_ES_CLOSECONTENT: CFD %x", CFD); } } while (0)
;
445
446 auto itr = m_ContentAccessMap.find(CFD);
447 if (itr == m_ContentAccessMap.end())
448 {
449 Memory::Write_U32(-1, _CommandAddress + 0x4);
450 return true;
451 }
452
453 delete itr->second.m_pFile;
454 m_ContentAccessMap.erase(itr);
455
456 Memory::Write_U32(0, _CommandAddress + 0x4);
457 return true;
458 }
459 break;
460
461 case IOCTL_ES_SEEKCONTENT:
462 {
463 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 3){};
464 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0){};
465
466 u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
467 u32 Addr = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
468 u32 Mode = Memory::Read_U32(Buffer.InBuffer[2].m_Address);
469
470 auto itr = m_ContentAccessMap.find(CFD);
471 if (itr == m_ContentAccessMap.end())
472 {
473 Memory::Write_U32(-1, _CommandAddress + 0x4);
474 return true;
475 }
476 SContentAccess& rContent = itr->second;
477
478 switch (Mode)
479 {
480 case 0: // SET
481 rContent.m_Position = Addr;
482 break;
483
484 case 1: // CUR
485 rContent.m_Position += Addr;
486 break;
487
488 case 2: // END
489 rContent.m_Position = rContent.m_pContent->m_Size + Addr;
490 break;
491 }
492
493 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"
, 493, "IOCTL_ES_SEEKCONTENT: CFD %x, Address 0x%x, Mode %i -> Pos %i"
, CFD, Addr, Mode, rContent.m_Position); } } while (0)
;
494
495 Memory::Write_U32(rContent.m_Position, _CommandAddress + 0x4);
496 return true;
497 }
498 break;
499
500 case IOCTL_ES_GETTITLEDIR:
501 {
502 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1){};
503 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1){};
504
505 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
506
507 char* Path = (char*)Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
508 sprintf(Path, "/title/%08x/%08x/data", (u32)(TitleID >> 32), (u32)TitleID);
509
510 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"
, 510, "IOCTL_ES_GETTITLEDIR: %s", Path); } } while (0)
;
511 }
512 break;
513
514 case IOCTL_ES_GETTITLEID:
515 {
516 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 0){};
517 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLEID no out buffer"){};
518
519 Memory::Write_U64(m_TitleID, Buffer.PayloadBuffer[0].m_Address);
520 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"
, 520, "IOCTL_ES_GETTITLEID: %08x/%08x", (u32)(m_TitleID>>
32), (u32)m_TitleID); } } while (0)
;
521 }
522 break;
523
524 case IOCTL_ES_SETUID:
525 {
526 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_SETUID no in buffer"){};
527 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0, "IOCTL_ES_SETUID has a payload, it shouldn't"){};
528 // TODO: fs permissions based on this
529 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
Value stored to 'TitleID' during its initialization is never read
530 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"
, 530, "IOCTL_ES_SETUID titleID: %08x/%08x", (u32)(TitleID>>
32), (u32)TitleID); } } while (0)
;
531 }
532 break;
533
534 case IOCTL_ES_GETTITLECNT:
535 {
536 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 0, "IOCTL_ES_GETTITLECNT has an in buffer"){};
537 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLECNT has no out buffer"){};
538 _dbg_assert_msg_(WII_IPC_ES, Buffer.PayloadBuffer[0].m_Size == 4, "IOCTL_ES_GETTITLECNT payload[0].size != 4"){};
539
540 Memory::Write_U32((u32)m_TitleIDs.size(), Buffer.PayloadBuffer[0].m_Address);
541
542 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"
, 543, "IOCTL_ES_GETTITLECNT: Number of Titles %lu", (unsigned
long)m_TitleIDs.size()); } } while (0)
543 (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"
, 543, "IOCTL_ES_GETTITLECNT: Number of Titles %lu", (unsigned
long)m_TitleIDs.size()); } } while (0)
;
544
545 Memory::Write_U32(0, _CommandAddress + 0x4);
546
547 return true;
548 }
549 break;
550
551
552 case IOCTL_ES_GETTITLES:
553 {
554 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETTITLES has an in buffer"){};
555 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLES has no out buffer"){};
556
557 u32 MaxCount = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
558 u32 Count = 0;
559 for (int i = 0; i < (int)m_TitleIDs.size(); i++)
560 {
561 Memory::Write_U64(m_TitleIDs[i], Buffer.PayloadBuffer[0].m_Address + i*8);
562 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"
, 562, "IOCTL_ES_GETTITLES: %08x/%08x", (u32)(m_TitleIDs[i] >>
32), (u32)m_TitleIDs[i]); } } while (0)
;
563 Count++;
564 if (Count >= MaxCount)
565 break;
566 }
567
568 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"
, 568, "IOCTL_ES_GETTITLES: Number of titles returned %i", Count
); } } while (0)
;
569 Memory::Write_U32(0, _CommandAddress + 0x4);
570 return true;
571 }
572 break;
573
574
575 case IOCTL_ES_GETVIEWCNT:
576 {
577 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETVIEWCNT no in buffer"){};
578 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETVIEWCNT no out buffer"){};
579
580 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
581
582 u32 retVal = 0;
583 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
584 u32 ViewCount = Loader.GetTIKSize() / DiscIO::INANDContentLoader::TICKET_SIZE;
585
586 if (!ViewCount)
587 {
588 std::string TicketFilename = Common::GetTicketFileName(TitleID);
589 if (File::Exists(TicketFilename))
590 {
591 u32 FileSize = (u32)File::GetSize(TicketFilename);
592 _dbg_assert_msg_(WII_IPC_ES, (FileSize % DiscIO::INANDContentLoader::TICKET_SIZE) == 0, "IOCTL_ES_GETVIEWCNT ticket file size seems to be wrong"){};
593
594 ViewCount = FileSize / DiscIO::INANDContentLoader::TICKET_SIZE;
595 _dbg_assert_msg_(WII_IPC_ES, (ViewCount>0) && (ViewCount<=4), "IOCTL_ES_GETVIEWCNT ticket count seems to be wrong"){};
596 }
597 else
598 {
599 if (TitleID == TITLEID_SYSMENU0x0000000100000002ull)
600 {
601 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."
)
;
602 }
603 ViewCount = 0;
604 //retVal = ES_NO_TICKET_INSTALLED;
605 }
606 }
607
608 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"
, 608, "IOCTL_ES_GETVIEWCNT for titleID: %08x/%08x (View Count = %i)"
, (u32)(TitleID>>32), (u32)TitleID, ViewCount); } } while
(0)
;
609
610 Memory::Write_U32(ViewCount, Buffer.PayloadBuffer[0].m_Address);
611 Memory::Write_U32(retVal, _CommandAddress + 0x4);
612 return true;
613 }
614 break;
615
616 case IOCTL_ES_GETVIEWS:
617 {
618 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETVIEWS no in buffer"){};
619 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETVIEWS no out buffer"){};
620
621 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
622 u32 maxViews = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
623 u32 retVal = 0;
624
625 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
626
627 const u8 *Ticket = Loader.GetTIK();
628 if (Ticket)
629 {
630 u32 viewCnt = Loader.GetTIKSize() / DiscIO::INANDContentLoader::TICKET_SIZE;
631 for (unsigned int View = 0; View != maxViews && View < viewCnt; ++View)
632 {
633 Memory::Write_U32(View, Buffer.PayloadBuffer[0].m_Address + View * 0xD8);
634 Memory::WriteBigEData(Ticket + 0x1D0 + (View * DiscIO::INANDContentLoader::TICKET_SIZE),
635 Buffer.PayloadBuffer[0].m_Address + 4 + View * 0xD8, 212);
636 }
637 }
638 else
639 {
640 std::string TicketFilename = Common::GetTicketFileName(TitleID);
641 if (File::Exists(TicketFilename))
642 {
643 File::IOFile pFile(TicketFilename, "rb");
644 if (pFile)
645 {
646 u8 FileTicket[DiscIO::INANDContentLoader::TICKET_SIZE];
647 for (unsigned int View = 0; View != maxViews && pFile.ReadBytes(FileTicket, DiscIO::INANDContentLoader::TICKET_SIZE); ++View)
648 {
649 Memory::Write_U32(View, Buffer.PayloadBuffer[0].m_Address + View * 0xD8);
650 Memory::WriteBigEData(FileTicket+0x1D0, Buffer.PayloadBuffer[0].m_Address + 4 + View * 0xD8, 212);
651 }
652 }
653 }
654 else
655 {
656 //retVal = ES_NO_TICKET_INSTALLED;
657 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)
;
658 }
659 }
660 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"
, 660, "IOCTL_ES_GETVIEWS for titleID: %08x/%08x (MaxViews = %i)"
, (u32)(TitleID >> 32), (u32)TitleID, maxViews); } } while
(0)
;
661
662 Memory::Write_U32(retVal, _CommandAddress + 0x4);
663 return true;
664 }
665 break;
666
667 case IOCTL_ES_GETTMDVIEWCNT:
668 {
669 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no in buffer"){};
670 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no out buffer"){};
671
672 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
673
674 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
675
676 u32 TMDViewCnt = 0;
677 if (Loader.IsValid())
678 {
679 TMDViewCnt += DiscIO::INANDContentLoader::TMD_VIEW_SIZE;
680 TMDViewCnt += 2; // title version
681 TMDViewCnt += 2; // num entries
682 TMDViewCnt += (u32)Loader.GetContentSize() * (4+2+2+8); // content id, index, type, size
683 }
684 Memory::Write_U32(TMDViewCnt, Buffer.PayloadBuffer[0].m_Address);
685
686 Memory::Write_U32(0, _CommandAddress + 0x4);
687
688 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"
, 688, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x (view size %i)"
, (u32)(TitleID >> 32), (u32)TitleID, TMDViewCnt); } } while
(0)
;
689 return true;
690 }
691 break;
692
693 case IOCTL_ES_GETTMDVIEWS:
694 {
695 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETTMDVIEWCNT no in buffer"){};
696 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no out buffer"){};
697
698 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
699 u32 MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
700
701 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
702
703 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"
, 703, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x buffer size: %i"
, (u32)(TitleID >> 32), (u32)TitleID, MaxCount); } } while
(0)
;
704
705 if (Loader.IsValid())
706 {
707 u32 Address = Buffer.PayloadBuffer[0].m_Address;
708
709 Memory::WriteBigEData(Loader.GetTMDView(), Address, DiscIO::INANDContentLoader::TMD_VIEW_SIZE);
710 Address += DiscIO::INANDContentLoader::TMD_VIEW_SIZE;
711
712 Memory::Write_U16(Loader.GetTitleVersion(), Address); Address += 2;
713 Memory::Write_U16(Loader.GetNumEntries(), Address); Address += 2;
714
715 const std::vector<DiscIO::SNANDContent>& rContent = Loader.GetContent();
716 for (size_t i=0; i<Loader.GetContentSize(); i++)
717 {
718 Memory::Write_U32(rContent[i].m_ContentID, Address); Address += 4;
719 Memory::Write_U16(rContent[i].m_Index, Address); Address += 2;
720 Memory::Write_U16(rContent[i].m_Type, Address); Address += 2;
721 Memory::Write_U64(rContent[i].m_Size, Address); Address += 8;
722 }
723
724 _dbg_assert_(WII_IPC_ES, (Address-Buffer.PayloadBuffer[0].m_Address) == Buffer.PayloadBuffer[0].m_Size){};
725 }
726 Memory::Write_U32(0, _CommandAddress + 0x4);
727
728 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"
, 728, "IOCTL_ES_GETTMDVIEWS: title: %08x/%08x (buffer size: %i)"
, (u32)(TitleID >> 32), (u32)TitleID, MaxCount); } } while
(0)
;
729 return true;
730 }
731 break;
732
733 case IOCTL_ES_GETCONSUMPTION: // This is at least what crediar's ES module does
734 Memory::Write_U32(0, Buffer.PayloadBuffer[1].m_Address);
735 Memory::Write_U32(0, _CommandAddress + 0x4);
736 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"
, 736, "IOCTL_ES_GETCONSUMPTION:%d", Memory::Read_U32(_CommandAddress
+4)); } } while (0)
;
737 return true;
738
739 case IOCTL_ES_DELETETICKET:
740 {
741 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
742 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"
, 742, "IOCTL_ES_DELETETICKET: title: %08x/%08x", (u32)(TitleID
>> 32), (u32)TitleID); } } while (0)
;
743 if (File::Delete(Common::GetTicketFileName(TitleID)))
744 {
745 Memory::Write_U32(0, _CommandAddress + 0x4);
746 }
747 else
748 {
749 // Presumably return -1017 when delete fails
750 Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT, _CommandAddress + 0x4);
751 }
752 }
753 break;
754 case IOCTL_ES_DELETETITLECONTENT:
755 {
756 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
757 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"
, 757, "IOCTL_ES_DELETETITLECONTENT: title: %08x/%08x", (u32)
(TitleID >> 32), (u32)TitleID); } } while (0)
;
758 if (DiscIO::CNANDContentManager::Access().RemoveTitle(TitleID))
759 {
760 Memory::Write_U32(0, _CommandAddress + 0x4);
761 }
762 else
763 {
764 // Presumably return -1017 when title not installed TODO verify
765 Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT, _CommandAddress + 0x4);
766 }
767
768 }
769 case IOCTL_ES_GETSTOREDTMDSIZE:
770 {
771 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETSTOREDTMDSIZE no in buffer"){};
772 // _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_ES_GETSTOREDTMDSIZE no out buffer");
773
774 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
775 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
776
777 _dbg_assert_(WII_IPC_ES, Loader.IsValid()){};
778 u32 TMDCnt = 0;
779 if (Loader.IsValid())
780 {
781 TMDCnt += DiscIO::INANDContentLoader::TMD_HEADER_SIZE;
782 TMDCnt += (u32)Loader.GetContentSize() * DiscIO::INANDContentLoader::CONTENT_HEADER_SIZE;
783 }
784 if(Buffer.NumberPayloadBuffer)
785 Memory::Write_U32(TMDCnt, Buffer.PayloadBuffer[0].m_Address);
786
787 Memory::Write_U32(0, _CommandAddress + 0x4);
788
789 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"
, 789, "IOCTL_ES_GETSTOREDTMDSIZE: title: %08x/%08x (view size %i)"
, (u32)(TitleID >> 32), (u32)TitleID, TMDCnt); } } while
(0)
;
790 return true;
791 }
792 break;
793 case IOCTL_ES_GETSTOREDTMD:
794 {
795 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer > 0, "IOCTL_ES_GETSTOREDTMD no in buffer"){};
796 // requires 1 inbuffer and no outbuffer, presumably outbuffer required when second inbuffer is used for maxcount (allocated mem?)
797 // called with 1 inbuffer after deleting a titleid
798 //_dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETSTOREDTMD no out buffer");
799
800 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
801 u32 MaxCount = 0;
802 if (Buffer.NumberInBuffer > 1)
803 {
804 // TODO: actually use this param in when writing to the outbuffer :/
805 MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
806 }
807 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
808
809
810 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"
, 810, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x buffer size: %i"
, (u32)(TitleID >> 32), (u32)TitleID, MaxCount); } } while
(0)
;
811
812 if (Loader.IsValid() && Buffer.NumberPayloadBuffer)
813 {
814 u32 Address = Buffer.PayloadBuffer[0].m_Address;
815
816 Memory::WriteBigEData(Loader.GetTMDHeader(), Address, DiscIO::INANDContentLoader::TMD_HEADER_SIZE);
817 Address += DiscIO::INANDContentLoader::TMD_HEADER_SIZE;
818
819 const std::vector<DiscIO::SNANDContent>& rContent = Loader.GetContent();
820 for (size_t i=0; i<Loader.GetContentSize(); i++)
821 {
822 Memory::WriteBigEData(rContent[i].m_Header, Address, DiscIO::INANDContentLoader::CONTENT_HEADER_SIZE);
823 Address += DiscIO::INANDContentLoader::CONTENT_HEADER_SIZE;
824 }
825
826 _dbg_assert_(WII_IPC_ES, (Address-Buffer.PayloadBuffer[0].m_Address) == Buffer.PayloadBuffer[0].m_Size){};
827 }
828 Memory::Write_U32(0, _CommandAddress + 0x4);
829
830 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"
, 830, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x (buffer size: %i)"
, (u32)(TitleID >> 32), (u32)TitleID, MaxCount); } } while
(0)
;
831 return true;
832 }
833 break;
834
835 case IOCTL_ES_ENCRYPT:
836 {
837 u32 keyIndex = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
838 u8* IV = Memory::GetPointer(Buffer.InBuffer[1].m_Address);
839 u8* source = Memory::GetPointer(Buffer.InBuffer[2].m_Address);
840 u32 size = Buffer.InBuffer[2].m_Size;
841 u8* newIV = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
842 u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address);
843
844 AES_KEY AESKey;
845 AES_set_encrypt_key(keyTable[keyIndex], 128, &AESKey);
846 memcpy(newIV, IV, 16);
847 AES_cbc_encrypt(source, destination, size, &AESKey, newIV, AES_ENCRYPT1);
848
849 _dbg_assert_msg_(WII_IPC_ES, keyIndex == 6, "IOCTL_ES_ENCRYPT: Key type is not SD, data will be crap"){};
850 }
851 break;
852
853 case IOCTL_ES_DECRYPT:
854 {
855 u32 keyIndex = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
856 u8* IV = Memory::GetPointer(Buffer.InBuffer[1].m_Address);
857 u8* source = Memory::GetPointer(Buffer.InBuffer[2].m_Address);
858 u32 size = Buffer.InBuffer[2].m_Size;
859 u8* newIV = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
860 u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address);
861
862 AES_KEY AESKey;
863 AES_set_decrypt_key(keyTable[keyIndex], 128, &AESKey);
864 memcpy(newIV, IV, 16);
865 AES_cbc_encrypt(source, destination, size, &AESKey, newIV, AES_DECRYPT0);
866
867 _dbg_assert_msg_(WII_IPC_ES, keyIndex == 6, "IOCTL_ES_DECRYPT: Key type is not SD, data will be crap"){};
868 }
869 break;
870
871
872 case IOCTL_ES_LAUNCH:
873 {
874 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 2){};
875 bool bSuccess = false;
876 u16 IOSv = 0xffff;
877
878 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
879 u32 view = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
880 u64 ticketid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+4);
881 u32 devicetype = Memory::Read_U32(Buffer.InBuffer[1].m_Address+12);
882 u64 titleid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+16);
883 u16 access = Memory::Read_U16(Buffer.InBuffer[1].m_Address+24);
884
885
886 if ((u32)(TitleID>>32) != 0x00000001 || TitleID == TITLEID_SYSMENU0x0000000100000002ull)
887 {
888 const DiscIO::INANDContentLoader& ContentLoader = AccessContentDevice(TitleID);
889 if (ContentLoader.IsValid())
890 {
891 u32 bootInd = ContentLoader.GetBootIndex();
892 const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(bootInd);
893 if (pContent)
894 {
895 LoadWAD(Common::GetTitleContentPath(TitleID));
896 std::unique_ptr<CDolLoader> pDolLoader;
897 if (pContent->m_pData)
898 {
899 pDolLoader.reset(new CDolLoader(pContent->m_pData, pContent->m_Size));
900 }
901 else
902 {
903 pDolLoader.reset(new CDolLoader(pContent->m_Filename.c_str()));
904 }
905 pDolLoader->Load(); // TODO: Check why sysmenu does not load the DOL correctly
906 PCPowerPC::ppcState.pc = pDolLoader->GetEntryPoint() | 0x80000000;
907 IOSv = ContentLoader.GetIosVersion();
908 bSuccess = true;
909 }
910 }
911 }
912 else // IOS, MIOS, BC etc
913 {
914 //TODO: fixme
915 // The following is obviously a hack
916 // Lie to mem about loading a different IOS
917 // someone with an affected game should test
918 IOSv = TitleID & 0xffff;
919 }
920 if (!bSuccess && IOSv >= 30 && IOSv != 0xffff)
921 {
922 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)
923 "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)
;
924 }
925 else
926 {
927 CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer();
928 size_t size = s_Usb->m_WiiMotes.size();
929 bool* wiiMoteConnected = new bool[size];
930 for (unsigned int i = 0; i < size; i++)
931 wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected();
932
933 std::string tContentFile(m_ContentFile.c_str());
934
935 WII_IPC_HLE_Interface::Reset(true);
936 WII_IPC_HLE_Interface::Init();
937 s_Usb = GetUsbPointer();
938 for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++)
939 {
940 if (wiiMoteConnected[i])
941 {
942 s_Usb->m_WiiMotes[i].Activate(false);
943 s_Usb->m_WiiMotes[i].Activate(true);
944 }
945 else
946 {
947 s_Usb->m_WiiMotes[i].Activate(false);
948 }
949 }
950
951 delete[] wiiMoteConnected;
952 WII_IPC_HLE_Interface::SetDefaultContentFile(tContentFile);
953 }
954 // Pass the "#002 check"
955 // Apploader should write the IOS version and revision to 0x3140, and compare it
956 // to 0x3188 to pass the check, but we don't do it, and i don't know where to read the IOS rev...
957 // Currently we just write 0xFFFF for the revision, copy manually and it works fine :p
958 // TODO : figure it correctly : where should we read the IOS rev that the wad "needs" ?
959 Memory::Write_U16(IOSv, 0x00003140);
960 Memory::Write_U16(0xFFFF, 0x00003142);
961 Memory::Write_U32(Memory::Read_U32(0x00003140), 0x00003188);
962
963 //TODO: provide correct return code when bSuccess= false
964 Memory::Write_U32(0, _CommandAddress + 0x4);
965
966 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"
, 966, "IOCTL_ES_LAUNCH %016llx %08x %016llx %08x %016llx %04x"
, TitleID,view,ticketid,devicetype,titleid,access); } } while
(0)
;
967 // IOCTL_ES_LAUNCH 0001000248414341 00000001 0001c0fef3df2cfa 00000000 0001000248414341 ffff
968
969 //We have to handle the reply ourselves as this handle is not valid anymore
970
971
972 // It seems that the original hardware overwrites the command after it has been
973 // executed. We write 8 which is not any valid command, and what IOS does
974 Memory::Write_U32(8, _CommandAddress);
975 // IOS seems to write back the command that was responded to
976 Memory::Write_U32(6, _CommandAddress + 8);
977
978 // Generate a reply to the IPC command
979 WII_IPC_HLE_Interface::EnqReply(_CommandAddress, 0);
980
981 return false;
982 }
983 break;
984
985 case IOCTL_ES_CHECKKOREAREGION: //note by DacoTaco : name is unknown, i just tried to name it SOMETHING
986 //IOS70 has this to let system menu 4.2 check if the console is region changed. it returns -1017
987 //if the IOS didn't find the Korean keys and 0 if it does. 0 leads to a error 003
988 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"
, 988, "IOCTL_ES_CHECKKOREAREGION: Title checked for Korean keys."
); } } while (0)
;
989 Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT , _CommandAddress + 0x4);
990 return true;
991
992 case IOCTL_ES_GETDEVICECERT: // (Input: none, Output: 384 bytes)
993 {
994 WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETDEVICECERT")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"
, 994, "IOCTL_ES_GETDEVICECERT"); } } while (0)
;
995 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1){};
996 u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
997
998 EcWii &ec = EcWii::GetInstance();
999 get_ng_cert(destination, ec.getNgId(), ec.getNgKeyId(), ec.getNgPriv(), ec.getNgSig());
1000 }
1001 break;
1002
1003 case IOCTL_ES_SIGN:
1004 {
1005 WARN_LOG(WII_IPC_ES, "IOCTL_ES_SIGN")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"
, 1005, "IOCTL_ES_SIGN"); } } while (0)
;
1006 u8 *ap_cert_out = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address);
1007 u8 *data = Memory::GetPointer(Buffer.InBuffer[0].m_Address);
1008 u32 data_size = Buffer.InBuffer[0].m_Size;
1009 u8 *sig_out = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
1010
1011 EcWii &ec = EcWii::GetInstance();
1012 get_ap_sig_and_cert(sig_out, ap_cert_out, m_TitleID, data, data_size, ec.getNgPriv(), ec.getNgId());
1013 }
1014 break;
1015
1016 case IOCTL_ES_GETBOOT2VERSION:
1017 {
1018 WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETBOOT2VERSION")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"
, 1018, "IOCTL_ES_GETBOOT2VERSION"); } } while (0)
;
1019
1020 Memory::Write_U32(4, Buffer.PayloadBuffer[0].m_Address); // as of 26/02/2012, this was latest bootmii version
1021 }
1022 break;
1023
1024 // ===============================================================================================
1025 // unsupported functions
1026 // ===============================================================================================
1027 case IOCTL_ES_DIGETTICKETVIEW: // (Input: none, Output: 216 bytes) bug crediar :D
1028 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"
, 1028, "IOCTL_ES_DIGETTICKETVIEW: this looks really wrong..."
); } } while (0)
;
1029 break;
1030
1031 case IOCTL_ES_GETOWNEDTITLECNT:
1032 WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETOWNEDTITLECNT")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"
, 1032, "IOCTL_ES_GETOWNEDTITLECNT"); } } while (0)
;
1033 Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address);
1034 break;
1035
1036 default:
1037 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"
, 1037, "CWII_IPC_HLE_Device_es: 0x%x", Buffer.Parameter); } }
while (0)
;
1038 DumpCommands(_CommandAddress, 8, LogTypes::WII_IPC_ES);
1039 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"
, 1039, "command.Parameter: 0x%08x", Buffer.Parameter); } } while
(0)
;
1040 break;
1041 }
1042
1043 // Write return value (0 means OK)
1044 Memory::Write_U32(0, _CommandAddress + 0x4);
1045
1046 return true;
1047}
1048
1049const DiscIO::INANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice(u64 _TitleID)
1050{
1051 if (m_pContentLoader->IsValid() && m_pContentLoader->GetTitleID() == _TitleID)
1052 return *m_pContentLoader;
1053
1054 CTitleToContentMap::iterator itr = m_NANDContent.find(_TitleID);
1055 if (itr != m_NANDContent.end())
1056 return *itr->second;
1057
1058 m_NANDContent[_TitleID] = &DiscIO::CNANDContentManager::Access().GetNANDLoader(_TitleID);
1059
1060 _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){};
1061 return *m_NANDContent[_TitleID];
1062}
1063
1064bool CWII_IPC_HLE_Device_es::IsValid(u64 _TitleID) const
1065{
1066 if (m_pContentLoader->IsValid() && m_pContentLoader->GetTitleID() == _TitleID)
1067 return true;
1068
1069 return false;
1070}
1071
1072
1073u32 CWII_IPC_HLE_Device_es::ES_DIVerify(u8* _pTMD, u32 _sz)
1074{
1075 u64 titleID = 0xDEADBEEFDEADBEEFull;
1076 u64 tmdTitleID = Common::swap64(*(u64*)(_pTMD+0x18c));
1077 VolumeHandler::GetVolume()->GetTitleID((u8*)&titleID);
1078 if (Common::swap64(titleID) != tmdTitleID)
1079 {
1080 return -1;
1081 }
1082 std::string tmdPath = Common::GetTMDFileName(tmdTitleID);
1083
1084 File::CreateFullPath(tmdPath);
1085 File::CreateFullPath(Common::GetTitleDataPath(tmdTitleID));
1086
1087 Movie::g_titleID = tmdTitleID;
1088 std::string savePath = Common::GetTitleDataPath(tmdTitleID);
1089 if (Movie::IsRecordingInput())
1090 {
1091 // TODO: Check for the actual save data
1092 if (File::Exists((savePath + "banner.bin").c_str()))
1093 Movie::g_bClearSave = false;
1094 else
1095 Movie::g_bClearSave = true;
1096 }
1097
1098 // TODO: Force the game to save to another location, instead of moving the user's save.
1099 if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsStartingFromClearSave())
1100 {
1101 if (File::Exists((savePath + "banner.bin").c_str()))
1102 {
1103 if (File::Exists((savePath + "../backup/").c_str()))
1104 {
1105 // The last run of this game must have been to play back a movie, so their save is already backed up.
1106 File::DeleteDirRecursively(savePath.c_str());
1107 }
1108 else
1109 {
1110 #ifdef _WIN32
1111 MoveFile(UTF8ToTStr(savePath).c_str(), UTF8ToTStr(savePath + "../backup/").c_str());
1112 #else
1113 File::CopyDir(savePath.c_str(),(savePath + "../backup/").c_str());
1114 File::DeleteDirRecursively(savePath.c_str());
1115 #endif
1116 }
1117 }
1118 }
1119 else if (File::Exists((savePath + "../backup/").c_str()))
1120 {
1121 // Delete the save made by a previous movie, and copy back the user's save.
1122 if (File::Exists((savePath + "banner.bin").c_str()))
1123 File::DeleteDirRecursively(savePath);
1124 #ifdef _WIN32
1125 MoveFile(UTF8ToTStr(savePath + "../backup/").c_str(), UTF8ToTStr(savePath).c_str());
1126 #else
1127 File::CopyDir((savePath + "../backup/").c_str(), savePath.c_str());
1128 File::DeleteDirRecursively((savePath + "../backup/").c_str());
1129 #endif
1130 }
1131
1132 if(!File::Exists(tmdPath))
1133 {
1134 File::IOFile _pTMDFile(tmdPath, "wb");
1135 if (!_pTMDFile.WriteBytes(_pTMD, _sz))
1136 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"
, 1136, "DIVerify failed to write disc TMD to NAND."); } } while
(0)
;
1137 }
1138 DiscIO::cUIDsys::AccessInstance().AddTitle(tmdTitleID);
1139 return 0;
1140}