Bug Summary

File:Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp
Location:line 824, column 5
Description:Value stored to 'MaxCount' 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);
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 if (TitleID >> 32 == 0x00000001)
598 {
599 // Fake a ticket view to make IOS reload work.
600 ViewCount = 1;
601 }
602 else
603 {
604 ViewCount = 0;
605 if (TitleID == TITLEID_SYSMENU0x0000000100000002ull)
606 {
607 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."
)
;
608 }
609 //retVal = ES_NO_TICKET_INSTALLED;
610 }
611 }
612
613 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"
, 613, "IOCTL_ES_GETVIEWCNT for titleID: %08x/%08x (View Count = %i)"
, (u32)(TitleID>>32), (u32)TitleID, ViewCount); } } while
(0)
;
614
615 Memory::Write_U32(ViewCount, Buffer.PayloadBuffer[0].m_Address);
616 Memory::Write_U32(retVal, _CommandAddress + 0x4);
617 return true;
618 }
619 break;
620
621 case IOCTL_ES_GETVIEWS:
622 {
623 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETVIEWS no in buffer"){};
624 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETVIEWS no out buffer"){};
625
626 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
627 u32 maxViews = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
628 u32 retVal = 0;
629
630 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
631
632 const u8 *Ticket = Loader.GetTIK();
633 if (Ticket)
634 {
635 u32 viewCnt = Loader.GetTIKSize() / DiscIO::INANDContentLoader::TICKET_SIZE;
636 for (unsigned int View = 0; View != maxViews && View < viewCnt; ++View)
637 {
638 Memory::Write_U32(View, Buffer.PayloadBuffer[0].m_Address + View * 0xD8);
639 Memory::WriteBigEData(Ticket + 0x1D0 + (View * DiscIO::INANDContentLoader::TICKET_SIZE),
640 Buffer.PayloadBuffer[0].m_Address + 4 + View * 0xD8, 212);
641 }
642 }
643 else
644 {
645 std::string TicketFilename = Common::GetTicketFileName(TitleID);
646 if (File::Exists(TicketFilename))
647 {
648 File::IOFile pFile(TicketFilename, "rb");
649 if (pFile)
650 {
651 u8 FileTicket[DiscIO::INANDContentLoader::TICKET_SIZE];
652 for (unsigned int View = 0; View != maxViews && pFile.ReadBytes(FileTicket, DiscIO::INANDContentLoader::TICKET_SIZE); ++View)
653 {
654 Memory::Write_U32(View, Buffer.PayloadBuffer[0].m_Address + View * 0xD8);
655 Memory::WriteBigEData(FileTicket+0x1D0, Buffer.PayloadBuffer[0].m_Address + 4 + View * 0xD8, 212);
656 }
657 }
658 }
659 else if (TitleID >> 32 == 0x00000001)
660 {
661 // For IOS titles, the ticket view isn't normally parsed by either the
662 // SDK or libogc, just passed to LaunchTitle, so this
663 // shouldn't matter at all. Just fill out some fields just
664 // to be on the safe side.
665 u32 Address = Buffer.PayloadBuffer[0].m_Address;
666 memset(Memory::GetPointer(Address), 0, 0xD8);
667 Memory::Write_U64(TitleID, Address + 4 + (0x1dc - 0x1d0)); // title ID
668 Memory::Write_U16(0xffff, Address + 4 + (0x1e4 - 0x1d0)); // unnnown
669 Memory::Write_U32(0xff00, Address + 4 + (0x1ec - 0x1d0)); // access mask
670 memset(Memory::GetPointer(Address + 4 + (0x222 - 0x1d0)), 0xff, 0x20); // content permissions
671 }
672 else
673 {
674 //retVal = ES_NO_TICKET_INSTALLED;
675 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)
;
676 }
677 }
678 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"
, 678, "IOCTL_ES_GETVIEWS for titleID: %08x/%08x (MaxViews = %i)"
, (u32)(TitleID >> 32), (u32)TitleID, maxViews); } } while
(0)
;
679
680 Memory::Write_U32(retVal, _CommandAddress + 0x4);
681 return true;
682 }
683 break;
684
685 case IOCTL_ES_GETTMDVIEWCNT:
686 {
687 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no in buffer"){};
688 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no out buffer"){};
689
690 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
691
692 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
693
694 u32 TMDViewCnt = 0;
695 if (Loader.IsValid())
696 {
697 TMDViewCnt += DiscIO::INANDContentLoader::TMD_VIEW_SIZE;
698 TMDViewCnt += 2; // title version
699 TMDViewCnt += 2; // num entries
700 TMDViewCnt += (u32)Loader.GetContentSize() * (4+2+2+8); // content id, index, type, size
701 }
702 Memory::Write_U32(TMDViewCnt, Buffer.PayloadBuffer[0].m_Address);
703
704 Memory::Write_U32(0, _CommandAddress + 0x4);
705
706 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"
, 706, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x (view size %i)"
, (u32)(TitleID >> 32), (u32)TitleID, TMDViewCnt); } } while
(0)
;
707 return true;
708 }
709 break;
710
711 case IOCTL_ES_GETTMDVIEWS:
712 {
713 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETTMDVIEWCNT no in buffer"){};
714 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no out buffer"){};
715
716 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
717 u32 MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
718
719 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
720
721 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"
, 721, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x buffer size: %i"
, (u32)(TitleID >> 32), (u32)TitleID, MaxCount); } } while
(0)
;
722
723 if (Loader.IsValid())
724 {
725 u32 Address = Buffer.PayloadBuffer[0].m_Address;
726
727 Memory::WriteBigEData(Loader.GetTMDView(), Address, DiscIO::INANDContentLoader::TMD_VIEW_SIZE);
728 Address += DiscIO::INANDContentLoader::TMD_VIEW_SIZE;
729
730 Memory::Write_U16(Loader.GetTitleVersion(), Address); Address += 2;
731 Memory::Write_U16(Loader.GetNumEntries(), Address); Address += 2;
732
733 const std::vector<DiscIO::SNANDContent>& rContent = Loader.GetContent();
734 for (size_t i=0; i<Loader.GetContentSize(); i++)
735 {
736 Memory::Write_U32(rContent[i].m_ContentID, Address); Address += 4;
737 Memory::Write_U16(rContent[i].m_Index, Address); Address += 2;
738 Memory::Write_U16(rContent[i].m_Type, Address); Address += 2;
739 Memory::Write_U64(rContent[i].m_Size, Address); Address += 8;
740 }
741
742 _dbg_assert_(WII_IPC_ES, (Address-Buffer.PayloadBuffer[0].m_Address) == Buffer.PayloadBuffer[0].m_Size){};
743 }
744 Memory::Write_U32(0, _CommandAddress + 0x4);
745
746 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"
, 746, "IOCTL_ES_GETTMDVIEWS: title: %08x/%08x (buffer size: %i)"
, (u32)(TitleID >> 32), (u32)TitleID, MaxCount); } } while
(0)
;
747 return true;
748 }
749 break;
750
751 case IOCTL_ES_GETCONSUMPTION: // This is at least what crediar's ES module does
752 Memory::Write_U32(0, Buffer.PayloadBuffer[1].m_Address);
753 Memory::Write_U32(0, _CommandAddress + 0x4);
754 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"
, 754, "IOCTL_ES_GETCONSUMPTION:%d", Memory::Read_U32(_CommandAddress
+4)); } } while (0)
;
755 return true;
756
757 case IOCTL_ES_DELETETICKET:
758 {
759 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
760 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"
, 760, "IOCTL_ES_DELETETICKET: title: %08x/%08x", (u32)(TitleID
>> 32), (u32)TitleID); } } while (0)
;
761 if (File::Delete(Common::GetTicketFileName(TitleID)))
762 {
763 Memory::Write_U32(0, _CommandAddress + 0x4);
764 }
765 else
766 {
767 // Presumably return -1017 when delete fails
768 Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT, _CommandAddress + 0x4);
769 }
770 }
771 break;
772 case IOCTL_ES_DELETETITLECONTENT:
773 {
774 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
775 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"
, 775, "IOCTL_ES_DELETETITLECONTENT: title: %08x/%08x", (u32)
(TitleID >> 32), (u32)TitleID); } } while (0)
;
776 if (DiscIO::CNANDContentManager::Access().RemoveTitle(TitleID))
777 {
778 Memory::Write_U32(0, _CommandAddress + 0x4);
779 }
780 else
781 {
782 // Presumably return -1017 when title not installed TODO verify
783 Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT, _CommandAddress + 0x4);
784 }
785
786 }
787 break;
788 case IOCTL_ES_GETSTOREDTMDSIZE:
789 {
790 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETSTOREDTMDSIZE no in buffer"){};
791 // _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_ES_GETSTOREDTMDSIZE no out buffer");
792
793 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
794 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
795
796 _dbg_assert_(WII_IPC_ES, Loader.IsValid()){};
797 u32 TMDCnt = 0;
798 if (Loader.IsValid())
799 {
800 TMDCnt += DiscIO::INANDContentLoader::TMD_HEADER_SIZE;
801 TMDCnt += (u32)Loader.GetContentSize() * DiscIO::INANDContentLoader::CONTENT_HEADER_SIZE;
802 }
803 if(Buffer.NumberPayloadBuffer)
804 Memory::Write_U32(TMDCnt, Buffer.PayloadBuffer[0].m_Address);
805
806 Memory::Write_U32(0, _CommandAddress + 0x4);
807
808 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"
, 808, "IOCTL_ES_GETSTOREDTMDSIZE: title: %08x/%08x (view size %i)"
, (u32)(TitleID >> 32), (u32)TitleID, TMDCnt); } } while
(0)
;
809 return true;
810 }
811 break;
812 case IOCTL_ES_GETSTOREDTMD:
813 {
814 _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer > 0, "IOCTL_ES_GETSTOREDTMD no in buffer"){};
815 // requires 1 inbuffer and no outbuffer, presumably outbuffer required when second inbuffer is used for maxcount (allocated mem?)
816 // called with 1 inbuffer after deleting a titleid
817 //_dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETSTOREDTMD no out buffer");
818
819 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
820 u32 MaxCount = 0;
821 if (Buffer.NumberInBuffer > 1)
822 {
823 // TODO: actually use this param in when writing to the outbuffer :/
824 MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
Value stored to 'MaxCount' is never read
825 }
826 const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
827
828
829 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"
, 829, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x buffer size: %i"
, (u32)(TitleID >> 32), (u32)TitleID, MaxCount); } } while
(0)
;
830
831 if (Loader.IsValid() && Buffer.NumberPayloadBuffer)
832 {
833 u32 Address = Buffer.PayloadBuffer[0].m_Address;
834
835 Memory::WriteBigEData(Loader.GetTMDHeader(), Address, DiscIO::INANDContentLoader::TMD_HEADER_SIZE);
836 Address += DiscIO::INANDContentLoader::TMD_HEADER_SIZE;
837
838 const std::vector<DiscIO::SNANDContent>& rContent = Loader.GetContent();
839 for (size_t i=0; i<Loader.GetContentSize(); i++)
840 {
841 Memory::WriteBigEData(rContent[i].m_Header, Address, DiscIO::INANDContentLoader::CONTENT_HEADER_SIZE);
842 Address += DiscIO::INANDContentLoader::CONTENT_HEADER_SIZE;
843 }
844
845 _dbg_assert_(WII_IPC_ES, (Address-Buffer.PayloadBuffer[0].m_Address) == Buffer.PayloadBuffer[0].m_Size){};
846 }
847 Memory::Write_U32(0, _CommandAddress + 0x4);
848
849 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"
, 849, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x (buffer size: %i)"
, (u32)(TitleID >> 32), (u32)TitleID, MaxCount); } } while
(0)
;
850 return true;
851 }
852 break;
853
854 case IOCTL_ES_ENCRYPT:
855 {
856 u32 keyIndex = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
857 u8* IV = Memory::GetPointer(Buffer.InBuffer[1].m_Address);
858 u8* source = Memory::GetPointer(Buffer.InBuffer[2].m_Address);
859 u32 size = Buffer.InBuffer[2].m_Size;
860 u8* newIV = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
861 u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address);
862
863 AES_KEY AESKey;
864 AES_set_encrypt_key(keyTable[keyIndex], 128, &AESKey);
865 memcpy(newIV, IV, 16);
866 AES_cbc_encrypt(source, destination, size, &AESKey, newIV, AES_ENCRYPT1);
867
868 _dbg_assert_msg_(WII_IPC_ES, keyIndex == 6, "IOCTL_ES_ENCRYPT: Key type is not SD, data will be crap"){};
869 }
870 break;
871
872 case IOCTL_ES_DECRYPT:
873 {
874 u32 keyIndex = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
875 u8* IV = Memory::GetPointer(Buffer.InBuffer[1].m_Address);
876 u8* source = Memory::GetPointer(Buffer.InBuffer[2].m_Address);
877 u32 size = Buffer.InBuffer[2].m_Size;
878 u8* newIV = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
879 u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address);
880
881 AES_KEY AESKey;
882 AES_set_decrypt_key(keyTable[keyIndex], 128, &AESKey);
883 memcpy(newIV, IV, 16);
884 AES_cbc_encrypt(source, destination, size, &AESKey, newIV, AES_DECRYPT0);
885
886 _dbg_assert_msg_(WII_IPC_ES, keyIndex == 6, "IOCTL_ES_DECRYPT: Key type is not SD, data will be crap"){};
887 }
888 break;
889
890
891 case IOCTL_ES_LAUNCH:
892 {
893 _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 2){};
894 bool bSuccess = false;
895 u16 IOSv = 0xffff;
896
897 u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
898 u32 view = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
899 u64 ticketid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+4);
900 u32 devicetype = Memory::Read_U32(Buffer.InBuffer[1].m_Address+12);
901 u64 titleid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+16);
902 u16 access = Memory::Read_U16(Buffer.InBuffer[1].m_Address+24);
903
904
905 if ((u32)(TitleID>>32) != 0x00000001 || TitleID == TITLEID_SYSMENU0x0000000100000002ull)
906 {
907 const DiscIO::INANDContentLoader& ContentLoader = AccessContentDevice(TitleID);
908 if (ContentLoader.IsValid())
909 {
910 u32 bootInd = ContentLoader.GetBootIndex();
911 const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(bootInd);
912 if (pContent)
913 {
914 LoadWAD(Common::GetTitleContentPath(TitleID));
915 std::unique_ptr<CDolLoader> pDolLoader;
916 if (pContent->m_pData)
917 {
918 pDolLoader.reset(new CDolLoader(pContent->m_pData, pContent->m_Size));
919 }
920 else
921 {
922 pDolLoader.reset(new CDolLoader(pContent->m_Filename.c_str()));
923 }
924 pDolLoader->Load(); // TODO: Check why sysmenu does not load the DOL correctly
925 PCPowerPC::ppcState.pc = pDolLoader->GetEntryPoint() | 0x80000000;
926 IOSv = ContentLoader.GetIosVersion();
927 bSuccess = true;
928 }
929 }
930 }
931 else // IOS, MIOS, BC etc
932 {
933 //TODO: fixme
934 // The following is obviously a hack
935 // Lie to mem about loading a different IOS
936 // someone with an affected game should test
937 IOSv = TitleID & 0xffff;
938 bSuccess = true;
939 }
940 if (!bSuccess)
941 {
942 PanicAlertT("IOCTL_ES_LAUNCH: Game tried to reload a title that is not available in your NAND dump\n"MsgAlert(false, WARNING, "IOCTL_ES_LAUNCH: Game tried to reload a title that is not available in your NAND dump\n"
"TitleID %016llx.\n Dolphin will likely hang now.", TitleID)
943 "TitleID %016llx.\n Dolphin will likely hang now.", TitleID)MsgAlert(false, WARNING, "IOCTL_ES_LAUNCH: Game tried to reload a title that is not available in your NAND dump\n"
"TitleID %016llx.\n Dolphin will likely hang now.", TitleID)
;
944 }
945 else
946 {
947 CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer();
948 size_t size = s_Usb->m_WiiMotes.size();
949 bool* wiiMoteConnected = new bool[size];
950 for (unsigned int i = 0; i < size; i++)
951 wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected();
952
953 std::string tContentFile(m_ContentFile.c_str());
954
955 WII_IPC_HLE_Interface::Reset(true);
956 WII_IPC_HLE_Interface::Init();
957 s_Usb = GetUsbPointer();
958 for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++)
959 {
960 if (wiiMoteConnected[i])
961 {
962 s_Usb->m_WiiMotes[i].Activate(false);
963 s_Usb->m_WiiMotes[i].Activate(true);
964 }
965 else
966 {
967 s_Usb->m_WiiMotes[i].Activate(false);
968 }
969 }
970
971 delete[] wiiMoteConnected;
972 WII_IPC_HLE_Interface::SetDefaultContentFile(tContentFile);
973 }
974 // Pass the "#002 check"
975 // Apploader should write the IOS version and revision to 0x3140, and compare it
976 // to 0x3188 to pass the check, but we don't do it, and i don't know where to read the IOS rev...
977 // Currently we just write 0xFFFF for the revision, copy manually and it works fine :p
978 // TODO : figure it correctly : where should we read the IOS rev that the wad "needs" ?
979 Memory::Write_U16(IOSv, 0x00003140);
980 Memory::Write_U16(0xFFFF, 0x00003142);
981 Memory::Write_U32(Memory::Read_U32(0x00003140), 0x00003188);
982
983 //TODO: provide correct return code when bSuccess= false
984 Memory::Write_U32(0, _CommandAddress + 0x4);
985
986 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"
, 986, "IOCTL_ES_LAUNCH %016llx %08x %016llx %08x %016llx %04x"
, TitleID,view,ticketid,devicetype,titleid,access); } } while
(0)
;
987 // IOCTL_ES_LAUNCH 0001000248414341 00000001 0001c0fef3df2cfa 00000000 0001000248414341 ffff
988
989 // This is necessary because Reset(true) above deleted this object. Ew.
990
991 // It seems that the original hardware overwrites the command after it has been
992 // executed. We write 8 which is not any valid command, and what IOS does
993 Memory::Write_U32(8, _CommandAddress);
994 // IOS seems to write back the command that was responded to
995 Memory::Write_U32(7, _CommandAddress + 8);
996
997 // Generate a reply to the IPC command
998 WII_IPC_HLE_Interface::EnqReply(_CommandAddress, 0);
999
1000 return false;
1001 }
1002 break;
1003
1004 case IOCTL_ES_CHECKKOREAREGION: //note by DacoTaco : name is unknown, i just tried to name it SOMETHING
1005 //IOS70 has this to let system menu 4.2 check if the console is region changed. it returns -1017
1006 //if the IOS didn't find the Korean keys and 0 if it does. 0 leads to a error 003
1007 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"
, 1007, "IOCTL_ES_CHECKKOREAREGION: Title checked for Korean keys."
); } } while (0)
;
1008 Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT , _CommandAddress + 0x4);
1009 return true;
1010
1011 case IOCTL_ES_GETDEVICECERT: // (Input: none, Output: 384 bytes)
1012 {
1013 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"
, 1013, "IOCTL_ES_GETDEVICECERT"); } } while (0)
;
1014 _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1){};
1015 u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
1016
1017 EcWii &ec = EcWii::GetInstance();
1018 get_ng_cert(destination, ec.getNgId(), ec.getNgKeyId(), ec.getNgPriv(), ec.getNgSig());
1019 }
1020 break;
1021
1022 case IOCTL_ES_SIGN:
1023 {
1024 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"
, 1024, "IOCTL_ES_SIGN"); } } while (0)
;
1025 u8 *ap_cert_out = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address);
1026 u8 *data = Memory::GetPointer(Buffer.InBuffer[0].m_Address);
1027 u32 data_size = Buffer.InBuffer[0].m_Size;
1028 u8 *sig_out = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
1029
1030 EcWii &ec = EcWii::GetInstance();
1031 get_ap_sig_and_cert(sig_out, ap_cert_out, m_TitleID, data, data_size, ec.getNgPriv(), ec.getNgId());
1032 }
1033 break;
1034
1035 case IOCTL_ES_GETBOOT2VERSION:
1036 {
1037 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"
, 1037, "IOCTL_ES_GETBOOT2VERSION"); } } while (0)
;
1038
1039 Memory::Write_U32(4, Buffer.PayloadBuffer[0].m_Address); // as of 26/02/2012, this was latest bootmii version
1040 }
1041 break;
1042
1043 // ===============================================================================================
1044 // unsupported functions
1045 // ===============================================================================================
1046 case IOCTL_ES_DIGETTICKETVIEW: // (Input: none, Output: 216 bytes) bug crediar :D
1047 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"
, 1047, "IOCTL_ES_DIGETTICKETVIEW: this looks really wrong..."
); } } while (0)
;
1048 break;
1049
1050 case IOCTL_ES_GETOWNEDTITLECNT:
1051 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"
, 1051, "IOCTL_ES_GETOWNEDTITLECNT"); } } while (0)
;
1052 Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address);
1053 break;
1054
1055 default:
1056 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"
, 1056, "CWII_IPC_HLE_Device_es: 0x%x", Buffer.Parameter); } }
while (0)
;
1057 DumpCommands(_CommandAddress, 8, LogTypes::WII_IPC_ES);
1058 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"
, 1058, "command.Parameter: 0x%08x", Buffer.Parameter); } } while
(0)
;
1059 break;
1060 }
1061
1062 // Write return value (0 means OK)
1063 Memory::Write_U32(0, _CommandAddress + 0x4);
1064
1065 return true;
1066}
1067
1068const DiscIO::INANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice(u64 _TitleID)
1069{
1070 if (m_pContentLoader->IsValid() && m_pContentLoader->GetTitleID() == _TitleID)
1071 return *m_pContentLoader;
1072
1073 CTitleToContentMap::iterator itr = m_NANDContent.find(_TitleID);
1074 if (itr != m_NANDContent.end())
1075 return *itr->second;
1076
1077 m_NANDContent[_TitleID] = &DiscIO::CNANDContentManager::Access().GetNANDLoader(_TitleID);
1078
1079 _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){};
1080 return *m_NANDContent[_TitleID];
1081}
1082
1083bool CWII_IPC_HLE_Device_es::IsValid(u64 _TitleID) const
1084{
1085 if (m_pContentLoader->IsValid() && m_pContentLoader->GetTitleID() == _TitleID)
1086 return true;
1087
1088 return false;
1089}
1090
1091
1092u32 CWII_IPC_HLE_Device_es::ES_DIVerify(u8* _pTMD, u32 _sz)
1093{
1094 u64 titleID = 0xDEADBEEFDEADBEEFull;
1095 u64 tmdTitleID = Common::swap64(*(u64*)(_pTMD+0x18c));
1096 VolumeHandler::GetVolume()->GetTitleID((u8*)&titleID);
1097 if (Common::swap64(titleID) != tmdTitleID)
1098 {
1099 return -1;
1100 }
1101 std::string tmdPath = Common::GetTMDFileName(tmdTitleID);
1102
1103 File::CreateFullPath(tmdPath);
1104 File::CreateFullPath(Common::GetTitleDataPath(tmdTitleID));
1105
1106 Movie::g_titleID = tmdTitleID;
1107 std::string savePath = Common::GetTitleDataPath(tmdTitleID);
1108 if (Movie::IsRecordingInput())
1109 {
1110 // TODO: Check for the actual save data
1111 if (File::Exists((savePath + "banner.bin").c_str()))
1112 Movie::g_bClearSave = false;
1113 else
1114 Movie::g_bClearSave = true;
1115 }
1116
1117 // TODO: Force the game to save to another location, instead of moving the user's save.
1118 if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsStartingFromClearSave())
1119 {
1120 if (File::Exists((savePath + "banner.bin").c_str()))
1121 {
1122 if (File::Exists((savePath + "../backup/").c_str()))
1123 {
1124 // The last run of this game must have been to play back a movie, so their save is already backed up.
1125 File::DeleteDirRecursively(savePath.c_str());
1126 }
1127 else
1128 {
1129 #ifdef _WIN32
1130 MoveFile(UTF8ToTStr(savePath).c_str(), UTF8ToTStr(savePath + "../backup/").c_str());
1131 #else
1132 File::CopyDir(savePath.c_str(),(savePath + "../backup/").c_str());
1133 File::DeleteDirRecursively(savePath.c_str());
1134 #endif
1135 }
1136 }
1137 }
1138 else if (File::Exists((savePath + "../backup/").c_str()))
1139 {
1140 // Delete the save made by a previous movie, and copy back the user's save.
1141 if (File::Exists((savePath + "banner.bin").c_str()))
1142 File::DeleteDirRecursively(savePath);
1143 #ifdef _WIN32
1144 MoveFile(UTF8ToTStr(savePath + "../backup/").c_str(), UTF8ToTStr(savePath).c_str());
1145 #else
1146 File::CopyDir((savePath + "../backup/").c_str(), savePath.c_str());
1147 File::DeleteDirRecursively((savePath + "../backup/").c_str());
1148 #endif
1149 }
1150
1151 if(!File::Exists(tmdPath))
1152 {
1153 File::IOFile _pTMDFile(tmdPath, "wb");
1154 if (!_pTMDFile.WriteBytes(_pTMD, _sz))
1155 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"
, 1155, "DIVerify failed to write disc TMD to NAND."); } } while
(0)
;
1156 }
1157 DiscIO::cUIDsys::AccessInstance().AddTitle(tmdTitleID);
1158 return 0;
1159}