Skip to content

Commit

Permalink
Merge pull request #4607 from leoetlino/execute
Browse files Browse the repository at this point in the history
IOS HLE: Refactor ExecuteCommand
  • Loading branch information
Parlane committed Jan 7, 2017
2 parents 3fdcbbd + a15be89 commit 7847ca4
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 215 deletions.
311 changes: 99 additions & 212 deletions Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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>;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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();

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());
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;
}

switch (Command)
{
case IPC_CMD_OPEN:
// 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)
{
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;
}
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;
}
case IPC_CMD_READ:
std::shared_ptr<IWII_IPC_HLE_Device> device;
if (device_name.find("/dev/es") == 0)
{
if (device)
{
result = device->Read(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
device = GetUnusedESDevice();
if (!device)
return FS_EESEXHAUSTED;
}
case IPC_CMD_WRITE:
else if (device_name.find("/dev/") == 0)
{
if (device)
{
result = device->Write(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
device = GetDeviceByName(device_name);
}
case IPC_CMD_SEEK:
else if (device_name.find('/') == 0)
{
if (device)
{
result = device->Seek(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
device = std::make_shared<CWII_IPC_HLE_Device_FileIO>(new_fd, device_name);
}
case IPC_CMD_IOCTL:

if (!device)
{
if (device)
{
result = device->IOCtl(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
ERROR_LOG(WII_IPC_HLE, "Unknown device: %s", device_name.c_str());
return FS_ENOENT;
}
case IPC_CMD_IOCTLV:

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)
{
if (device)
{
result = device->IOCtlV(address);
}
else
{
Memory::Write_U32(FS_EINVAL, address + 4);
result = IWII_IPC_HLE_Device::GetDefaultReply();
}
break;
const s32 new_fd = OpenDevice(address);
Memory::Write_U32(new_fd, address + 4);
return IWII_IPC_HLE_Device::GetDefaultReply();
}
default:

const s32 fd = Memory::Read_U32(address + 8);
const auto device = (fd >= 0 && fd < IPC_MAX_FDS) ? s_fdmap[fd] : nullptr;
if (!device)
{
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, address);
break;
Memory::Write_U32(FS_EINVAL, address + 4);
return IWII_IPC_HLE_Device::GetDefaultReply();
}

switch (command)
{
case IPC_CMD_CLOSE:
s_fdmap[fd].reset();
return device->Close(address);
case IPC_CMD_READ:
return device->Read(address);
case IPC_CMD_WRITE:
return device->Write(address);
case IPC_CMD_SEEK:
return device->Seek(address);
case IPC_CMD_IOCTL:
return device->IOCtl(address);
case IPC_CMD_IOCTLV:
return device->IOCtlV(address);
default:
_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();
Expand Down
2 changes: 0 additions & 2 deletions Source/Core/Core/IPC_HLE/WII_IPC_HLE.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 7847ca4

Please sign in to comment.