Bug Summary

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