Merge pull request #4607 from leoetlino/execute

IOS HLE: Refactor ExecuteCommand
This commit is contained in:
Matthew Parlane 2017-01-08 11:20:49 +13:00 committed by GitHub
commit 7847ca41e2
3 changed files with 106 additions and 221 deletions

View File

@ -2,23 +2,19 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // Refer to the license.txt file included.
/* // This is the main Wii IPC file that handles all incoming IPC requests and directs them
This is the main Wii IPC file that handles all incoming IPC calls and directs them // to the right function.
to the right function. //
// IPC basics (IOS' usage):
IPC basics (IOS' usage): // All IPC request handlers will write a return value to 0x04.
// Open: Device file descriptor or error code
Return values for file handles: All IPC calls will generate a return value to 0x04, // Close: IPC_SUCCESS
in case of success they are // Read: Bytes read
Open: DeviceID // Write: Bytes written
Close: 0 // Seek: Seek position
Read: Bytes read // Ioctl: Depends on the handler
Write: Bytes written // Ioctlv: Depends on the handler
Seek: Seek position // Replies may be sent immediately or asynchronously for ioctls and ioctlvs.
Ioctl: 0 (in addition to that there may be messages to the out buffers)
Ioctlv: 0 (in addition to that there may be messages to the out buffers)
They will also generate a true or false return for UpdateInterrupts() in WII_IPC.cpp.
*/
#include <deque> #include <deque>
#include <map> #include <map>
@ -68,10 +64,9 @@ static std::map<u32, std::shared_ptr<IWII_IPC_HLE_Device>> s_device_map;
static std::mutex s_device_map_mutex; static std::mutex s_device_map_mutex;
// STATE_TO_SAVE // STATE_TO_SAVE
#define IPC_MAX_FDS 0x18 constexpr u8 IPC_MAX_FDS = 0x18;
#define ES_MAX_COUNT 2 constexpr u8 ES_MAX_COUNT = 2;
static std::shared_ptr<IWII_IPC_HLE_Device> s_fdmap[IPC_MAX_FDS]; static std::shared_ptr<IWII_IPC_HLE_Device> s_fdmap[IPC_MAX_FDS];
static bool s_es_inuse[ES_MAX_COUNT];
static std::shared_ptr<IWII_IPC_HLE_Device> s_es_handles[ES_MAX_COUNT]; static std::shared_ptr<IWII_IPC_HLE_Device> s_es_handles[ES_MAX_COUNT];
using IPCMsgQueue = std::deque<u32>; using IPCMsgQueue = std::deque<u32>;
@ -141,11 +136,8 @@ void Reinit()
AddDevice<CWII_IPC_HLE_Device_fs>("/dev/fs"); AddDevice<CWII_IPC_HLE_Device_fs>("/dev/fs");
// IOS allows two ES devices at a time // IOS allows two ES devices at a time
for (u32 j = 0; j < ES_MAX_COUNT; j++) for (auto& es_device : s_es_handles)
{ es_device = AddDevice<CWII_IPC_HLE_Device_es>("/dev/es");
s_es_handles[j] = AddDevice<CWII_IPC_HLE_Device_es>("/dev/es");
s_es_inuse[j] = false;
}
AddDevice<CWII_IPC_HLE_Device_di>("/dev/di"); AddDevice<CWII_IPC_HLE_Device_di>("/dev/di");
AddDevice<CWII_IPC_HLE_Device_net_kd_request>("/dev/net/kd/request"); AddDevice<CWII_IPC_HLE_Device_net_kd_request>("/dev/net/kd/request");
@ -189,11 +181,6 @@ void Reset(bool hard)
dev.reset(); dev.reset();
} }
for (bool& in_use : s_es_inuse)
{
in_use = false;
}
{ {
std::lock_guard<std::mutex> lock(s_device_map_mutex); std::lock_guard<std::mutex> lock(s_device_map_mutex);
for (const auto& entry : s_device_map) for (const auto& entry : s_device_map)
@ -283,14 +270,6 @@ std::shared_ptr<IWII_IPC_HLE_Device> AccessDeviceByID(u32 id)
return nullptr; return nullptr;
} }
// This is called from ExecuteCommand() COMMAND_OPEN_DEVICE
std::shared_ptr<IWII_IPC_HLE_Device> CreateFileIO(u32 device_id, const std::string& device_name)
{
// scan device name and create the right one
INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", device_name.c_str());
return std::make_shared<CWII_IPC_HLE_Device_FileIO>(device_id, device_name);
}
void DoState(PointerWrap& p) void DoState(PointerWrap& p)
{ {
p.Do(s_request_queue); p.Do(s_request_queue);
@ -337,13 +316,11 @@ void DoState(PointerWrap& p)
} }
} }
for (u32 i = 0; i < ES_MAX_COUNT; i++) for (auto& es_device : s_es_handles)
{ {
p.Do(s_es_inuse[i]); const u32 handle_id = es_device->GetDeviceID();
u32 handleID = s_es_handles[i]->GetDeviceID(); p.Do(handle_id);
p.Do(handleID); es_device = AccessDeviceByID(handle_id);
s_es_handles[i] = AccessDeviceByID(handleID);
} }
} }
else else
@ -368,197 +345,107 @@ void DoState(PointerWrap& p)
} }
} }
for (u32 i = 0; i < ES_MAX_COUNT; i++) for (const auto& es_device : s_es_handles)
{ {
p.Do(s_es_inuse[i]); const u32 handle_id = es_device->GetDeviceID();
u32 handleID = s_es_handles[i]->GetDeviceID(); p.Do(handle_id);
p.Do(handleID);
} }
} }
} }
void ExecuteCommand(u32 address) static std::shared_ptr<IWII_IPC_HLE_Device> GetUnusedESDevice()
{ {
IPCCommandResult result = IWII_IPC_HLE_Device::GetNoReply(); const auto iterator = std::find_if(std::begin(s_es_handles), std::end(s_es_handles),
[](const auto& es_device) { return !es_device->IsOpened(); });
return (iterator != std::end(s_es_handles)) ? *iterator : nullptr;
}
IPCCommandType Command = static_cast<IPCCommandType>(Memory::Read_U32(address)); // Returns the FD for the newly opened device (on success) or an error code.
s32 DeviceID = Memory::Read_U32(address + 8); static s32 OpenDevice(const u32 address)
{
std::shared_ptr<IWII_IPC_HLE_Device> device = const std::string device_name = Memory::GetString(Memory::Read_U32(address + 0xC));
(DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? s_fdmap[DeviceID] : nullptr; const u32 open_mode = Memory::Read_U32(address + 0x10);
const s32 new_fd = GetFreeDeviceID();
DEBUG_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", address, INFO_LOG(WII_IPC_HLE, "Opening %s (mode %d, fd %d)", device_name.c_str(), open_mode, new_fd);
Command, DeviceID, device.get()); if (new_fd < 0 || new_fd >= IPC_MAX_FDS)
switch (Command)
{ {
case IPC_CMD_OPEN: ERROR_LOG(WII_IPC_HLE, "Couldn't get a free fd, too many open files");
{ return FS_EFDEXHAUSTED;
u32 Mode = Memory::Read_U32(address + 0x10);
DeviceID = GetFreeDeviceID();
std::string device_name = Memory::GetString(Memory::Read_U32(address + 0xC));
INFO_LOG(WII_IPC_HLE, "Trying to open %s as %d", device_name.c_str(), DeviceID);
if (DeviceID >= 0)
{
if (device_name.find("/dev/es") == 0)
{
u32 j;
for (j = 0; j < ES_MAX_COUNT; j++)
{
if (!s_es_inuse[j])
{
s_es_inuse[j] = true;
s_fdmap[DeviceID] = s_es_handles[j];
result = s_es_handles[j]->Open(address, Mode);
Memory::Write_U32(DeviceID, address + 4);
break;
}
}
if (j == ES_MAX_COUNT)
{
Memory::Write_U32(FS_EESEXHAUSTED, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
}
else if (device_name.find("/dev/") == 0)
{
device = GetDeviceByName(device_name);
if (device)
{
s_fdmap[DeviceID] = device;
result = device->Open(address, Mode);
DEBUG_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
device->GetDeviceName().c_str(), DeviceID, Mode);
Memory::Write_U32(DeviceID, address + 4);
}
else
{
WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", device_name.c_str());
Memory::Write_U32(FS_ENOENT, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
}
else if (device_name.find('/') == 0)
{
device = CreateFileIO(DeviceID, device_name);
result = device->Open(address, Mode);
DEBUG_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
device->GetDeviceName().c_str(), DeviceID, Mode);
if (Memory::Read_U32(address + 4) == (u32)DeviceID)
s_fdmap[DeviceID] = device;
}
else
{
WARN_LOG(WII_IPC_HLE, "Invalid device: %s", device_name.c_str());
Memory::Write_U32(FS_ENOENT, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
}
else
{
Memory::Write_U32(FS_EFDEXHAUSTED, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
} }
std::shared_ptr<IWII_IPC_HLE_Device> device;
if (device_name.find("/dev/es") == 0)
{
device = GetUnusedESDevice();
if (!device)
return FS_EESEXHAUSTED;
}
else if (device_name.find("/dev/") == 0)
{
device = GetDeviceByName(device_name);
}
else if (device_name.find('/') == 0)
{
device = std::make_shared<CWII_IPC_HLE_Device_FileIO>(new_fd, device_name);
}
if (!device)
{
ERROR_LOG(WII_IPC_HLE, "Unknown device: %s", device_name.c_str());
return FS_ENOENT;
}
Memory::Write_U32(new_fd, address + 4);
device->Open(address, open_mode);
const s32 open_return_code = Memory::Read_U32(address + 4);
if (open_return_code < 0)
return open_return_code;
s_fdmap[new_fd] = device;
return new_fd;
}
static IPCCommandResult HandleCommand(const u32 address)
{
const auto command = static_cast<IPCCommandType>(Memory::Read_U32(address));
if (command == IPC_CMD_OPEN)
{
const s32 new_fd = OpenDevice(address);
Memory::Write_U32(new_fd, address + 4);
return IWII_IPC_HLE_Device::GetDefaultReply();
}
const s32 fd = Memory::Read_U32(address + 8);
const auto device = (fd >= 0 && fd < IPC_MAX_FDS) ? s_fdmap[fd] : nullptr;
if (!device)
{
Memory::Write_U32(FS_EINVAL, address + 4);
return IWII_IPC_HLE_Device::GetDefaultReply();
}
switch (command)
{
case IPC_CMD_CLOSE: case IPC_CMD_CLOSE:
{ s_fdmap[fd].reset();
if (device) return device->Close(address);
{
result = device->Close(address);
for (u32 j = 0; j < ES_MAX_COUNT; j++)
{
if (s_es_handles[j] == s_fdmap[DeviceID])
{
s_es_inuse[j] = false;
}
}
s_fdmap[DeviceID].reset();
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
}
case IPC_CMD_READ: case IPC_CMD_READ:
{ return device->Read(address);
if (device)
{
result = device->Read(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
}
case IPC_CMD_WRITE: case IPC_CMD_WRITE:
{ return device->Write(address);
if (device)
{
result = device->Write(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
}
case IPC_CMD_SEEK: case IPC_CMD_SEEK:
{ return device->Seek(address);
if (device)
{
result = device->Seek(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
}
case IPC_CMD_IOCTL: case IPC_CMD_IOCTL:
{ return device->IOCtl(address);
if (device)
{
result = device->IOCtl(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
}
case IPC_CMD_IOCTLV: case IPC_CMD_IOCTLV:
{ return device->IOCtlV(address);
if (device)
{
result = device->IOCtlV(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
}
default: default:
{ _assert_msg_(WII_IPC_HLE, false, "Unexpected command: %x", command);
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, address); return IWII_IPC_HLE_Device::GetDefaultReply();
break;
}
} }
}
void ExecuteCommand(const u32 address)
{
IPCCommandResult result = HandleCommand(address);
// Ensure replies happen in order // Ensure replies happen in order
const s64 ticks_until_last_reply = s_last_reply_time - CoreTiming::GetTicks(); const s64 ticks_until_last_reply = s_last_reply_time - CoreTiming::GetTicks();

View File

@ -62,8 +62,6 @@ void ES_DIVerify(const std::vector<u8>& tmd);
void SDIO_EventNotify(); void SDIO_EventNotify();
std::shared_ptr<IWII_IPC_HLE_Device> CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName);
std::shared_ptr<IWII_IPC_HLE_Device> GetDeviceByName(const std::string& _rDeviceName); std::shared_ptr<IWII_IPC_HLE_Device> GetDeviceByName(const std::string& _rDeviceName);
std::shared_ptr<IWII_IPC_HLE_Device> AccessDeviceByID(u32 _ID); std::shared_ptr<IWII_IPC_HLE_Device> AccessDeviceByID(u32 _ID);

View File

@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // Don't forget to increase this after doing changes on the savestate system
static const u32 STATE_VERSION = 65; // Last changed in PR 4120 static const u32 STATE_VERSION = 66; // Last changed in PR 4607
// Maps savestate versions to Dolphin versions. // Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list, // Versions after 42 don't need to be added to this list,