1
// Copyright 2013 Dolphin Emulator Project
2
// Licensed under GPLv2
3
// Refer to the license.txt file included.
6
This is the main Wii IPC file that handles all incoming IPC calls and directs them
9
IPC basics (IOS' usage):
11
Return values for file handles: All IPC calls will generate a return value to 0x04,
12
in case of success they are
18
Ioctl: 0 (in addition to that there may be messages to the out buffers)
19
Ioctlv: 0 (in addition to that there may be messages to the out buffers)
20
They will also generate a true or false return for UpdateInterrupts() in WII_IPC.cpp.
28
#include "CommonPaths.h"
30
#include "WII_IPC_HLE.h"
31
#include "WII_IPC_HLE_Device.h"
32
#include "WII_IPC_HLE_Device_DI.h"
33
#include "WII_IPC_HLE_Device_FileIO.h"
34
#include "WII_IPC_HLE_Device_stm.h"
35
#include "WII_IPC_HLE_Device_fs.h"
36
#include "WII_IPC_HLE_Device_net.h"
37
#include "WII_IPC_HLE_Device_net_ssl.h"
38
#include "WII_IPC_HLE_Device_es.h"
39
#include "WII_IPC_HLE_Device_usb.h"
40
#include "WII_IPC_HLE_Device_usb_kbd.h"
41
#include "WII_IPC_HLE_Device_sdio_slot0.h"
43
#if defined(__LIBUSB__) || defined (_WIN32)
44
#include "WII_IPC_HLE_Device_hid.h"
47
#include "FileUtil.h" // For Copy
48
#include "../ConfigManager.h"
49
#include "../HW/CPU.h"
50
#include "../HW/Memmap.h"
51
#include "../HW/WII_IPC.h"
52
#include "../Debugger/Debugger_SymbolMap.h"
53
#include "../PowerPC/PowerPC.h"
54
#include "../HW/SystemTimers.h"
55
#include "CoreTiming.h"
58
namespace WII_IPC_HLE_Interface
61
typedef std::map<u32, IWII_IPC_HLE_Device*> TDeviceMap;
62
TDeviceMap g_DeviceMap;
65
typedef std::map<u32, std::string> TFileNameMap;
67
#define IPC_MAX_FDS 0x18
68
#define ES_MAX_COUNT 2
69
IWII_IPC_HLE_Device* g_FdMap[IPC_MAX_FDS];
70
bool es_inuse[ES_MAX_COUNT];
71
IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT];
74
typedef std::deque<u32> ipc_msg_queue;
75
static ipc_msg_queue request_queue; // ppc -> arm
76
static ipc_msg_queue reply_queue; // arm -> ppc
77
static std::mutex s_reply_queue;
79
static int enque_reply;
81
static u64 last_reply_time;
83
void EnqueReplyCallback(u64 userdata, int)
85
std::lock_guard<std::mutex> lk(s_reply_queue);
86
reply_queue.push_back(userdata);
92
_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init");
93
CWII_IPC_HLE_Device_es::m_ContentFile = "";
95
for (i=0; i<IPC_MAX_FDS; i++)
101
// Build hardware devices
102
g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_oh1_57e_305(i, std::string("/dev/usb/oh1/57e/305")); i++;
103
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_immediate(i, std::string("/dev/stm/immediate")); i++;
104
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_eventhook(i, std::string("/dev/stm/eventhook")); i++;
105
g_DeviceMap[i] = new CWII_IPC_HLE_Device_fs(i, std::string("/dev/fs")); i++;
107
// IOS allows two ES devices at a time<
109
for (j=0; j<ES_MAX_COUNT; j++)
111
g_DeviceMap[i] = es_handles[j] = new CWII_IPC_HLE_Device_es(i, std::string("/dev/es")); i++;
115
g_DeviceMap[i] = new CWII_IPC_HLE_Device_di(i, std::string("/dev/di")); i++;
116
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_request(i, std::string("/dev/net/kd/request")); i++;
117
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_time(i, std::string("/dev/net/kd/time")); i++;
118
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ncd_manage(i, std::string("/dev/net/ncd/manage")); i++;
119
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_wd_command(i, std::string("/dev/net/wd/command")); i++;
120
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ip_top(i, std::string("/dev/net/ip/top")); i++;
121
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ssl(i, std::string("/dev/net/ssl")); i++;
122
g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_kbd(i, std::string("/dev/usb/kbd")); i++;
123
g_DeviceMap[i] = new CWII_IPC_HLE_Device_sdio_slot0(i, std::string("/dev/sdio/slot0")); i++;
124
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/sdio/slot1")); i++;
125
#if defined(__LIBUSB__) || defined(_WIN32)
126
g_DeviceMap[i] = new CWII_IPC_HLE_Device_hid(i, std::string("/dev/usb/hid")); i++;
128
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/hid")); i++;
130
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/oh1")); i++;
131
g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, std::string("_Unimplemented_Device_")); i++;
133
enque_reply = CoreTiming::RegisterEvent("IPCReply", EnqueReplyCallback);
136
void Reset(bool _bHard)
138
CoreTiming::RemoveAllEvents(enque_reply);
141
for (i=0; i<IPC_MAX_FDS; i++)
143
if (g_FdMap[i] != NULL && !g_FdMap[i]->IsHardware())
145
// close all files and delete their resources
146
g_FdMap[i]->Close(0, true);
153
for (j=0; j<ES_MAX_COUNT; j++)
158
TDeviceMap::iterator itr = g_DeviceMap.begin();
159
while (itr != g_DeviceMap.end())
164
itr->second->Close(0, true);
165
// Hardware should not be deleted unless it is a hard reset
173
g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end());
175
request_queue.clear();
177
// lock due to using reply_queue
179
std::lock_guard<std::mutex> lk(s_reply_queue);
190
void SetDefaultContentFile(const std::string& _rFilename)
192
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
193
while (itr != g_DeviceMap.end())
195
if (itr->second && itr->second->GetDeviceName().find(std::string("/dev/es")) == 0)
197
((CWII_IPC_HLE_Device_es*)itr->second)->LoadWAD(_rFilename);
203
void ES_DIVerify(u8 *_pTMD, u32 _sz)
205
CWII_IPC_HLE_Device_es::ES_DIVerify(_pTMD, _sz);
208
void SDIO_EventNotify()
210
CWII_IPC_HLE_Device_sdio_slot0 *pDevice =
211
(CWII_IPC_HLE_Device_sdio_slot0*)GetDeviceByName(std::string("/dev/sdio/slot0"));
213
pDevice->EventNotify();
215
int getFreeDeviceId()
218
for (i=0; i<IPC_MAX_FDS; i++)
220
if (g_FdMap[i] == NULL)
228
IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName)
230
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
231
while (itr != g_DeviceMap.end())
233
if (itr->second && itr->second->GetDeviceName() == _rDeviceName)
241
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
243
if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
244
return g_DeviceMap[_ID];
249
// This is called from ExecuteCommand() COMMAND_OPEN_DEVICE
250
IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName)
252
// scan device name and create the right one
253
IWII_IPC_HLE_Device* pDevice = NULL;
255
INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", _rDeviceName.c_str());
256
pDevice = new CWII_IPC_HLE_Device_FileIO(_DeviceID, _rDeviceName);
262
void DoState(PointerWrap &p)
264
std::lock_guard<std::mutex> lk(s_reply_queue);
268
p.Do(last_reply_time);
270
TDeviceMap::const_iterator itr;
272
itr = g_DeviceMap.begin();
273
while (itr != g_DeviceMap.end())
275
if (itr->second->IsHardware())
277
itr->second->DoState(p);
282
if (p.GetMode() == PointerWrap::MODE_READ)
285
for (i=0; i<IPC_MAX_FDS; i++)
297
g_FdMap[i] = AccessDeviceByID(hwId);
301
g_FdMap[i] = new CWII_IPC_HLE_Device_FileIO(i, "");
302
g_FdMap[i]->DoState(p);
310
for (i=0; i<ES_MAX_COUNT; i++)
313
u32 handleID = es_handles[i]->GetDeviceID();
316
es_handles[i] = AccessDeviceByID(handleID);
322
for (i=0; i<IPC_MAX_FDS; i++)
324
u32 exists = g_FdMap[i] ? 1 : 0;
328
u32 isHw = g_FdMap[i]->IsHardware() ? 1 : 0;
332
u32 hwId = g_FdMap[i]->GetDeviceID();
337
g_FdMap[i]->DoState(p);
341
for (i=0; i<ES_MAX_COUNT; i++)
344
u32 handleID = es_handles[i]->GetDeviceID();
350
void ExecuteCommand(u32 _Address)
352
bool CmdSuccess = false;
354
ECommandType Command = static_cast<ECommandType>(Memory::Read_U32(_Address));
355
volatile s32 DeviceID = Memory::Read_U32(_Address + 8);
357
IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : NULL;
359
INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice);
363
case COMMAND_OPEN_DEVICE:
365
u32 Mode = Memory::Read_U32(_Address + 0x10);
366
DeviceID = getFreeDeviceId();
368
std::string DeviceName;
369
Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
372
WARN_LOG(WII_IPC_HLE, "Trying to open %s as %d", DeviceName.c_str(), DeviceID);
375
if (DeviceName.find("/dev/es") == 0)
378
for (j=0; j<ES_MAX_COUNT; j++)
383
g_FdMap[DeviceID] = es_handles[j];
384
CmdSuccess = es_handles[j]->Open(_Address, Mode);
385
Memory::Write_U32(DeviceID, _Address+4);
389
if (j == ES_MAX_COUNT)
391
Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4);
396
else if (DeviceName.find("/dev/") == 0)
398
pDevice = GetDeviceByName(DeviceName);
401
g_FdMap[DeviceID] = pDevice;
402
CmdSuccess = pDevice->Open(_Address, Mode);
403
INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
404
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
405
Memory::Write_U32(DeviceID, _Address+4);
409
WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str());
410
Memory::Write_U32(FS_ENOENT, _Address+4);
416
pDevice = CreateFileIO(DeviceID, DeviceName);
417
CmdSuccess = pDevice->Open(_Address, Mode);
419
INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
420
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
421
if (Memory::Read_U32(_Address + 4) == (u32)DeviceID)
423
g_FdMap[DeviceID] = pDevice;
435
Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4);
440
case COMMAND_CLOSE_DEVICE:
444
CmdSuccess = pDevice->Close(_Address);
447
for (j=0; j<ES_MAX_COUNT; j++)
449
if (es_handles[j] == g_FdMap[DeviceID])
455
g_FdMap[DeviceID] = NULL;
457
// Don't delete hardware
458
if (!pDevice->IsHardware())
466
Memory::Write_U32(FS_EINVAL, _Address + 4);
475
CmdSuccess = pDevice->Read(_Address);
479
Memory::Write_U32(FS_EINVAL, _Address + 4);
488
CmdSuccess = pDevice->Write(_Address);
492
Memory::Write_U32(FS_EINVAL, _Address + 4);
501
CmdSuccess = pDevice->Seek(_Address);
505
Memory::Write_U32(FS_EINVAL, _Address + 4);
514
CmdSuccess = pDevice->IOCtl(_Address);
522
CmdSuccess = pDevice->IOCtlV(_Address);
528
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address);
536
// It seems that the original hardware overwrites the command after it has been
537
// executed. We write 8 which is not any valid command, and what IOS does
538
Memory::Write_U32(8, _Address);
539
// IOS seems to write back the command that was responded to
540
Memory::Write_U32(Command, _Address + 8);
542
// Ensure replies happen in order, fairly ugly
543
// Without this, tons of games fail now that DI commands have different reply delays
544
int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0;
546
const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks();
548
if (ticks_til_last_reply > 0)
549
reply_delay = ticks_til_last_reply;
551
last_reply_time = CoreTiming::GetTicks() + reply_delay;
553
// Generate a reply to the IPC command
554
EnqReply(_Address, reply_delay);
558
// Happens AS SOON AS IPC gets a new pointer!
559
void EnqRequest(u32 _Address)
561
request_queue.push_back(_Address);
564
// Called when IOS module has some reply
565
void EnqReply(u32 _Address, int cycles_in_future)
567
CoreTiming::ScheduleEvent(cycles_in_future, enque_reply, _Address);
570
// This is called every IPC_HLE_PERIOD from SystemTimers.cpp
571
// Takes care of routing ipc <-> ipc HLE
574
if (!WII_IPCInterface::IsReady())
579
if (request_queue.size())
581
WII_IPCInterface::GenerateAck(request_queue.front());
582
INFO_LOG(WII_IPC_HLE, "||-- Acknowledge IPC Request @ 0x%08x", request_queue.front());
583
u32 command = request_queue.front();
584
request_queue.pop_front();
585
ExecuteCommand(command);
587
#if MAX_LOGLEVEL >= DEBUG_LEVEL
588
Dolphin_Debugger::PrintCallstack(LogTypes::WII_IPC_HLE, LogTypes::LDEBUG);
592
// lock due to using reply_queue
594
std::lock_guard<std::mutex> lk(s_reply_queue);
595
if (reply_queue.size())
597
WII_IPCInterface::GenerateReply(reply_queue.front());
598
INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front());
599
reply_queue.pop_front();
606
// Check if a hardware device must be updated
607
for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != g_DeviceMap.end(); ++itr)
609
if (itr->second->IsOpened() && itr->second->Update())
617
} // end of namespace WII_IPC_HLE_Interface
619
// TODO: create WII_IPC_HLE_Device.cpp ?
620
void IWII_IPC_HLE_Device::DoStateShared(PointerWrap& p)