Bug Summary

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