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+
// Refer to the license.txt file included.
/*
This is the main Wii IPC file that handles all incoming IPC calls and directs them
to the right function.
IPC basics (IOS' usage):
Return values for file handles: All IPC calls will generate a return value to 0x04,
in case of success they are
Open: DeviceID
Close: 0
Read: Bytes read
Write: Bytes written
Seek: Seek position
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.
*/
// This is the main Wii IPC file that handles all incoming IPC requests and directs them
// to the right function.
//
// IPC basics (IOS' usage):
// All IPC request handlers will write a return value to 0x04.
// Open: Device file descriptor or error code
// Close: IPC_SUCCESS
// Read: Bytes read
// Write: Bytes written
// Seek: Seek position
// Ioctl: Depends on the handler
// Ioctlv: Depends on the handler
// Replies may be sent immediately or asynchronously for ioctls and ioctlvs.
#include <deque>
#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;
// STATE_TO_SAVE
#define IPC_MAX_FDS 0x18
#define ES_MAX_COUNT 2
constexpr u8 IPC_MAX_FDS = 0x18;
constexpr u8 ES_MAX_COUNT = 2;
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];
using IPCMsgQueue = std::deque<u32>;
@ -141,11 +136,8 @@ void Reinit()
AddDevice<CWII_IPC_HLE_Device_fs>("/dev/fs");
// IOS allows two ES devices at a time
for (u32 j = 0; j < ES_MAX_COUNT; j++)
{
s_es_handles[j] = AddDevice<CWII_IPC_HLE_Device_es>("/dev/es");
s_es_inuse[j] = false;
}
for (auto& es_device : s_es_handles)
es_device = AddDevice<CWII_IPC_HLE_Device_es>("/dev/es");
AddDevice<CWII_IPC_HLE_Device_di>("/dev/di");
AddDevice<CWII_IPC_HLE_Device_net_kd_request>("/dev/net/kd/request");
@ -189,11 +181,6 @@ void Reset(bool hard)
dev.reset();
}
for (bool& in_use : s_es_inuse)
{
in_use = false;
}
{
std::lock_guard<std::mutex> lock(s_device_map_mutex);
for (const auto& entry : s_device_map)
@ -283,14 +270,6 @@ std::shared_ptr<IWII_IPC_HLE_Device> AccessDeviceByID(u32 id)
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)
{
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]);
u32 handleID = s_es_handles[i]->GetDeviceID();
p.Do(handleID);
s_es_handles[i] = AccessDeviceByID(handleID);
const u32 handle_id = es_device->GetDeviceID();
p.Do(handle_id);
es_device = AccessDeviceByID(handle_id);
}
}
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]);
u32 handleID = s_es_handles[i]->GetDeviceID();
p.Do(handleID);
const u32 handle_id = es_device->GetDeviceID();
p.Do(handle_id);
}
}
}
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));
s32 DeviceID = Memory::Read_U32(address + 8);
std::shared_ptr<IWII_IPC_HLE_Device> device =
(DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? s_fdmap[DeviceID] : nullptr;
DEBUG_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", address,
Command, DeviceID, device.get());
switch (Command)
// Returns the FD for the newly opened device (on success) or an error code.
static s32 OpenDevice(const u32 address)
{
const std::string device_name = Memory::GetString(Memory::Read_U32(address + 0xC));
const u32 open_mode = Memory::Read_U32(address + 0x10);
const s32 new_fd = GetFreeDeviceID();
INFO_LOG(WII_IPC_HLE, "Opening %s (mode %d, fd %d)", device_name.c_str(), open_mode, new_fd);
if (new_fd < 0 || new_fd >= IPC_MAX_FDS)
{
case IPC_CMD_OPEN:
{
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;
ERROR_LOG(WII_IPC_HLE, "Couldn't get a free fd, too many open files");
return FS_EFDEXHAUSTED;
}
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:
{
if (device)
{
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;
}
s_fdmap[fd].reset();
return device->Close(address);
case IPC_CMD_READ:
{
if (device)
{
result = device->Read(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
}
return device->Read(address);
case IPC_CMD_WRITE:
{
if (device)
{
result = device->Write(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
}
return device->Write(address);
case IPC_CMD_SEEK:
{
if (device)
{
result = device->Seek(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
}
return device->Seek(address);
case IPC_CMD_IOCTL:
{
if (device)
{
result = device->IOCtl(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
}
return device->IOCtl(address);
case IPC_CMD_IOCTLV:
{
if (device)
{
result = device->IOCtlV(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
}
return device->IOCtlV(address);
default:
{
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, address);
break;
}
_assert_msg_(WII_IPC_HLE, false, "Unexpected command: %x", command);
return IWII_IPC_HLE_Device::GetDefaultReply();
}
}
void ExecuteCommand(const u32 address)
{
IPCCommandResult result = HandleCommand(address);
// Ensure replies happen in order
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();
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> AccessDeviceByID(u32 _ID);

View File

@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread;
// 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.
// Versions after 42 don't need to be added to this list,