Merge pull request #4607 from leoetlino/execute
IOS HLE: Refactor ExecuteCommand
This commit is contained in:
commit
7847ca41e2
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue