PageRenderTime 55ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp

https://github.com/bunnei/dolphin
C++ | 626 lines | 496 code | 82 blank | 48 comment | 72 complexity | 42b19d22f279dec6b8fd604fb632aa5c MD5 | raw file
Possible License(s): GPL-2.0
  1. // Copyright 2013 Dolphin Emulator Project
  2. // Licensed under GPLv2
  3. // Refer to the license.txt file included.
  4. /*
  5. This is the main Wii IPC file that handles all incoming IPC calls and directs them
  6. to the right function.
  7. IPC basics (IOS' usage):
  8. Return values for file handles: All IPC calls will generate a return value to 0x04,
  9. in case of success they are
  10. Open: DeviceID
  11. Close: 0
  12. Read: Bytes read
  13. Write: Bytes written
  14. Seek: Seek position
  15. Ioctl: 0 (in addition to that there may be messages to the out buffers)
  16. Ioctlv: 0 (in addition to that there may be messages to the out buffers)
  17. They will also generate a true or false return for UpdateInterrupts() in WII_IPC.cpp.
  18. */
  19. #include <list>
  20. #include <map>
  21. #include <string>
  22. #include "Common/Common.h"
  23. #include "Common/CommonPaths.h"
  24. #include "Common/FileUtil.h"
  25. #include "Common/Thread.h"
  26. #include "Core/ConfigManager.h"
  27. #include "Core/CoreTiming.h"
  28. #include "Core/Debugger/Debugger_SymbolMap.h"
  29. #include "Core/HW/CPU.h"
  30. #include "Core/HW/Memmap.h"
  31. #include "Core/HW/SystemTimers.h"
  32. #include "Core/HW/WII_IPC.h"
  33. #include "Core/IPC_HLE/WII_IPC_HLE.h"
  34. #include "Core/IPC_HLE/WII_IPC_HLE_Device.h"
  35. #include "Core/IPC_HLE/WII_IPC_HLE_Device_DI.h"
  36. #include "Core/IPC_HLE/WII_IPC_HLE_Device_es.h"
  37. #include "Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h"
  38. #include "Core/IPC_HLE/WII_IPC_HLE_Device_fs.h"
  39. #include "Core/IPC_HLE/WII_IPC_HLE_Device_net.h"
  40. #include "Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.h"
  41. #include "Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h"
  42. #include "Core/IPC_HLE/WII_IPC_HLE_Device_stm.h"
  43. #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h"
  44. #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.h"
  45. #if defined(__LIBUSB__) || defined (_WIN32)
  46. #include "Core/IPC_HLE/WII_IPC_HLE_Device_hid.h"
  47. #endif
  48. #include "Core/PowerPC/PowerPC.h"
  49. namespace WII_IPC_HLE_Interface
  50. {
  51. typedef std::map<u32, IWII_IPC_HLE_Device*> TDeviceMap;
  52. TDeviceMap g_DeviceMap;
  53. // STATE_TO_SAVE
  54. typedef std::map<u32, std::string> TFileNameMap;
  55. #define IPC_MAX_FDS 0x18
  56. #define ES_MAX_COUNT 2
  57. IWII_IPC_HLE_Device* g_FdMap[IPC_MAX_FDS];
  58. bool es_inuse[ES_MAX_COUNT];
  59. IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT];
  60. typedef std::deque<u32> ipc_msg_queue;
  61. static ipc_msg_queue request_queue; // ppc -> arm
  62. static ipc_msg_queue reply_queue; // arm -> ppc
  63. static std::mutex s_reply_queue;
  64. static int enque_reply;
  65. static u64 last_reply_time;
  66. // NOTE: Only call this if you have correctly handled
  67. // CommandAddress+0 and CommandAddress+8.
  68. // Please search for examples of this being called elsewhere.
  69. void EnqueReplyCallback(u64 userdata, int)
  70. {
  71. std::lock_guard<std::mutex> lk(s_reply_queue);
  72. reply_queue.push_back((u32)userdata);
  73. }
  74. void Init()
  75. {
  76. _dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init");
  77. CWII_IPC_HLE_Device_es::m_ContentFile = "";
  78. for (IWII_IPC_HLE_Device*& dev : g_FdMap)
  79. {
  80. dev = nullptr;
  81. }
  82. u32 i = 0;
  83. // Build hardware devices
  84. g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_oh1_57e_305(i, "/dev/usb/oh1/57e/305"); i++;
  85. g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_immediate(i, "/dev/stm/immediate"); i++;
  86. g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_eventhook(i, "/dev/stm/eventhook"); i++;
  87. g_DeviceMap[i] = new CWII_IPC_HLE_Device_fs(i, "/dev/fs"); i++;
  88. // IOS allows two ES devices at a time
  89. for (u32 j=0; j<ES_MAX_COUNT; j++)
  90. {
  91. g_DeviceMap[i] = es_handles[j] = new CWII_IPC_HLE_Device_es(i, "/dev/es"); i++;
  92. es_inuse[j] = false;
  93. }
  94. g_DeviceMap[i] = new CWII_IPC_HLE_Device_di(i, std::string("/dev/di")); i++;
  95. g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_request(i, "/dev/net/kd/request"); i++;
  96. g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_time(i, "/dev/net/kd/time"); i++;
  97. g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ncd_manage(i, "/dev/net/ncd/manage"); i++;
  98. g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_wd_command(i, "/dev/net/wd/command"); i++;
  99. g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ip_top(i, "/dev/net/ip/top"); i++;
  100. g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ssl(i, "/dev/net/ssl"); i++;
  101. g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_kbd(i, "/dev/usb/kbd"); i++;
  102. g_DeviceMap[i] = new CWII_IPC_HLE_Device_sdio_slot0(i, "/dev/sdio/slot0"); i++;
  103. g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, "/dev/sdio/slot1"); i++;
  104. #if defined(__LIBUSB__) || defined(_WIN32)
  105. g_DeviceMap[i] = new CWII_IPC_HLE_Device_hid(i, "/dev/usb/hid"); i++;
  106. #else
  107. g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, "/dev/usb/hid"); i++;
  108. #endif
  109. g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, "/dev/usb/oh1"); i++;
  110. g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, "_Unimplemented_Device_"); i++;
  111. enque_reply = CoreTiming::RegisterEvent("IPCReply", EnqueReplyCallback);
  112. }
  113. void Reset(bool _bHard)
  114. {
  115. CoreTiming::RemoveAllEvents(enque_reply);
  116. for (IWII_IPC_HLE_Device*& dev : g_FdMap)
  117. {
  118. if (dev != nullptr && !dev->IsHardware())
  119. {
  120. // close all files and delete their resources
  121. dev->Close(0, true);
  122. delete dev;
  123. }
  124. dev = nullptr;
  125. }
  126. for (bool& in_use : es_inuse)
  127. {
  128. in_use = false;
  129. }
  130. for (const auto& entry : g_DeviceMap)
  131. {
  132. if (entry.second)
  133. {
  134. // Force close
  135. entry.second->Close(0, true);
  136. // Hardware should not be deleted unless it is a hard reset
  137. if (_bHard)
  138. delete entry.second;
  139. }
  140. }
  141. if (_bHard)
  142. {
  143. g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end());
  144. }
  145. request_queue.clear();
  146. // lock due to using reply_queue
  147. {
  148. std::lock_guard<std::mutex> lk(s_reply_queue);
  149. reply_queue.clear();
  150. }
  151. last_reply_time = 0;
  152. }
  153. void Shutdown()
  154. {
  155. Reset(true);
  156. }
  157. void SetDefaultContentFile(const std::string& _rFilename)
  158. {
  159. for (const auto& entry : g_DeviceMap)
  160. {
  161. if (entry.second && entry.second->GetDeviceName().find("/dev/es") == 0)
  162. {
  163. ((CWII_IPC_HLE_Device_es*)entry.second)->LoadWAD(_rFilename);
  164. }
  165. }
  166. }
  167. void ES_DIVerify(u8 *_pTMD, u32 _sz)
  168. {
  169. CWII_IPC_HLE_Device_es::ES_DIVerify(_pTMD, _sz);
  170. }
  171. void SDIO_EventNotify()
  172. {
  173. CWII_IPC_HLE_Device_sdio_slot0 *pDevice =
  174. (CWII_IPC_HLE_Device_sdio_slot0*)GetDeviceByName("/dev/sdio/slot0");
  175. if (pDevice)
  176. pDevice->EventNotify();
  177. }
  178. int getFreeDeviceId()
  179. {
  180. for (u32 i=0; i<IPC_MAX_FDS; i++)
  181. {
  182. if (g_FdMap[i] == nullptr)
  183. {
  184. return i;
  185. }
  186. }
  187. return -1;
  188. }
  189. IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName)
  190. {
  191. for (const auto& entry : g_DeviceMap)
  192. {
  193. if (entry.second && entry.second->GetDeviceName() == _rDeviceName)
  194. {
  195. return entry.second;
  196. }
  197. }
  198. return nullptr;
  199. }
  200. IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
  201. {
  202. if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
  203. {
  204. return g_DeviceMap[_ID];
  205. }
  206. return nullptr;
  207. }
  208. // This is called from ExecuteCommand() COMMAND_OPEN_DEVICE
  209. IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName)
  210. {
  211. // scan device name and create the right one
  212. IWII_IPC_HLE_Device* pDevice = nullptr;
  213. INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", _rDeviceName.c_str());
  214. pDevice = new CWII_IPC_HLE_Device_FileIO(_DeviceID, _rDeviceName);
  215. return pDevice;
  216. }
  217. void DoState(PointerWrap &p)
  218. {
  219. std::lock_guard<std::mutex> lk(s_reply_queue);
  220. p.Do(request_queue);
  221. p.Do(reply_queue);
  222. p.Do(last_reply_time);
  223. for (const auto& entry : g_DeviceMap)
  224. {
  225. if (entry.second->IsHardware())
  226. {
  227. entry.second->DoState(p);
  228. }
  229. }
  230. if (p.GetMode() == PointerWrap::MODE_READ)
  231. {
  232. for (u32 i=0; i<IPC_MAX_FDS; i++)
  233. {
  234. u32 exists = 0;
  235. p.Do(exists);
  236. if (exists)
  237. {
  238. u32 isHw = 0;
  239. p.Do(isHw);
  240. if (isHw)
  241. {
  242. u32 hwId = 0;
  243. p.Do(hwId);
  244. g_FdMap[i] = AccessDeviceByID(hwId);
  245. }
  246. else
  247. {
  248. g_FdMap[i] = new CWII_IPC_HLE_Device_FileIO(i, "");
  249. g_FdMap[i]->DoState(p);
  250. }
  251. }
  252. else
  253. {
  254. g_FdMap[i] = nullptr;
  255. }
  256. }
  257. for (u32 i=0; i<ES_MAX_COUNT; i++)
  258. {
  259. p.Do(es_inuse[i]);
  260. u32 handleID = es_handles[i]->GetDeviceID();
  261. p.Do(handleID);
  262. es_handles[i] = AccessDeviceByID(handleID);
  263. }
  264. }
  265. else
  266. {
  267. for (IWII_IPC_HLE_Device*& dev : g_FdMap)
  268. {
  269. u32 exists = dev ? 1 : 0;
  270. p.Do(exists);
  271. if (exists)
  272. {
  273. u32 isHw = dev->IsHardware() ? 1 : 0;
  274. p.Do(isHw);
  275. if (isHw)
  276. {
  277. u32 hwId = dev->GetDeviceID();
  278. p.Do(hwId);
  279. }
  280. else
  281. {
  282. dev->DoState(p);
  283. }
  284. }
  285. }
  286. for (u32 i=0; i<ES_MAX_COUNT; i++)
  287. {
  288. p.Do(es_inuse[i]);
  289. u32 handleID = es_handles[i]->GetDeviceID();
  290. p.Do(handleID);
  291. }
  292. }
  293. }
  294. void ExecuteCommand(u32 _Address)
  295. {
  296. bool CmdSuccess = false;
  297. IPCCommandType Command = static_cast<IPCCommandType>(Memory::Read_U32(_Address));
  298. volatile s32 DeviceID = Memory::Read_U32(_Address + 8);
  299. IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : nullptr;
  300. INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice);
  301. switch (Command)
  302. {
  303. case IPC_CMD_OPEN:
  304. {
  305. u32 Mode = Memory::Read_U32(_Address + 0x10);
  306. DeviceID = getFreeDeviceId();
  307. std::string DeviceName;
  308. Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
  309. WARN_LOG(WII_IPC_HLE, "Trying to open %s as %d", DeviceName.c_str(), DeviceID);
  310. if (DeviceID >= 0)
  311. {
  312. if (DeviceName.find("/dev/es") == 0)
  313. {
  314. u32 j;
  315. for (j=0; j<ES_MAX_COUNT; j++)
  316. {
  317. if (!es_inuse[j])
  318. {
  319. es_inuse[j] = true;
  320. g_FdMap[DeviceID] = es_handles[j];
  321. CmdSuccess = es_handles[j]->Open(_Address, Mode);
  322. Memory::Write_U32(DeviceID, _Address+4);
  323. break;
  324. }
  325. }
  326. if (j == ES_MAX_COUNT)
  327. {
  328. Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4);
  329. CmdSuccess = true;
  330. }
  331. }
  332. else if (DeviceName.find("/dev/") == 0)
  333. {
  334. pDevice = GetDeviceByName(DeviceName);
  335. if (pDevice)
  336. {
  337. g_FdMap[DeviceID] = pDevice;
  338. CmdSuccess = pDevice->Open(_Address, Mode);
  339. INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
  340. pDevice->GetDeviceName().c_str(), DeviceID, Mode);
  341. Memory::Write_U32(DeviceID, _Address+4);
  342. }
  343. else
  344. {
  345. WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str());
  346. Memory::Write_U32(FS_ENOENT, _Address+4);
  347. CmdSuccess = true;
  348. }
  349. }
  350. else
  351. {
  352. pDevice = CreateFileIO(DeviceID, DeviceName);
  353. CmdSuccess = pDevice->Open(_Address, Mode);
  354. INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
  355. pDevice->GetDeviceName().c_str(), DeviceID, Mode);
  356. if (Memory::Read_U32(_Address + 4) == (u32)DeviceID)
  357. {
  358. g_FdMap[DeviceID] = pDevice;
  359. }
  360. else
  361. {
  362. delete pDevice;
  363. pDevice = nullptr;
  364. }
  365. }
  366. }
  367. else
  368. {
  369. Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4);
  370. CmdSuccess = true;
  371. }
  372. break;
  373. }
  374. case IPC_CMD_CLOSE:
  375. {
  376. if (pDevice)
  377. {
  378. CmdSuccess = pDevice->Close(_Address);
  379. for (u32 j=0; j<ES_MAX_COUNT; j++)
  380. {
  381. if (es_handles[j] == g_FdMap[DeviceID])
  382. {
  383. es_inuse[j] = false;
  384. }
  385. }
  386. g_FdMap[DeviceID] = nullptr;
  387. // Don't delete hardware
  388. if (!pDevice->IsHardware())
  389. {
  390. delete pDevice;
  391. pDevice = nullptr;
  392. }
  393. }
  394. else
  395. {
  396. Memory::Write_U32(FS_EINVAL, _Address + 4);
  397. CmdSuccess = true;
  398. }
  399. break;
  400. }
  401. case IPC_CMD_READ:
  402. {
  403. if (pDevice)
  404. {
  405. CmdSuccess = pDevice->Read(_Address);
  406. }
  407. else
  408. {
  409. Memory::Write_U32(FS_EINVAL, _Address + 4);
  410. CmdSuccess = true;
  411. }
  412. break;
  413. }
  414. case IPC_CMD_WRITE:
  415. {
  416. if (pDevice)
  417. {
  418. CmdSuccess = pDevice->Write(_Address);
  419. }
  420. else
  421. {
  422. Memory::Write_U32(FS_EINVAL, _Address + 4);
  423. CmdSuccess = true;
  424. }
  425. break;
  426. }
  427. case IPC_CMD_SEEK:
  428. {
  429. if (pDevice)
  430. {
  431. CmdSuccess = pDevice->Seek(_Address);
  432. }
  433. else
  434. {
  435. Memory::Write_U32(FS_EINVAL, _Address + 4);
  436. CmdSuccess = true;
  437. }
  438. break;
  439. }
  440. case IPC_CMD_IOCTL:
  441. {
  442. if (pDevice)
  443. {
  444. CmdSuccess = pDevice->IOCtl(_Address);
  445. }
  446. break;
  447. }
  448. case IPC_CMD_IOCTLV:
  449. {
  450. if (pDevice)
  451. {
  452. CmdSuccess = pDevice->IOCtlV(_Address);
  453. }
  454. break;
  455. }
  456. default:
  457. {
  458. _dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address);
  459. break;
  460. }
  461. }
  462. if (CmdSuccess)
  463. {
  464. // The original hardware overwrites the command type with the async reply type.
  465. Memory::Write_U32(IPC_REP_ASYNC, _Address);
  466. // IOS also seems to write back the command that was responded to in the FD field.
  467. Memory::Write_U32(Command, _Address + 8);
  468. // Ensure replies happen in order, fairly ugly
  469. // Without this, tons of games fail now that DI commands have different reply delays
  470. int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0;
  471. const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks();
  472. if (ticks_til_last_reply > 0)
  473. {
  474. reply_delay = (int)ticks_til_last_reply;
  475. }
  476. last_reply_time = CoreTiming::GetTicks() + reply_delay;
  477. // Generate a reply to the IPC command
  478. EnqReply(_Address, reply_delay);
  479. }
  480. }
  481. // Happens AS SOON AS IPC gets a new pointer!
  482. void EnqRequest(u32 _Address)
  483. {
  484. request_queue.push_back(_Address);
  485. }
  486. // Called when IOS module has some reply
  487. // NOTE: Only call this if you have correctly handled
  488. // CommandAddress+0 and CommandAddress+8.
  489. // Please search for examples of this being called elsewhere.
  490. void EnqReply(u32 _Address, int cycles_in_future)
  491. {
  492. CoreTiming::ScheduleEvent(cycles_in_future, enque_reply, _Address);
  493. }
  494. // This is called every IPC_HLE_PERIOD from SystemTimers.cpp
  495. // Takes care of routing ipc <-> ipc HLE
  496. void Update()
  497. {
  498. if (!WII_IPCInterface::IsReady())
  499. return;
  500. UpdateDevices();
  501. if (request_queue.size())
  502. {
  503. WII_IPCInterface::GenerateAck(request_queue.front());
  504. INFO_LOG(WII_IPC_HLE, "||-- Acknowledge IPC Request @ 0x%08x", request_queue.front());
  505. u32 command = request_queue.front();
  506. request_queue.pop_front();
  507. ExecuteCommand(command);
  508. #if MAX_LOGLEVEL >= DEBUG_LEVEL
  509. Dolphin_Debugger::PrintCallstack(LogTypes::WII_IPC_HLE, LogTypes::LDEBUG);
  510. #endif
  511. }
  512. // lock due to using reply_queue
  513. {
  514. std::lock_guard<std::mutex> lk(s_reply_queue);
  515. if (reply_queue.size())
  516. {
  517. WII_IPCInterface::GenerateReply(reply_queue.front());
  518. INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front());
  519. reply_queue.pop_front();
  520. }
  521. }
  522. }
  523. void UpdateDevices()
  524. {
  525. // Check if a hardware device must be updated
  526. for (const auto& entry : g_DeviceMap)
  527. {
  528. if (entry.second->IsOpened() && entry.second->Update())
  529. {
  530. break;
  531. }
  532. }
  533. }
  534. } // end of namespace WII_IPC_HLE_Interface
  535. // TODO: create WII_IPC_HLE_Device.cpp ?
  536. void IWII_IPC_HLE_Device::DoStateShared(PointerWrap& p)
  537. {
  538. p.Do(m_Name);
  539. p.Do(m_DeviceID);
  540. p.Do(m_Hardware);
  541. p.Do(m_Active);
  542. }