mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-10 01:44:41 +02:00
IOS: Clean up the way IPC replies are constructed
Instead of constructing IPCCommandResult with static member functions in the Device class, we can just add the relevant constructors to the reply struct itself. Makes more sense than putting it in Device when the struct is used in the kernel code and doesn't use any Device specific members... This commit also changes the IPC command handlers to return an optional IPCCommandResult rather than an IPCCommandResult. This removes the need for a separate boolean that indicates whether the "result" is actually a reply, and also avoids the need to set dummy result values and ticks. It also makes it really obvious which commands can result in no reply being generated. Finally, this commit renames IPCCommandResult to IPCReply since the struct is now only used for actual replies. This new name is less verbose in my opinion. The diff is quite large since this touches every command handler, but the only functional change is that I fixed EnqueueIPCReply to take a s64 for cycles_in_future to match IPCReply.
This commit is contained in:
@@ -57,13 +57,13 @@ void DIDevice::DoState(PointerWrap& p)
|
|||||||
p.Do(m_last_length);
|
p.Do(m_last_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult DIDevice::Open(const OpenRequest& request)
|
std::optional<IPCReply> DIDevice::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
InitializeIfFirstTime();
|
InitializeIfFirstTime();
|
||||||
return Device::Open(request);
|
return Device::Open(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult DIDevice::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> DIDevice::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
InitializeIfFirstTime();
|
InitializeIfFirstTime();
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ IPCCommandResult DIDevice::IOCtl(const IOCtlRequest& request)
|
|||||||
|
|
||||||
// FinishIOCtl will be called after the command has been executed
|
// FinishIOCtl will be called after the command has been executed
|
||||||
// to reply to the request, so we shouldn't reply here.
|
// to reply to the request, so we shouldn't reply here.
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DIDevice::ProcessQueuedIOCtl()
|
void DIDevice::ProcessQueuedIOCtl()
|
||||||
@@ -612,7 +612,7 @@ void DIDevice::FinishDICommand(DIResult result)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult DIDevice::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> DIDevice::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
// IOCtlVs are not queued since they don't (currently) go into DVDInterface and act
|
// IOCtlVs are not queued since they don't (currently) go into DVDInterface and act
|
||||||
// asynchronously. This does mean that an IOCtlV can be executed while an IOCtl is in progress,
|
// asynchronously. This does mean that an IOCtlV can be executed while an IOCtl is in progress,
|
||||||
@@ -623,7 +623,7 @@ IPCCommandResult DIDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_DI, "IOCtlV: Received bad input buffer size {:#04x}, should be 0x20",
|
ERROR_LOG_FMT(IOS_DI, "IOCtlV: Received bad input buffer size {:#04x}, should be 0x20",
|
||||||
request.in_vectors[0].size);
|
request.in_vectors[0].size);
|
||||||
return GetDefaultReply(static_cast<s32>(DIResult::BadArgument));
|
return IPCReply{static_cast<s32>(DIResult::BadArgument)};
|
||||||
}
|
}
|
||||||
const u8 command = Memory::Read_U8(request.in_vectors[0].address);
|
const u8 command = Memory::Read_U8(request.in_vectors[0].address);
|
||||||
if (request.request != command)
|
if (request.request != command)
|
||||||
@@ -704,7 +704,7 @@ IPCCommandResult DIDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
ERROR_LOG_FMT(IOS_DI, "Unknown ioctlv {:#04x}", request.request);
|
ERROR_LOG_FMT(IOS_DI, "Unknown ioctlv {:#04x}", request.request);
|
||||||
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_DI);
|
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_DI);
|
||||||
}
|
}
|
||||||
return GetDefaultReply(static_cast<s32>(return_value));
|
return IPCReply{static_cast<s32>(return_value)};
|
||||||
}
|
}
|
||||||
|
|
||||||
void DIDevice::ChangePartition(const DiscIO::Partition partition)
|
void DIDevice::ChangePartition(const DiscIO::Partition partition)
|
||||||
|
@@ -42,9 +42,9 @@ public:
|
|||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
IPCCommandResult Open(const OpenRequest& request) override;
|
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
enum class DIIoctl : u32
|
enum class DIIoctl : u32
|
||||||
{
|
{
|
||||||
|
@@ -160,19 +160,19 @@ void Device::DoStateShared(PointerWrap& p)
|
|||||||
p.Do(m_is_active);
|
p.Do(m_is_active);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult Device::Open(const OpenRequest& request)
|
std::optional<IPCReply> Device::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
m_is_active = true;
|
m_is_active = true;
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply{IPC_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult Device::Close(u32 fd)
|
std::optional<IPCReply> Device::Close(u32 fd)
|
||||||
{
|
{
|
||||||
m_is_active = false;
|
m_is_active = false;
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply{IPC_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult Device::Unsupported(const Request& request)
|
std::optional<IPCReply> Device::Unsupported(const Request& request)
|
||||||
{
|
{
|
||||||
static const std::map<IPCCommandType, std::string_view> names{{
|
static const std::map<IPCCommandType, std::string_view> names{{
|
||||||
{IPC_CMD_READ, "Read"},
|
{IPC_CMD_READ, "Read"},
|
||||||
@@ -183,27 +183,6 @@ IPCCommandResult Device::Unsupported(const Request& request)
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
WARN_LOG_FMT(IOS, "{} does not support {}()", m_name, names.at(request.command));
|
WARN_LOG_FMT(IOS, "{} does not support {}()", m_name, names.at(request.command));
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply{IPC_EINVAL};
|
||||||
}
|
|
||||||
|
|
||||||
// Returns an IPCCommandResult for a reply with an average reply time for devices
|
|
||||||
// Please avoid using this function if more accurate timings are known.
|
|
||||||
IPCCommandResult Device::GetDefaultReply(const s32 return_value)
|
|
||||||
{
|
|
||||||
// Based on a hardware test, a device takes at least ~2700 ticks to reply to an IPC request.
|
|
||||||
// Depending on how much work a command performs, this can take much longer (10000+)
|
|
||||||
// especially if the NAND filesystem is accessed.
|
|
||||||
//
|
|
||||||
// Because we currently don't emulate timing very accurately, we should not return
|
|
||||||
// the minimum possible reply time (~960 ticks from the kernel or ~2700 from devices)
|
|
||||||
// but an average time, otherwise we are going to be much too fast in most cases.
|
|
||||||
return {return_value, true, 4000 * SystemTimers::TIMER_RATIO};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns an IPCCommandResult with no reply. Useful for async commands that will generate a reply
|
|
||||||
// later. This takes no return value because it won't be used.
|
|
||||||
IPCCommandResult Device::GetNoReply()
|
|
||||||
{
|
|
||||||
return {IPC_SUCCESS, false, 0};
|
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -186,19 +187,23 @@ public:
|
|||||||
const std::string& GetDeviceName() const { return m_name; }
|
const std::string& GetDeviceName() const { return m_name; }
|
||||||
// Replies to Open and Close requests are sent by the IPC request handler (HandleCommand),
|
// Replies to Open and Close requests are sent by the IPC request handler (HandleCommand),
|
||||||
// not by the devices themselves.
|
// not by the devices themselves.
|
||||||
virtual IPCCommandResult Open(const OpenRequest& request);
|
virtual std::optional<IPCReply> Open(const OpenRequest& request);
|
||||||
virtual IPCCommandResult Close(u32 fd);
|
virtual std::optional<IPCReply> Close(u32 fd);
|
||||||
virtual IPCCommandResult Seek(const SeekRequest& seek) { return Unsupported(seek); }
|
virtual std::optional<IPCReply> Seek(const SeekRequest& seek) { return Unsupported(seek); }
|
||||||
virtual IPCCommandResult Read(const ReadWriteRequest& read) { return Unsupported(read); }
|
virtual std::optional<IPCReply> Read(const ReadWriteRequest& read) { return Unsupported(read); }
|
||||||
virtual IPCCommandResult Write(const ReadWriteRequest& write) { return Unsupported(write); }
|
virtual std::optional<IPCReply> Write(const ReadWriteRequest& write)
|
||||||
virtual IPCCommandResult IOCtl(const IOCtlRequest& ioctl) { return Unsupported(ioctl); }
|
{
|
||||||
virtual IPCCommandResult IOCtlV(const IOCtlVRequest& ioctlv) { return Unsupported(ioctlv); }
|
return Unsupported(write);
|
||||||
|
}
|
||||||
|
virtual std::optional<IPCReply> IOCtl(const IOCtlRequest& ioctl) { return Unsupported(ioctl); }
|
||||||
|
virtual std::optional<IPCReply> IOCtlV(const IOCtlVRequest& ioctlv)
|
||||||
|
{
|
||||||
|
return Unsupported(ioctlv);
|
||||||
|
}
|
||||||
virtual void Update() {}
|
virtual void Update() {}
|
||||||
virtual void UpdateWantDeterminism(bool new_want_determinism) {}
|
virtual void UpdateWantDeterminism(bool new_want_determinism) {}
|
||||||
virtual DeviceType GetDeviceType() const { return m_device_type; }
|
virtual DeviceType GetDeviceType() const { return m_device_type; }
|
||||||
virtual bool IsOpened() const { return m_is_active; }
|
virtual bool IsOpened() const { return m_is_active; }
|
||||||
static IPCCommandResult GetDefaultReply(s32 return_value);
|
|
||||||
static IPCCommandResult GetNoReply();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Kernel& m_ios;
|
Kernel& m_ios;
|
||||||
@@ -209,6 +214,6 @@ protected:
|
|||||||
bool m_is_active = false;
|
bool m_is_active = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IPCCommandResult Unsupported(const Request& request);
|
std::optional<IPCReply> Unsupported(const Request& request);
|
||||||
};
|
};
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -8,22 +8,22 @@
|
|||||||
|
|
||||||
namespace IOS::HLE
|
namespace IOS::HLE
|
||||||
{
|
{
|
||||||
IPCCommandResult DeviceStub::Open(const OpenRequest& request)
|
std::optional<IPCReply> DeviceStub::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
WARN_LOG_FMT(IOS, "{} faking Open()", m_name);
|
WARN_LOG_FMT(IOS, "{} faking Open()", m_name);
|
||||||
m_is_active = true;
|
m_is_active = true;
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult DeviceStub::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> DeviceStub::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
WARN_LOG_FMT(IOS, "{} faking IOCtl()", m_name);
|
WARN_LOG_FMT(IOS, "{} faking IOCtl()", m_name);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult DeviceStub::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> DeviceStub::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
WARN_LOG_FMT(IOS, "{} faking IOCtlV()", m_name);
|
WARN_LOG_FMT(IOS, "{} faking IOCtlV()", m_name);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -17,8 +17,8 @@ class DeviceStub final : public Device
|
|||||||
public:
|
public:
|
||||||
// Inherit the constructor from the Device class, since we don't need to do anything special.
|
// Inherit the constructor from the Device class, since we don't need to do anything special.
|
||||||
using Device::Device;
|
using Device::Device;
|
||||||
IPCCommandResult Open(const OpenRequest& request) override;
|
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
};
|
};
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -34,29 +34,29 @@ enum
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
IPCCommandResult GetSystemTime(const IOCtlVRequest& request)
|
IPCReply GetSystemTime(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 1))
|
if (!request.HasNumberOfValidVectors(0, 1))
|
||||||
{
|
{
|
||||||
return DolphinDevice::GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.io_vectors[0].size != 4)
|
if (request.io_vectors[0].size != 4)
|
||||||
{
|
{
|
||||||
return DolphinDevice::GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 milliseconds = Common::Timer::GetTimeMs();
|
const u32 milliseconds = Common::Timer::GetTimeMs();
|
||||||
|
|
||||||
Memory::Write_U32(milliseconds, request.io_vectors[0].address);
|
Memory::Write_U32(milliseconds, request.io_vectors[0].address);
|
||||||
return DolphinDevice::GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult GetVersion(const IOCtlVRequest& request)
|
IPCReply GetVersion(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 1))
|
if (!request.HasNumberOfValidVectors(0, 1))
|
||||||
{
|
{
|
||||||
return DolphinDevice::GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto length = std::min(size_t(request.io_vectors[0].size), std::strlen(SCM_DESC_STR));
|
const auto length = std::min(size_t(request.io_vectors[0].size), std::strlen(SCM_DESC_STR));
|
||||||
@@ -64,19 +64,19 @@ IPCCommandResult GetVersion(const IOCtlVRequest& request)
|
|||||||
Memory::Memset(request.io_vectors[0].address, 0, request.io_vectors[0].size);
|
Memory::Memset(request.io_vectors[0].address, 0, request.io_vectors[0].size);
|
||||||
Memory::CopyToEmu(request.io_vectors[0].address, SCM_DESC_STR, length);
|
Memory::CopyToEmu(request.io_vectors[0].address, SCM_DESC_STR, length);
|
||||||
|
|
||||||
return DolphinDevice::GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult GetCPUSpeed(const IOCtlVRequest& request)
|
IPCReply GetCPUSpeed(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 1))
|
if (!request.HasNumberOfValidVectors(0, 1))
|
||||||
{
|
{
|
||||||
return DolphinDevice::GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.io_vectors[0].size != 4)
|
if (request.io_vectors[0].size != 4)
|
||||||
{
|
{
|
||||||
return DolphinDevice::GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SConfig& config = SConfig::GetInstance();
|
const SConfig& config = SConfig::GetInstance();
|
||||||
@@ -86,66 +86,66 @@ IPCCommandResult GetCPUSpeed(const IOCtlVRequest& request)
|
|||||||
|
|
||||||
Memory::Write_U32(core_clock, request.io_vectors[0].address);
|
Memory::Write_U32(core_clock, request.io_vectors[0].address);
|
||||||
|
|
||||||
return DolphinDevice::GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult GetSpeedLimit(const IOCtlVRequest& request)
|
IPCReply GetSpeedLimit(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
// get current speed limit
|
// get current speed limit
|
||||||
if (!request.HasNumberOfValidVectors(0, 1))
|
if (!request.HasNumberOfValidVectors(0, 1))
|
||||||
{
|
{
|
||||||
return DolphinDevice::GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.io_vectors[0].size != 4)
|
if (request.io_vectors[0].size != 4)
|
||||||
{
|
{
|
||||||
return DolphinDevice::GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SConfig& config = SConfig::GetInstance();
|
const SConfig& config = SConfig::GetInstance();
|
||||||
const u32 speed_percent = config.m_EmulationSpeed * 100;
|
const u32 speed_percent = config.m_EmulationSpeed * 100;
|
||||||
Memory::Write_U32(speed_percent, request.io_vectors[0].address);
|
Memory::Write_U32(speed_percent, request.io_vectors[0].address);
|
||||||
|
|
||||||
return DolphinDevice::GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SetSpeedLimit(const IOCtlVRequest& request)
|
IPCReply SetSpeedLimit(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
// set current speed limit
|
// set current speed limit
|
||||||
if (!request.HasNumberOfValidVectors(1, 0))
|
if (!request.HasNumberOfValidVectors(1, 0))
|
||||||
{
|
{
|
||||||
return DolphinDevice::GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.in_vectors[0].size != 4)
|
if (request.in_vectors[0].size != 4)
|
||||||
{
|
{
|
||||||
return DolphinDevice::GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const float speed = float(Memory::Read_U32(request.in_vectors[0].address)) / 100.0f;
|
const float speed = float(Memory::Read_U32(request.in_vectors[0].address)) / 100.0f;
|
||||||
SConfig::GetInstance().m_EmulationSpeed = speed;
|
SConfig::GetInstance().m_EmulationSpeed = speed;
|
||||||
BootManager::SetEmulationSpeedReset(true);
|
BootManager::SetEmulationSpeedReset(true);
|
||||||
|
|
||||||
return DolphinDevice::GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult GetRealProductCode(const IOCtlVRequest& request)
|
IPCReply GetRealProductCode(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 1))
|
if (!request.HasNumberOfValidVectors(0, 1))
|
||||||
{
|
{
|
||||||
return DolphinDevice::GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string backup_file_path = File::GetUserPath(D_BACKUP_IDX) + DIR_SEP + WII_SETTING;
|
const std::string backup_file_path = File::GetUserPath(D_BACKUP_IDX) + DIR_SEP + WII_SETTING;
|
||||||
|
|
||||||
File::IOFile file(backup_file_path, "rb");
|
File::IOFile file(backup_file_path, "rb");
|
||||||
if (!file)
|
if (!file)
|
||||||
return DolphinDevice::GetDefaultReply(IPC_ENOENT);
|
return IPCReply(IPC_ENOENT);
|
||||||
|
|
||||||
Common::SettingsHandler::Buffer data;
|
Common::SettingsHandler::Buffer data;
|
||||||
|
|
||||||
if (!file.ReadBytes(data.data(), data.size()))
|
if (!file.ReadBytes(data.data(), data.size()))
|
||||||
return DolphinDevice::GetDefaultReply(IPC_ENOENT);
|
return IPCReply(IPC_ENOENT);
|
||||||
|
|
||||||
Common::SettingsHandler gen;
|
Common::SettingsHandler gen;
|
||||||
gen.SetBytes(std::move(data));
|
gen.SetBytes(std::move(data));
|
||||||
@@ -153,21 +153,19 @@ IPCCommandResult GetRealProductCode(const IOCtlVRequest& request)
|
|||||||
|
|
||||||
const size_t length = std::min<size_t>(request.io_vectors[0].size, code.length());
|
const size_t length = std::min<size_t>(request.io_vectors[0].size, code.length());
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
return DolphinDevice::GetDefaultReply(IPC_ENOENT);
|
return IPCReply(IPC_ENOENT);
|
||||||
|
|
||||||
Memory::Memset(request.io_vectors[0].address, 0, request.io_vectors[0].size);
|
Memory::Memset(request.io_vectors[0].address, 0, request.io_vectors[0].size);
|
||||||
Memory::CopyToEmu(request.io_vectors[0].address, code.c_str(), length);
|
Memory::CopyToEmu(request.io_vectors[0].address, code.c_str(), length);
|
||||||
return DolphinDevice::GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
IPCCommandResult DolphinDevice::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> DolphinDevice::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (Core::WantsDeterminism())
|
if (Core::WantsDeterminism())
|
||||||
{
|
return IPCReply(IPC_EACCES);
|
||||||
return DolphinDevice::GetDefaultReply(IPC_EACCES);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
@@ -184,7 +182,7 @@ IPCCommandResult DolphinDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
case IOCTL_DOLPHIN_GET_REAL_PRODUCTCODE:
|
case IOCTL_DOLPHIN_GET_REAL_PRODUCTCODE:
|
||||||
return GetRealProductCode(request);
|
return GetRealProductCode(request);
|
||||||
default:
|
default:
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -13,6 +13,6 @@ class DolphinDevice final : public Device
|
|||||||
public:
|
public:
|
||||||
// Inherit the constructor from the Device class, since we don't need to do anything special.
|
// Inherit the constructor from the Device class, since we don't need to do anything special.
|
||||||
using Device::Device;
|
using Device::Device;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
};
|
};
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -120,10 +120,10 @@ void TitleContext::Update(const ES::TMDReader& tmd_, const ES::TicketReader& tic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTitleDirectory(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTitleDirectory(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1))
|
if (!request.HasNumberOfValidVectors(1, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ IPCCommandResult ESDevice::GetTitleDirectory(const IOCtlVRequest& request)
|
|||||||
static_cast<u32>(title_id));
|
static_cast<u32>(title_id));
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETTITLEDIR: {}", path);
|
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETTITLEDIR: {}", path);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::GetTitleId(u64* title_id) const
|
ReturnCode ESDevice::GetTitleId(u64* title_id) const
|
||||||
@@ -143,20 +143,20 @@ ReturnCode ESDevice::GetTitleId(u64* title_id) const
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTitleId(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTitleId(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 1))
|
if (!request.HasNumberOfValidVectors(0, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
const ReturnCode ret = GetTitleId(&title_id);
|
const ReturnCode ret = GetTitleId(&title_id);
|
||||||
if (ret != IPC_SUCCESS)
|
if (ret != IPC_SUCCESS)
|
||||||
return GetDefaultReply(ret);
|
return IPCReply(ret);
|
||||||
|
|
||||||
Memory::Write_U64(title_id, request.io_vectors[0].address);
|
Memory::Write_U64(title_id, request.io_vectors[0].address);
|
||||||
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETTITLEID: {:08x}/{:08x}", static_cast<u32>(title_id >> 32),
|
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETTITLEID: {:08x}/{:08x}", static_cast<u32>(title_id >> 32),
|
||||||
static_cast<u32>(title_id));
|
static_cast<u32>(title_id));
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool UpdateUIDAndGID(Kernel& kernel, const ES::TMDReader& tmd)
|
static bool UpdateUIDAndGID(Kernel& kernel, const ES::TMDReader& tmd)
|
||||||
@@ -196,10 +196,10 @@ static ReturnCode CheckIsAllowedToSetUID(Kernel& kernel, const u32 caller_uid,
|
|||||||
return ES_EINVAL;
|
return ES_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::SetUID(u32 uid, const IOCtlVRequest& request)
|
IPCReply ESDevice::SetUID(u32 uid, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 8)
|
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 8)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
|
|
||||||
@@ -207,20 +207,20 @@ IPCCommandResult ESDevice::SetUID(u32 uid, const IOCtlVRequest& request)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_ES, "SetUID: Permission check failed with error {}", ret);
|
ERROR_LOG_FMT(IOS_ES, "SetUID: Permission check failed with error {}", ret);
|
||||||
return GetDefaultReply(ret);
|
return IPCReply(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto tmd = FindInstalledTMD(title_id);
|
const auto tmd = FindInstalledTMD(title_id);
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(FS_ENOENT);
|
return IPCReply(FS_ENOENT);
|
||||||
|
|
||||||
if (!UpdateUIDAndGID(m_ios, tmd))
|
if (!UpdateUIDAndGID(m_ios, tmd))
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_ES, "SetUID: Failed to get UID for title {:016x}", title_id);
|
ERROR_LOG_FMT(IOS_ES, "SetUID: Failed to get UID for title {:016x}", title_id);
|
||||||
return GetDefaultReply(ES_SHORT_READ);
|
return IPCReply(ES_SHORT_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ESDevice::LaunchTitle(u64 title_id, bool skip_reload)
|
bool ESDevice::LaunchTitle(u64 title_id, bool skip_reload)
|
||||||
@@ -380,11 +380,11 @@ ESDevice::ContextArray::iterator ESDevice::FindInactiveContext()
|
|||||||
[](const auto& context) { return !context.active; });
|
[](const auto& context) { return !context.active; });
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::Open(const OpenRequest& request)
|
std::optional<IPCReply> ESDevice::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
auto context = FindInactiveContext();
|
auto context = FindInactiveContext();
|
||||||
if (context == m_contexts.end())
|
if (context == m_contexts.end())
|
||||||
return GetDefaultReply(ES_FD_EXHAUSTED);
|
return IPCReply{ES_FD_EXHAUSTED};
|
||||||
|
|
||||||
context->active = true;
|
context->active = true;
|
||||||
context->uid = request.uid;
|
context->uid = request.uid;
|
||||||
@@ -393,26 +393,26 @@ IPCCommandResult ESDevice::Open(const OpenRequest& request)
|
|||||||
return Device::Open(request);
|
return Device::Open(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::Close(u32 fd)
|
std::optional<IPCReply> ESDevice::Close(u32 fd)
|
||||||
{
|
{
|
||||||
auto context = FindActiveContext(fd);
|
auto context = FindActiveContext(fd);
|
||||||
if (context == m_contexts.end())
|
if (context == m_contexts.end())
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
context->active = false;
|
context->active = false;
|
||||||
context->ipc_fd = -1;
|
context->ipc_fd = -1;
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "ES: Close");
|
INFO_LOG_FMT(IOS_ES, "ES: Close");
|
||||||
m_is_active = false;
|
m_is_active = false;
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> ESDevice::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
DEBUG_LOG_FMT(IOS_ES, "{} ({:#x})", GetDeviceName(), request.request);
|
DEBUG_LOG_FMT(IOS_ES, "{} ({:#x})", GetDeviceName(), request.request);
|
||||||
auto context = FindActiveContext(request.fd);
|
auto context = FindActiveContext(request.fd);
|
||||||
if (context == m_contexts.end())
|
if (context == m_contexts.end())
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
@@ -562,29 +562,29 @@ IPCCommandResult ESDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
PanicAlertFmt("IOS-ES: Unimplemented ioctlv {:#x} ({} in vectors, {} io vectors)",
|
PanicAlertFmt("IOS-ES: Unimplemented ioctlv {:#x} ({} in vectors, {} io vectors)",
|
||||||
request.request, request.in_vectors.size(), request.io_vectors.size());
|
request.request, request.in_vectors.size(), request.io_vectors.size());
|
||||||
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_ES, Common::Log::LERROR);
|
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_ES, Common::Log::LERROR);
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
case IOCTL_ES_INVALID_3F:
|
case IOCTL_ES_INVALID_3F:
|
||||||
default:
|
default:
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetConsumption(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetConsumption(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 2))
|
if (!request.HasNumberOfValidVectors(1, 2))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
// This is at least what crediar's ES module does
|
// This is at least what crediar's ES module does
|
||||||
Memory::Write_U32(0, request.io_vectors[1].address);
|
Memory::Write_U32(0, request.io_vectors[1].address);
|
||||||
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETCONSUMPTION");
|
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETCONSUMPTION");
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::Launch(const IOCtlVRequest& request)
|
std::optional<IPCReply> ESDevice::Launch(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 0))
|
if (!request.HasNumberOfValidVectors(2, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
const u32 view = Memory::Read_U32(request.in_vectors[1].address);
|
const u32 view = Memory::Read_U32(request.in_vectors[1].address);
|
||||||
@@ -598,41 +598,41 @@ IPCCommandResult ESDevice::Launch(const IOCtlVRequest& request)
|
|||||||
|
|
||||||
// Prevent loading installed IOSes that are not emulated.
|
// Prevent loading installed IOSes that are not emulated.
|
||||||
if (!IsEmulated(title_id))
|
if (!IsEmulated(title_id))
|
||||||
return GetDefaultReply(FS_ENOENT);
|
return IPCReply(FS_ENOENT);
|
||||||
|
|
||||||
// IOS replies to the request through the mailbox on failure, and acks if the launch succeeds.
|
// IOS replies to the request through the mailbox on failure, and acks if the launch succeeds.
|
||||||
// Note: Launch will potentially reset the whole IOS state -- including this ES instance.
|
// Note: Launch will potentially reset the whole IOS state -- including this ES instance.
|
||||||
if (!LaunchTitle(title_id))
|
if (!LaunchTitle(title_id))
|
||||||
return GetDefaultReply(FS_ENOENT);
|
return IPCReply(FS_ENOENT);
|
||||||
|
|
||||||
// ES_LAUNCH involves restarting IOS, which results in two acknowledgements in a row
|
// ES_LAUNCH involves restarting IOS, which results in two acknowledgements in a row
|
||||||
// (one from the previous IOS for this IPC request, and one from the new one as it boots).
|
// (one from the previous IOS for this IPC request, and one from the new one as it boots).
|
||||||
// Nothing should be written to the command buffer if the launch succeeded for obvious reasons.
|
// Nothing should be written to the command buffer if the launch succeeded for obvious reasons.
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::LaunchBC(const IOCtlVRequest& request)
|
std::optional<IPCReply> ESDevice::LaunchBC(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 0))
|
if (!request.HasNumberOfValidVectors(0, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
// Here, IOS checks the clock speed and prevents ioctlv 0x25 from being used in GC mode.
|
// Here, IOS checks the clock speed and prevents ioctlv 0x25 from being used in GC mode.
|
||||||
// An alternative way to do this is to check whether the current active IOS is MIOS.
|
// An alternative way to do this is to check whether the current active IOS is MIOS.
|
||||||
if (m_ios.GetVersion() == 0x101)
|
if (m_ios.GetVersion() == 0x101)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
if (!LaunchTitle(0x0000000100000100))
|
if (!LaunchTitle(0x0000000100000100))
|
||||||
return GetDefaultReply(FS_ENOENT);
|
return IPCReply(FS_ENOENT);
|
||||||
|
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is technically an ioctlv in IOS's ES, but it is an internal API which cannot be
|
// This is technically an ioctlv in IOS's ES, but it is an internal API which cannot be
|
||||||
// used from the PowerPC (for unpatched and up-to-date IOSes anyway).
|
// used from the PowerPC (for unpatched and up-to-date IOSes anyway).
|
||||||
// So we block access to it from the IPC interface.
|
// So we block access to it from the IPC interface.
|
||||||
IPCCommandResult ESDevice::DIVerify(const IOCtlVRequest& request)
|
IPCReply ESDevice::DIVerify(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ReturnCode WriteTmdForDiVerify(FS::FileSystem* fs, const ES::TMDReader& tmd)
|
static ReturnCode WriteTmdForDiVerify(FS::FileSystem* fs, const ES::TMDReader& tmd)
|
||||||
@@ -796,13 +796,13 @@ ReturnCode ESDevice::SetUpStreamKey(const u32 uid, const u8* ticket_view, const
|
|||||||
&ticket_bytes[offsetof(ES::Ticket, title_key)], PID_ES);
|
&ticket_bytes[offsetof(ES::Ticket, title_key)], PID_ES);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::SetUpStreamKey(const Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::SetUpStreamKey(const Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 1) ||
|
if (!request.HasNumberOfValidVectors(2, 1) ||
|
||||||
request.in_vectors[0].size != sizeof(ES::TicketView) ||
|
request.in_vectors[0].size != sizeof(ES::TicketView) ||
|
||||||
!ES::IsValidTMDSize(request.in_vectors[1].size) || request.io_vectors[0].size != sizeof(u32))
|
!ES::IsValidTMDSize(request.in_vectors[1].size) || request.io_vectors[0].size != sizeof(u32))
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> tmd_bytes(request.in_vectors[1].size);
|
std::vector<u8> tmd_bytes(request.in_vectors[1].size);
|
||||||
@@ -810,22 +810,22 @@ IPCCommandResult ESDevice::SetUpStreamKey(const Context& context, const IOCtlVRe
|
|||||||
const ES::TMDReader tmd{std::move(tmd_bytes)};
|
const ES::TMDReader tmd{std::move(tmd_bytes)};
|
||||||
|
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
u32 handle;
|
u32 handle;
|
||||||
const ReturnCode ret =
|
const ReturnCode ret =
|
||||||
SetUpStreamKey(context.uid, Memory::GetPointer(request.in_vectors[0].address), tmd, &handle);
|
SetUpStreamKey(context.uid, Memory::GetPointer(request.in_vectors[0].address), tmd, &handle);
|
||||||
Memory::Write_U32(handle, request.io_vectors[0].address);
|
Memory::Write_U32(handle, request.io_vectors[0].address);
|
||||||
return GetDefaultReply(ret);
|
return IPCReply(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::DeleteStreamKey(const IOCtlVRequest& request)
|
IPCReply ESDevice::DeleteStreamKey(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
|
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u32 handle = Memory::Read_U32(request.in_vectors[0].address);
|
const u32 handle = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
return GetDefaultReply(m_ios.GetIOSC().DeleteObject(handle, PID_ES));
|
return IPCReply(m_ios.GetIOSC().DeleteObject(handle, PID_ES));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ESDevice::IsActiveTitlePermittedByTicket(const u8* ticket_view) const
|
bool ESDevice::IsActiveTitlePermittedByTicket(const u8* ticket_view) const
|
||||||
|
@@ -48,9 +48,9 @@ public:
|
|||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
IPCCommandResult Open(const OpenRequest& request) override;
|
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||||
IPCCommandResult Close(u32 fd) override;
|
std::optional<IPCReply> Close(u32 fd) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
struct TitleImportExportContext
|
struct TitleImportExportContext
|
||||||
{
|
{
|
||||||
@@ -261,84 +261,84 @@ private:
|
|||||||
using ContextArray = std::array<Context, 3>;
|
using ContextArray = std::array<Context, 3>;
|
||||||
|
|
||||||
// Title management
|
// Title management
|
||||||
IPCCommandResult ImportTicket(const IOCtlVRequest& request);
|
IPCReply ImportTicket(const IOCtlVRequest& request);
|
||||||
IPCCommandResult ImportTmd(Context& context, const IOCtlVRequest& request);
|
IPCReply ImportTmd(Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult ImportTitleInit(Context& context, const IOCtlVRequest& request);
|
IPCReply ImportTitleInit(Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult ImportContentBegin(Context& context, const IOCtlVRequest& request);
|
IPCReply ImportContentBegin(Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult ImportContentData(Context& context, const IOCtlVRequest& request);
|
IPCReply ImportContentData(Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult ImportContentEnd(Context& context, const IOCtlVRequest& request);
|
IPCReply ImportContentEnd(Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult ImportTitleDone(Context& context, const IOCtlVRequest& request);
|
IPCReply ImportTitleDone(Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult ImportTitleCancel(Context& context, const IOCtlVRequest& request);
|
IPCReply ImportTitleCancel(Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult ExportTitleInit(Context& context, const IOCtlVRequest& request);
|
IPCReply ExportTitleInit(Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult ExportContentBegin(Context& context, const IOCtlVRequest& request);
|
IPCReply ExportContentBegin(Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult ExportContentData(Context& context, const IOCtlVRequest& request);
|
IPCReply ExportContentData(Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult ExportContentEnd(Context& context, const IOCtlVRequest& request);
|
IPCReply ExportContentEnd(Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult ExportTitleDone(Context& context, const IOCtlVRequest& request);
|
IPCReply ExportTitleDone(Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult DeleteTitle(const IOCtlVRequest& request);
|
IPCReply DeleteTitle(const IOCtlVRequest& request);
|
||||||
IPCCommandResult DeleteTitleContent(const IOCtlVRequest& request);
|
IPCReply DeleteTitleContent(const IOCtlVRequest& request);
|
||||||
IPCCommandResult DeleteTicket(const IOCtlVRequest& request);
|
IPCReply DeleteTicket(const IOCtlVRequest& request);
|
||||||
IPCCommandResult DeleteSharedContent(const IOCtlVRequest& request);
|
IPCReply DeleteSharedContent(const IOCtlVRequest& request);
|
||||||
IPCCommandResult DeleteContent(const IOCtlVRequest& request);
|
IPCReply DeleteContent(const IOCtlVRequest& request);
|
||||||
|
|
||||||
// Device identity and encryption
|
// Device identity and encryption
|
||||||
IPCCommandResult GetDeviceId(const IOCtlVRequest& request);
|
IPCReply GetDeviceId(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetDeviceCertificate(const IOCtlVRequest& request);
|
IPCReply GetDeviceCertificate(const IOCtlVRequest& request);
|
||||||
IPCCommandResult CheckKoreaRegion(const IOCtlVRequest& request);
|
IPCReply CheckKoreaRegion(const IOCtlVRequest& request);
|
||||||
IPCCommandResult Sign(const IOCtlVRequest& request);
|
IPCReply Sign(const IOCtlVRequest& request);
|
||||||
IPCCommandResult VerifySign(const IOCtlVRequest& request);
|
IPCReply VerifySign(const IOCtlVRequest& request);
|
||||||
IPCCommandResult Encrypt(u32 uid, const IOCtlVRequest& request);
|
IPCReply Encrypt(u32 uid, const IOCtlVRequest& request);
|
||||||
IPCCommandResult Decrypt(u32 uid, const IOCtlVRequest& request);
|
IPCReply Decrypt(u32 uid, const IOCtlVRequest& request);
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
IPCCommandResult SetUID(u32 uid, const IOCtlVRequest& request);
|
IPCReply SetUID(u32 uid, const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetTitleDirectory(const IOCtlVRequest& request);
|
IPCReply GetTitleDirectory(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetTitleId(const IOCtlVRequest& request);
|
IPCReply GetTitleId(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetConsumption(const IOCtlVRequest& request);
|
IPCReply GetConsumption(const IOCtlVRequest& request);
|
||||||
IPCCommandResult Launch(const IOCtlVRequest& request);
|
std::optional<IPCReply> Launch(const IOCtlVRequest& request);
|
||||||
IPCCommandResult LaunchBC(const IOCtlVRequest& request);
|
std::optional<IPCReply> LaunchBC(const IOCtlVRequest& request);
|
||||||
IPCCommandResult DIVerify(const IOCtlVRequest& request);
|
IPCReply DIVerify(const IOCtlVRequest& request);
|
||||||
IPCCommandResult SetUpStreamKey(const Context& context, const IOCtlVRequest& request);
|
IPCReply SetUpStreamKey(const Context& context, const IOCtlVRequest& request);
|
||||||
IPCCommandResult DeleteStreamKey(const IOCtlVRequest& request);
|
IPCReply DeleteStreamKey(const IOCtlVRequest& request);
|
||||||
|
|
||||||
// Title contents
|
// Title contents
|
||||||
IPCCommandResult OpenActiveTitleContent(u32 uid, const IOCtlVRequest& request);
|
IPCReply OpenActiveTitleContent(u32 uid, const IOCtlVRequest& request);
|
||||||
IPCCommandResult OpenContent(u32 uid, const IOCtlVRequest& request);
|
IPCReply OpenContent(u32 uid, const IOCtlVRequest& request);
|
||||||
IPCCommandResult ReadContent(u32 uid, const IOCtlVRequest& request);
|
IPCReply ReadContent(u32 uid, const IOCtlVRequest& request);
|
||||||
IPCCommandResult CloseContent(u32 uid, const IOCtlVRequest& request);
|
IPCReply CloseContent(u32 uid, const IOCtlVRequest& request);
|
||||||
IPCCommandResult SeekContent(u32 uid, const IOCtlVRequest& request);
|
IPCReply SeekContent(u32 uid, const IOCtlVRequest& request);
|
||||||
|
|
||||||
// Title information
|
// Title information
|
||||||
IPCCommandResult GetTitleCount(const std::vector<u64>& titles, const IOCtlVRequest& request);
|
IPCReply GetTitleCount(const std::vector<u64>& titles, const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetTitles(const std::vector<u64>& titles, const IOCtlVRequest& request);
|
IPCReply GetTitles(const std::vector<u64>& titles, const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetOwnedTitleCount(const IOCtlVRequest& request);
|
IPCReply GetOwnedTitleCount(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetOwnedTitles(const IOCtlVRequest& request);
|
IPCReply GetOwnedTitles(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetTitleCount(const IOCtlVRequest& request);
|
IPCReply GetTitleCount(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetTitles(const IOCtlVRequest& request);
|
IPCReply GetTitles(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetBoot2Version(const IOCtlVRequest& request);
|
IPCReply GetBoot2Version(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetStoredContentsCount(const ES::TMDReader& tmd, const IOCtlVRequest& request);
|
IPCReply GetStoredContentsCount(const ES::TMDReader& tmd, const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetStoredContents(const ES::TMDReader& tmd, const IOCtlVRequest& request);
|
IPCReply GetStoredContents(const ES::TMDReader& tmd, const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetStoredContentsCount(const IOCtlVRequest& request);
|
IPCReply GetStoredContentsCount(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetStoredContents(const IOCtlVRequest& request);
|
IPCReply GetStoredContents(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetTMDStoredContentsCount(const IOCtlVRequest& request);
|
IPCReply GetTMDStoredContentsCount(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetTMDStoredContents(const IOCtlVRequest& request);
|
IPCReply GetTMDStoredContents(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetStoredTMDSize(const IOCtlVRequest& request);
|
IPCReply GetStoredTMDSize(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetStoredTMD(const IOCtlVRequest& request);
|
IPCReply GetStoredTMD(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetSharedContentsCount(const IOCtlVRequest& request) const;
|
IPCReply GetSharedContentsCount(const IOCtlVRequest& request) const;
|
||||||
IPCCommandResult GetSharedContents(const IOCtlVRequest& request) const;
|
IPCReply GetSharedContents(const IOCtlVRequest& request) const;
|
||||||
|
|
||||||
// Views for tickets and TMDs
|
// Views for tickets and TMDs
|
||||||
IPCCommandResult GetTicketViewCount(const IOCtlVRequest& request);
|
IPCReply GetTicketViewCount(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetTicketViews(const IOCtlVRequest& request);
|
IPCReply GetTicketViews(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetV0TicketFromView(const IOCtlVRequest& request);
|
IPCReply GetV0TicketFromView(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetTicketSizeFromView(const IOCtlVRequest& request);
|
IPCReply GetTicketSizeFromView(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetTicketFromView(const IOCtlVRequest& request);
|
IPCReply GetTicketFromView(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetTMDViewSize(const IOCtlVRequest& request);
|
IPCReply GetTMDViewSize(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetTMDViews(const IOCtlVRequest& request);
|
IPCReply GetTMDViews(const IOCtlVRequest& request);
|
||||||
IPCCommandResult DIGetTicketView(const IOCtlVRequest& request);
|
IPCReply DIGetTicketView(const IOCtlVRequest& request);
|
||||||
IPCCommandResult DIGetTMDViewSize(const IOCtlVRequest& request);
|
IPCReply DIGetTMDViewSize(const IOCtlVRequest& request);
|
||||||
IPCCommandResult DIGetTMDView(const IOCtlVRequest& request);
|
IPCReply DIGetTMDView(const IOCtlVRequest& request);
|
||||||
IPCCommandResult DIGetTMDSize(const IOCtlVRequest& request);
|
IPCReply DIGetTMDSize(const IOCtlVRequest& request);
|
||||||
IPCCommandResult DIGetTMD(const IOCtlVRequest& request);
|
IPCReply DIGetTMD(const IOCtlVRequest& request);
|
||||||
|
|
||||||
ContextArray::iterator FindActiveContext(s32 fd);
|
ContextArray::iterator FindActiveContext(s32 fd);
|
||||||
ContextArray::iterator FindInactiveContext();
|
ContextArray::iterator FindInactiveContext();
|
||||||
|
@@ -27,23 +27,23 @@ ReturnCode ESDevice::GetDeviceId(u32* device_id) const
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetDeviceId(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetDeviceId(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
|
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
u32 device_id;
|
u32 device_id;
|
||||||
const ReturnCode ret = GetDeviceId(&device_id);
|
const ReturnCode ret = GetDeviceId(&device_id);
|
||||||
if (ret != IPC_SUCCESS)
|
if (ret != IPC_SUCCESS)
|
||||||
return GetDefaultReply(ret);
|
return IPCReply(ret);
|
||||||
Memory::Write_U32(device_id, request.io_vectors[0].address);
|
Memory::Write_U32(device_id, request.io_vectors[0].address);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::Encrypt(u32 uid, const IOCtlVRequest& request)
|
IPCReply ESDevice::Encrypt(u32 uid, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(3, 2))
|
if (!request.HasNumberOfValidVectors(3, 2))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address);
|
u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
u8* source = Memory::GetPointer(request.in_vectors[2].address);
|
u8* source = Memory::GetPointer(request.in_vectors[2].address);
|
||||||
@@ -54,13 +54,13 @@ IPCCommandResult ESDevice::Encrypt(u32 uid, const IOCtlVRequest& request)
|
|||||||
// TODO: Check whether the active title is allowed to encrypt.
|
// TODO: Check whether the active title is allowed to encrypt.
|
||||||
|
|
||||||
const ReturnCode ret = m_ios.GetIOSC().Encrypt(keyIndex, iv, source, size, destination, PID_ES);
|
const ReturnCode ret = m_ios.GetIOSC().Encrypt(keyIndex, iv, source, size, destination, PID_ES);
|
||||||
return GetDefaultReply(ret);
|
return IPCReply(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::Decrypt(u32 uid, const IOCtlVRequest& request)
|
IPCReply ESDevice::Decrypt(u32 uid, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(3, 2))
|
if (!request.HasNumberOfValidVectors(3, 2))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address);
|
u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
u8* source = Memory::GetPointer(request.in_vectors[2].address);
|
u8* source = Memory::GetPointer(request.in_vectors[2].address);
|
||||||
@@ -71,38 +71,38 @@ IPCCommandResult ESDevice::Decrypt(u32 uid, const IOCtlVRequest& request)
|
|||||||
// TODO: Check whether the active title is allowed to decrypt.
|
// TODO: Check whether the active title is allowed to decrypt.
|
||||||
|
|
||||||
const ReturnCode ret = m_ios.GetIOSC().Decrypt(keyIndex, iv, source, size, destination, PID_ES);
|
const ReturnCode ret = m_ios.GetIOSC().Decrypt(keyIndex, iv, source, size, destination, PID_ES);
|
||||||
return GetDefaultReply(ret);
|
return IPCReply(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::CheckKoreaRegion(const IOCtlVRequest& request)
|
IPCReply ESDevice::CheckKoreaRegion(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 0))
|
if (!request.HasNumberOfValidVectors(0, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
// note by DacoTaco : name is unknown, I just tried to name it SOMETHING.
|
// note by DacoTaco : name is unknown, I just tried to name it SOMETHING.
|
||||||
// IOS70 has this to let system menu 4.2 check if the console is region changed. it returns
|
// IOS70 has this to let system menu 4.2 check if the console is region changed. it returns
|
||||||
// -1017
|
// -1017
|
||||||
// if the IOS didn't find the Korean keys and 0 if it does. 0 leads to a error 003
|
// if the IOS didn't find the Korean keys and 0 if it does. 0 leads to a error 003
|
||||||
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_CHECKKOREAREGION: Title checked for Korean keys.");
|
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_CHECKKOREAREGION: Title checked for Korean keys.");
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetDeviceCertificate(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetDeviceCertificate(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 0x180)
|
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 0x180)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETDEVICECERT");
|
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETDEVICECERT");
|
||||||
|
|
||||||
const IOS::CertECC cert = m_ios.GetIOSC().GetDeviceCertificate();
|
const IOS::CertECC cert = m_ios.GetIOSC().GetDeviceCertificate();
|
||||||
Memory::CopyToEmu(request.io_vectors[0].address, &cert, sizeof(cert));
|
Memory::CopyToEmu(request.io_vectors[0].address, &cert, sizeof(cert));
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::Sign(const IOCtlVRequest& request)
|
IPCReply ESDevice::Sign(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 2))
|
if (!request.HasNumberOfValidVectors(1, 2))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_SIGN");
|
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_SIGN");
|
||||||
u8* ap_cert_out = Memory::GetPointer(request.io_vectors[1].address);
|
u8* ap_cert_out = Memory::GetPointer(request.io_vectors[1].address);
|
||||||
@@ -111,10 +111,10 @@ IPCCommandResult ESDevice::Sign(const IOCtlVRequest& request)
|
|||||||
u8* sig_out = Memory::GetPointer(request.io_vectors[0].address);
|
u8* sig_out = Memory::GetPointer(request.io_vectors[0].address);
|
||||||
|
|
||||||
if (!m_title_context.active)
|
if (!m_title_context.active)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
m_ios.GetIOSC().Sign(sig_out, ap_cert_out, m_title_context.tmd.GetTitleId(), data, data_size);
|
m_ios.GetIOSC().Sign(sig_out, ap_cert_out, m_title_context.tmd.GetTitleId(), data, data_size);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::VerifySign(const std::vector<u8>& hash, const std::vector<u8>& ecc_signature,
|
ReturnCode ESDevice::VerifySign(const std::vector<u8>& hash, const std::vector<u8>& ecc_signature,
|
||||||
@@ -185,12 +185,12 @@ ReturnCode ESDevice::VerifySign(const std::vector<u8>& hash, const std::vector<u
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::VerifySign(const IOCtlVRequest& request)
|
IPCReply ESDevice::VerifySign(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(3, 0))
|
if (!request.HasNumberOfValidVectors(3, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
if (request.in_vectors[1].size != sizeof(Common::ec::Signature))
|
if (request.in_vectors[1].size != sizeof(Common::ec::Signature))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
std::vector<u8> hash(request.in_vectors[0].size);
|
std::vector<u8> hash(request.in_vectors[0].size);
|
||||||
Memory::CopyFromEmu(hash.data(), request.in_vectors[0].address, hash.size());
|
Memory::CopyFromEmu(hash.data(), request.in_vectors[0].address, hash.size());
|
||||||
@@ -201,6 +201,6 @@ IPCCommandResult ESDevice::VerifySign(const IOCtlVRequest& request)
|
|||||||
std::vector<u8> certs(request.in_vectors[2].size);
|
std::vector<u8> certs(request.in_vectors[2].size);
|
||||||
Memory::CopyFromEmu(certs.data(), request.in_vectors[2].address, certs.size());
|
Memory::CopyFromEmu(certs.data(), request.in_vectors[2].address, certs.size());
|
||||||
|
|
||||||
return GetDefaultReply(VerifySign(hash, ecc_signature, certs));
|
return IPCReply(VerifySign(hash, ecc_signature, certs));
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -46,13 +46,13 @@ s32 ESDevice::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid)
|
|||||||
return FS_EFDEXHAUSTED;
|
return FS_EFDEXHAUSTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::OpenContent(u32 uid, const IOCtlVRequest& request)
|
IPCReply ESDevice::OpenContent(u32 uid, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(3, 0) || request.in_vectors[0].size != sizeof(u64) ||
|
if (!request.HasNumberOfValidVectors(3, 0) || request.in_vectors[0].size != sizeof(u64) ||
|
||||||
request.in_vectors[1].size != sizeof(ES::TicketView) ||
|
request.in_vectors[1].size != sizeof(ES::TicketView) ||
|
||||||
request.in_vectors[2].size != sizeof(u32))
|
request.in_vectors[2].size != sizeof(u32))
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
@@ -61,27 +61,27 @@ IPCCommandResult ESDevice::OpenContent(u32 uid, const IOCtlVRequest& request)
|
|||||||
|
|
||||||
const auto tmd = FindInstalledTMD(title_id);
|
const auto tmd = FindInstalledTMD(title_id);
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(FS_ENOENT);
|
return IPCReply(FS_ENOENT);
|
||||||
|
|
||||||
return GetDefaultReply(OpenContent(tmd, content_index, uid));
|
return IPCReply(OpenContent(tmd, content_index, uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::OpenActiveTitleContent(u32 caller_uid, const IOCtlVRequest& request)
|
IPCReply ESDevice::OpenActiveTitleContent(u32 caller_uid, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
|
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u32 content_index = Memory::Read_U32(request.in_vectors[0].address);
|
const u32 content_index = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
|
|
||||||
if (!m_title_context.active)
|
if (!m_title_context.active)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
ES::UIDSys uid_map{m_ios.GetFS()};
|
ES::UIDSys uid_map{m_ios.GetFS()};
|
||||||
const u32 uid = uid_map.GetOrInsertUIDForTitle(m_title_context.tmd.GetTitleId());
|
const u32 uid = uid_map.GetOrInsertUIDForTitle(m_title_context.tmd.GetTitleId());
|
||||||
if (caller_uid != 0 && caller_uid != uid)
|
if (caller_uid != 0 && caller_uid != uid)
|
||||||
return GetDefaultReply(ES_EACCES);
|
return IPCReply(ES_EACCES);
|
||||||
|
|
||||||
return GetDefaultReply(OpenContent(m_title_context.tmd, content_index, caller_uid));
|
return IPCReply(OpenContent(m_title_context.tmd, content_index, caller_uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 ESDevice::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid)
|
s32 ESDevice::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid)
|
||||||
@@ -99,16 +99,16 @@ s32 ESDevice::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid)
|
|||||||
return result.Succeeded() ? *result : FS::ConvertResult(result.Error());
|
return result.Succeeded() ? *result : FS::ConvertResult(result.Error());
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ReadContent(u32 uid, const IOCtlVRequest& request)
|
IPCReply ESDevice::ReadContent(u32 uid, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
|
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u32 cfd = Memory::Read_U32(request.in_vectors[0].address);
|
const u32 cfd = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
const u32 size = request.io_vectors[0].size;
|
const u32 size = request.io_vectors[0].size;
|
||||||
const u32 addr = request.io_vectors[0].address;
|
const u32 addr = request.io_vectors[0].address;
|
||||||
|
|
||||||
return GetDefaultReply(ReadContent(cfd, Memory::GetPointer(addr), size, uid));
|
return IPCReply(ReadContent(cfd, Memory::GetPointer(addr), size, uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::CloseContent(u32 cfd, u32 uid)
|
ReturnCode ESDevice::CloseContent(u32 cfd, u32 uid)
|
||||||
@@ -128,13 +128,13 @@ ReturnCode ESDevice::CloseContent(u32 cfd, u32 uid)
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::CloseContent(u32 uid, const IOCtlVRequest& request)
|
IPCReply ESDevice::CloseContent(u32 uid, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
|
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u32 cfd = Memory::Read_U32(request.in_vectors[0].address);
|
const u32 cfd = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
return GetDefaultReply(CloseContent(cfd, uid));
|
return IPCReply(CloseContent(cfd, uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 ESDevice::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid)
|
s32 ESDevice::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid)
|
||||||
@@ -152,15 +152,15 @@ s32 ESDevice::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid)
|
|||||||
return result.Succeeded() ? *result : FS::ConvertResult(result.Error());
|
return result.Succeeded() ? *result : FS::ConvertResult(result.Error());
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::SeekContent(u32 uid, const IOCtlVRequest& request)
|
IPCReply ESDevice::SeekContent(u32 uid, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(3, 0))
|
if (!request.HasNumberOfValidVectors(3, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u32 cfd = Memory::Read_U32(request.in_vectors[0].address);
|
const u32 cfd = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
const u32 offset = Memory::Read_U32(request.in_vectors[1].address);
|
const u32 offset = Memory::Read_U32(request.in_vectors[1].address);
|
||||||
const SeekMode mode = static_cast<SeekMode>(Memory::Read_U32(request.in_vectors[2].address));
|
const SeekMode mode = static_cast<SeekMode>(Memory::Read_U32(request.in_vectors[2].address));
|
||||||
|
|
||||||
return GetDefaultReply(SeekContent(cfd, offset, mode, uid));
|
return IPCReply(SeekContent(cfd, offset, mode, uid));
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -16,31 +16,30 @@ namespace IOS::HLE
|
|||||||
{
|
{
|
||||||
// Used by the GetStoredContents ioctlvs. This assumes that the first output vector
|
// Used by the GetStoredContents ioctlvs. This assumes that the first output vector
|
||||||
// is used for the content count (u32).
|
// is used for the content count (u32).
|
||||||
IPCCommandResult ESDevice::GetStoredContentsCount(const ES::TMDReader& tmd,
|
IPCReply ESDevice::GetStoredContentsCount(const ES::TMDReader& tmd, const IOCtlVRequest& request)
|
||||||
const IOCtlVRequest& request)
|
|
||||||
{
|
{
|
||||||
if (request.io_vectors[0].size != sizeof(u32) || !tmd.IsValid())
|
if (request.io_vectors[0].size != sizeof(u32) || !tmd.IsValid())
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u16 num_contents = static_cast<u16>(GetStoredContentsFromTMD(tmd).size());
|
const u16 num_contents = static_cast<u16>(GetStoredContentsFromTMD(tmd).size());
|
||||||
Memory::Write_U32(num_contents, request.io_vectors[0].address);
|
Memory::Write_U32(num_contents, request.io_vectors[0].address);
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "GetStoredContentsCount ({:#x}): {} content(s) for {:016x}",
|
INFO_LOG_FMT(IOS_ES, "GetStoredContentsCount ({:#x}): {} content(s) for {:016x}",
|
||||||
request.request, num_contents, tmd.GetTitleId());
|
request.request, num_contents, tmd.GetTitleId());
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by the GetStoredContents ioctlvs. This assumes that the second input vector is used
|
// Used by the GetStoredContents ioctlvs. This assumes that the second input vector is used
|
||||||
// for the content count and the output vector is used to store a list of content IDs (u32s).
|
// for the content count and the output vector is used to store a list of content IDs (u32s).
|
||||||
IPCCommandResult ESDevice::GetStoredContents(const ES::TMDReader& tmd, const IOCtlVRequest& request)
|
IPCReply ESDevice::GetStoredContents(const ES::TMDReader& tmd, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
if (request.in_vectors[1].size != sizeof(u32) ||
|
if (request.in_vectors[1].size != sizeof(u32) ||
|
||||||
request.io_vectors[0].size != Memory::Read_U32(request.in_vectors[1].address) * sizeof(u32))
|
request.io_vectors[0].size != Memory::Read_U32(request.in_vectors[1].address) * sizeof(u32))
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto contents = GetStoredContentsFromTMD(tmd);
|
const auto contents = GetStoredContentsFromTMD(tmd);
|
||||||
@@ -48,82 +47,81 @@ IPCCommandResult ESDevice::GetStoredContents(const ES::TMDReader& tmd, const IOC
|
|||||||
for (u32 i = 0; i < std::min(static_cast<u32>(contents.size()), max_content_count); ++i)
|
for (u32 i = 0; i < std::min(static_cast<u32>(contents.size()), max_content_count); ++i)
|
||||||
Memory::Write_U32(contents[i].id, request.io_vectors[0].address + i * sizeof(u32));
|
Memory::Write_U32(contents[i].id, request.io_vectors[0].address + i * sizeof(u32));
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetStoredContentsCount(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetStoredContentsCount(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u64))
|
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u64))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
const ES::TMDReader tmd = FindInstalledTMD(title_id);
|
const ES::TMDReader tmd = FindInstalledTMD(title_id);
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(FS_ENOENT);
|
return IPCReply(FS_ENOENT);
|
||||||
return GetStoredContentsCount(tmd, request);
|
return GetStoredContentsCount(tmd, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetStoredContents(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetStoredContents(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 1) || request.in_vectors[0].size != sizeof(u64))
|
if (!request.HasNumberOfValidVectors(2, 1) || request.in_vectors[0].size != sizeof(u64))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
const ES::TMDReader tmd = FindInstalledTMD(title_id);
|
const ES::TMDReader tmd = FindInstalledTMD(title_id);
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(FS_ENOENT);
|
return IPCReply(FS_ENOENT);
|
||||||
return GetStoredContents(tmd, request);
|
return GetStoredContents(tmd, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTMDStoredContentsCount(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTMDStoredContentsCount(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1))
|
if (!request.HasNumberOfValidVectors(1, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
std::vector<u8> tmd_bytes(request.in_vectors[0].size);
|
std::vector<u8> tmd_bytes(request.in_vectors[0].size);
|
||||||
Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size());
|
Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size());
|
||||||
return GetStoredContentsCount(ES::TMDReader{std::move(tmd_bytes)}, request);
|
return GetStoredContentsCount(ES::TMDReader{std::move(tmd_bytes)}, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTMDStoredContents(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTMDStoredContents(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 1))
|
if (!request.HasNumberOfValidVectors(2, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
std::vector<u8> tmd_bytes(request.in_vectors[0].size);
|
std::vector<u8> tmd_bytes(request.in_vectors[0].size);
|
||||||
Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size());
|
Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size());
|
||||||
|
|
||||||
const ES::TMDReader tmd{std::move(tmd_bytes)};
|
const ES::TMDReader tmd{std::move(tmd_bytes)};
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
std::vector<u8> cert_store;
|
std::vector<u8> cert_store;
|
||||||
ReturnCode ret = ReadCertStore(&cert_store);
|
ReturnCode ret = ReadCertStore(&cert_store);
|
||||||
if (ret != IPC_SUCCESS)
|
if (ret != IPC_SUCCESS)
|
||||||
return GetDefaultReply(ret);
|
return IPCReply(ret);
|
||||||
|
|
||||||
ret = VerifyContainer(VerifyContainerType::TMD, VerifyMode::UpdateCertStore, tmd, cert_store);
|
ret = VerifyContainer(VerifyContainerType::TMD, VerifyMode::UpdateCertStore, tmd, cert_store);
|
||||||
if (ret != IPC_SUCCESS)
|
if (ret != IPC_SUCCESS)
|
||||||
return GetDefaultReply(ret);
|
return IPCReply(ret);
|
||||||
|
|
||||||
return GetStoredContents(tmd, request);
|
return GetStoredContents(tmd, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTitleCount(const std::vector<u64>& titles,
|
IPCReply ESDevice::GetTitleCount(const std::vector<u64>& titles, const IOCtlVRequest& request)
|
||||||
const IOCtlVRequest& request)
|
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 4)
|
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 4)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
Memory::Write_U32(static_cast<u32>(titles.size()), request.io_vectors[0].address);
|
Memory::Write_U32(static_cast<u32>(titles.size()), request.io_vectors[0].address);
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTitles(const std::vector<u64>& titles, const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTitles(const std::vector<u64>& titles, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1))
|
if (!request.HasNumberOfValidVectors(1, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const size_t max_count = Memory::Read_U32(request.in_vectors[0].address);
|
const size_t max_count = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
for (size_t i = 0; i < std::min(max_count, titles.size()); i++)
|
for (size_t i = 0; i < std::min(max_count, titles.size()); i++)
|
||||||
@@ -131,112 +129,112 @@ IPCCommandResult ESDevice::GetTitles(const std::vector<u64>& titles, const IOCtl
|
|||||||
Memory::Write_U64(titles[i], request.io_vectors[0].address + static_cast<u32>(i) * sizeof(u64));
|
Memory::Write_U64(titles[i], request.io_vectors[0].address + static_cast<u32>(i) * sizeof(u64));
|
||||||
INFO_LOG_FMT(IOS_ES, " title {:016x}", titles[i]);
|
INFO_LOG_FMT(IOS_ES, " title {:016x}", titles[i]);
|
||||||
}
|
}
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTitleCount(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTitleCount(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
const std::vector<u64> titles = GetInstalledTitles();
|
const std::vector<u64> titles = GetInstalledTitles();
|
||||||
INFO_LOG_FMT(IOS_ES, "GetTitleCount: {} titles", titles.size());
|
INFO_LOG_FMT(IOS_ES, "GetTitleCount: {} titles", titles.size());
|
||||||
return GetTitleCount(titles, request);
|
return GetTitleCount(titles, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTitles(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTitles(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
return GetTitles(GetInstalledTitles(), request);
|
return GetTitles(GetInstalledTitles(), request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetStoredTMDSize(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetStoredTMDSize(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1))
|
if (!request.HasNumberOfValidVectors(1, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
const ES::TMDReader tmd = FindInstalledTMD(title_id);
|
const ES::TMDReader tmd = FindInstalledTMD(title_id);
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(FS_ENOENT);
|
return IPCReply(FS_ENOENT);
|
||||||
|
|
||||||
const u32 tmd_size = static_cast<u32>(tmd.GetBytes().size());
|
const u32 tmd_size = static_cast<u32>(tmd.GetBytes().size());
|
||||||
Memory::Write_U32(tmd_size, request.io_vectors[0].address);
|
Memory::Write_U32(tmd_size, request.io_vectors[0].address);
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "GetStoredTMDSize: {} bytes for {:016x}", tmd_size, title_id);
|
INFO_LOG_FMT(IOS_ES, "GetStoredTMDSize: {} bytes for {:016x}", tmd_size, title_id);
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetStoredTMD(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetStoredTMD(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 1))
|
if (!request.HasNumberOfValidVectors(2, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
const ES::TMDReader tmd = FindInstalledTMD(title_id);
|
const ES::TMDReader tmd = FindInstalledTMD(title_id);
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(FS_ENOENT);
|
return IPCReply(FS_ENOENT);
|
||||||
|
|
||||||
// TODO: actually use this param in when writing to the outbuffer :/
|
// TODO: actually use this param in when writing to the outbuffer :/
|
||||||
const u32 MaxCount = Memory::Read_U32(request.in_vectors[1].address);
|
const u32 MaxCount = Memory::Read_U32(request.in_vectors[1].address);
|
||||||
|
|
||||||
const std::vector<u8>& raw_tmd = tmd.GetBytes();
|
const std::vector<u8>& raw_tmd = tmd.GetBytes();
|
||||||
if (raw_tmd.size() != request.io_vectors[0].size)
|
if (raw_tmd.size() != request.io_vectors[0].size)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size());
|
Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size());
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "GetStoredTMD: title {:016x} (buffer size: {})", title_id, MaxCount);
|
INFO_LOG_FMT(IOS_ES, "GetStoredTMD: title {:016x} (buffer size: {})", title_id, MaxCount);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetOwnedTitleCount(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetOwnedTitleCount(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
const std::vector<u64> titles = GetTitlesWithTickets();
|
const std::vector<u64> titles = GetTitlesWithTickets();
|
||||||
INFO_LOG_FMT(IOS_ES, "GetOwnedTitleCount: {} titles", titles.size());
|
INFO_LOG_FMT(IOS_ES, "GetOwnedTitleCount: {} titles", titles.size());
|
||||||
return GetTitleCount(titles, request);
|
return GetTitleCount(titles, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetOwnedTitles(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetOwnedTitles(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
return GetTitles(GetTitlesWithTickets(), request);
|
return GetTitles(GetTitlesWithTickets(), request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetBoot2Version(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetBoot2Version(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 1))
|
if (!request.HasNumberOfValidVectors(0, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETBOOT2VERSION");
|
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETBOOT2VERSION");
|
||||||
|
|
||||||
// as of 26/02/2012, this was latest bootmii version
|
// as of 26/02/2012, this was latest bootmii version
|
||||||
Memory::Write_U32(4, request.io_vectors[0].address);
|
Memory::Write_U32(4, request.io_vectors[0].address);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetSharedContentsCount(const IOCtlVRequest& request) const
|
IPCReply ESDevice::GetSharedContentsCount(const IOCtlVRequest& request) const
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
|
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u32 count = GetSharedContentsCount();
|
const u32 count = GetSharedContentsCount();
|
||||||
Memory::Write_U32(count, request.io_vectors[0].address);
|
Memory::Write_U32(count, request.io_vectors[0].address);
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "GetSharedContentsCount: {} contents", count);
|
INFO_LOG_FMT(IOS_ES, "GetSharedContentsCount: {} contents", count);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetSharedContents(const IOCtlVRequest& request) const
|
IPCReply ESDevice::GetSharedContents(const IOCtlVRequest& request) const
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
|
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u32 max_count = Memory::Read_U32(request.in_vectors[0].address);
|
const u32 max_count = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
if (request.io_vectors[0].size != 20 * max_count)
|
if (request.io_vectors[0].size != 20 * max_count)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const std::vector<std::array<u8, 20>> hashes = GetSharedContents();
|
const std::vector<std::array<u8, 20>> hashes = GetSharedContents();
|
||||||
const u32 count = std::min(static_cast<u32>(hashes.size()), max_count);
|
const u32 count = std::min(static_cast<u32>(hashes.size()), max_count);
|
||||||
Memory::CopyToEmu(request.io_vectors[0].address, hashes.data(), 20 * count);
|
Memory::CopyToEmu(request.io_vectors[0].address, hashes.data(), 20 * count);
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "GetSharedContents: {} contents ({} requested)", count, max_count);
|
INFO_LOG_FMT(IOS_ES, "GetSharedContents: {} contents ({} requested)", count, max_count);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -93,16 +93,16 @@ ReturnCode ESDevice::ImportTicket(const std::vector<u8>& ticket_bytes,
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ImportTicket(const IOCtlVRequest& request)
|
IPCReply ESDevice::ImportTicket(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(3, 0))
|
if (!request.HasNumberOfValidVectors(3, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
std::vector<u8> bytes(request.in_vectors[0].size);
|
std::vector<u8> bytes(request.in_vectors[0].size);
|
||||||
Memory::CopyFromEmu(bytes.data(), request.in_vectors[0].address, request.in_vectors[0].size);
|
Memory::CopyFromEmu(bytes.data(), request.in_vectors[0].address, request.in_vectors[0].size);
|
||||||
std::vector<u8> cert_chain(request.in_vectors[1].size);
|
std::vector<u8> cert_chain(request.in_vectors[1].size);
|
||||||
Memory::CopyFromEmu(cert_chain.data(), request.in_vectors[1].address, request.in_vectors[1].size);
|
Memory::CopyFromEmu(cert_chain.data(), request.in_vectors[1].address, request.in_vectors[1].size);
|
||||||
return GetDefaultReply(ImportTicket(bytes, cert_chain));
|
return IPCReply(ImportTicket(bytes, cert_chain));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr std::array<u8, 16> NULL_KEY{};
|
constexpr std::array<u8, 16> NULL_KEY{};
|
||||||
@@ -180,18 +180,18 @@ ReturnCode ESDevice::ImportTmd(Context& context, const std::vector<u8>& tmd_byte
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ImportTmd(Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::ImportTmd(Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 0))
|
if (!request.HasNumberOfValidVectors(1, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
if (!ES::IsValidTMDSize(request.in_vectors[0].size))
|
if (!ES::IsValidTMDSize(request.in_vectors[0].size))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
std::vector<u8> tmd(request.in_vectors[0].size);
|
std::vector<u8> tmd(request.in_vectors[0].size);
|
||||||
Memory::CopyFromEmu(tmd.data(), request.in_vectors[0].address, request.in_vectors[0].size);
|
Memory::CopyFromEmu(tmd.data(), request.in_vectors[0].address, request.in_vectors[0].size);
|
||||||
return GetDefaultReply(ImportTmd(context, tmd, m_title_context.tmd.GetTitleId(),
|
return IPCReply(ImportTmd(context, tmd, m_title_context.tmd.GetTitleId(),
|
||||||
m_title_context.tmd.GetTitleFlags()));
|
m_title_context.tmd.GetTitleFlags()));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ReturnCode InitTitleImportKey(const std::vector<u8>& ticket_bytes, IOSC& iosc,
|
static ReturnCode InitTitleImportKey(const std::vector<u8>& ticket_bytes, IOSC& iosc,
|
||||||
@@ -266,19 +266,19 @@ ReturnCode ESDevice::ImportTitleInit(Context& context, const std::vector<u8>& tm
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ImportTitleInit(Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::ImportTitleInit(Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(4, 0))
|
if (!request.HasNumberOfValidVectors(4, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
if (!ES::IsValidTMDSize(request.in_vectors[0].size))
|
if (!ES::IsValidTMDSize(request.in_vectors[0].size))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
std::vector<u8> tmd(request.in_vectors[0].size);
|
std::vector<u8> tmd(request.in_vectors[0].size);
|
||||||
Memory::CopyFromEmu(tmd.data(), request.in_vectors[0].address, request.in_vectors[0].size);
|
Memory::CopyFromEmu(tmd.data(), request.in_vectors[0].address, request.in_vectors[0].size);
|
||||||
std::vector<u8> certs(request.in_vectors[1].size);
|
std::vector<u8> certs(request.in_vectors[1].size);
|
||||||
Memory::CopyFromEmu(certs.data(), request.in_vectors[1].address, request.in_vectors[1].size);
|
Memory::CopyFromEmu(certs.data(), request.in_vectors[1].address, request.in_vectors[1].size);
|
||||||
return GetDefaultReply(ImportTitleInit(context, tmd, certs));
|
return IPCReply(ImportTitleInit(context, tmd, certs));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::ImportContentBegin(Context& context, u64 title_id, u32 content_id)
|
ReturnCode ESDevice::ImportContentBegin(Context& context, u64 title_id, u32 content_id)
|
||||||
@@ -324,14 +324,14 @@ ReturnCode ESDevice::ImportContentBegin(Context& context, u64 title_id, u32 cont
|
|||||||
return static_cast<ReturnCode>(content_fd);
|
return static_cast<ReturnCode>(content_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ImportContentBegin(Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::ImportContentBegin(Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 0))
|
if (!request.HasNumberOfValidVectors(2, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
u32 content_id = Memory::Read_U32(request.in_vectors[1].address);
|
u32 content_id = Memory::Read_U32(request.in_vectors[1].address);
|
||||||
return GetDefaultReply(ImportContentBegin(context, title_id, content_id));
|
return IPCReply(ImportContentBegin(context, title_id, content_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::ImportContentData(Context& context, u32 content_fd, const u8* data,
|
ReturnCode ESDevice::ImportContentData(Context& context, u32 content_fd, const u8* data,
|
||||||
@@ -343,15 +343,14 @@ ReturnCode ESDevice::ImportContentData(Context& context, u32 content_fd, const u
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ImportContentData(Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::ImportContentData(Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 0))
|
if (!request.HasNumberOfValidVectors(2, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
u32 content_fd = Memory::Read_U32(request.in_vectors[0].address);
|
u32 content_fd = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
u8* data_start = Memory::GetPointer(request.in_vectors[1].address);
|
u8* data_start = Memory::GetPointer(request.in_vectors[1].address);
|
||||||
return GetDefaultReply(
|
return IPCReply(ImportContentData(context, content_fd, data_start, request.in_vectors[1].size));
|
||||||
ImportContentData(context, content_fd, data_start, request.in_vectors[1].size));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CheckIfContentHashMatches(const std::vector<u8>& content, const ES::Content& info)
|
static bool CheckIfContentHashMatches(const std::vector<u8>& content, const ES::Content& info)
|
||||||
@@ -429,13 +428,13 @@ ReturnCode ESDevice::ImportContentEnd(Context& context, u32 content_fd)
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ImportContentEnd(Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::ImportContentEnd(Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 0))
|
if (!request.HasNumberOfValidVectors(1, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
u32 content_fd = Memory::Read_U32(request.in_vectors[0].address);
|
u32 content_fd = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
return GetDefaultReply(ImportContentEnd(context, content_fd));
|
return IPCReply(ImportContentEnd(context, content_fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool HasAllRequiredContents(Kernel& ios, const ES::TMDReader& tmd)
|
static bool HasAllRequiredContents(Kernel& ios, const ES::TMDReader& tmd)
|
||||||
@@ -492,12 +491,12 @@ ReturnCode ESDevice::ImportTitleDone(Context& context)
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ImportTitleDone(Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::ImportTitleDone(Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 0))
|
if (!request.HasNumberOfValidVectors(0, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
return GetDefaultReply(ImportTitleDone(context));
|
return IPCReply(ImportTitleDone(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::ImportTitleCancel(Context& context)
|
ReturnCode ESDevice::ImportTitleCancel(Context& context)
|
||||||
@@ -518,12 +517,12 @@ ReturnCode ESDevice::ImportTitleCancel(Context& context)
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ImportTitleCancel(Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::ImportTitleCancel(Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 0))
|
if (!request.HasNumberOfValidVectors(0, 0))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
return GetDefaultReply(ImportTitleCancel(context));
|
return IPCReply(ImportTitleCancel(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CanDeleteTitle(u64 title_id)
|
static bool CanDeleteTitle(u64 title_id)
|
||||||
@@ -541,13 +540,13 @@ ReturnCode ESDevice::DeleteTitle(u64 title_id)
|
|||||||
return FS::ConvertResult(m_ios.GetFS()->Delete(PID_KERNEL, PID_KERNEL, title_dir));
|
return FS::ConvertResult(m_ios.GetFS()->Delete(PID_KERNEL, PID_KERNEL, title_dir));
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::DeleteTitle(const IOCtlVRequest& request)
|
IPCReply ESDevice::DeleteTitle(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 8)
|
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 8)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
return GetDefaultReply(DeleteTitle(title_id));
|
return IPCReply(DeleteTitle(title_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::DeleteTicket(const u8* ticket_view)
|
ReturnCode ESDevice::DeleteTicket(const u8* ticket_view)
|
||||||
@@ -590,14 +589,14 @@ ReturnCode ESDevice::DeleteTicket(const u8* ticket_view)
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::DeleteTicket(const IOCtlVRequest& request)
|
IPCReply ESDevice::DeleteTicket(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 0) ||
|
if (!request.HasNumberOfValidVectors(1, 0) ||
|
||||||
request.in_vectors[0].size != sizeof(ES::TicketView))
|
request.in_vectors[0].size != sizeof(ES::TicketView))
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
return GetDefaultReply(DeleteTicket(Memory::GetPointer(request.in_vectors[0].address)));
|
return IPCReply(DeleteTicket(Memory::GetPointer(request.in_vectors[0].address)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::DeleteTitleContent(u64 title_id) const
|
ReturnCode ESDevice::DeleteTitleContent(u64 title_id) const
|
||||||
@@ -619,11 +618,11 @@ ReturnCode ESDevice::DeleteTitleContent(u64 title_id) const
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::DeleteTitleContent(const IOCtlVRequest& request)
|
IPCReply ESDevice::DeleteTitleContent(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u64))
|
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u64))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
return GetDefaultReply(DeleteTitleContent(Memory::Read_U64(request.in_vectors[0].address)));
|
return IPCReply(DeleteTitleContent(Memory::Read_U64(request.in_vectors[0].address)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::DeleteContent(u64 title_id, u32 content_id) const
|
ReturnCode ESDevice::DeleteContent(u64 title_id, u32 content_id) const
|
||||||
@@ -644,15 +643,15 @@ ReturnCode ESDevice::DeleteContent(u64 title_id, u32 content_id) const
|
|||||||
return FS::ConvertResult(m_ios.GetFS()->Delete(PID_KERNEL, PID_KERNEL, path));
|
return FS::ConvertResult(m_ios.GetFS()->Delete(PID_KERNEL, PID_KERNEL, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::DeleteContent(const IOCtlVRequest& request)
|
IPCReply ESDevice::DeleteContent(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 0) || request.in_vectors[0].size != sizeof(u64) ||
|
if (!request.HasNumberOfValidVectors(2, 0) || request.in_vectors[0].size != sizeof(u64) ||
|
||||||
request.in_vectors[1].size != sizeof(u32))
|
request.in_vectors[1].size != sizeof(u32))
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
return GetDefaultReply(DeleteContent(Memory::Read_U64(request.in_vectors[0].address),
|
return IPCReply(DeleteContent(Memory::Read_U64(request.in_vectors[0].address),
|
||||||
Memory::Read_U32(request.in_vectors[1].address)));
|
Memory::Read_U32(request.in_vectors[1].address)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::ExportTitleInit(Context& context, u64 title_id, u8* tmd_bytes, u32 tmd_size,
|
ReturnCode ESDevice::ExportTitleInit(Context& context, u64 title_id, u8* tmd_bytes, u32 tmd_size,
|
||||||
@@ -684,18 +683,18 @@ ReturnCode ESDevice::ExportTitleInit(Context& context, u64 title_id, u8* tmd_byt
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ExportTitleInit(Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::ExportTitleInit(Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != 8)
|
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != 8)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
u8* tmd_bytes = Memory::GetPointer(request.io_vectors[0].address);
|
u8* tmd_bytes = Memory::GetPointer(request.io_vectors[0].address);
|
||||||
const u32 tmd_size = request.io_vectors[0].size;
|
const u32 tmd_size = request.io_vectors[0].size;
|
||||||
|
|
||||||
return GetDefaultReply(ExportTitleInit(context, title_id, tmd_bytes, tmd_size,
|
return IPCReply(ExportTitleInit(context, title_id, tmd_bytes, tmd_size,
|
||||||
m_title_context.tmd.GetTitleId(),
|
m_title_context.tmd.GetTitleId(),
|
||||||
m_title_context.tmd.GetTitleFlags()));
|
m_title_context.tmd.GetTitleFlags()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::ExportContentBegin(Context& context, u64 title_id, u32 content_id)
|
ReturnCode ESDevice::ExportContentBegin(Context& context, u64 title_id, u32 content_id)
|
||||||
@@ -729,16 +728,16 @@ ReturnCode ESDevice::ExportContentBegin(Context& context, u64 title_id, u32 cont
|
|||||||
return static_cast<ReturnCode>(ret);
|
return static_cast<ReturnCode>(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ExportContentBegin(Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::ExportContentBegin(Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 0) || request.in_vectors[0].size != 8 ||
|
if (!request.HasNumberOfValidVectors(2, 0) || request.in_vectors[0].size != 8 ||
|
||||||
request.in_vectors[1].size != 4)
|
request.in_vectors[1].size != 4)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
const u32 content_id = Memory::Read_U32(request.in_vectors[1].address);
|
const u32 content_id = Memory::Read_U32(request.in_vectors[1].address);
|
||||||
|
|
||||||
return GetDefaultReply(ExportContentBegin(context, title_id, content_id));
|
return IPCReply(ExportContentBegin(context, title_id, content_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::ExportContentData(Context& context, u32 content_fd, u8* data, u32 data_size)
|
ReturnCode ESDevice::ExportContentData(Context& context, u32 content_fd, u8* data, u32 data_size)
|
||||||
@@ -775,19 +774,19 @@ ReturnCode ESDevice::ExportContentData(Context& context, u32 content_fd, u8* dat
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ExportContentData(Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::ExportContentData(Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != 4 ||
|
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != 4 ||
|
||||||
request.io_vectors[0].size == 0)
|
request.io_vectors[0].size == 0)
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 content_fd = Memory::Read_U32(request.in_vectors[0].address);
|
const u32 content_fd = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
u8* data = Memory::GetPointer(request.io_vectors[0].address);
|
u8* data = Memory::GetPointer(request.io_vectors[0].address);
|
||||||
const u32 bytes_to_read = request.io_vectors[0].size;
|
const u32 bytes_to_read = request.io_vectors[0].size;
|
||||||
|
|
||||||
return GetDefaultReply(ExportContentData(context, content_fd, data, bytes_to_read));
|
return IPCReply(ExportContentData(context, content_fd, data, bytes_to_read));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::ExportContentEnd(Context& context, u32 content_fd)
|
ReturnCode ESDevice::ExportContentEnd(Context& context, u32 content_fd)
|
||||||
@@ -797,13 +796,13 @@ ReturnCode ESDevice::ExportContentEnd(Context& context, u32 content_fd)
|
|||||||
return CloseContent(content_fd, 0);
|
return CloseContent(content_fd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ExportContentEnd(Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::ExportContentEnd(Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 4)
|
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 4)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u32 content_fd = Memory::Read_U32(request.in_vectors[0].address);
|
const u32 content_fd = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
return GetDefaultReply(ExportContentEnd(context, content_fd));
|
return IPCReply(ExportContentEnd(context, content_fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::ExportTitleDone(Context& context)
|
ReturnCode ESDevice::ExportTitleDone(Context& context)
|
||||||
@@ -812,9 +811,9 @@ ReturnCode ESDevice::ExportTitleDone(Context& context)
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::ExportTitleDone(Context& context, const IOCtlVRequest& request)
|
IPCReply ESDevice::ExportTitleDone(Context& context, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ExportTitleDone(context));
|
return IPCReply(ExportTitleDone(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::DeleteSharedContent(const std::array<u8, 20>& sha1) const
|
ReturnCode ESDevice::DeleteSharedContent(const std::array<u8, 20>& sha1) const
|
||||||
@@ -854,12 +853,12 @@ ReturnCode ESDevice::DeleteSharedContent(const std::array<u8, 20>& sha1) const
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::DeleteSharedContent(const IOCtlVRequest& request)
|
IPCReply ESDevice::DeleteSharedContent(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
std::array<u8, 20> sha1;
|
std::array<u8, 20> sha1;
|
||||||
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sha1.size())
|
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sha1.size())
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
Memory::CopyFromEmu(sha1.data(), request.in_vectors[0].address, request.in_vectors[0].size);
|
Memory::CopyFromEmu(sha1.data(), request.in_vectors[0].address, request.in_vectors[0].size);
|
||||||
return GetDefaultReply(DeleteSharedContent(sha1));
|
return IPCReply(DeleteSharedContent(sha1));
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -36,10 +36,10 @@ static bool ShouldReturnFakeViewsForIOSes(u64 title_id, const TitleContext& cont
|
|||||||
(ios && SConfig::GetInstance().m_disc_booted_from_game_list && disc_title);
|
(ios && SConfig::GetInstance().m_disc_booted_from_game_list && disc_title);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTicketViewCount(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTicketViewCount(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1))
|
if (!request.HasNumberOfValidVectors(1, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
|
|
||||||
@@ -61,13 +61,13 @@ IPCCommandResult ESDevice::GetTicketViewCount(const IOCtlVRequest& request)
|
|||||||
view_count);
|
view_count);
|
||||||
|
|
||||||
Memory::Write_U32(view_count, request.io_vectors[0].address);
|
Memory::Write_U32(view_count, request.io_vectors[0].address);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTicketViews(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTicketViews(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 1))
|
if (!request.HasNumberOfValidVectors(2, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
const u32 maxViews = Memory::Read_U32(request.in_vectors[1].address);
|
const u32 maxViews = Memory::Read_U32(request.in_vectors[1].address);
|
||||||
@@ -96,7 +96,7 @@ IPCCommandResult ESDevice::GetTicketViews(const IOCtlVRequest& request)
|
|||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETVIEWS for titleID: {:016x} (MaxViews = {})", TitleID, maxViews);
|
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETVIEWS for titleID: {:016x} (MaxViews = {})", TitleID, maxViews);
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode ESDevice::GetV0TicketFromView(const u8* ticket_view, u8* ticket) const
|
ReturnCode ESDevice::GetV0TicketFromView(const u8* ticket_view, u8* ticket) const
|
||||||
@@ -157,106 +157,106 @@ ReturnCode ESDevice::GetTicketFromView(const u8* ticket_view, u8* ticket, u32* t
|
|||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetV0TicketFromView(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetV0TicketFromView(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1) ||
|
if (!request.HasNumberOfValidVectors(1, 1) ||
|
||||||
request.in_vectors[0].size != sizeof(ES::TicketView) ||
|
request.in_vectors[0].size != sizeof(ES::TicketView) ||
|
||||||
request.io_vectors[0].size != sizeof(ES::Ticket))
|
request.io_vectors[0].size != sizeof(ES::Ticket))
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
return GetDefaultReply(GetV0TicketFromView(Memory::GetPointer(request.in_vectors[0].address),
|
return IPCReply(GetV0TicketFromView(Memory::GetPointer(request.in_vectors[0].address),
|
||||||
Memory::GetPointer(request.io_vectors[0].address)));
|
Memory::GetPointer(request.io_vectors[0].address)));
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTicketSizeFromView(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTicketSizeFromView(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
u32 ticket_size = 0;
|
u32 ticket_size = 0;
|
||||||
if (!request.HasNumberOfValidVectors(1, 1) ||
|
if (!request.HasNumberOfValidVectors(1, 1) ||
|
||||||
request.in_vectors[0].size != sizeof(ES::TicketView) ||
|
request.in_vectors[0].size != sizeof(ES::TicketView) ||
|
||||||
request.io_vectors[0].size != sizeof(ticket_size))
|
request.io_vectors[0].size != sizeof(ticket_size))
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
const ReturnCode ret =
|
const ReturnCode ret =
|
||||||
GetTicketFromView(Memory::GetPointer(request.in_vectors[0].address), nullptr, &ticket_size);
|
GetTicketFromView(Memory::GetPointer(request.in_vectors[0].address), nullptr, &ticket_size);
|
||||||
Memory::Write_U32(ticket_size, request.io_vectors[0].address);
|
Memory::Write_U32(ticket_size, request.io_vectors[0].address);
|
||||||
return GetDefaultReply(ret);
|
return IPCReply(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTicketFromView(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTicketFromView(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 1) ||
|
if (!request.HasNumberOfValidVectors(2, 1) ||
|
||||||
request.in_vectors[0].size != sizeof(ES::TicketView) ||
|
request.in_vectors[0].size != sizeof(ES::TicketView) ||
|
||||||
request.in_vectors[1].size != sizeof(u32))
|
request.in_vectors[1].size != sizeof(u32))
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ticket_size = Memory::Read_U32(request.in_vectors[1].address);
|
u32 ticket_size = Memory::Read_U32(request.in_vectors[1].address);
|
||||||
if (ticket_size != request.io_vectors[0].size)
|
if (ticket_size != request.io_vectors[0].size)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
return GetDefaultReply(GetTicketFromView(Memory::GetPointer(request.in_vectors[0].address),
|
return IPCReply(GetTicketFromView(Memory::GetPointer(request.in_vectors[0].address),
|
||||||
Memory::GetPointer(request.io_vectors[0].address),
|
Memory::GetPointer(request.io_vectors[0].address),
|
||||||
&ticket_size));
|
&ticket_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTMDViewSize(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTMDViewSize(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1))
|
if (!request.HasNumberOfValidVectors(1, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
const ES::TMDReader tmd = FindInstalledTMD(TitleID);
|
const ES::TMDReader tmd = FindInstalledTMD(TitleID);
|
||||||
|
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(FS_ENOENT);
|
return IPCReply(FS_ENOENT);
|
||||||
|
|
||||||
const u32 view_size = static_cast<u32>(tmd.GetRawView().size());
|
const u32 view_size = static_cast<u32>(tmd.GetRawView().size());
|
||||||
Memory::Write_U32(view_size, request.io_vectors[0].address);
|
Memory::Write_U32(view_size, request.io_vectors[0].address);
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "GetTMDViewSize: {} bytes for title {:016x}", view_size, TitleID);
|
INFO_LOG_FMT(IOS_ES, "GetTMDViewSize: {} bytes for title {:016x}", view_size, TitleID);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::GetTMDViews(const IOCtlVRequest& request)
|
IPCReply ESDevice::GetTMDViews(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 1) ||
|
if (!request.HasNumberOfValidVectors(2, 1) ||
|
||||||
request.in_vectors[0].size != sizeof(ES::TMDHeader::title_id) ||
|
request.in_vectors[0].size != sizeof(ES::TMDHeader::title_id) ||
|
||||||
request.in_vectors[1].size != sizeof(u32) ||
|
request.in_vectors[1].size != sizeof(u32) ||
|
||||||
Memory::Read_U32(request.in_vectors[1].address) != request.io_vectors[0].size)
|
Memory::Read_U32(request.in_vectors[1].address) != request.io_vectors[0].size)
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
|
||||||
const ES::TMDReader tmd = FindInstalledTMD(title_id);
|
const ES::TMDReader tmd = FindInstalledTMD(title_id);
|
||||||
|
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(FS_ENOENT);
|
return IPCReply(FS_ENOENT);
|
||||||
|
|
||||||
const std::vector<u8> raw_view = tmd.GetRawView();
|
const std::vector<u8> raw_view = tmd.GetRawView();
|
||||||
if (request.io_vectors[0].size < raw_view.size())
|
if (request.io_vectors[0].size < raw_view.size())
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
Memory::CopyToEmu(request.io_vectors[0].address, raw_view.data(), raw_view.size());
|
Memory::CopyToEmu(request.io_vectors[0].address, raw_view.data(), raw_view.size());
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_ES, "GetTMDView: {} bytes for title {:016x}", raw_view.size(), title_id);
|
INFO_LOG_FMT(IOS_ES, "GetTMDView: {} bytes for title {:016x}", raw_view.size(), title_id);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::DIGetTMDViewSize(const IOCtlVRequest& request)
|
IPCReply ESDevice::DIGetTMDViewSize(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1))
|
if (!request.HasNumberOfValidVectors(1, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
// Sanity check the TMD size.
|
// Sanity check the TMD size.
|
||||||
if (request.in_vectors[0].size >= 4 * 1024 * 1024)
|
if (request.in_vectors[0].size >= 4 * 1024 * 1024)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
if (request.io_vectors[0].size != sizeof(u32))
|
if (request.io_vectors[0].size != sizeof(u32))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const bool has_tmd = request.in_vectors[0].size != 0;
|
const bool has_tmd = request.in_vectors[0].size != 0;
|
||||||
size_t tmd_view_size = 0;
|
size_t tmd_view_size = 0;
|
||||||
@@ -270,7 +270,7 @@ IPCCommandResult ESDevice::DIGetTMDViewSize(const IOCtlVRequest& request)
|
|||||||
// Yes, this returns -1017, not ES_INVALID_TMD.
|
// Yes, this returns -1017, not ES_INVALID_TMD.
|
||||||
// IOS simply checks whether the TMD has all required content entries.
|
// IOS simply checks whether the TMD has all required content entries.
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
tmd_view_size = tmd.GetRawView().size();
|
tmd_view_size = tmd.GetRawView().size();
|
||||||
}
|
}
|
||||||
@@ -278,29 +278,29 @@ IPCCommandResult ESDevice::DIGetTMDViewSize(const IOCtlVRequest& request)
|
|||||||
{
|
{
|
||||||
// If no TMD was passed in and no title is active, IOS returns -1017.
|
// If no TMD was passed in and no title is active, IOS returns -1017.
|
||||||
if (!m_title_context.active)
|
if (!m_title_context.active)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
tmd_view_size = m_title_context.tmd.GetRawView().size();
|
tmd_view_size = m_title_context.tmd.GetRawView().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory::Write_U32(static_cast<u32>(tmd_view_size), request.io_vectors[0].address);
|
Memory::Write_U32(static_cast<u32>(tmd_view_size), request.io_vectors[0].address);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::DIGetTMDView(const IOCtlVRequest& request)
|
IPCReply ESDevice::DIGetTMDView(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 1))
|
if (!request.HasNumberOfValidVectors(2, 1))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
// Sanity check the TMD size.
|
// Sanity check the TMD size.
|
||||||
if (request.in_vectors[0].size >= 4 * 1024 * 1024)
|
if (request.in_vectors[0].size >= 4 * 1024 * 1024)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
// Check whether the TMD view size is consistent.
|
// Check whether the TMD view size is consistent.
|
||||||
if (request.in_vectors[1].size != sizeof(u32) ||
|
if (request.in_vectors[1].size != sizeof(u32) ||
|
||||||
Memory::Read_U32(request.in_vectors[1].address) != request.io_vectors[0].size)
|
Memory::Read_U32(request.in_vectors[1].address) != request.io_vectors[0].size)
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool has_tmd = request.in_vectors[0].size != 0;
|
const bool has_tmd = request.in_vectors[0].size != 0;
|
||||||
@@ -313,7 +313,7 @@ IPCCommandResult ESDevice::DIGetTMDView(const IOCtlVRequest& request)
|
|||||||
const ES::TMDReader tmd{std::move(tmd_bytes)};
|
const ES::TMDReader tmd{std::move(tmd_bytes)};
|
||||||
|
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
tmd_view = tmd.GetRawView();
|
tmd_view = tmd.GetRawView();
|
||||||
}
|
}
|
||||||
@@ -321,31 +321,31 @@ IPCCommandResult ESDevice::DIGetTMDView(const IOCtlVRequest& request)
|
|||||||
{
|
{
|
||||||
// If no TMD was passed in and no title is active, IOS returns -1017.
|
// If no TMD was passed in and no title is active, IOS returns -1017.
|
||||||
if (!m_title_context.active)
|
if (!m_title_context.active)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
tmd_view = m_title_context.tmd.GetRawView();
|
tmd_view = m_title_context.tmd.GetRawView();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmd_view.size() > request.io_vectors[0].size)
|
if (tmd_view.size() > request.io_vectors[0].size)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
Memory::CopyToEmu(request.io_vectors[0].address, tmd_view.data(), tmd_view.size());
|
Memory::CopyToEmu(request.io_vectors[0].address, tmd_view.data(), tmd_view.size());
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::DIGetTicketView(const IOCtlVRequest& request)
|
IPCReply ESDevice::DIGetTicketView(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1) ||
|
if (!request.HasNumberOfValidVectors(1, 1) ||
|
||||||
request.io_vectors[0].size != sizeof(ES::TicketView))
|
request.io_vectors[0].size != sizeof(ES::TicketView))
|
||||||
{
|
{
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool has_ticket_vector = request.in_vectors[0].size == sizeof(ES::Ticket);
|
const bool has_ticket_vector = request.in_vectors[0].size == sizeof(ES::Ticket);
|
||||||
|
|
||||||
// This ioctlv takes either a signed ticket or no ticket, in which case the ticket size must be 0.
|
// This ioctlv takes either a signed ticket or no ticket, in which case the ticket size must be 0.
|
||||||
if (!has_ticket_vector && request.in_vectors[0].size != 0)
|
if (!has_ticket_vector && request.in_vectors[0].size != 0)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
std::vector<u8> view;
|
std::vector<u8> view;
|
||||||
|
|
||||||
@@ -354,7 +354,7 @@ IPCCommandResult ESDevice::DIGetTicketView(const IOCtlVRequest& request)
|
|||||||
if (!has_ticket_vector)
|
if (!has_ticket_vector)
|
||||||
{
|
{
|
||||||
if (!m_title_context.active)
|
if (!m_title_context.active)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
view = m_title_context.ticket.GetRawTicketView(0);
|
view = m_title_context.ticket.GetRawTicketView(0);
|
||||||
}
|
}
|
||||||
@@ -368,40 +368,40 @@ IPCCommandResult ESDevice::DIGetTicketView(const IOCtlVRequest& request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Memory::CopyToEmu(request.io_vectors[0].address, view.data(), view.size());
|
Memory::CopyToEmu(request.io_vectors[0].address, view.data(), view.size());
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::DIGetTMDSize(const IOCtlVRequest& request)
|
IPCReply ESDevice::DIGetTMDSize(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
|
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
if (!m_title_context.active)
|
if (!m_title_context.active)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
Memory::Write_U32(static_cast<u32>(m_title_context.tmd.GetBytes().size()),
|
Memory::Write_U32(static_cast<u32>(m_title_context.tmd.GetBytes().size()),
|
||||||
request.io_vectors[0].address);
|
request.io_vectors[0].address);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ESDevice::DIGetTMD(const IOCtlVRequest& request)
|
IPCReply ESDevice::DIGetTMD(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
|
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const u32 tmd_size = Memory::Read_U32(request.in_vectors[0].address);
|
const u32 tmd_size = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
if (tmd_size != request.io_vectors[0].size)
|
if (tmd_size != request.io_vectors[0].size)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
if (!m_title_context.active)
|
if (!m_title_context.active)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
const std::vector<u8>& tmd_bytes = m_title_context.tmd.GetBytes();
|
const std::vector<u8>& tmd_bytes = m_title_context.tmd.GetBytes();
|
||||||
|
|
||||||
if (static_cast<u32>(tmd_bytes.size()) > tmd_size)
|
if (static_cast<u32>(tmd_bytes.size()) > tmd_size)
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return IPCReply(ES_EINVAL);
|
||||||
|
|
||||||
Memory::CopyToEmu(request.io_vectors[0].address, tmd_bytes.data(), tmd_bytes.size());
|
Memory::CopyToEmu(request.io_vectors[0].address, tmd_bytes.data(), tmd_bytes.size());
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -22,10 +22,10 @@ namespace IOS::HLE
|
|||||||
{
|
{
|
||||||
using namespace IOS::HLE::FS;
|
using namespace IOS::HLE::FS;
|
||||||
|
|
||||||
static IPCCommandResult GetFSReply(s32 return_value, u64 extra_tb_ticks = 0)
|
static IPCReply GetFSReply(s32 return_value, u64 extra_tb_ticks = 0)
|
||||||
{
|
{
|
||||||
// According to hardware tests, FS takes at least 2700 TB ticks to reply to commands.
|
// According to hardware tests, FS takes at least 2700 TB ticks to reply to commands.
|
||||||
return {return_value, true, (2700 + extra_tb_ticks) * SystemTimers::TIMER_RATIO};
|
return IPCReply{return_value, (2700 + extra_tb_ticks) * SystemTimers::TIMER_RATIO};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Amount of TB ticks required for a superblock write to complete.
|
/// Amount of TB ticks required for a superblock write to complete.
|
||||||
@@ -97,13 +97,13 @@ static u64 EstimateFileLookupTicks(const std::string& path, FileLookupMode mode)
|
|||||||
///
|
///
|
||||||
/// A superblock flush takes a very large amount of time, so other delays are ignored
|
/// A superblock flush takes a very large amount of time, so other delays are ignored
|
||||||
/// to simplify the implementation as they are insignificant.
|
/// to simplify the implementation as they are insignificant.
|
||||||
static IPCCommandResult GetReplyForSuperblockOperation(ResultCode result)
|
static IPCReply GetReplyForSuperblockOperation(ResultCode result)
|
||||||
{
|
{
|
||||||
const u64 ticks = result == ResultCode::Success ? SUPERBLOCK_WRITE_TICKS : 0;
|
const u64 ticks = result == ResultCode::Success ? SUPERBLOCK_WRITE_TICKS : 0;
|
||||||
return GetFSReply(ConvertResult(result), ticks);
|
return GetFSReply(ConvertResult(result), ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::Open(const OpenRequest& request)
|
std::optional<IPCReply> FSDevice::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
if (m_fd_map.size() >= 16)
|
if (m_fd_map.size() >= 16)
|
||||||
return GetFSReply(ConvertResult(ResultCode::NoFreeHandle));
|
return GetFSReply(ConvertResult(ResultCode::NoFreeHandle));
|
||||||
@@ -130,7 +130,7 @@ IPCCommandResult FSDevice::Open(const OpenRequest& request)
|
|||||||
return GetFSReply(IPC_SUCCESS, ticks);
|
return GetFSReply(IPC_SUCCESS, ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::Close(u32 fd)
|
std::optional<IPCReply> FSDevice::Close(u32 fd)
|
||||||
{
|
{
|
||||||
u64 ticks = 0;
|
u64 ticks = 0;
|
||||||
if (m_fd_map[fd].fs_fd != INVALID_FD)
|
if (m_fd_map[fd].fs_fd != INVALID_FD)
|
||||||
@@ -229,7 +229,7 @@ bool FSDevice::HasCacheForFile(u32 fd, u32 offset) const
|
|||||||
return m_cache_fd == fd && m_cache_chain_index == chain_index;
|
return m_cache_fd == fd && m_cache_chain_index == chain_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::Read(const ReadWriteRequest& request)
|
std::optional<IPCReply> FSDevice::Read(const ReadWriteRequest& request)
|
||||||
{
|
{
|
||||||
const Handle& handle = m_fd_map[request.fd];
|
const Handle& handle = m_fd_map[request.fd];
|
||||||
if (handle.fs_fd == INVALID_FD)
|
if (handle.fs_fd == INVALID_FD)
|
||||||
@@ -247,7 +247,7 @@ IPCCommandResult FSDevice::Read(const ReadWriteRequest& request)
|
|||||||
return GetFSReply(*result, ticks);
|
return GetFSReply(*result, ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::Write(const ReadWriteRequest& request)
|
std::optional<IPCReply> FSDevice::Write(const ReadWriteRequest& request)
|
||||||
{
|
{
|
||||||
const Handle& handle = m_fd_map[request.fd];
|
const Handle& handle = m_fd_map[request.fd];
|
||||||
if (handle.fs_fd == INVALID_FD)
|
if (handle.fs_fd == INVALID_FD)
|
||||||
@@ -265,7 +265,7 @@ IPCCommandResult FSDevice::Write(const ReadWriteRequest& request)
|
|||||||
return GetFSReply(*result, ticks);
|
return GetFSReply(*result, ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::Seek(const SeekRequest& request)
|
std::optional<IPCReply> FSDevice::Seek(const SeekRequest& request)
|
||||||
{
|
{
|
||||||
const Handle& handle = m_fd_map[request.fd];
|
const Handle& handle = m_fd_map[request.fd];
|
||||||
if (handle.fs_fd == INVALID_FD)
|
if (handle.fs_fd == INVALID_FD)
|
||||||
@@ -318,11 +318,11 @@ static Result<T> GetParams(const IOCtlRequest& request)
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> FSDevice::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const auto it = m_fd_map.find(request.fd);
|
const auto it = m_fd_map.find(request.fd);
|
||||||
if (it == m_fd_map.end())
|
if (it == m_fd_map.end())
|
||||||
return GetDefaultReply(ConvertResult(ResultCode::Invalid));
|
return IPCReply(ConvertResult(ResultCode::Invalid));
|
||||||
|
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
@@ -353,11 +353,11 @@ IPCCommandResult FSDevice::IOCtl(const IOCtlRequest& request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> FSDevice::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
const auto it = m_fd_map.find(request.fd);
|
const auto it = m_fd_map.find(request.fd);
|
||||||
if (it == m_fd_map.end())
|
if (it == m_fd_map.end())
|
||||||
return GetDefaultReply(ConvertResult(ResultCode::Invalid));
|
return IPCReply(ConvertResult(ResultCode::Invalid));
|
||||||
|
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
@@ -370,7 +370,7 @@ IPCCommandResult FSDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::Format(const Handle& handle, const IOCtlRequest& request)
|
IPCReply FSDevice::Format(const Handle& handle, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (handle.uid != 0)
|
if (handle.uid != 0)
|
||||||
return GetFSReply(ConvertResult(ResultCode::AccessDenied));
|
return GetFSReply(ConvertResult(ResultCode::AccessDenied));
|
||||||
@@ -379,7 +379,7 @@ IPCCommandResult FSDevice::Format(const Handle& handle, const IOCtlRequest& requ
|
|||||||
return GetReplyForSuperblockOperation(result);
|
return GetReplyForSuperblockOperation(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::GetStats(const Handle& handle, const IOCtlRequest& request)
|
IPCReply FSDevice::GetStats(const Handle& handle, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.buffer_out_size < sizeof(ISFSNandStats))
|
if (request.buffer_out_size < sizeof(ISFSNandStats))
|
||||||
return GetFSReply(ConvertResult(ResultCode::Invalid));
|
return GetFSReply(ConvertResult(ResultCode::Invalid));
|
||||||
@@ -387,7 +387,7 @@ IPCCommandResult FSDevice::GetStats(const Handle& handle, const IOCtlRequest& re
|
|||||||
const Result<NandStats> stats = m_ios.GetFS()->GetNandStats();
|
const Result<NandStats> stats = m_ios.GetFS()->GetNandStats();
|
||||||
LogResult(stats, "GetNandStats");
|
LogResult(stats, "GetNandStats");
|
||||||
if (!stats)
|
if (!stats)
|
||||||
return GetDefaultReply(ConvertResult(stats.Error()));
|
return IPCReply(ConvertResult(stats.Error()));
|
||||||
|
|
||||||
ISFSNandStats out;
|
ISFSNandStats out;
|
||||||
out.cluster_size = stats->cluster_size;
|
out.cluster_size = stats->cluster_size;
|
||||||
@@ -398,10 +398,10 @@ IPCCommandResult FSDevice::GetStats(const Handle& handle, const IOCtlRequest& re
|
|||||||
out.free_inodes = stats->free_inodes;
|
out.free_inodes = stats->free_inodes;
|
||||||
out.used_inodes = stats->used_inodes;
|
out.used_inodes = stats->used_inodes;
|
||||||
Memory::CopyToEmu(request.buffer_out, &out, sizeof(out));
|
Memory::CopyToEmu(request.buffer_out, &out, sizeof(out));
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::CreateDirectory(const Handle& handle, const IOCtlRequest& request)
|
IPCReply FSDevice::CreateDirectory(const Handle& handle, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const auto params = GetParams<ISFSParams>(request);
|
const auto params = GetParams<ISFSParams>(request);
|
||||||
if (!params)
|
if (!params)
|
||||||
@@ -413,7 +413,7 @@ IPCCommandResult FSDevice::CreateDirectory(const Handle& handle, const IOCtlRequ
|
|||||||
return GetReplyForSuperblockOperation(result);
|
return GetReplyForSuperblockOperation(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::ReadDirectory(const Handle& handle, const IOCtlVRequest& request)
|
IPCReply FSDevice::ReadDirectory(const Handle& handle, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (request.in_vectors.empty() || request.in_vectors.size() != request.io_vectors.size() ||
|
if (request.in_vectors.empty() || request.in_vectors.size() != request.io_vectors.size() ||
|
||||||
request.in_vectors.size() > 2 || request.in_vectors[0].size != 64)
|
request.in_vectors.size() > 2 || request.in_vectors[0].size != 64)
|
||||||
@@ -467,7 +467,7 @@ IPCCommandResult FSDevice::ReadDirectory(const Handle& handle, const IOCtlVReque
|
|||||||
return GetFSReply(IPC_SUCCESS);
|
return GetFSReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::SetAttribute(const Handle& handle, const IOCtlRequest& request)
|
IPCReply FSDevice::SetAttribute(const Handle& handle, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const auto params = GetParams<ISFSParams>(request);
|
const auto params = GetParams<ISFSParams>(request);
|
||||||
if (!params)
|
if (!params)
|
||||||
@@ -479,7 +479,7 @@ IPCCommandResult FSDevice::SetAttribute(const Handle& handle, const IOCtlRequest
|
|||||||
return GetReplyForSuperblockOperation(result);
|
return GetReplyForSuperblockOperation(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::GetAttribute(const Handle& handle, const IOCtlRequest& request)
|
IPCReply FSDevice::GetAttribute(const Handle& handle, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.buffer_in_size < 64 || request.buffer_out_size < sizeof(ISFSParams))
|
if (request.buffer_in_size < 64 || request.buffer_out_size < sizeof(ISFSParams))
|
||||||
return GetFSReply(ConvertResult(ResultCode::Invalid));
|
return GetFSReply(ConvertResult(ResultCode::Invalid));
|
||||||
@@ -503,7 +503,7 @@ IPCCommandResult FSDevice::GetAttribute(const Handle& handle, const IOCtlRequest
|
|||||||
return GetFSReply(IPC_SUCCESS, ticks);
|
return GetFSReply(IPC_SUCCESS, ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::DeleteFile(const Handle& handle, const IOCtlRequest& request)
|
IPCReply FSDevice::DeleteFile(const Handle& handle, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.buffer_in_size < 64)
|
if (request.buffer_in_size < 64)
|
||||||
return GetFSReply(ConvertResult(ResultCode::Invalid));
|
return GetFSReply(ConvertResult(ResultCode::Invalid));
|
||||||
@@ -514,7 +514,7 @@ IPCCommandResult FSDevice::DeleteFile(const Handle& handle, const IOCtlRequest&
|
|||||||
return GetReplyForSuperblockOperation(result);
|
return GetReplyForSuperblockOperation(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::RenameFile(const Handle& handle, const IOCtlRequest& request)
|
IPCReply FSDevice::RenameFile(const Handle& handle, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.buffer_in_size < 64 * 2)
|
if (request.buffer_in_size < 64 * 2)
|
||||||
return GetFSReply(ConvertResult(ResultCode::Invalid));
|
return GetFSReply(ConvertResult(ResultCode::Invalid));
|
||||||
@@ -526,7 +526,7 @@ IPCCommandResult FSDevice::RenameFile(const Handle& handle, const IOCtlRequest&
|
|||||||
return GetReplyForSuperblockOperation(result);
|
return GetReplyForSuperblockOperation(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::CreateFile(const Handle& handle, const IOCtlRequest& request)
|
IPCReply FSDevice::CreateFile(const Handle& handle, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const auto params = GetParams<ISFSParams>(request);
|
const auto params = GetParams<ISFSParams>(request);
|
||||||
if (!params)
|
if (!params)
|
||||||
@@ -538,7 +538,7 @@ IPCCommandResult FSDevice::CreateFile(const Handle& handle, const IOCtlRequest&
|
|||||||
return GetReplyForSuperblockOperation(result);
|
return GetReplyForSuperblockOperation(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::SetFileVersionControl(const Handle& handle, const IOCtlRequest& request)
|
IPCReply FSDevice::SetFileVersionControl(const Handle& handle, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const auto params = GetParams<ISFSParams>(request);
|
const auto params = GetParams<ISFSParams>(request);
|
||||||
if (!params)
|
if (!params)
|
||||||
@@ -550,7 +550,7 @@ IPCCommandResult FSDevice::SetFileVersionControl(const Handle& handle, const IOC
|
|||||||
return GetFSReply(IPC_SUCCESS);
|
return GetFSReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::GetFileStats(const Handle& handle, const IOCtlRequest& request)
|
IPCReply FSDevice::GetFileStats(const Handle& handle, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.buffer_out_size < 8 || handle.fs_fd == INVALID_FD)
|
if (request.buffer_out_size < 8 || handle.fs_fd == INVALID_FD)
|
||||||
return GetFSReply(ConvertResult(ResultCode::Invalid));
|
return GetFSReply(ConvertResult(ResultCode::Invalid));
|
||||||
@@ -558,16 +558,16 @@ IPCCommandResult FSDevice::GetFileStats(const Handle& handle, const IOCtlRequest
|
|||||||
const Result<FileStatus> status = m_ios.GetFS()->GetFileStatus(handle.fs_fd);
|
const Result<FileStatus> status = m_ios.GetFS()->GetFileStatus(handle.fs_fd);
|
||||||
LogResult(status, "GetFileStatus({})", handle.name.data());
|
LogResult(status, "GetFileStatus({})", handle.name.data());
|
||||||
if (!status)
|
if (!status)
|
||||||
return GetDefaultReply(ConvertResult(status.Error()));
|
return IPCReply(ConvertResult(status.Error()));
|
||||||
|
|
||||||
ISFSFileStats out;
|
ISFSFileStats out;
|
||||||
out.size = status->size;
|
out.size = status->size;
|
||||||
out.seek_position = status->offset;
|
out.seek_position = status->offset;
|
||||||
Memory::CopyToEmu(request.buffer_out, &out, sizeof(out));
|
Memory::CopyToEmu(request.buffer_out, &out, sizeof(out));
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::GetUsage(const Handle& handle, const IOCtlVRequest& request)
|
IPCReply FSDevice::GetUsage(const Handle& handle, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 2) || request.in_vectors[0].size != 64 ||
|
if (!request.HasNumberOfValidVectors(1, 2) || request.in_vectors[0].size != 64 ||
|
||||||
request.io_vectors[0].size != 4 || request.io_vectors[1].size != 4)
|
request.io_vectors[0].size != 4 || request.io_vectors[1].size != 4)
|
||||||
@@ -586,7 +586,7 @@ IPCCommandResult FSDevice::GetUsage(const Handle& handle, const IOCtlVRequest& r
|
|||||||
return GetFSReply(IPC_SUCCESS);
|
return GetFSReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult FSDevice::Shutdown(const Handle& handle, const IOCtlRequest& request)
|
IPCReply FSDevice::Shutdown(const Handle& handle, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
INFO_LOG_FMT(IOS_FS, "Shutdown");
|
INFO_LOG_FMT(IOS_FS, "Shutdown");
|
||||||
return GetFSReply(IPC_SUCCESS);
|
return GetFSReply(IPC_SUCCESS);
|
||||||
|
@@ -26,13 +26,13 @@ public:
|
|||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
IPCCommandResult Open(const OpenRequest& request) override;
|
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||||
IPCCommandResult Close(u32 fd) override;
|
std::optional<IPCReply> Close(u32 fd) override;
|
||||||
IPCCommandResult Read(const ReadWriteRequest& request) override;
|
std::optional<IPCReply> Read(const ReadWriteRequest& request) override;
|
||||||
IPCCommandResult Write(const ReadWriteRequest& request) override;
|
std::optional<IPCReply> Write(const ReadWriteRequest& request) override;
|
||||||
IPCCommandResult Seek(const SeekRequest& request) override;
|
std::optional<IPCReply> Seek(const SeekRequest& request) override;
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Handle
|
struct Handle
|
||||||
@@ -62,19 +62,19 @@ private:
|
|||||||
ISFS_IOCTL_SHUTDOWN = 13,
|
ISFS_IOCTL_SHUTDOWN = 13,
|
||||||
};
|
};
|
||||||
|
|
||||||
IPCCommandResult Format(const Handle& handle, const IOCtlRequest& request);
|
IPCReply Format(const Handle& handle, const IOCtlRequest& request);
|
||||||
IPCCommandResult GetStats(const Handle& handle, const IOCtlRequest& request);
|
IPCReply GetStats(const Handle& handle, const IOCtlRequest& request);
|
||||||
IPCCommandResult CreateDirectory(const Handle& handle, const IOCtlRequest& request);
|
IPCReply CreateDirectory(const Handle& handle, const IOCtlRequest& request);
|
||||||
IPCCommandResult ReadDirectory(const Handle& handle, const IOCtlVRequest& request);
|
IPCReply ReadDirectory(const Handle& handle, const IOCtlVRequest& request);
|
||||||
IPCCommandResult SetAttribute(const Handle& handle, const IOCtlRequest& request);
|
IPCReply SetAttribute(const Handle& handle, const IOCtlRequest& request);
|
||||||
IPCCommandResult GetAttribute(const Handle& handle, const IOCtlRequest& request);
|
IPCReply GetAttribute(const Handle& handle, const IOCtlRequest& request);
|
||||||
IPCCommandResult DeleteFile(const Handle& handle, const IOCtlRequest& request);
|
IPCReply DeleteFile(const Handle& handle, const IOCtlRequest& request);
|
||||||
IPCCommandResult RenameFile(const Handle& handle, const IOCtlRequest& request);
|
IPCReply RenameFile(const Handle& handle, const IOCtlRequest& request);
|
||||||
IPCCommandResult CreateFile(const Handle& handle, const IOCtlRequest& request);
|
IPCReply CreateFile(const Handle& handle, const IOCtlRequest& request);
|
||||||
IPCCommandResult SetFileVersionControl(const Handle& handle, const IOCtlRequest& request);
|
IPCReply SetFileVersionControl(const Handle& handle, const IOCtlRequest& request);
|
||||||
IPCCommandResult GetFileStats(const Handle& handle, const IOCtlRequest& request);
|
IPCReply GetFileStats(const Handle& handle, const IOCtlRequest& request);
|
||||||
IPCCommandResult GetUsage(const Handle& handle, const IOCtlVRequest& request);
|
IPCReply GetUsage(const Handle& handle, const IOCtlVRequest& request);
|
||||||
IPCCommandResult Shutdown(const Handle& handle, const IOCtlRequest& request);
|
IPCReply Shutdown(const Handle& handle, const IOCtlRequest& request);
|
||||||
|
|
||||||
u64 EstimateTicksForReadWrite(const Handle& handle, const ReadWriteRequest& request);
|
u64 EstimateTicksForReadWrite(const Handle& handle, const ReadWriteRequest& request);
|
||||||
u64 SimulatePopulateFileCache(u32 fd, u32 offset, u32 file_size);
|
u64 SimulatePopulateFileCache(u32 fd, u32 offset, u32 file_size);
|
||||||
|
@@ -518,14 +518,14 @@ std::shared_ptr<Device> EmulationKernel::GetDeviceByName(std::string_view device
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the FD for the newly opened device (on success) or an error code.
|
// Returns the FD for the newly opened device (on success) or an error code.
|
||||||
IPCCommandResult Kernel::OpenDevice(OpenRequest& request)
|
std::optional<IPCReply> Kernel::OpenDevice(OpenRequest& request)
|
||||||
{
|
{
|
||||||
const s32 new_fd = GetFreeDeviceID();
|
const s32 new_fd = GetFreeDeviceID();
|
||||||
INFO_LOG_FMT(IOS, "Opening {} (mode {}, fd {})", request.path, request.flags, new_fd);
|
INFO_LOG_FMT(IOS, "Opening {} (mode {}, fd {})", request.path, request.flags, new_fd);
|
||||||
if (new_fd < 0 || new_fd >= IPC_MAX_FDS)
|
if (new_fd < 0 || new_fd >= IPC_MAX_FDS)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS, "Couldn't get a free fd, too many open files");
|
ERROR_LOG_FMT(IOS, "Couldn't get a free fd, too many open files");
|
||||||
return IPCCommandResult{IPC_EMAX, true, 5000 * SystemTimers::TIMER_RATIO};
|
return IPCReply{IPC_EMAX, 5000_tbticks};
|
||||||
}
|
}
|
||||||
request.fd = new_fd;
|
request.fd = new_fd;
|
||||||
|
|
||||||
@@ -547,22 +547,22 @@ IPCCommandResult Kernel::OpenDevice(OpenRequest& request)
|
|||||||
if (!device)
|
if (!device)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS, "Unknown device: {}", request.path);
|
ERROR_LOG_FMT(IOS, "Unknown device: {}", request.path);
|
||||||
return {IPC_ENOENT, true, 3700 * SystemTimers::TIMER_RATIO};
|
return IPCReply{IPC_ENOENT, 3700_tbticks};
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult result = device->Open(request);
|
std::optional<IPCReply> result = device->Open(request);
|
||||||
if (result.return_value >= IPC_SUCCESS)
|
if (result && result->return_value >= IPC_SUCCESS)
|
||||||
{
|
{
|
||||||
m_fdmap[new_fd] = device;
|
m_fdmap[new_fd] = device;
|
||||||
result.return_value = new_fd;
|
result->return_value = new_fd;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult Kernel::HandleIPCCommand(const Request& request)
|
std::optional<IPCReply> Kernel::HandleIPCCommand(const Request& request)
|
||||||
{
|
{
|
||||||
if (request.command < IPC_CMD_OPEN || request.command > IPC_CMD_IOCTLV)
|
if (request.command < IPC_CMD_OPEN || request.command > IPC_CMD_IOCTLV)
|
||||||
return IPCCommandResult{IPC_EINVAL, true, 978 * SystemTimers::TIMER_RATIO};
|
return IPCReply{IPC_EINVAL, 978_tbticks};
|
||||||
|
|
||||||
if (request.command == IPC_CMD_OPEN)
|
if (request.command == IPC_CMD_OPEN)
|
||||||
{
|
{
|
||||||
@@ -572,9 +572,9 @@ IPCCommandResult Kernel::HandleIPCCommand(const Request& request)
|
|||||||
|
|
||||||
const auto device = (request.fd < IPC_MAX_FDS) ? m_fdmap[request.fd] : nullptr;
|
const auto device = (request.fd < IPC_MAX_FDS) ? m_fdmap[request.fd] : nullptr;
|
||||||
if (!device)
|
if (!device)
|
||||||
return IPCCommandResult{IPC_EINVAL, true, 550 * SystemTimers::TIMER_RATIO};
|
return IPCReply{IPC_EINVAL, 550_tbticks};
|
||||||
|
|
||||||
IPCCommandResult ret;
|
std::optional<IPCReply> ret;
|
||||||
const u64 wall_time_before = Common::Timer::GetTimeUs();
|
const u64 wall_time_before = Common::Timer::GetTimeUs();
|
||||||
|
|
||||||
switch (request.command)
|
switch (request.command)
|
||||||
@@ -600,7 +600,7 @@ IPCCommandResult Kernel::HandleIPCCommand(const Request& request)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ASSERT_MSG(IOS, false, "Unexpected command: %x", request.command);
|
ASSERT_MSG(IOS, false, "Unexpected command: %x", request.command);
|
||||||
ret = IPCCommandResult{IPC_EINVAL, true, 978 * SystemTimers::TIMER_RATIO};
|
ret = IPCReply{IPC_EINVAL, 978_tbticks};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,18 +618,18 @@ IPCCommandResult Kernel::HandleIPCCommand(const Request& request)
|
|||||||
void Kernel::ExecuteIPCCommand(const u32 address)
|
void Kernel::ExecuteIPCCommand(const u32 address)
|
||||||
{
|
{
|
||||||
Request request{address};
|
Request request{address};
|
||||||
IPCCommandResult result = HandleIPCCommand(request);
|
std::optional<IPCReply> result = HandleIPCCommand(request);
|
||||||
|
|
||||||
if (!result.send_reply)
|
if (!result)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Ensure replies happen in order
|
// Ensure replies happen in order
|
||||||
const s64 ticks_until_last_reply = m_last_reply_time - CoreTiming::GetTicks();
|
const s64 ticks_until_last_reply = m_last_reply_time - CoreTiming::GetTicks();
|
||||||
if (ticks_until_last_reply > 0)
|
if (ticks_until_last_reply > 0)
|
||||||
result.reply_delay_ticks += ticks_until_last_reply;
|
result->reply_delay_ticks += ticks_until_last_reply;
|
||||||
m_last_reply_time = CoreTiming::GetTicks() + result.reply_delay_ticks;
|
m_last_reply_time = CoreTiming::GetTicks() + result->reply_delay_ticks;
|
||||||
|
|
||||||
EnqueueIPCReply(request, result.return_value, static_cast<int>(result.reply_delay_ticks));
|
EnqueueIPCReply(request, result->return_value, result->reply_delay_ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Happens AS SOON AS IPC gets a new pointer!
|
// Happens AS SOON AS IPC gets a new pointer!
|
||||||
@@ -638,12 +638,11 @@ void Kernel::EnqueueIPCRequest(u32 address)
|
|||||||
// Based on hardware tests, IOS takes between 5µs and 10µs to acknowledge an IPC request.
|
// Based on hardware tests, IOS takes between 5µs and 10µs to acknowledge an IPC request.
|
||||||
// Console 1: 456 TB ticks before ACK
|
// Console 1: 456 TB ticks before ACK
|
||||||
// Console 2: 658 TB ticks before ACK
|
// Console 2: 658 TB ticks before ACK
|
||||||
CoreTiming::ScheduleEvent(500 * SystemTimers::TIMER_RATIO, s_event_enqueue,
|
CoreTiming::ScheduleEvent(500_tbticks, s_event_enqueue, address | ENQUEUE_REQUEST_FLAG);
|
||||||
address | ENQUEUE_REQUEST_FLAG);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called to send a reply to an IOS syscall
|
// Called to send a reply to an IOS syscall
|
||||||
void Kernel::EnqueueIPCReply(const Request& request, const s32 return_value, int cycles_in_future,
|
void Kernel::EnqueueIPCReply(const Request& request, const s32 return_value, s64 cycles_in_future,
|
||||||
CoreTiming::FromThread from)
|
CoreTiming::FromThread from)
|
||||||
{
|
{
|
||||||
Memory::Write_U32(static_cast<u32>(return_value), request.address + 4);
|
Memory::Write_U32(static_cast<u32>(return_value), request.address + 4);
|
||||||
@@ -852,4 +851,20 @@ EmulationKernel* GetIOS()
|
|||||||
{
|
{
|
||||||
return s_ios.get();
|
return s_ios.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Based on a hardware test, a device takes at least ~2700 ticks to reply to an IPC request.
|
||||||
|
// Depending on how much work a command performs, this can take much longer (10000+)
|
||||||
|
// especially if the NAND filesystem is accessed.
|
||||||
|
//
|
||||||
|
// Because we currently don't emulate timing very accurately, we should not return
|
||||||
|
// the minimum possible reply time (~960 ticks from the kernel or ~2700 from devices)
|
||||||
|
// but an average value, otherwise we are going to be much too fast in most cases.
|
||||||
|
IPCReply::IPCReply(s32 return_value_) : IPCReply(return_value_, 4000_tbticks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IPCReply::IPCReply(s32 return_value_, u64 reply_delay_ticks_)
|
||||||
|
: return_value(return_value_), reply_delay_ticks(reply_delay_ticks_)
|
||||||
|
{
|
||||||
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -33,10 +34,14 @@ class ESDevice;
|
|||||||
struct Request;
|
struct Request;
|
||||||
struct OpenRequest;
|
struct OpenRequest;
|
||||||
|
|
||||||
struct IPCCommandResult
|
struct IPCReply
|
||||||
{
|
{
|
||||||
|
/// Constructs a reply with an average reply time.
|
||||||
|
/// Please avoid using this function if more accurate timings are known.
|
||||||
|
explicit IPCReply(s32 return_value_);
|
||||||
|
explicit IPCReply(s32 return_value_, u64 reply_delay_ticks_);
|
||||||
|
|
||||||
s32 return_value;
|
s32 return_value;
|
||||||
bool send_reply;
|
|
||||||
u64 reply_delay_ticks;
|
u64 reply_delay_ticks;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -84,7 +89,7 @@ public:
|
|||||||
void SDIO_EventNotify();
|
void SDIO_EventNotify();
|
||||||
|
|
||||||
void EnqueueIPCRequest(u32 address);
|
void EnqueueIPCRequest(u32 address);
|
||||||
void EnqueueIPCReply(const Request& request, s32 return_value, int cycles_in_future = 0,
|
void EnqueueIPCReply(const Request& request, s32 return_value, s64 cycles_in_future = 0,
|
||||||
CoreTiming::FromThread from = CoreTiming::FromThread::CPU);
|
CoreTiming::FromThread from = CoreTiming::FromThread::CPU);
|
||||||
|
|
||||||
void SetUidForPPC(u32 uid);
|
void SetUidForPPC(u32 uid);
|
||||||
@@ -102,7 +107,7 @@ protected:
|
|||||||
explicit Kernel(u64 title_id);
|
explicit Kernel(u64 title_id);
|
||||||
|
|
||||||
void ExecuteIPCCommand(u32 address);
|
void ExecuteIPCCommand(u32 address);
|
||||||
IPCCommandResult HandleIPCCommand(const Request& request);
|
std::optional<IPCReply> HandleIPCCommand(const Request& request);
|
||||||
void EnqueueIPCAcknowledgement(u32 address, int cycles_in_future = 0);
|
void EnqueueIPCAcknowledgement(u32 address, int cycles_in_future = 0);
|
||||||
|
|
||||||
void AddDevice(std::unique_ptr<Device> device);
|
void AddDevice(std::unique_ptr<Device> device);
|
||||||
@@ -110,7 +115,7 @@ protected:
|
|||||||
void AddStaticDevices();
|
void AddStaticDevices();
|
||||||
std::shared_ptr<Device> GetDeviceByName(std::string_view device_name);
|
std::shared_ptr<Device> GetDeviceByName(std::string_view device_name);
|
||||||
s32 GetFreeDeviceID();
|
s32 GetFreeDeviceID();
|
||||||
IPCCommandResult OpenDevice(OpenRequest& request);
|
std::optional<IPCReply> OpenDevice(OpenRequest& request);
|
||||||
|
|
||||||
bool m_is_responsible_for_nand_root = false;
|
bool m_is_responsible_for_nand_root = false;
|
||||||
u64 m_title_id = 0;
|
u64 m_title_id = 0;
|
||||||
|
@@ -285,11 +285,11 @@ static DefaultInterface GetSystemDefaultInterfaceOrFallback()
|
|||||||
return GetSystemDefaultInterface().value_or(FALLBACK_VALUES);
|
return GetSystemDefaultInterface().value_or(FALLBACK_VALUES);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> NetIPTopDevice::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (Core::WantsDeterminism())
|
if (Core::WantsDeterminism())
|
||||||
{
|
{
|
||||||
return GetDefaultReply(IPC_EACCES);
|
return IPCReply(IPC_EACCES);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
@@ -339,10 +339,10 @@ IPCCommandResult NetIPTopDevice::IOCtl(const IOCtlRequest& request)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> NetIPTopDevice::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
@@ -361,7 +361,7 @@ IPCCommandResult NetIPTopDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetIPTopDevice::Update()
|
void NetIPTopDevice::Update()
|
||||||
@@ -369,13 +369,13 @@ void NetIPTopDevice::Update()
|
|||||||
WiiSockMan::GetInstance().Update();
|
WiiSockMan::GetInstance().Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleInitInterfaceRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleInitInterfaceRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
request.Log(GetDeviceName(), Common::Log::IOS_WC24);
|
request.Log(GetDeviceName(), Common::Log::IOS_WC24);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleSocketRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleSocketRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const u32 af = Memory::Read_U32(request.buffer_in);
|
const u32 af = Memory::Read_U32(request.buffer_in);
|
||||||
const u32 type = Memory::Read_U32(request.buffer_in + 4);
|
const u32 type = Memory::Read_U32(request.buffer_in + 4);
|
||||||
@@ -389,20 +389,20 @@ IPCCommandResult NetIPTopDevice::HandleSocketRequest(const IOCtlRequest& request
|
|||||||
return_value, af, type, prot, request.buffer_in, request.buffer_in_size,
|
return_value, af, type, prot, request.buffer_in, request.buffer_in_size,
|
||||||
request.buffer_out, request.buffer_out_size);
|
request.buffer_out, request.buffer_out_size);
|
||||||
|
|
||||||
return GetDefaultReply(return_value);
|
return IPCReply(return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleICMPSocketRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleICMPSocketRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const u32 pf = Memory::Read_U32(request.buffer_in);
|
const u32 pf = Memory::Read_U32(request.buffer_in);
|
||||||
|
|
||||||
WiiSockMan& sm = WiiSockMan::GetInstance();
|
WiiSockMan& sm = WiiSockMan::GetInstance();
|
||||||
const s32 return_value = sm.NewSocket(pf, SOCK_RAW, IPPROTO_ICMP);
|
const s32 return_value = sm.NewSocket(pf, SOCK_RAW, IPPROTO_ICMP);
|
||||||
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_ICMPSOCKET({:x}) {}", pf, return_value);
|
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_ICMPSOCKET({:x}) {}", pf, return_value);
|
||||||
return GetDefaultReply(return_value);
|
return IPCReply(return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleCloseRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleCloseRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const u32 fd = Memory::Read_U32(request.buffer_in);
|
const u32 fd = Memory::Read_U32(request.buffer_in);
|
||||||
WiiSockMan& sm = WiiSockMan::GetInstance();
|
WiiSockMan& sm = WiiSockMan::GetInstance();
|
||||||
@@ -412,24 +412,24 @@ IPCCommandResult NetIPTopDevice::HandleCloseRequest(const IOCtlRequest& request)
|
|||||||
|
|
||||||
INFO_LOG_FMT(IOS_NET, "{}({:x}) {:x}", close_fn, fd, return_value);
|
INFO_LOG_FMT(IOS_NET, "{}({:x}) {:x}", close_fn, fd, return_value);
|
||||||
|
|
||||||
return GetDefaultReply(return_value);
|
return IPCReply(return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleDoSockRequest(const IOCtlRequest& request)
|
std::optional<IPCReply> NetIPTopDevice::HandleDoSockRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const u32 fd = Memory::Read_U32(request.buffer_in);
|
const u32 fd = Memory::Read_U32(request.buffer_in);
|
||||||
WiiSockMan& sm = WiiSockMan::GetInstance();
|
WiiSockMan& sm = WiiSockMan::GetInstance();
|
||||||
sm.DoSock(fd, request, static_cast<NET_IOCTL>(request.request));
|
sm.DoSock(fd, request, static_cast<NET_IOCTL>(request.request));
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleShutdownRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleShutdownRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.buffer_in == 0 || request.buffer_in_size < 8)
|
if (request.buffer_in == 0 || request.buffer_in_size < 8)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_NET, "IOCTL_SO_SHUTDOWN = EINVAL, BufferIn: ({:08x}, {})", request.buffer_in,
|
ERROR_LOG_FMT(IOS_NET, "IOCTL_SO_SHUTDOWN = EINVAL, BufferIn: ({:08x}, {})", request.buffer_in,
|
||||||
request.buffer_in_size);
|
request.buffer_in_size);
|
||||||
return GetDefaultReply(-SO_EINVAL);
|
return IPCReply(-SO_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 fd = Memory::Read_U32(request.buffer_in);
|
const u32 fd = Memory::Read_U32(request.buffer_in);
|
||||||
@@ -438,20 +438,20 @@ IPCCommandResult NetIPTopDevice::HandleShutdownRequest(const IOCtlRequest& reque
|
|||||||
const s32 return_value = sm.ShutdownSocket(fd, how);
|
const s32 return_value = sm.ShutdownSocket(fd, how);
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_SHUTDOWN(fd={}, how={}) = {}", fd, how, return_value);
|
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_SHUTDOWN(fd={}, how={}) = {}", fd, how, return_value);
|
||||||
return GetDefaultReply(return_value);
|
return IPCReply(return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleListenRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleListenRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
u32 fd = Memory::Read_U32(request.buffer_in);
|
u32 fd = Memory::Read_U32(request.buffer_in);
|
||||||
u32 BACKLOG = Memory::Read_U32(request.buffer_in + 0x04);
|
u32 BACKLOG = Memory::Read_U32(request.buffer_in + 0x04);
|
||||||
u32 ret = listen(WiiSockMan::GetInstance().GetHostSocket(fd), BACKLOG);
|
u32 ret = listen(WiiSockMan::GetInstance().GetHostSocket(fd), BACKLOG);
|
||||||
|
|
||||||
request.Log(GetDeviceName(), Common::Log::IOS_WC24);
|
request.Log(GetDeviceName(), Common::Log::IOS_WC24);
|
||||||
return GetDefaultReply(WiiSockMan::GetNetErrorCode(ret, "SO_LISTEN", false));
|
return IPCReply(WiiSockMan::GetNetErrorCode(ret, "SO_LISTEN", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleGetSockOptRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleGetSockOptRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
u32 fd = Memory::Read_U32(request.buffer_out);
|
u32 fd = Memory::Read_U32(request.buffer_out);
|
||||||
u32 level = Memory::Read_U32(request.buffer_out + 4);
|
u32 level = Memory::Read_U32(request.buffer_out + 4);
|
||||||
@@ -481,10 +481,10 @@ IPCCommandResult NetIPTopDevice::HandleGetSockOptRequest(const IOCtlRequest& req
|
|||||||
Memory::Write_U32(last_error, request.buffer_out + 0x10);
|
Memory::Write_U32(last_error, request.buffer_out + 0x10);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(return_value);
|
return IPCReply(return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleSetSockOptRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleSetSockOptRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const u32 fd = Memory::Read_U32(request.buffer_in);
|
const u32 fd = Memory::Read_U32(request.buffer_in);
|
||||||
const u32 level = Memory::Read_U32(request.buffer_in + 4);
|
const u32 level = Memory::Read_U32(request.buffer_in + 4);
|
||||||
@@ -508,7 +508,7 @@ IPCCommandResult NetIPTopDevice::HandleSetSockOptRequest(const IOCtlRequest& req
|
|||||||
// TODO: bug booto about this, 0x2005 most likely timeout related, default value on Wii is ,
|
// TODO: bug booto about this, 0x2005 most likely timeout related, default value on Wii is ,
|
||||||
// 0x2001 is most likely tcpnodelay
|
// 0x2001 is most likely tcpnodelay
|
||||||
if (level == 6 && (optname == 0x2005 || optname == 0x2001))
|
if (level == 6 && (optname == 0x2005 || optname == 0x2001))
|
||||||
return GetDefaultReply(0);
|
return IPCReply(0);
|
||||||
|
|
||||||
// Do the level/optname translation
|
// Do the level/optname translation
|
||||||
const int nat_level = MapWiiSockOptLevelToNative(level);
|
const int nat_level = MapWiiSockOptLevelToNative(level);
|
||||||
@@ -516,10 +516,10 @@ IPCCommandResult NetIPTopDevice::HandleSetSockOptRequest(const IOCtlRequest& req
|
|||||||
|
|
||||||
const int ret = setsockopt(WiiSockMan::GetInstance().GetHostSocket(fd), nat_level, nat_optname,
|
const int ret = setsockopt(WiiSockMan::GetInstance().GetHostSocket(fd), nat_level, nat_optname,
|
||||||
reinterpret_cast<char*>(optval), optlen);
|
reinterpret_cast<char*>(optval), optlen);
|
||||||
return GetDefaultReply(WiiSockMan::GetNetErrorCode(ret, "SO_SETSOCKOPT", false));
|
return IPCReply(WiiSockMan::GetNetErrorCode(ret, "SO_SETSOCKOPT", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleGetSockNameRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleGetSockNameRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
u32 fd = Memory::Read_U32(request.buffer_in);
|
u32 fd = Memory::Read_U32(request.buffer_in);
|
||||||
|
|
||||||
@@ -542,10 +542,10 @@ IPCCommandResult NetIPTopDevice::HandleGetSockNameRequest(const IOCtlRequest& re
|
|||||||
std::min<size_t>(sizeof(sa.sa_data), request.buffer_out_size - 2));
|
std::min<size_t>(sizeof(sa.sa_data), request.buffer_out_size - 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(ret);
|
return IPCReply(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleGetPeerNameRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleGetPeerNameRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
u32 fd = Memory::Read_U32(request.buffer_in);
|
u32 fd = Memory::Read_U32(request.buffer_in);
|
||||||
|
|
||||||
@@ -567,19 +567,19 @@ IPCCommandResult NetIPTopDevice::HandleGetPeerNameRequest(const IOCtlRequest& re
|
|||||||
}
|
}
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_GETPEERNAME({:x})", fd);
|
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_GETPEERNAME({:x})", fd);
|
||||||
return GetDefaultReply(ret);
|
return IPCReply(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleGetHostIDRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleGetHostIDRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const DefaultInterface interface = GetSystemDefaultInterfaceOrFallback();
|
const DefaultInterface interface = GetSystemDefaultInterfaceOrFallback();
|
||||||
const u32 host_ip = Common::swap32(interface.inet);
|
const u32 host_ip = Common::swap32(interface.inet);
|
||||||
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_GETHOSTID = {}.{}.{}.{}", host_ip >> 24, (host_ip >> 16) & 0xFF,
|
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_GETHOSTID = {}.{}.{}.{}", host_ip >> 24, (host_ip >> 16) & 0xFF,
|
||||||
(host_ip >> 8) & 0xFF, host_ip & 0xFF);
|
(host_ip >> 8) & 0xFF, host_ip & 0xFF);
|
||||||
return GetDefaultReply(host_ip);
|
return IPCReply(host_ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleInetAToNRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleInetAToNRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const std::string hostname = Memory::GetString(request.buffer_in);
|
const std::string hostname = Memory::GetString(request.buffer_in);
|
||||||
struct hostent* remoteHost = gethostbyname(hostname.c_str());
|
struct hostent* remoteHost = gethostbyname(hostname.c_str());
|
||||||
@@ -593,7 +593,7 @@ IPCCommandResult NetIPTopDevice::HandleInetAToNRequest(const IOCtlRequest& reque
|
|||||||
hostname, request.buffer_in, request.buffer_in_size, request.buffer_out,
|
hostname, request.buffer_in, request.buffer_in_size, request.buffer_out,
|
||||||
request.buffer_out_size);
|
request.buffer_out_size);
|
||||||
|
|
||||||
return GetDefaultReply(0);
|
return IPCReply(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto ip = Common::swap32(reinterpret_cast<u8*>(remoteHost->h_addr_list[0]));
|
const auto ip = Common::swap32(reinterpret_cast<u8*>(remoteHost->h_addr_list[0]));
|
||||||
@@ -605,17 +605,17 @@ IPCCommandResult NetIPTopDevice::HandleInetAToNRequest(const IOCtlRequest& reque
|
|||||||
hostname, request.buffer_in, request.buffer_in_size, request.buffer_out,
|
hostname, request.buffer_in, request.buffer_in_size, request.buffer_out,
|
||||||
request.buffer_out_size, ip);
|
request.buffer_out_size, ip);
|
||||||
|
|
||||||
return GetDefaultReply(1);
|
return IPCReply(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleInetPToNRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleInetPToNRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const std::string address = Memory::GetString(request.buffer_in);
|
const std::string address = Memory::GetString(request.buffer_in);
|
||||||
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_INETPTON (Translating: {})", address);
|
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_INETPTON (Translating: {})", address);
|
||||||
return GetDefaultReply(inet_pton(address.c_str(), Memory::GetPointer(request.buffer_out + 4)));
|
return IPCReply(inet_pton(address.c_str(), Memory::GetPointer(request.buffer_out + 4)));
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleInetNToPRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleInetNToPRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
// u32 af = Memory::Read_U32(BufferIn);
|
// u32 af = Memory::Read_U32(BufferIn);
|
||||||
// u32 validAddress = Memory::Read_U32(request.buffer_in + 4);
|
// u32 validAddress = Memory::Read_U32(request.buffer_in + 4);
|
||||||
@@ -628,15 +628,15 @@ IPCCommandResult NetIPTopDevice::HandleInetNToPRequest(const IOCtlRequest& reque
|
|||||||
|
|
||||||
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_INETNTOP {}", ip_s);
|
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_INETNTOP {}", ip_s);
|
||||||
Memory::CopyToEmu(request.buffer_out, reinterpret_cast<u8*>(ip_s), std::strlen(ip_s));
|
Memory::CopyToEmu(request.buffer_out, reinterpret_cast<u8*>(ip_s), std::strlen(ip_s));
|
||||||
return GetDefaultReply(0);
|
return IPCReply(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandlePollRequest(const IOCtlRequest& request)
|
std::optional<IPCReply> NetIPTopDevice::HandlePollRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
WiiSockMan& sm = WiiSockMan::GetInstance();
|
WiiSockMan& sm = WiiSockMan::GetInstance();
|
||||||
|
|
||||||
if (!request.buffer_in || !request.buffer_out)
|
if (!request.buffer_in || !request.buffer_out)
|
||||||
return GetDefaultReply(-SO_EINVAL);
|
return IPCReply(-SO_EINVAL);
|
||||||
|
|
||||||
// Negative timeout indicates wait forever
|
// Negative timeout indicates wait forever
|
||||||
const s64 timeout = static_cast<s64>(Memory::Read_U64(request.buffer_in));
|
const s64 timeout = static_cast<s64>(Memory::Read_U64(request.buffer_in));
|
||||||
@@ -645,7 +645,7 @@ IPCCommandResult NetIPTopDevice::HandlePollRequest(const IOCtlRequest& request)
|
|||||||
if (nfds == 0 || nfds > WII_SOCKET_FD_MAX)
|
if (nfds == 0 || nfds > WII_SOCKET_FD_MAX)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_NET, "IOCTL_SO_POLL failed: Invalid array size {}, ret={}", nfds, -SO_EINVAL);
|
ERROR_LOG_FMT(IOS_NET, "IOCTL_SO_POLL failed: Invalid array size {}, ret={}", nfds, -SO_EINVAL);
|
||||||
return GetDefaultReply(-SO_EINVAL);
|
return IPCReply(-SO_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<pollfd_t> ufds(nfds);
|
std::vector<pollfd_t> ufds(nfds);
|
||||||
@@ -671,15 +671,15 @@ IPCCommandResult NetIPTopDevice::HandlePollRequest(const IOCtlRequest& request)
|
|||||||
|
|
||||||
// Prevents blocking emulation on a blocking poll
|
// Prevents blocking emulation on a blocking poll
|
||||||
sm.AddPollCommand({request.address, request.buffer_out, std::move(ufds), timeout});
|
sm.AddPollCommand({request.address, request.buffer_out, std::move(ufds), timeout});
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleGetHostByNameRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleGetHostByNameRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.buffer_out_size != 0x460)
|
if (request.buffer_out_size != 0x460)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_NET, "Bad buffer size for IOCTL_SO_GETHOSTBYNAME");
|
ERROR_LOG_FMT(IOS_NET, "Bad buffer size for IOCTL_SO_GETHOSTBYNAME");
|
||||||
return GetDefaultReply(-1);
|
return IPCReply(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string hostname = Memory::GetString(request.buffer_in);
|
const std::string hostname = Memory::GetString(request.buffer_in);
|
||||||
@@ -692,7 +692,7 @@ IPCCommandResult NetIPTopDevice::HandleGetHostByNameRequest(const IOCtlRequest&
|
|||||||
request.buffer_out_size);
|
request.buffer_out_size);
|
||||||
|
|
||||||
if (remoteHost == nullptr)
|
if (remoteHost == nullptr)
|
||||||
return GetDefaultReply(-1);
|
return IPCReply(-1);
|
||||||
|
|
||||||
for (int i = 0; remoteHost->h_aliases[i]; ++i)
|
for (int i = 0; remoteHost->h_aliases[i]; ++i)
|
||||||
{
|
{
|
||||||
@@ -715,7 +715,7 @@ IPCCommandResult NetIPTopDevice::HandleGetHostByNameRequest(const IOCtlRequest&
|
|||||||
if (name_length > (GETHOSTBYNAME_IP_LIST_OFFSET - GETHOSTBYNAME_STRUCT_SIZE))
|
if (name_length > (GETHOSTBYNAME_IP_LIST_OFFSET - GETHOSTBYNAME_STRUCT_SIZE))
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_NET, "Hostname too long in IOCTL_SO_GETHOSTBYNAME");
|
ERROR_LOG_FMT(IOS_NET, "Hostname too long in IOCTL_SO_GETHOSTBYNAME");
|
||||||
return GetDefaultReply(-1);
|
return IPCReply(-1);
|
||||||
}
|
}
|
||||||
Memory::CopyToEmu(request.buffer_out + GETHOSTBYNAME_STRUCT_SIZE, remoteHost->h_name,
|
Memory::CopyToEmu(request.buffer_out + GETHOSTBYNAME_STRUCT_SIZE, remoteHost->h_name,
|
||||||
name_length);
|
name_length);
|
||||||
@@ -757,16 +757,16 @@ IPCCommandResult NetIPTopDevice::HandleGetHostByNameRequest(const IOCtlRequest&
|
|||||||
Memory::Write_U16(AF_INET, request.buffer_out + 8);
|
Memory::Write_U16(AF_INET, request.buffer_out + 8);
|
||||||
Memory::Write_U16(sizeof(u32), request.buffer_out + 10);
|
Memory::Write_U16(sizeof(u32), request.buffer_out + 10);
|
||||||
|
|
||||||
return GetDefaultReply(0);
|
return IPCReply(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleICMPCancelRequest(const IOCtlRequest& request)
|
IPCReply NetIPTopDevice::HandleICMPCancelRequest(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_NET, "IOCTL_SO_ICMPCANCEL");
|
ERROR_LOG_FMT(IOS_NET, "IOCTL_SO_ICMPCANCEL");
|
||||||
return GetDefaultReply(0);
|
return IPCReply(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleGetInterfaceOptRequest(const IOCtlVRequest& request)
|
IPCReply NetIPTopDevice::HandleGetInterfaceOptRequest(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
const u32 param = Memory::Read_U32(request.in_vectors[0].address);
|
const u32 param = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
const u32 param2 = Memory::Read_U32(request.in_vectors[0].address + 4);
|
const u32 param2 = Memory::Read_U32(request.in_vectors[0].address + 4);
|
||||||
@@ -777,7 +777,7 @@ IPCCommandResult NetIPTopDevice::HandleGetInterfaceOptRequest(const IOCtlVReques
|
|||||||
if (param != 0xfffe)
|
if (param != 0xfffe)
|
||||||
{
|
{
|
||||||
WARN_LOG_FMT(IOS_NET, "GetInterfaceOpt: received invalid request with param0={:08x}", param);
|
WARN_LOG_FMT(IOS_NET, "GetInterfaceOpt: received invalid request with param0={:08x}", param);
|
||||||
return GetDefaultReply(SO_ERROR_INVALID_REQUEST);
|
return IPCReply(SO_ERROR_INVALID_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.io_vectors[0].size >= 8)
|
if (request.io_vectors[0].size >= 8)
|
||||||
@@ -939,26 +939,26 @@ IPCCommandResult NetIPTopDevice::HandleGetInterfaceOptRequest(const IOCtlVReques
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(0);
|
return IPCReply(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleSendToRequest(const IOCtlVRequest& request)
|
std::optional<IPCReply> NetIPTopDevice::HandleSendToRequest(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
u32 fd = Memory::Read_U32(request.in_vectors[1].address);
|
u32 fd = Memory::Read_U32(request.in_vectors[1].address);
|
||||||
WiiSockMan& sm = WiiSockMan::GetInstance();
|
WiiSockMan& sm = WiiSockMan::GetInstance();
|
||||||
sm.DoSock(fd, request, IOCTLV_SO_SENDTO);
|
sm.DoSock(fd, request, IOCTLV_SO_SENDTO);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleRecvFromRequest(const IOCtlVRequest& request)
|
std::optional<IPCReply> NetIPTopDevice::HandleRecvFromRequest(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
u32 fd = Memory::Read_U32(request.in_vectors[0].address);
|
u32 fd = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
WiiSockMan& sm = WiiSockMan::GetInstance();
|
WiiSockMan& sm = WiiSockMan::GetInstance();
|
||||||
sm.DoSock(fd, request, IOCTLV_SO_RECVFROM);
|
sm.DoSock(fd, request, IOCTLV_SO_RECVFROM);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleGetAddressInfoRequest(const IOCtlVRequest& request)
|
IPCReply NetIPTopDevice::HandleGetAddressInfoRequest(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
addrinfo hints;
|
addrinfo hints;
|
||||||
const bool hints_valid = request.in_vectors.size() > 2 && request.in_vectors[2].size;
|
const bool hints_valid = request.in_vectors.size() > 2 && request.in_vectors[2].size;
|
||||||
@@ -1044,10 +1044,10 @@ IPCCommandResult NetIPTopDevice::HandleGetAddressInfoRequest(const IOCtlVRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
request.Dump(GetDeviceName(), Common::Log::IOS_NET, Common::Log::LINFO);
|
request.Dump(GetDeviceName(), Common::Log::IOS_NET, Common::Log::LINFO);
|
||||||
return GetDefaultReply(ret);
|
return IPCReply(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetIPTopDevice::HandleICMPPingRequest(const IOCtlVRequest& request)
|
IPCReply NetIPTopDevice::HandleICMPPingRequest(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@@ -1111,6 +1111,6 @@ IPCCommandResult NetIPTopDevice::HandleICMPPingRequest(const IOCtlVRequest& requ
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO proper error codes
|
// TODO proper error codes
|
||||||
return GetDefaultReply(0);
|
return IPCReply(0);
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -68,36 +68,36 @@ public:
|
|||||||
virtual ~NetIPTopDevice();
|
virtual ~NetIPTopDevice();
|
||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
void Update() override;
|
void Update() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IPCCommandResult HandleInitInterfaceRequest(const IOCtlRequest& request);
|
IPCReply HandleInitInterfaceRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleSocketRequest(const IOCtlRequest& request);
|
IPCReply HandleSocketRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleICMPSocketRequest(const IOCtlRequest& request);
|
IPCReply HandleICMPSocketRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleCloseRequest(const IOCtlRequest& request);
|
IPCReply HandleCloseRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleDoSockRequest(const IOCtlRequest& request);
|
std::optional<IPCReply> HandleDoSockRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleShutdownRequest(const IOCtlRequest& request);
|
IPCReply HandleShutdownRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleListenRequest(const IOCtlRequest& request);
|
IPCReply HandleListenRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleGetSockOptRequest(const IOCtlRequest& request);
|
IPCReply HandleGetSockOptRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleSetSockOptRequest(const IOCtlRequest& request);
|
IPCReply HandleSetSockOptRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleGetSockNameRequest(const IOCtlRequest& request);
|
IPCReply HandleGetSockNameRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleGetPeerNameRequest(const IOCtlRequest& request);
|
IPCReply HandleGetPeerNameRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleGetHostIDRequest(const IOCtlRequest& request);
|
IPCReply HandleGetHostIDRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleInetAToNRequest(const IOCtlRequest& request);
|
IPCReply HandleInetAToNRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleInetPToNRequest(const IOCtlRequest& request);
|
IPCReply HandleInetPToNRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleInetNToPRequest(const IOCtlRequest& request);
|
IPCReply HandleInetNToPRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandlePollRequest(const IOCtlRequest& request);
|
std::optional<IPCReply> HandlePollRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleGetHostByNameRequest(const IOCtlRequest& request);
|
IPCReply HandleGetHostByNameRequest(const IOCtlRequest& request);
|
||||||
IPCCommandResult HandleICMPCancelRequest(const IOCtlRequest& request);
|
IPCReply HandleICMPCancelRequest(const IOCtlRequest& request);
|
||||||
|
|
||||||
IPCCommandResult HandleGetInterfaceOptRequest(const IOCtlVRequest& request);
|
IPCReply HandleGetInterfaceOptRequest(const IOCtlVRequest& request);
|
||||||
IPCCommandResult HandleSendToRequest(const IOCtlVRequest& request);
|
std::optional<IPCReply> HandleSendToRequest(const IOCtlVRequest& request);
|
||||||
IPCCommandResult HandleRecvFromRequest(const IOCtlVRequest& request);
|
std::optional<IPCReply> HandleRecvFromRequest(const IOCtlVRequest& request);
|
||||||
IPCCommandResult HandleGetAddressInfoRequest(const IOCtlVRequest& request);
|
IPCReply HandleGetAddressInfoRequest(const IOCtlVRequest& request);
|
||||||
IPCCommandResult HandleICMPPingRequest(const IOCtlVRequest& request);
|
IPCReply HandleICMPPingRequest(const IOCtlVRequest& request);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WSADATA InitData;
|
WSADATA InitData;
|
||||||
|
@@ -32,7 +32,7 @@ NetKDRequestDevice::~NetKDRequestDevice()
|
|||||||
WiiSockMan::GetInstance().Clean();
|
WiiSockMan::GetInstance().Clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
s32 return_value = 0;
|
s32 return_value = 0;
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
@@ -169,7 +169,7 @@ IPCCommandResult NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
|
|||||||
request.Log(GetDeviceName(), Common::Log::IOS_WC24);
|
request.Log(GetDeviceName(), Common::Log::IOS_WC24);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(return_value);
|
return IPCReply(return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 NetKDRequestDevice::GetAreaCode(const std::string& area) const
|
u8 NetKDRequestDevice::GetAreaCode(const std::string& area) const
|
||||||
|
@@ -21,7 +21,7 @@ public:
|
|||||||
NetKDRequestDevice(Kernel& ios, const std::string& device_name);
|
NetKDRequestDevice(Kernel& ios, const std::string& device_name);
|
||||||
~NetKDRequestDevice() override;
|
~NetKDRequestDevice() override;
|
||||||
|
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum
|
enum
|
||||||
|
@@ -19,7 +19,7 @@ NetKDTimeDevice::NetKDTimeDevice(Kernel& ios, const std::string& device_name)
|
|||||||
|
|
||||||
NetKDTimeDevice::~NetKDTimeDevice() = default;
|
NetKDTimeDevice::~NetKDTimeDevice() = default;
|
||||||
|
|
||||||
IPCCommandResult NetKDTimeDevice::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> NetKDTimeDevice::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
s32 result = 0;
|
s32 result = 0;
|
||||||
u32 common_result = 0;
|
u32 common_result = 0;
|
||||||
@@ -72,7 +72,7 @@ IPCCommandResult NetKDTimeDevice::IOCtl(const IOCtlRequest& request)
|
|||||||
|
|
||||||
// write return values
|
// write return values
|
||||||
Memory::Write_U32(common_result, request.buffer_out);
|
Memory::Write_U32(common_result, request.buffer_out);
|
||||||
return GetDefaultReply(result);
|
return IPCReply(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 NetKDTimeDevice::GetAdjustedUTC() const
|
u64 NetKDTimeDevice::GetAdjustedUTC() const
|
||||||
|
@@ -17,7 +17,7 @@ public:
|
|||||||
NetKDTimeDevice(Kernel& ios, const std::string& device_name);
|
NetKDTimeDevice(Kernel& ios, const std::string& device_name);
|
||||||
~NetKDTimeDevice() override;
|
~NetKDTimeDevice() override;
|
||||||
|
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO: depending on CEXIIPL is a hack which I don't feel like
|
// TODO: depending on CEXIIPL is a hack which I don't feel like
|
||||||
|
@@ -27,7 +27,7 @@ void NetNCDManageDevice::DoState(PointerWrap& p)
|
|||||||
p.Do(m_ipc_fd);
|
p.Do(m_ipc_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetNCDManageDevice::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> NetNCDManageDevice::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
s32 return_value = IPC_SUCCESS;
|
s32 return_value = IPC_SUCCESS;
|
||||||
u32 common_result = 0;
|
u32 common_result = 0;
|
||||||
@@ -37,10 +37,10 @@ IPCCommandResult NetNCDManageDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
{
|
{
|
||||||
case IOCTLV_NCD_LOCKWIRELESSDRIVER:
|
case IOCTLV_NCD_LOCKWIRELESSDRIVER:
|
||||||
if (!request.HasNumberOfValidVectors(0, 1))
|
if (!request.HasNumberOfValidVectors(0, 1))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
if (request.io_vectors[0].size < 2 * sizeof(u32))
|
if (request.io_vectors[0].size < 2 * sizeof(u32))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
if (m_ipc_fd != 0)
|
if (m_ipc_fd != 0)
|
||||||
{
|
{
|
||||||
@@ -60,13 +60,13 @@ IPCCommandResult NetNCDManageDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
case IOCTLV_NCD_UNLOCKWIRELESSDRIVER:
|
case IOCTLV_NCD_UNLOCKWIRELESSDRIVER:
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1))
|
if (!request.HasNumberOfValidVectors(1, 1))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
if (request.in_vectors[0].size < sizeof(u32))
|
if (request.in_vectors[0].size < sizeof(u32))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
if (request.io_vectors[0].size < sizeof(u32))
|
if (request.io_vectors[0].size < sizeof(u32))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
const u32 request_handle = Memory::Read_U32(request.in_vectors[0].address);
|
const u32 request_handle = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
if (m_ipc_fd == request_handle)
|
if (m_ipc_fd == request_handle)
|
||||||
@@ -130,6 +130,6 @@ IPCCommandResult NetNCDManageDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
{
|
{
|
||||||
Memory::Write_U32(common_result, request.io_vectors.at(common_vector).address + 4);
|
Memory::Write_U32(common_result, request.io_vectors.at(common_vector).address + 4);
|
||||||
}
|
}
|
||||||
return GetDefaultReply(return_value);
|
return IPCReply(return_value);
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -18,7 +18,7 @@ class NetNCDManageDevice : public Device
|
|||||||
public:
|
public:
|
||||||
NetNCDManageDevice(Kernel& ios, const std::string& device_name);
|
NetNCDManageDevice(Kernel& ios, const std::string& device_name);
|
||||||
|
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
|
@@ -113,10 +113,10 @@ int NetSSLDevice::GetSSLFreeID() const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetSSLDevice::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> NetSSLDevice::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
request.Log(GetDeviceName(), Common::Log::IOS_SSL, Common::Log::LINFO);
|
request.Log(GetDeviceName(), Common::Log::IOS_SSL, Common::Log::LINFO);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr std::array<u8, 32> s_client_cert_hash = {
|
constexpr std::array<u8, 32> s_client_cert_hash = {
|
||||||
@@ -167,7 +167,7 @@ static std::vector<u8> ReadCertFile(const std::string& path, const std::array<u8
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetSSLDevice::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> NetSSLDevice::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
u32 BufferIn = 0, BufferIn2 = 0, BufferIn3 = 0;
|
u32 BufferIn = 0, BufferIn2 = 0, BufferIn3 = 0;
|
||||||
u32 BufferInSize = 0, BufferInSize2 = 0, BufferInSize3 = 0;
|
u32 BufferInSize = 0, BufferInSize2 = 0, BufferInSize3 = 0;
|
||||||
@@ -210,7 +210,7 @@ IPCCommandResult NetSSLDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
// I don't trust SSL to be deterministic, and this is never going to sync
|
// I don't trust SSL to be deterministic, and this is never going to sync
|
||||||
// as such (as opposed to forwarding IPC results or whatever), so -
|
// as such (as opposed to forwarding IPC results or whatever), so -
|
||||||
if (Core::WantsDeterminism())
|
if (Core::WantsDeterminism())
|
||||||
return GetDefaultReply(IPC_EACCES);
|
return IPCReply(IPC_EACCES);
|
||||||
|
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
@@ -499,7 +499,7 @@ IPCCommandResult NetSSLDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
{
|
{
|
||||||
WiiSockMan& sm = WiiSockMan::GetInstance();
|
WiiSockMan& sm = WiiSockMan::GetInstance();
|
||||||
sm.DoSock(_SSL[sslID].sockfd, request, IOCTLV_NET_SSL_DOHANDSHAKE);
|
sm.DoSock(_SSL[sslID].sockfd, request, IOCTLV_NET_SSL_DOHANDSHAKE);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -514,7 +514,7 @@ IPCCommandResult NetSSLDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
{
|
{
|
||||||
WiiSockMan& sm = WiiSockMan::GetInstance();
|
WiiSockMan& sm = WiiSockMan::GetInstance();
|
||||||
sm.DoSock(_SSL[sslID].sockfd, request, IOCTLV_NET_SSL_WRITE);
|
sm.DoSock(_SSL[sslID].sockfd, request, IOCTLV_NET_SSL_WRITE);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -538,7 +538,7 @@ IPCCommandResult NetSSLDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
{
|
{
|
||||||
WiiSockMan& sm = WiiSockMan::GetInstance();
|
WiiSockMan& sm = WiiSockMan::GetInstance();
|
||||||
sm.DoSock(_SSL[sslID].sockfd, request, IOCTLV_NET_SSL_READ);
|
sm.DoSock(_SSL[sslID].sockfd, request, IOCTLV_NET_SSL_READ);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -600,6 +600,6 @@ IPCCommandResult NetSSLDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SSL return codes are written to BufferIn
|
// SSL return codes are written to BufferIn
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -87,8 +87,8 @@ public:
|
|||||||
|
|
||||||
virtual ~NetSSLDevice();
|
virtual ~NetSSLDevice();
|
||||||
|
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
int GetSSLFreeID() const;
|
int GetSSLFreeID() const;
|
||||||
|
|
||||||
|
@@ -183,7 +183,7 @@ void NetWDCommandDevice::DoState(PointerWrap& p)
|
|||||||
p.Do(m_recv_notification_requests);
|
p.Do(m_recv_notification_requests);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetWDCommandDevice::Open(const OpenRequest& request)
|
std::optional<IPCReply> NetWDCommandDevice::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
if (m_ipc_owner_fd < 0)
|
if (m_ipc_owner_fd < 0)
|
||||||
{
|
{
|
||||||
@@ -197,7 +197,7 @@ IPCCommandResult NetWDCommandDevice::Open(const OpenRequest& request)
|
|||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_NET, "Unsupported WD operating mode: {}", mode);
|
ERROR_LOG_FMT(IOS_NET, "Unsupported WD operating mode: {}", mode);
|
||||||
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_UNCOMMON_WD_MODE);
|
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_UNCOMMON_WD_MODE);
|
||||||
return GetDefaultReply(s32(ResultCode::UnavailableCommand));
|
return IPCReply(s32(ResultCode::UnavailableCommand));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_target_status == Status::Idle && mode <= WD::Mode::Unknown6)
|
if (m_target_status == Status::Idle && mode <= WD::Mode::Unknown6)
|
||||||
@@ -212,12 +212,12 @@ IPCCommandResult NetWDCommandDevice::Open(const OpenRequest& request)
|
|||||||
return Device::Open(request);
|
return Device::Open(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetWDCommandDevice::Close(u32 fd)
|
std::optional<IPCReply> NetWDCommandDevice::Close(u32 fd)
|
||||||
{
|
{
|
||||||
if (m_ipc_owner_fd < 0 || fd != u32(m_ipc_owner_fd))
|
if (m_ipc_owner_fd < 0 || fd != u32(m_ipc_owner_fd))
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_NET, "Invalid close attempt.");
|
ERROR_LOG_FMT(IOS_NET, "Invalid close attempt.");
|
||||||
return GetDefaultReply(u32(ResultCode::InvalidFd));
|
return IPCReply(u32(ResultCode::InvalidFd));
|
||||||
}
|
}
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_NET, "Closing and resetting status to Idle");
|
INFO_LOG_FMT(IOS_NET, "Closing and resetting status to Idle");
|
||||||
@@ -228,11 +228,11 @@ IPCCommandResult NetWDCommandDevice::Close(u32 fd)
|
|||||||
return Device::Close(fd);
|
return Device::Close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetWDCommandDevice::SetLinkState(const IOCtlVRequest& request)
|
IPCReply NetWDCommandDevice::SetLinkState(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
const auto* vector = request.GetVector(0);
|
const auto* vector = request.GetVector(0);
|
||||||
if (!vector || vector->address == 0)
|
if (!vector || vector->address == 0)
|
||||||
return GetDefaultReply(u32(ResultCode::IllegalParameter));
|
return IPCReply(u32(ResultCode::IllegalParameter));
|
||||||
|
|
||||||
const u32 state = Memory::Read_U32(vector->address);
|
const u32 state = Memory::Read_U32(vector->address);
|
||||||
INFO_LOG_FMT(IOS_NET, "WD_SetLinkState called (state={}, mode={})", state, m_mode);
|
INFO_LOG_FMT(IOS_NET, "WD_SetLinkState called (state={}, mode={})", state, m_mode);
|
||||||
@@ -240,7 +240,7 @@ IPCCommandResult NetWDCommandDevice::SetLinkState(const IOCtlVRequest& request)
|
|||||||
if (state == 0)
|
if (state == 0)
|
||||||
{
|
{
|
||||||
if (!WD::IsValidMode(m_mode))
|
if (!WD::IsValidMode(m_mode))
|
||||||
return GetDefaultReply(u32(ResultCode::UnavailableCommand));
|
return IPCReply(u32(ResultCode::UnavailableCommand));
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_NET, "WD_SetLinkState: setting target status to 1 (Idle)");
|
INFO_LOG_FMT(IOS_NET, "WD_SetLinkState: setting target status to 1 (Idle)");
|
||||||
m_target_status = Status::Idle;
|
m_target_status = Status::Idle;
|
||||||
@@ -248,37 +248,37 @@ IPCCommandResult NetWDCommandDevice::SetLinkState(const IOCtlVRequest& request)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (state != 1)
|
if (state != 1)
|
||||||
return GetDefaultReply(u32(ResultCode::IllegalParameter));
|
return IPCReply(u32(ResultCode::IllegalParameter));
|
||||||
|
|
||||||
if (!WD::IsValidMode(m_mode))
|
if (!WD::IsValidMode(m_mode))
|
||||||
return GetDefaultReply(u32(ResultCode::UnavailableCommand));
|
return IPCReply(u32(ResultCode::UnavailableCommand));
|
||||||
|
|
||||||
const auto target_status = GetTargetStatusForMode(m_mode);
|
const auto target_status = GetTargetStatusForMode(m_mode);
|
||||||
if (m_status != target_status && m_info.enabled_channels == 0)
|
if (m_status != target_status && m_info.enabled_channels == 0)
|
||||||
return GetDefaultReply(u32(ResultCode::UnavailableCommand));
|
return IPCReply(u32(ResultCode::UnavailableCommand));
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_NET, "WD_SetLinkState: setting target status to {}", target_status);
|
INFO_LOG_FMT(IOS_NET, "WD_SetLinkState: setting target status to {}", target_status);
|
||||||
m_target_status = target_status;
|
m_target_status = target_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetWDCommandDevice::GetLinkState(const IOCtlVRequest& request) const
|
IPCReply NetWDCommandDevice::GetLinkState(const IOCtlVRequest& request) const
|
||||||
{
|
{
|
||||||
INFO_LOG_FMT(IOS_NET, "WD_GetLinkState called (status={}, mode={})", m_status, m_mode);
|
INFO_LOG_FMT(IOS_NET, "WD_GetLinkState called (status={}, mode={})", m_status, m_mode);
|
||||||
if (!WD::IsValidMode(m_mode))
|
if (!WD::IsValidMode(m_mode))
|
||||||
return GetDefaultReply(u32(ResultCode::UnavailableCommand));
|
return IPCReply(u32(ResultCode::UnavailableCommand));
|
||||||
|
|
||||||
// Contrary to what the name of the ioctl suggests, this returns a boolean, not the current state.
|
// Contrary to what the name of the ioctl suggests, this returns a boolean, not the current state.
|
||||||
return GetDefaultReply(u32(m_status == GetTargetStatusForMode(m_mode)));
|
return IPCReply(u32(m_status == GetTargetStatusForMode(m_mode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetWDCommandDevice::Disassociate(const IOCtlVRequest& request)
|
IPCReply NetWDCommandDevice::Disassociate(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
const auto* vector = request.GetVector(0);
|
const auto* vector = request.GetVector(0);
|
||||||
if (!vector || vector->address == 0)
|
if (!vector || vector->address == 0)
|
||||||
return GetDefaultReply(u32(ResultCode::IllegalParameter));
|
return IPCReply(u32(ResultCode::IllegalParameter));
|
||||||
|
|
||||||
Common::MACAddress mac;
|
Common::MACAddress mac;
|
||||||
Memory::CopyFromEmu(mac.data(), vector->address, mac.size());
|
Memory::CopyFromEmu(mac.data(), vector->address, mac.size());
|
||||||
@@ -289,7 +289,7 @@ IPCCommandResult NetWDCommandDevice::Disassociate(const IOCtlVRequest& request)
|
|||||||
m_mode != WD::Mode::Unknown6)
|
m_mode != WD::Mode::Unknown6)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_NET, "WD_Disassociate: cannot disassociate in mode {}", m_mode);
|
ERROR_LOG_FMT(IOS_NET, "WD_Disassociate: cannot disassociate in mode {}", m_mode);
|
||||||
return GetDefaultReply(u32(ResultCode::UnavailableCommand));
|
return IPCReply(u32(ResultCode::UnavailableCommand));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto target_status = GetTargetStatusForMode(m_mode);
|
const auto target_status = GetTargetStatusForMode(m_mode);
|
||||||
@@ -297,31 +297,31 @@ IPCCommandResult NetWDCommandDevice::Disassociate(const IOCtlVRequest& request)
|
|||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_NET, "WD_Disassociate: cannot disassociate in status {} (target {})",
|
ERROR_LOG_FMT(IOS_NET, "WD_Disassociate: cannot disassociate in status {} (target {})",
|
||||||
m_status, target_status);
|
m_status, target_status);
|
||||||
return GetDefaultReply(u32(ResultCode::UnavailableCommand));
|
return IPCReply(u32(ResultCode::UnavailableCommand));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check the input MAC address and only return 0x80008001 if it is unknown.
|
// TODO: Check the input MAC address and only return 0x80008001 if it is unknown.
|
||||||
return GetDefaultReply(u32(ResultCode::IllegalParameter));
|
return IPCReply(u32(ResultCode::IllegalParameter));
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetWDCommandDevice::GetInfo(const IOCtlVRequest& request) const
|
IPCReply NetWDCommandDevice::GetInfo(const IOCtlVRequest& request) const
|
||||||
{
|
{
|
||||||
const auto* vector = request.GetVector(0);
|
const auto* vector = request.GetVector(0);
|
||||||
if (!vector || vector->address == 0)
|
if (!vector || vector->address == 0)
|
||||||
return GetDefaultReply(u32(ResultCode::IllegalParameter));
|
return IPCReply(u32(ResultCode::IllegalParameter));
|
||||||
|
|
||||||
Memory::CopyToEmu(vector->address, &m_info, sizeof(m_info));
|
Memory::CopyToEmu(vector->address, &m_info, sizeof(m_info));
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult NetWDCommandDevice::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> NetWDCommandDevice::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
case IOCTLV_WD_INVALID:
|
case IOCTLV_WD_INVALID:
|
||||||
return GetDefaultReply(u32(ResultCode::UnavailableCommand));
|
return IPCReply(u32(ResultCode::UnavailableCommand));
|
||||||
case IOCTLV_WD_GET_MODE:
|
case IOCTLV_WD_GET_MODE:
|
||||||
return GetDefaultReply(s32(m_mode));
|
return IPCReply(s32(m_mode));
|
||||||
case IOCTLV_WD_SET_LINKSTATE:
|
case IOCTLV_WD_SET_LINKSTATE:
|
||||||
return SetLinkState(request);
|
return SetLinkState(request);
|
||||||
case IOCTLV_WD_GET_LINKSTATE:
|
case IOCTLV_WD_GET_LINKSTATE:
|
||||||
@@ -361,11 +361,11 @@ IPCCommandResult NetWDCommandDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
|
|
||||||
case IOCTLV_WD_RECV_FRAME:
|
case IOCTLV_WD_RECV_FRAME:
|
||||||
m_recv_frame_requests.emplace_back(request.address);
|
m_recv_frame_requests.emplace_back(request.address);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
|
|
||||||
case IOCTLV_WD_RECV_NOTIFICATION:
|
case IOCTLV_WD_RECV_NOTIFICATION:
|
||||||
m_recv_notification_requests.emplace_back(request.address);
|
m_recv_notification_requests.emplace_back(request.address);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
|
|
||||||
case IOCTLV_WD_SET_CONFIG:
|
case IOCTLV_WD_SET_CONFIG:
|
||||||
case IOCTLV_WD_GET_CONFIG:
|
case IOCTLV_WD_GET_CONFIG:
|
||||||
@@ -382,6 +382,6 @@ IPCCommandResult NetWDCommandDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
request.Dump(GetDeviceName(), Common::Log::IOS_NET, Common::Log::LWARNING);
|
request.Dump(GetDeviceName(), Common::Log::IOS_NET, Common::Log::LWARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -52,9 +52,9 @@ public:
|
|||||||
|
|
||||||
NetWDCommandDevice(Kernel& ios, const std::string& device_name);
|
NetWDCommandDevice(Kernel& ios, const std::string& device_name);
|
||||||
|
|
||||||
IPCCommandResult Open(const OpenRequest& request) override;
|
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||||
IPCCommandResult Close(u32 fd) override;
|
std::optional<IPCReply> Close(u32 fd) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
void Update() override;
|
void Update() override;
|
||||||
bool IsOpened() const override { return true; }
|
bool IsOpened() const override { return true; }
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
@@ -153,10 +153,10 @@ private:
|
|||||||
void HandleStateChange();
|
void HandleStateChange();
|
||||||
static Status GetTargetStatusForMode(WD::Mode mode);
|
static Status GetTargetStatusForMode(WD::Mode mode);
|
||||||
|
|
||||||
IPCCommandResult SetLinkState(const IOCtlVRequest& request);
|
IPCReply SetLinkState(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetLinkState(const IOCtlVRequest& request) const;
|
IPCReply GetLinkState(const IOCtlVRequest& request) const;
|
||||||
IPCCommandResult Disassociate(const IOCtlVRequest& request);
|
IPCReply Disassociate(const IOCtlVRequest& request);
|
||||||
IPCCommandResult GetInfo(const IOCtlVRequest& request) const;
|
IPCReply GetInfo(const IOCtlVRequest& request) const;
|
||||||
|
|
||||||
s32 m_ipc_owner_fd = -1;
|
s32 m_ipc_owner_fd = -1;
|
||||||
WD::Mode m_mode = WD::Mode::NotInitialized;
|
WD::Mode m_mode = WD::Mode::NotInitialized;
|
||||||
|
@@ -79,17 +79,17 @@ void SDIOSlot0Device::OpenInternal()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SDIOSlot0Device::Open(const OpenRequest& request)
|
std::optional<IPCReply> SDIOSlot0Device::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
OpenInternal();
|
OpenInternal();
|
||||||
m_registers.fill(0);
|
m_registers.fill(0);
|
||||||
|
|
||||||
m_is_active = true;
|
m_is_active = true;
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SDIOSlot0Device::Close(u32 fd)
|
std::optional<IPCReply> SDIOSlot0Device::Close(u32 fd)
|
||||||
{
|
{
|
||||||
m_card.Close();
|
m_card.Close();
|
||||||
m_block_length = 0;
|
m_block_length = 0;
|
||||||
@@ -98,7 +98,7 @@ IPCCommandResult SDIOSlot0Device::Close(u32 fd)
|
|||||||
return Device::Close(fd);
|
return Device::Close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SDIOSlot0Device::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> SDIOSlot0Device::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
Memory::Memset(request.buffer_out, 0, request.buffer_out_size);
|
Memory::Memset(request.buffer_out, 0, request.buffer_out_size);
|
||||||
|
|
||||||
@@ -123,10 +123,10 @@ IPCCommandResult SDIOSlot0Device::IOCtl(const IOCtlRequest& request)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SDIOSlot0Device::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> SDIOSlot0Device::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
@@ -137,7 +137,7 @@ IPCCommandResult SDIOSlot0Device::IOCtlV(const IOCtlVRequest& request)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 SDIOSlot0Device::ExecuteCommand(const Request& request, u32 buffer_in, u32 buffer_in_size,
|
s32 SDIOSlot0Device::ExecuteCommand(const Request& request, u32 buffer_in, u32 buffer_in_size,
|
||||||
@@ -325,7 +325,7 @@ s32 SDIOSlot0Device::ExecuteCommand(const Request& request, u32 buffer_in, u32 b
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SDIOSlot0Device::WriteHCRegister(const IOCtlRequest& request)
|
IPCReply SDIOSlot0Device::WriteHCRegister(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const u32 reg = Memory::Read_U32(request.buffer_in);
|
const u32 reg = Memory::Read_U32(request.buffer_in);
|
||||||
const u32 val = Memory::Read_U32(request.buffer_in + 16);
|
const u32 val = Memory::Read_U32(request.buffer_in + 16);
|
||||||
@@ -335,7 +335,7 @@ IPCCommandResult SDIOSlot0Device::WriteHCRegister(const IOCtlRequest& request)
|
|||||||
if (reg >= m_registers.size())
|
if (reg >= m_registers.size())
|
||||||
{
|
{
|
||||||
WARN_LOG_FMT(IOS_SD, "IOCTL_WRITEHCR out of range");
|
WARN_LOG_FMT(IOS_SD, "IOCTL_WRITEHCR out of range");
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((reg == HCR_CLOCKCONTROL) && (val & 1))
|
if ((reg == HCR_CLOCKCONTROL) && (val & 1))
|
||||||
@@ -354,17 +354,17 @@ IPCCommandResult SDIOSlot0Device::WriteHCRegister(const IOCtlRequest& request)
|
|||||||
m_registers[reg] = val;
|
m_registers[reg] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SDIOSlot0Device::ReadHCRegister(const IOCtlRequest& request)
|
IPCReply SDIOSlot0Device::ReadHCRegister(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const u32 reg = Memory::Read_U32(request.buffer_in);
|
const u32 reg = Memory::Read_U32(request.buffer_in);
|
||||||
|
|
||||||
if (reg >= m_registers.size())
|
if (reg >= m_registers.size())
|
||||||
{
|
{
|
||||||
WARN_LOG_FMT(IOS_SD, "IOCTL_READHCR out of range");
|
WARN_LOG_FMT(IOS_SD, "IOCTL_READHCR out of range");
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 val = m_registers[reg];
|
const u32 val = m_registers[reg];
|
||||||
@@ -372,20 +372,20 @@ IPCCommandResult SDIOSlot0Device::ReadHCRegister(const IOCtlRequest& request)
|
|||||||
|
|
||||||
// Just reading the register
|
// Just reading the register
|
||||||
Memory::Write_U32(val, request.buffer_out);
|
Memory::Write_U32(val, request.buffer_out);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SDIOSlot0Device::ResetCard(const IOCtlRequest& request)
|
IPCReply SDIOSlot0Device::ResetCard(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
INFO_LOG_FMT(IOS_SD, "IOCTL_RESETCARD");
|
INFO_LOG_FMT(IOS_SD, "IOCTL_RESETCARD");
|
||||||
|
|
||||||
// Returns 16bit RCA and 16bit 0s (meaning success)
|
// Returns 16bit RCA and 16bit 0s (meaning success)
|
||||||
Memory::Write_U32(m_status, request.buffer_out);
|
Memory::Write_U32(m_status, request.buffer_out);
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SDIOSlot0Device::SetClk(const IOCtlRequest& request)
|
IPCReply SDIOSlot0Device::SetClk(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
INFO_LOG_FMT(IOS_SD, "IOCTL_SETCLK");
|
INFO_LOG_FMT(IOS_SD, "IOCTL_SETCLK");
|
||||||
|
|
||||||
@@ -395,10 +395,10 @@ IPCCommandResult SDIOSlot0Device::SetClk(const IOCtlRequest& request)
|
|||||||
if (clock != 1)
|
if (clock != 1)
|
||||||
INFO_LOG_FMT(IOS_SD, "Setting to {}, interesting", clock);
|
INFO_LOG_FMT(IOS_SD, "Setting to {}, interesting", clock);
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SDIOSlot0Device::SendCommand(const IOCtlRequest& request)
|
std::optional<IPCReply> SDIOSlot0Device::SendCommand(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
INFO_LOG_FMT(IOS_SD, "IOCTL_SENDCMD {:x} IPC:{:08x}", Memory::Read_U32(request.buffer_in),
|
INFO_LOG_FMT(IOS_SD, "IOCTL_SENDCMD {:x} IPC:{:08x}", Memory::Read_U32(request.buffer_in),
|
||||||
request.address);
|
request.address);
|
||||||
@@ -410,13 +410,13 @@ IPCCommandResult SDIOSlot0Device::SendCommand(const IOCtlRequest& request)
|
|||||||
{
|
{
|
||||||
// Check if the condition is already true
|
// Check if the condition is already true
|
||||||
EventNotify();
|
EventNotify();
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SDIOSlot0Device::GetStatus(const IOCtlRequest& request)
|
IPCReply SDIOSlot0Device::GetStatus(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
// Since IOS does the SD initialization itself, we just say we're always initialized.
|
// Since IOS does the SD initialization itself, we just say we're always initialized.
|
||||||
if (m_card)
|
if (m_card)
|
||||||
@@ -450,19 +450,19 @@ IPCCommandResult SDIOSlot0Device::GetStatus(const IOCtlRequest& request)
|
|||||||
(status & CARD_INITIALIZED) ? " and initialized" : "");
|
(status & CARD_INITIALIZED) ? " and initialized" : "");
|
||||||
|
|
||||||
Memory::Write_U32(status, request.buffer_out);
|
Memory::Write_U32(status, request.buffer_out);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SDIOSlot0Device::GetOCRegister(const IOCtlRequest& request)
|
IPCReply SDIOSlot0Device::GetOCRegister(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const u32 ocr = GetOCRegister();
|
const u32 ocr = GetOCRegister();
|
||||||
INFO_LOG_FMT(IOS_SD, "IOCTL_GETOCR. Replying with ocr {:x}", ocr);
|
INFO_LOG_FMT(IOS_SD, "IOCTL_GETOCR. Replying with ocr {:x}", ocr);
|
||||||
Memory::Write_U32(ocr, request.buffer_out);
|
Memory::Write_U32(ocr, request.buffer_out);
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult SDIOSlot0Device::SendCommand(const IOCtlVRequest& request)
|
IPCReply SDIOSlot0Device::SendCommand(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
DEBUG_LOG_FMT(IOS_SD, "IOCTLV_SENDCMD {:#010x}", Memory::Read_U32(request.in_vectors[0].address));
|
DEBUG_LOG_FMT(IOS_SD, "IOCTLV_SENDCMD {:#010x}", Memory::Read_U32(request.in_vectors[0].address));
|
||||||
Memory::Memset(request.io_vectors[0].address, 0, request.io_vectors[0].size);
|
Memory::Memset(request.io_vectors[0].address, 0, request.io_vectors[0].size);
|
||||||
@@ -472,7 +472,7 @@ IPCCommandResult SDIOSlot0Device::SendCommand(const IOCtlVRequest& request)
|
|||||||
request.in_vectors[1].address, request.in_vectors[1].size,
|
request.in_vectors[1].address, request.in_vectors[1].size,
|
||||||
request.io_vectors[0].address, request.io_vectors[0].size);
|
request.io_vectors[0].address, request.io_vectors[0].size);
|
||||||
|
|
||||||
return GetDefaultReply(return_value);
|
return IPCReply(return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 SDIOSlot0Device::GetOCRegister() const
|
u32 SDIOSlot0Device::GetOCRegister() const
|
||||||
|
@@ -26,10 +26,10 @@ public:
|
|||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
IPCCommandResult Open(const OpenRequest& request) override;
|
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||||
IPCCommandResult Close(u32 fd) override;
|
std::optional<IPCReply> Close(u32 fd) override;
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
void EventNotify();
|
void EventNotify();
|
||||||
|
|
||||||
@@ -125,15 +125,15 @@ private:
|
|||||||
Request request;
|
Request request;
|
||||||
};
|
};
|
||||||
|
|
||||||
IPCCommandResult WriteHCRegister(const IOCtlRequest& request);
|
IPCReply WriteHCRegister(const IOCtlRequest& request);
|
||||||
IPCCommandResult ReadHCRegister(const IOCtlRequest& request);
|
IPCReply ReadHCRegister(const IOCtlRequest& request);
|
||||||
IPCCommandResult ResetCard(const IOCtlRequest& request);
|
IPCReply ResetCard(const IOCtlRequest& request);
|
||||||
IPCCommandResult SetClk(const IOCtlRequest& request);
|
IPCReply SetClk(const IOCtlRequest& request);
|
||||||
IPCCommandResult SendCommand(const IOCtlRequest& request);
|
std::optional<IPCReply> SendCommand(const IOCtlRequest& request);
|
||||||
IPCCommandResult GetStatus(const IOCtlRequest& request);
|
IPCReply GetStatus(const IOCtlRequest& request);
|
||||||
IPCCommandResult GetOCRegister(const IOCtlRequest& request);
|
IPCReply GetOCRegister(const IOCtlRequest& request);
|
||||||
|
|
||||||
IPCCommandResult SendCommand(const IOCtlVRequest& request);
|
IPCReply SendCommand(const IOCtlVRequest& request);
|
||||||
|
|
||||||
s32 ExecuteCommand(const Request& request, u32 buffer_in, u32 buffer_in_size, u32 rw_buffer,
|
s32 ExecuteCommand(const Request& request, u32 buffer_in, u32 buffer_in_size, u32 rw_buffer,
|
||||||
u32 rw_buffer_size, u32 buffer_out, u32 buffer_out_size);
|
u32 rw_buffer_size, u32 buffer_out, u32 buffer_out_size);
|
||||||
|
@@ -16,7 +16,7 @@ namespace IOS::HLE
|
|||||||
{
|
{
|
||||||
static std::unique_ptr<IOCtlRequest> s_event_hook_request;
|
static std::unique_ptr<IOCtlRequest> s_event_hook_request;
|
||||||
|
|
||||||
IPCCommandResult STMImmediateDevice::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> STMImmediateDevice::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
s32 return_value = IPC_SUCCESS;
|
s32 return_value = IPC_SUCCESS;
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
@@ -59,7 +59,7 @@ IPCCommandResult STMImmediateDevice::IOCtl(const IOCtlRequest& request)
|
|||||||
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_STM);
|
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_STM);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(return_value);
|
return IPCReply(return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
STMEventHookDevice::~STMEventHookDevice()
|
STMEventHookDevice::~STMEventHookDevice()
|
||||||
@@ -67,17 +67,17 @@ STMEventHookDevice::~STMEventHookDevice()
|
|||||||
s_event_hook_request.reset();
|
s_event_hook_request.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult STMEventHookDevice::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> STMEventHookDevice::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.request != IOCTL_STM_EVENTHOOK)
|
if (request.request != IOCTL_STM_EVENTHOOK)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
if (s_event_hook_request)
|
if (s_event_hook_request)
|
||||||
return GetDefaultReply(IPC_EEXIST);
|
return IPCReply(IPC_EEXIST);
|
||||||
|
|
||||||
// IOCTL_STM_EVENTHOOK waits until the reset button or power button is pressed.
|
// IOCTL_STM_EVENTHOOK waits until the reset button or power button is pressed.
|
||||||
s_event_hook_request = std::make_unique<IOCtlRequest>(request.address);
|
s_event_hook_request = std::make_unique<IOCtlRequest>(request.address);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void STMEventHookDevice::DoState(PointerWrap& p)
|
void STMEventHookDevice::DoState(PointerWrap& p)
|
||||||
|
@@ -43,7 +43,7 @@ class STMImmediateDevice final : public Device
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Device::Device;
|
using Device::Device;
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The /dev/stm/eventhook
|
// The /dev/stm/eventhook
|
||||||
@@ -52,7 +52,7 @@ class STMEventHookDevice final : public Device
|
|||||||
public:
|
public:
|
||||||
using Device::Device;
|
using Device::Device;
|
||||||
~STMEventHookDevice() override;
|
~STMEventHookDevice() override;
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
bool HasHookInstalled() const;
|
bool HasHookInstalled() const;
|
||||||
|
@@ -127,7 +127,7 @@ bool BluetoothEmuDevice::RemoteDisconnect(const bdaddr_t& address)
|
|||||||
return SendEventDisconnect(GetConnectionHandle(address), 0x13);
|
return SendEventDisconnect(GetConnectionHandle(address), 0x13);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult BluetoothEmuDevice::Close(u32 fd)
|
std::optional<IPCReply> BluetoothEmuDevice::Close(u32 fd)
|
||||||
{
|
{
|
||||||
// Clean up state
|
// Clean up state
|
||||||
m_scan_enable = 0;
|
m_scan_enable = 0;
|
||||||
@@ -139,7 +139,7 @@ IPCCommandResult BluetoothEmuDevice::Close(u32 fd)
|
|||||||
return Device::Close(fd);
|
return Device::Close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult BluetoothEmuDevice::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> BluetoothEmuDevice::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
bool send_reply = true;
|
bool send_reply = true;
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
@@ -204,7 +204,9 @@ IPCCommandResult BluetoothEmuDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_WIIMOTE);
|
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_WIIMOTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return send_reply ? GetDefaultReply(IPC_SUCCESS) : GetNoReply();
|
if (!send_reply)
|
||||||
|
return std::nullopt;
|
||||||
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here we handle the USB::IOCTLV_USBV0_BLKMSG Ioctlv
|
// Here we handle the USB::IOCTLV_USBV0_BLKMSG Ioctlv
|
||||||
|
@@ -44,8 +44,8 @@ public:
|
|||||||
|
|
||||||
virtual ~BluetoothEmuDevice();
|
virtual ~BluetoothEmuDevice();
|
||||||
|
|
||||||
IPCCommandResult Close(u32 fd) override;
|
std::optional<IPCReply> Close(u32 fd) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
void Update() override;
|
void Update() override;
|
||||||
|
|
||||||
|
@@ -77,10 +77,10 @@ BluetoothRealDevice::~BluetoothRealDevice()
|
|||||||
SaveLinkKeys();
|
SaveLinkKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult BluetoothRealDevice::Open(const OpenRequest& request)
|
std::optional<IPCReply> BluetoothRealDevice::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
if (!m_context.IsValid())
|
if (!m_context.IsValid())
|
||||||
return GetDefaultReply(IPC_EACCES);
|
return IPCReply(IPC_EACCES);
|
||||||
|
|
||||||
m_last_open_error.clear();
|
m_last_open_error.clear();
|
||||||
m_context.GetDeviceList([this](libusb_device* device) {
|
m_context.GetDeviceList([this](libusb_device* device) {
|
||||||
@@ -132,13 +132,13 @@ IPCCommandResult BluetoothRealDevice::Open(const OpenRequest& request)
|
|||||||
m_last_open_error);
|
m_last_open_error);
|
||||||
}
|
}
|
||||||
Core::QueueHostJob(Core::Stop);
|
Core::QueueHostJob(Core::Stop);
|
||||||
return GetDefaultReply(IPC_ENOENT);
|
return IPCReply(IPC_ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Device::Open(request);
|
return Device::Open(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult BluetoothRealDevice::Close(u32 fd)
|
std::optional<IPCReply> BluetoothRealDevice::Close(u32 fd)
|
||||||
{
|
{
|
||||||
if (m_handle)
|
if (m_handle)
|
||||||
{
|
{
|
||||||
@@ -151,7 +151,7 @@ IPCCommandResult BluetoothRealDevice::Close(u32 fd)
|
|||||||
return Device::Close(fd);
|
return Device::Close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult BluetoothRealDevice::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> BluetoothRealDevice::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!m_is_wii_bt_module && m_need_reset_keys.TestAndClear())
|
if (!m_is_wii_bt_module && m_need_reset_keys.TestAndClear())
|
||||||
{
|
{
|
||||||
@@ -173,13 +173,13 @@ IPCCommandResult BluetoothRealDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
if (opcode == HCI_CMD_READ_BUFFER_SIZE)
|
if (opcode == HCI_CMD_READ_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
m_fake_read_buffer_size_reply.Set();
|
m_fake_read_buffer_size_reply.Set();
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
if (!m_is_wii_bt_module && (opcode == 0xFC4C || opcode == 0xFC4F))
|
if (!m_is_wii_bt_module && (opcode == 0xFC4C || opcode == 0xFC4F))
|
||||||
{
|
{
|
||||||
m_fake_vendor_command_reply.Set();
|
m_fake_vendor_command_reply.Set();
|
||||||
m_fake_vendor_command_reply_opcode = opcode;
|
m_fake_vendor_command_reply_opcode = opcode;
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
if (opcode == HCI_CMD_DELETE_STORED_LINK_KEY)
|
if (opcode == HCI_CMD_DELETE_STORED_LINK_KEY)
|
||||||
{
|
{
|
||||||
@@ -218,23 +218,23 @@ IPCCommandResult BluetoothRealDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
{
|
{
|
||||||
Core::DisplayMessage("Scanning for Wii Remotes", 2000);
|
Core::DisplayMessage("Scanning for Wii Remotes", 2000);
|
||||||
FakeSyncButtonPressedEvent(*cmd);
|
FakeSyncButtonPressedEvent(*cmd);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
if (m_sync_button_state == SyncButtonState::LongPressed)
|
if (m_sync_button_state == SyncButtonState::LongPressed)
|
||||||
{
|
{
|
||||||
Core::DisplayMessage("Reset saved Wii Remote pairings", 2000);
|
Core::DisplayMessage("Reset saved Wii Remote pairings", 2000);
|
||||||
FakeSyncButtonHeldEvent(*cmd);
|
FakeSyncButtonHeldEvent(*cmd);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
if (m_fake_read_buffer_size_reply.TestAndClear())
|
if (m_fake_read_buffer_size_reply.TestAndClear())
|
||||||
{
|
{
|
||||||
FakeReadBufferSizeReply(*cmd);
|
FakeReadBufferSizeReply(*cmd);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
if (m_fake_vendor_command_reply.TestAndClear())
|
if (m_fake_vendor_command_reply.TestAndClear())
|
||||||
{
|
{
|
||||||
FakeVendorCommandReply(*cmd);
|
FakeVendorCommandReply(*cmd);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto buffer = cmd->MakeBuffer(cmd->length);
|
auto buffer = cmd->MakeBuffer(cmd->length);
|
||||||
@@ -258,7 +258,7 @@ IPCCommandResult BluetoothRealDevice::IOCtlV(const IOCtlVRequest& request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Replies are generated inside of the message handlers (and asynchronously).
|
// Replies are generated inside of the message handlers (and asynchronously).
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool s_has_shown_savestate_warning = false;
|
static bool s_has_shown_savestate_warning = false;
|
||||||
|
@@ -46,9 +46,9 @@ public:
|
|||||||
BluetoothRealDevice(Kernel& ios, const std::string& device_name);
|
BluetoothRealDevice(Kernel& ios, const std::string& device_name);
|
||||||
~BluetoothRealDevice() override;
|
~BluetoothRealDevice() override;
|
||||||
|
|
||||||
IPCCommandResult Open(const OpenRequest& request) override;
|
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||||
IPCCommandResult Close(u32 fd) override;
|
std::optional<IPCReply> Close(u32 fd) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
void UpdateSyncButtonState(bool is_held) override;
|
void UpdateSyncButtonState(bool is_held) override;
|
||||||
|
@@ -10,11 +10,11 @@
|
|||||||
|
|
||||||
namespace IOS::HLE
|
namespace IOS::HLE
|
||||||
{
|
{
|
||||||
IPCCommandResult BluetoothStubDevice::Open(const OpenRequest& request)
|
std::optional<IPCReply> BluetoothStubDevice::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
PanicAlertFmtT("Bluetooth passthrough mode is enabled, but Dolphin was built without libusb."
|
PanicAlertFmtT("Bluetooth passthrough mode is enabled, but Dolphin was built without libusb."
|
||||||
" Passthrough mode cannot be used.");
|
" Passthrough mode cannot be used.");
|
||||||
return GetDefaultReply(IPC_ENOENT);
|
return IPCReply(IPC_ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BluetoothStubDevice::DoState(PointerWrap& p)
|
void BluetoothStubDevice::DoState(PointerWrap& p)
|
||||||
|
@@ -18,7 +18,7 @@ class BluetoothStubDevice final : public BluetoothBaseDevice
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using BluetoothBaseDevice::BluetoothBaseDevice;
|
using BluetoothBaseDevice::BluetoothBaseDevice;
|
||||||
IPCCommandResult Open(const OpenRequest& request) override;
|
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
};
|
};
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -33,7 +33,7 @@ USBHost::USBHost(Kernel& ios, const std::string& device_name) : Device(ios, devi
|
|||||||
|
|
||||||
USBHost::~USBHost() = default;
|
USBHost::~USBHost() = default;
|
||||||
|
|
||||||
IPCCommandResult USBHost::Open(const OpenRequest& request)
|
std::optional<IPCReply> USBHost::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
if (!m_has_initialised && !Core::WantsDeterminism())
|
if (!m_has_initialised && !Core::WantsDeterminism())
|
||||||
{
|
{
|
||||||
@@ -43,7 +43,7 @@ IPCCommandResult USBHost::Open(const OpenRequest& request)
|
|||||||
GetScanThread().WaitForFirstScan();
|
GetScanThread().WaitForFirstScan();
|
||||||
m_has_initialised = true;
|
m_has_initialised = true;
|
||||||
}
|
}
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBHost::UpdateWantDeterminism(const bool new_want_determinism)
|
void USBHost::UpdateWantDeterminism(const bool new_want_determinism)
|
||||||
@@ -213,18 +213,18 @@ void USBHost::ScanThread::Stop()
|
|||||||
m_host->DispatchHooks(hooks);
|
m_host->DispatchHooks(hooks);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USBHost::HandleTransfer(std::shared_ptr<USB::Device> device, u32 request,
|
std::optional<IPCReply> USBHost::HandleTransfer(std::shared_ptr<USB::Device> device, u32 request,
|
||||||
std::function<s32()> submit) const
|
std::function<s32()> submit) const
|
||||||
{
|
{
|
||||||
if (!device)
|
if (!device)
|
||||||
return GetDefaultReply(IPC_ENOENT);
|
return IPCReply(IPC_ENOENT);
|
||||||
|
|
||||||
const s32 ret = submit();
|
const s32 ret = submit();
|
||||||
if (ret == IPC_SUCCESS)
|
if (ret == IPC_SUCCESS)
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
|
|
||||||
ERROR_LOG_FMT(IOS_USB, "[{:04x}:{:04x}] Failed to submit transfer (request {}): {}",
|
ERROR_LOG_FMT(IOS_USB, "[{:04x}:{:04x}] Failed to submit transfer (request {}): {}",
|
||||||
device->GetVid(), device->GetPid(), request, device->GetErrorName(ret));
|
device->GetVid(), device->GetPid(), request, device->GetErrorName(ret));
|
||||||
return GetDefaultReply(ret <= 0 ? ret : IPC_EINVAL);
|
return IPCReply(ret <= 0 ? ret : IPC_EINVAL);
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -33,7 +33,7 @@ public:
|
|||||||
USBHost(Kernel& ios, const std::string& device_name);
|
USBHost(Kernel& ios, const std::string& device_name);
|
||||||
virtual ~USBHost();
|
virtual ~USBHost();
|
||||||
|
|
||||||
IPCCommandResult Open(const OpenRequest& request) override;
|
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||||
|
|
||||||
void UpdateWantDeterminism(bool new_want_determinism) override;
|
void UpdateWantDeterminism(bool new_want_determinism) override;
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
@@ -72,8 +72,8 @@ protected:
|
|||||||
virtual bool ShouldAddDevice(const USB::Device& device) const;
|
virtual bool ShouldAddDevice(const USB::Device& device) const;
|
||||||
virtual ScanThread& GetScanThread() = 0;
|
virtual ScanThread& GetScanThread() = 0;
|
||||||
|
|
||||||
IPCCommandResult HandleTransfer(std::shared_ptr<USB::Device> device, u32 request,
|
std::optional<IPCReply> HandleTransfer(std::shared_ptr<USB::Device> device, u32 request,
|
||||||
std::function<s32()> submit) const;
|
std::function<s32()> submit) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool AddDevice(std::unique_ptr<USB::Device> device);
|
bool AddDevice(std::unique_ptr<USB::Device> device);
|
||||||
|
@@ -31,14 +31,14 @@ OH0::~OH0()
|
|||||||
m_scan_thread.Stop();
|
m_scan_thread.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::Open(const OpenRequest& request)
|
std::optional<IPCReply> OH0::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
if (HasFeature(m_ios.GetVersion(), Feature::NewUSB))
|
if (HasFeature(m_ios.GetVersion(), Feature::NewUSB))
|
||||||
return GetDefaultReply(IPC_EACCES);
|
return IPCReply(IPC_EACCES);
|
||||||
return USBHost::Open(request);
|
return USBHost::Open(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> OH0::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
request.Log(GetDeviceName(), Common::Log::IOS_USB);
|
request.Log(GetDeviceName(), Common::Log::IOS_USB);
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
@@ -48,11 +48,11 @@ IPCCommandResult OH0::IOCtl(const IOCtlRequest& request)
|
|||||||
case USB::IOCTL_USBV0_CANCEL_INSERT_HOOK:
|
case USB::IOCTL_USBV0_CANCEL_INSERT_HOOK:
|
||||||
return CancelInsertionHook(request);
|
return CancelInsertionHook(request);
|
||||||
default:
|
default:
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> OH0::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
INFO_LOG_FMT(IOS_USB, "/dev/usb/oh0 - IOCtlV {}", request.request);
|
INFO_LOG_FMT(IOS_USB, "/dev/usb/oh0 - IOCtlV {}", request.request);
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
@@ -70,7 +70,7 @@ IPCCommandResult OH0::IOCtlV(const IOCtlVRequest& request)
|
|||||||
case USB::IOCTLV_USBV0_DEVINSERTHOOKID:
|
case USB::IOCTLV_USBV0_DEVINSERTHOOKID:
|
||||||
return RegisterInsertionHookWithID(request);
|
return RegisterInsertionHookWithID(request);
|
||||||
default:
|
default:
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,26 +88,26 @@ void OH0::DoState(PointerWrap& p)
|
|||||||
USBHost::DoState(p);
|
USBHost::DoState(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::CancelInsertionHook(const IOCtlRequest& request)
|
IPCReply OH0::CancelInsertionHook(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.buffer_in || request.buffer_in_size != 4)
|
if (!request.buffer_in || request.buffer_in_size != 4)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
// IOS assigns random IDs, but ours are simply the VID + PID (see RegisterInsertionHookWithID)
|
// IOS assigns random IDs, but ours are simply the VID + PID (see RegisterInsertionHookWithID)
|
||||||
TriggerHook(m_insertion_hooks,
|
TriggerHook(m_insertion_hooks,
|
||||||
{Memory::Read_U16(request.buffer_in), Memory::Read_U16(request.buffer_in + 2)},
|
{Memory::Read_U16(request.buffer_in), Memory::Read_U16(request.buffer_in + 2)},
|
||||||
USB_ECANCELED);
|
USB_ECANCELED);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::GetDeviceList(const IOCtlVRequest& request) const
|
IPCReply OH0::GetDeviceList(const IOCtlVRequest& request) const
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 2))
|
if (!request.HasNumberOfValidVectors(2, 2))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
const u8 max_entries_count = Memory::Read_U8(request.in_vectors[0].address);
|
const u8 max_entries_count = Memory::Read_U8(request.in_vectors[0].address);
|
||||||
if (request.io_vectors[1].size != max_entries_count * sizeof(DeviceEntry))
|
if (request.io_vectors[1].size != max_entries_count * sizeof(DeviceEntry))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
const u8 interface_class = Memory::Read_U8(request.in_vectors[1].address);
|
const u8 interface_class = Memory::Read_U8(request.in_vectors[1].address);
|
||||||
u8 entries_count = 0;
|
u8 entries_count = 0;
|
||||||
@@ -126,91 +126,91 @@ IPCCommandResult OH0::GetDeviceList(const IOCtlVRequest& request) const
|
|||||||
Memory::CopyToEmu(request.io_vectors[1].address + 8 * entries_count++, &entry, 8);
|
Memory::CopyToEmu(request.io_vectors[1].address + 8 * entries_count++, &entry, 8);
|
||||||
}
|
}
|
||||||
Memory::Write_U8(entries_count, request.io_vectors[0].address);
|
Memory::Write_U8(entries_count, request.io_vectors[0].address);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::GetRhDesca(const IOCtlRequest& request) const
|
IPCReply OH0::GetRhDesca(const IOCtlRequest& request) const
|
||||||
{
|
{
|
||||||
if (!request.buffer_out || request.buffer_out_size != 4)
|
if (!request.buffer_out || request.buffer_out_size != 4)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
// Based on a hardware test, this ioctl seems to return a constant value
|
// Based on a hardware test, this ioctl seems to return a constant value
|
||||||
Memory::Write_U32(0x02000302, request.buffer_out);
|
Memory::Write_U32(0x02000302, request.buffer_out);
|
||||||
request.Dump(GetDeviceName(), Common::Log::IOS_USB, Common::Log::LWARNING);
|
request.Dump(GetDeviceName(), Common::Log::IOS_USB, Common::Log::LWARNING);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::GetRhPortStatus(const IOCtlVRequest& request) const
|
IPCReply OH0::GetRhPortStatus(const IOCtlVRequest& request) const
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 1))
|
if (!request.HasNumberOfValidVectors(1, 1))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
ERROR_LOG_FMT(IOS_USB, "Unimplemented IOCtlV: IOCTLV_USBV0_GETRHPORTSTATUS");
|
ERROR_LOG_FMT(IOS_USB, "Unimplemented IOCtlV: IOCTLV_USBV0_GETRHPORTSTATUS");
|
||||||
request.Dump(GetDeviceName(), Common::Log::IOS_USB, Common::Log::LERROR);
|
request.Dump(GetDeviceName(), Common::Log::IOS_USB, Common::Log::LERROR);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::SetRhPortStatus(const IOCtlVRequest& request)
|
IPCReply OH0::SetRhPortStatus(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 0))
|
if (!request.HasNumberOfValidVectors(2, 0))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
ERROR_LOG_FMT(IOS_USB, "Unimplemented IOCtlV: IOCTLV_USBV0_SETRHPORTSTATUS");
|
ERROR_LOG_FMT(IOS_USB, "Unimplemented IOCtlV: IOCTLV_USBV0_SETRHPORTSTATUS");
|
||||||
request.Dump(GetDeviceName(), Common::Log::IOS_USB, Common::Log::LERROR);
|
request.Dump(GetDeviceName(), Common::Log::IOS_USB, Common::Log::LERROR);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::RegisterRemovalHook(const u64 device_id, const IOCtlRequest& request)
|
std::optional<IPCReply> OH0::RegisterRemovalHook(const u64 device_id, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
std::lock_guard lock{m_hooks_mutex};
|
std::lock_guard lock{m_hooks_mutex};
|
||||||
// IOS only allows a single device removal hook.
|
// IOS only allows a single device removal hook.
|
||||||
if (m_removal_hooks.find(device_id) != m_removal_hooks.end())
|
if (m_removal_hooks.find(device_id) != m_removal_hooks.end())
|
||||||
return GetDefaultReply(IPC_EEXIST);
|
return IPCReply(IPC_EEXIST);
|
||||||
m_removal_hooks.insert({device_id, request.address});
|
m_removal_hooks.insert({device_id, request.address});
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::RegisterInsertionHook(const IOCtlVRequest& request)
|
std::optional<IPCReply> OH0::RegisterInsertionHook(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(2, 0))
|
if (!request.HasNumberOfValidVectors(2, 0))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
const u16 vid = Memory::Read_U16(request.in_vectors[0].address);
|
const u16 vid = Memory::Read_U16(request.in_vectors[0].address);
|
||||||
const u16 pid = Memory::Read_U16(request.in_vectors[1].address);
|
const u16 pid = Memory::Read_U16(request.in_vectors[1].address);
|
||||||
if (HasDeviceWithVidPid(vid, pid))
|
if (HasDeviceWithVidPid(vid, pid))
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
|
|
||||||
std::lock_guard lock{m_hooks_mutex};
|
std::lock_guard lock{m_hooks_mutex};
|
||||||
// TODO: figure out whether IOS allows more than one hook.
|
// TODO: figure out whether IOS allows more than one hook.
|
||||||
m_insertion_hooks[{vid, pid}] = request.address;
|
m_insertion_hooks[{vid, pid}] = request.address;
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::RegisterInsertionHookWithID(const IOCtlVRequest& request)
|
std::optional<IPCReply> OH0::RegisterInsertionHookWithID(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(3, 1))
|
if (!request.HasNumberOfValidVectors(3, 1))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
std::lock_guard lock{m_hooks_mutex};
|
std::lock_guard lock{m_hooks_mutex};
|
||||||
const u16 vid = Memory::Read_U16(request.in_vectors[0].address);
|
const u16 vid = Memory::Read_U16(request.in_vectors[0].address);
|
||||||
const u16 pid = Memory::Read_U16(request.in_vectors[1].address);
|
const u16 pid = Memory::Read_U16(request.in_vectors[1].address);
|
||||||
const bool trigger_only_for_new_device = Memory::Read_U8(request.in_vectors[2].address) == 1;
|
const bool trigger_only_for_new_device = Memory::Read_U8(request.in_vectors[2].address) == 1;
|
||||||
if (!trigger_only_for_new_device && HasDeviceWithVidPid(vid, pid))
|
if (!trigger_only_for_new_device && HasDeviceWithVidPid(vid, pid))
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
// TODO: figure out whether IOS allows more than one hook.
|
// TODO: figure out whether IOS allows more than one hook.
|
||||||
m_insertion_hooks.insert({{vid, pid}, request.address});
|
m_insertion_hooks.insert({{vid, pid}, request.address});
|
||||||
// The output vector is overwritten with an ID to use with ioctl 31 for cancelling the hook.
|
// The output vector is overwritten with an ID to use with ioctl 31 for cancelling the hook.
|
||||||
Memory::Write_U32(vid << 16 | pid, request.io_vectors[0].address);
|
Memory::Write_U32(vid << 16 | pid, request.io_vectors[0].address);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::RegisterClassChangeHook(const IOCtlVRequest& request)
|
std::optional<IPCReply> OH0::RegisterClassChangeHook(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 0))
|
if (!request.HasNumberOfValidVectors(1, 0))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
WARN_LOG_FMT(IOS_USB, "Unimplemented IOCtlV: USB::IOCTLV_USBV0_DEVICECLASSCHANGE (no reply)");
|
WARN_LOG_FMT(IOS_USB, "Unimplemented IOCtlV: USB::IOCTLV_USBV0_DEVICECLASSCHANGE (no reply)");
|
||||||
request.Dump(GetDeviceName(), Common::Log::IOS_USB, Common::Log::LWARNING);
|
request.Dump(GetDeviceName(), Common::Log::IOS_USB, Common::Log::LWARNING);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OH0::HasDeviceWithVidPid(const u16 vid, const u16 pid) const
|
bool OH0::HasDeviceWithVidPid(const u16 vid, const u16 pid) const
|
||||||
@@ -270,11 +270,11 @@ void OH0::DeviceClose(const u64 device_id)
|
|||||||
m_opened_devices.erase(device_id);
|
m_opened_devices.erase(device_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::DeviceIOCtl(const u64 device_id, const IOCtlRequest& request)
|
std::optional<IPCReply> OH0::DeviceIOCtl(const u64 device_id, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const auto device = GetDeviceById(device_id);
|
const auto device = GetDeviceById(device_id);
|
||||||
if (!device)
|
if (!device)
|
||||||
return GetDefaultReply(IPC_ENOENT);
|
return IPCReply(IPC_ENOENT);
|
||||||
|
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
@@ -283,20 +283,20 @@ IPCCommandResult OH0::DeviceIOCtl(const u64 device_id, const IOCtlRequest& reque
|
|||||||
case USB::IOCTL_USBV0_SUSPENDDEV:
|
case USB::IOCTL_USBV0_SUSPENDDEV:
|
||||||
case USB::IOCTL_USBV0_RESUMEDEV:
|
case USB::IOCTL_USBV0_RESUMEDEV:
|
||||||
// Unimplemented because libusb doesn't do power management.
|
// Unimplemented because libusb doesn't do power management.
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
case USB::IOCTL_USBV0_RESET_DEVICE:
|
case USB::IOCTL_USBV0_RESET_DEVICE:
|
||||||
TriggerHook(m_removal_hooks, device_id, IPC_SUCCESS);
|
TriggerHook(m_removal_hooks, device_id, IPC_SUCCESS);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
default:
|
default:
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0::DeviceIOCtlV(const u64 device_id, const IOCtlVRequest& request)
|
std::optional<IPCReply> OH0::DeviceIOCtlV(const u64 device_id, const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
const auto device = GetDeviceById(device_id);
|
const auto device = GetDeviceById(device_id);
|
||||||
if (!device)
|
if (!device)
|
||||||
return GetDefaultReply(IPC_ENOENT);
|
return IPCReply(IPC_ENOENT);
|
||||||
|
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
@@ -309,9 +309,9 @@ IPCCommandResult OH0::DeviceIOCtlV(const u64 device_id, const IOCtlVRequest& req
|
|||||||
[&, this]() { return SubmitTransfer(*device, request); });
|
[&, this]() { return SubmitTransfer(*device, request); });
|
||||||
case USB::IOCTLV_USBV0_UNKNOWN_32:
|
case USB::IOCTLV_USBV0_UNKNOWN_32:
|
||||||
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_USB);
|
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_USB);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
default:
|
default:
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -37,27 +37,27 @@ public:
|
|||||||
OH0(Kernel& ios, const std::string& device_name);
|
OH0(Kernel& ios, const std::string& device_name);
|
||||||
~OH0() override;
|
~OH0() override;
|
||||||
|
|
||||||
IPCCommandResult Open(const OpenRequest& request) override;
|
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
std::pair<ReturnCode, u64> DeviceOpen(u16 vid, u16 pid);
|
std::pair<ReturnCode, u64> DeviceOpen(u16 vid, u16 pid);
|
||||||
void DeviceClose(u64 device_id);
|
void DeviceClose(u64 device_id);
|
||||||
IPCCommandResult DeviceIOCtl(u64 device_id, const IOCtlRequest& request);
|
std::optional<IPCReply> DeviceIOCtl(u64 device_id, const IOCtlRequest& request);
|
||||||
IPCCommandResult DeviceIOCtlV(u64 device_id, const IOCtlVRequest& request);
|
std::optional<IPCReply> DeviceIOCtlV(u64 device_id, const IOCtlVRequest& request);
|
||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IPCCommandResult CancelInsertionHook(const IOCtlRequest& request);
|
IPCReply CancelInsertionHook(const IOCtlRequest& request);
|
||||||
IPCCommandResult GetDeviceList(const IOCtlVRequest& request) const;
|
IPCReply GetDeviceList(const IOCtlVRequest& request) const;
|
||||||
IPCCommandResult GetRhDesca(const IOCtlRequest& request) const;
|
IPCReply GetRhDesca(const IOCtlRequest& request) const;
|
||||||
IPCCommandResult GetRhPortStatus(const IOCtlVRequest& request) const;
|
IPCReply GetRhPortStatus(const IOCtlVRequest& request) const;
|
||||||
IPCCommandResult SetRhPortStatus(const IOCtlVRequest& request);
|
IPCReply SetRhPortStatus(const IOCtlVRequest& request);
|
||||||
IPCCommandResult RegisterRemovalHook(u64 device_id, const IOCtlRequest& request);
|
std::optional<IPCReply> RegisterRemovalHook(u64 device_id, const IOCtlRequest& request);
|
||||||
IPCCommandResult RegisterInsertionHook(const IOCtlVRequest& request);
|
std::optional<IPCReply> RegisterInsertionHook(const IOCtlVRequest& request);
|
||||||
IPCCommandResult RegisterInsertionHookWithID(const IOCtlVRequest& request);
|
std::optional<IPCReply> RegisterInsertionHookWithID(const IOCtlVRequest& request);
|
||||||
IPCCommandResult RegisterClassChangeHook(const IOCtlVRequest& request);
|
std::optional<IPCReply> RegisterClassChangeHook(const IOCtlVRequest& request);
|
||||||
s32 SubmitTransfer(USB::Device& device, const IOCtlVRequest& request);
|
s32 SubmitTransfer(USB::Device& device, const IOCtlVRequest& request);
|
||||||
|
|
||||||
bool HasDeviceWithVidPid(u16 vid, u16 pid) const;
|
bool HasDeviceWithVidPid(u16 vid, u16 pid) const;
|
||||||
|
@@ -51,30 +51,30 @@ void OH0Device::DoState(PointerWrap& p)
|
|||||||
p.Do(m_device_id);
|
p.Do(m_device_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0Device::Open(const OpenRequest& request)
|
std::optional<IPCReply> OH0Device::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
if (m_vid == 0 && m_pid == 0)
|
if (m_vid == 0 && m_pid == 0)
|
||||||
return GetDefaultReply(IPC_ENOENT);
|
return IPCReply(IPC_ENOENT);
|
||||||
|
|
||||||
m_oh0 = std::static_pointer_cast<OH0>(GetIOS()->GetDeviceByName("/dev/usb/oh0"));
|
m_oh0 = std::static_pointer_cast<OH0>(GetIOS()->GetDeviceByName("/dev/usb/oh0"));
|
||||||
|
|
||||||
ReturnCode return_code;
|
ReturnCode return_code;
|
||||||
std::tie(return_code, m_device_id) = m_oh0->DeviceOpen(m_vid, m_pid);
|
std::tie(return_code, m_device_id) = m_oh0->DeviceOpen(m_vid, m_pid);
|
||||||
return GetDefaultReply(return_code);
|
return IPCReply(return_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0Device::Close(u32 fd)
|
std::optional<IPCReply> OH0Device::Close(u32 fd)
|
||||||
{
|
{
|
||||||
m_oh0->DeviceClose(m_device_id);
|
m_oh0->DeviceClose(m_device_id);
|
||||||
return Device::Close(fd);
|
return Device::Close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0Device::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> OH0Device::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
return m_oh0->DeviceIOCtl(m_device_id, request);
|
return m_oh0->DeviceIOCtl(m_device_id, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult OH0Device::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> OH0Device::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
return m_oh0->DeviceIOCtlV(m_device_id, request);
|
return m_oh0->DeviceIOCtlV(m_device_id, request);
|
||||||
}
|
}
|
||||||
|
@@ -20,10 +20,10 @@ class OH0Device final : public Device
|
|||||||
public:
|
public:
|
||||||
OH0Device(Kernel& ios, const std::string& device_name);
|
OH0Device(Kernel& ios, const std::string& device_name);
|
||||||
|
|
||||||
IPCCommandResult Open(const OpenRequest& request) override;
|
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||||
IPCCommandResult Close(u32 fd) override;
|
std::optional<IPCReply> Close(u32 fd) override;
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -113,10 +113,10 @@ USBV5ResourceManager::USBV5Device* USBV5ResourceManager::GetUSBV5Device(u32 in_b
|
|||||||
return usbv5_device;
|
return usbv5_device;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USBV5ResourceManager::GetDeviceChange(const IOCtlRequest& request)
|
std::optional<IPCReply> USBV5ResourceManager::GetDeviceChange(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.buffer_out_size != 0x180 || m_devicechange_hook_request)
|
if (request.buffer_out_size != 0x180 || m_devicechange_hook_request)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
std::lock_guard lk{m_devicechange_hook_address_mutex};
|
std::lock_guard lk{m_devicechange_hook_address_mutex};
|
||||||
m_devicechange_hook_request = std::make_unique<IOCtlRequest>(request.address);
|
m_devicechange_hook_request = std::make_unique<IOCtlRequest>(request.address);
|
||||||
@@ -126,28 +126,27 @@ IPCCommandResult USBV5ResourceManager::GetDeviceChange(const IOCtlRequest& reque
|
|||||||
TriggerDeviceChangeReply();
|
TriggerDeviceChangeReply();
|
||||||
m_devicechange_first_call = false;
|
m_devicechange_first_call = false;
|
||||||
}
|
}
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USBV5ResourceManager::SetAlternateSetting(USBV5Device& device,
|
IPCReply USBV5ResourceManager::SetAlternateSetting(USBV5Device& device, const IOCtlRequest& request)
|
||||||
const IOCtlRequest& request)
|
|
||||||
{
|
{
|
||||||
const auto host_device = GetDeviceById(device.host_id);
|
const auto host_device = GetDeviceById(device.host_id);
|
||||||
if (!host_device->AttachAndChangeInterface(device.interface_number))
|
if (!host_device->AttachAndChangeInterface(device.interface_number))
|
||||||
return GetDefaultReply(-1);
|
return IPCReply(-1);
|
||||||
|
|
||||||
const u8 alt_setting = Memory::Read_U8(request.buffer_in + 2 * sizeof(s32));
|
const u8 alt_setting = Memory::Read_U8(request.buffer_in + 2 * sizeof(s32));
|
||||||
|
|
||||||
const bool success = host_device->SetAltSetting(alt_setting) == 0;
|
const bool success = host_device->SetAltSetting(alt_setting) == 0;
|
||||||
return GetDefaultReply(success ? IPC_SUCCESS : IPC_EINVAL);
|
return IPCReply(success ? IPC_SUCCESS : IPC_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USBV5ResourceManager::Shutdown(const IOCtlRequest& request)
|
IPCReply USBV5ResourceManager::Shutdown(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.buffer_in != 0 || request.buffer_in_size != 0 || request.buffer_out != 0 ||
|
if (request.buffer_in != 0 || request.buffer_in_size != 0 || request.buffer_out != 0 ||
|
||||||
request.buffer_out_size != 0)
|
request.buffer_out_size != 0)
|
||||||
{
|
{
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard lk{m_devicechange_hook_address_mutex};
|
std::lock_guard lk{m_devicechange_hook_address_mutex};
|
||||||
@@ -156,11 +155,10 @@ IPCCommandResult USBV5ResourceManager::Shutdown(const IOCtlRequest& request)
|
|||||||
m_ios.EnqueueIPCReply(*m_devicechange_hook_request, IPC_SUCCESS);
|
m_ios.EnqueueIPCReply(*m_devicechange_hook_request, IPC_SUCCESS);
|
||||||
m_devicechange_hook_request.reset();
|
m_devicechange_hook_request.reset();
|
||||||
}
|
}
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USBV5ResourceManager::SuspendResume(USBV5Device& device,
|
IPCReply USBV5ResourceManager::SuspendResume(USBV5Device& device, const IOCtlRequest& request)
|
||||||
const IOCtlRequest& request)
|
|
||||||
{
|
{
|
||||||
const auto host_device = GetDeviceById(device.host_id);
|
const auto host_device = GetDeviceById(device.host_id);
|
||||||
const s32 resumed = Memory::Read_U32(request.buffer_in + 8);
|
const s32 resumed = Memory::Read_U32(request.buffer_in + 8);
|
||||||
@@ -169,19 +167,19 @@ IPCCommandResult USBV5ResourceManager::SuspendResume(USBV5Device& device,
|
|||||||
// platform-independant way (libusb does not support power management).
|
// platform-independant way (libusb does not support power management).
|
||||||
INFO_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Received {} command", host_device->GetVid(),
|
INFO_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Received {} command", host_device->GetVid(),
|
||||||
host_device->GetPid(), device.interface_number, resumed == 0 ? "suspend" : "resume");
|
host_device->GetPid(), device.interface_number, resumed == 0 ? "suspend" : "resume");
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USBV5ResourceManager::HandleDeviceIOCtl(const IOCtlRequest& request,
|
std::optional<IPCReply> USBV5ResourceManager::HandleDeviceIOCtl(const IOCtlRequest& request,
|
||||||
Handler handler)
|
Handler handler)
|
||||||
{
|
{
|
||||||
if (request.buffer_in == 0 || request.buffer_in_size != 0x20)
|
if (request.buffer_in == 0 || request.buffer_in_size != 0x20)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
std::lock_guard lock{m_usbv5_devices_mutex};
|
std::lock_guard lock{m_usbv5_devices_mutex};
|
||||||
USBV5Device* device = GetUSBV5Device(request.buffer_in);
|
USBV5Device* device = GetUSBV5Device(request.buffer_in);
|
||||||
if (!device)
|
if (!device)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
return handler(*device);
|
return handler(*device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -68,8 +68,8 @@ class USBV5ResourceManager : public USBHost
|
|||||||
public:
|
public:
|
||||||
using USBHost::USBHost;
|
using USBHost::USBHost;
|
||||||
|
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override = 0;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override = 0;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override = 0;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override = 0;
|
||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
@@ -77,13 +77,13 @@ protected:
|
|||||||
struct USBV5Device;
|
struct USBV5Device;
|
||||||
USBV5Device* GetUSBV5Device(u32 in_buffer);
|
USBV5Device* GetUSBV5Device(u32 in_buffer);
|
||||||
|
|
||||||
IPCCommandResult GetDeviceChange(const IOCtlRequest& request);
|
std::optional<IPCReply> GetDeviceChange(const IOCtlRequest& request);
|
||||||
IPCCommandResult SetAlternateSetting(USBV5Device& device, const IOCtlRequest& request);
|
IPCReply SetAlternateSetting(USBV5Device& device, const IOCtlRequest& request);
|
||||||
IPCCommandResult Shutdown(const IOCtlRequest& request);
|
IPCReply Shutdown(const IOCtlRequest& request);
|
||||||
IPCCommandResult SuspendResume(USBV5Device& device, const IOCtlRequest& request);
|
IPCReply SuspendResume(USBV5Device& device, const IOCtlRequest& request);
|
||||||
|
|
||||||
using Handler = std::function<IPCCommandResult(USBV5Device&)>;
|
using Handler = std::function<std::optional<IPCReply>(USBV5Device&)>;
|
||||||
IPCCommandResult HandleDeviceIOCtl(const IOCtlRequest& request, Handler handler);
|
std::optional<IPCReply> HandleDeviceIOCtl(const IOCtlRequest& request, Handler handler);
|
||||||
|
|
||||||
void OnDeviceChange(ChangeEvent event, std::shared_ptr<USB::Device> device) override;
|
void OnDeviceChange(ChangeEvent event, std::shared_ptr<USB::Device> device) override;
|
||||||
void OnDeviceChangeEnd() override;
|
void OnDeviceChangeEnd() override;
|
||||||
|
@@ -31,20 +31,20 @@ USB_HIDv4::~USB_HIDv4()
|
|||||||
m_scan_thread.Stop();
|
m_scan_thread.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_HIDv4::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> USB_HIDv4::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
request.Log(GetDeviceName(), Common::Log::IOS_USB);
|
request.Log(GetDeviceName(), Common::Log::IOS_USB);
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
case USB::IOCTL_USBV4_GETVERSION:
|
case USB::IOCTL_USBV4_GETVERSION:
|
||||||
return GetDefaultReply(VERSION);
|
return IPCReply(VERSION);
|
||||||
case USB::IOCTL_USBV4_GETDEVICECHANGE:
|
case USB::IOCTL_USBV4_GETDEVICECHANGE:
|
||||||
return GetDeviceChange(request);
|
return GetDeviceChange(request);
|
||||||
case USB::IOCTL_USBV4_SHUTDOWN:
|
case USB::IOCTL_USBV4_SHUTDOWN:
|
||||||
return Shutdown(request);
|
return Shutdown(request);
|
||||||
case USB::IOCTL_USBV4_SET_SUSPEND:
|
case USB::IOCTL_USBV4_SET_SUSPEND:
|
||||||
// Not implemented in IOS
|
// Not implemented in IOS
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
case USB::IOCTL_USBV4_CANCELINTERRUPT:
|
case USB::IOCTL_USBV4_CANCELINTERRUPT:
|
||||||
return CancelInterrupt(request);
|
return CancelInterrupt(request);
|
||||||
case USB::IOCTL_USBV4_GET_US_STRING:
|
case USB::IOCTL_USBV4_GET_US_STRING:
|
||||||
@@ -53,36 +53,36 @@ IPCCommandResult USB_HIDv4::IOCtl(const IOCtlRequest& request)
|
|||||||
case USB::IOCTL_USBV4_INTRMSG_OUT:
|
case USB::IOCTL_USBV4_INTRMSG_OUT:
|
||||||
{
|
{
|
||||||
if (request.buffer_in == 0 || request.buffer_in_size != 32)
|
if (request.buffer_in == 0 || request.buffer_in_size != 32)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
const auto device = GetDeviceByIOSID(Memory::Read_U32(request.buffer_in + 16));
|
const auto device = GetDeviceByIOSID(Memory::Read_U32(request.buffer_in + 16));
|
||||||
if (!device->Attach())
|
if (!device->Attach())
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
return HandleTransfer(device, request.request,
|
return HandleTransfer(device, request.request,
|
||||||
[&, this]() { return SubmitTransfer(*device, request); });
|
[&, this]() { return SubmitTransfer(*device, request); });
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_USB);
|
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_USB);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_HIDv4::CancelInterrupt(const IOCtlRequest& request)
|
IPCReply USB_HIDv4::CancelInterrupt(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.buffer_in == 0 || request.buffer_in_size != 8)
|
if (request.buffer_in == 0 || request.buffer_in_size != 8)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
auto device = GetDeviceByIOSID(Memory::Read_U32(request.buffer_in));
|
auto device = GetDeviceByIOSID(Memory::Read_U32(request.buffer_in));
|
||||||
if (!device)
|
if (!device)
|
||||||
return GetDefaultReply(IPC_ENOENT);
|
return IPCReply(IPC_ENOENT);
|
||||||
device->CancelTransfer(Memory::Read_U8(request.buffer_in + 4));
|
device->CancelTransfer(Memory::Read_U8(request.buffer_in + 4));
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_HIDv4::GetDeviceChange(const IOCtlRequest& request)
|
std::optional<IPCReply> USB_HIDv4::GetDeviceChange(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
std::lock_guard lk{m_devicechange_hook_address_mutex};
|
std::lock_guard lk{m_devicechange_hook_address_mutex};
|
||||||
if (request.buffer_out == 0 || request.buffer_out_size != 0x600)
|
if (request.buffer_out == 0 || request.buffer_out_size != 0x600)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
m_devicechange_hook_request = std::make_unique<IOCtlRequest>(request.address);
|
m_devicechange_hook_request = std::make_unique<IOCtlRequest>(request.address);
|
||||||
// On the first call, the reply is sent immediately (instead of on device insertion/removal)
|
// On the first call, the reply is sent immediately (instead of on device insertion/removal)
|
||||||
@@ -91,10 +91,10 @@ IPCCommandResult USB_HIDv4::GetDeviceChange(const IOCtlRequest& request)
|
|||||||
TriggerDeviceChangeReply();
|
TriggerDeviceChangeReply();
|
||||||
m_devicechange_first_call = false;
|
m_devicechange_first_call = false;
|
||||||
}
|
}
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_HIDv4::Shutdown(const IOCtlRequest& request)
|
IPCReply USB_HIDv4::Shutdown(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
std::lock_guard lk{m_devicechange_hook_address_mutex};
|
std::lock_guard lk{m_devicechange_hook_address_mutex};
|
||||||
if (m_devicechange_hook_request != 0)
|
if (m_devicechange_hook_request != 0)
|
||||||
@@ -103,7 +103,7 @@ IPCCommandResult USB_HIDv4::Shutdown(const IOCtlRequest& request)
|
|||||||
m_ios.EnqueueIPCReply(*m_devicechange_hook_request, -1);
|
m_ios.EnqueueIPCReply(*m_devicechange_hook_request, -1);
|
||||||
m_devicechange_hook_request.reset();
|
m_devicechange_hook_request.reset();
|
||||||
}
|
}
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 USB_HIDv4::SubmitTransfer(USB::Device& device, const IOCtlRequest& request)
|
s32 USB_HIDv4::SubmitTransfer(USB::Device& device, const IOCtlRequest& request)
|
||||||
|
@@ -24,16 +24,16 @@ public:
|
|||||||
USB_HIDv4(Kernel& ios, const std::string& device_name);
|
USB_HIDv4(Kernel& ios, const std::string& device_name);
|
||||||
~USB_HIDv4() override;
|
~USB_HIDv4() override;
|
||||||
|
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<USB::Device> GetDeviceByIOSID(s32 ios_id) const;
|
std::shared_ptr<USB::Device> GetDeviceByIOSID(s32 ios_id) const;
|
||||||
|
|
||||||
IPCCommandResult CancelInterrupt(const IOCtlRequest& request);
|
IPCReply CancelInterrupt(const IOCtlRequest& request);
|
||||||
IPCCommandResult GetDeviceChange(const IOCtlRequest& request);
|
std::optional<IPCReply> GetDeviceChange(const IOCtlRequest& request);
|
||||||
IPCCommandResult Shutdown(const IOCtlRequest& request);
|
IPCReply Shutdown(const IOCtlRequest& request);
|
||||||
s32 SubmitTransfer(USB::Device& device, const IOCtlRequest& request);
|
s32 SubmitTransfer(USB::Device& device, const IOCtlRequest& request);
|
||||||
|
|
||||||
void TriggerDeviceChangeReply();
|
void TriggerDeviceChangeReply();
|
||||||
|
@@ -23,14 +23,14 @@ USB_HIDv5::~USB_HIDv5()
|
|||||||
m_scan_thread.Stop();
|
m_scan_thread.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_HIDv5::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> USB_HIDv5::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
request.Log(GetDeviceName(), Common::Log::IOS_USB);
|
request.Log(GetDeviceName(), Common::Log::IOS_USB);
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
case USB::IOCTL_USBV5_GETVERSION:
|
case USB::IOCTL_USBV5_GETVERSION:
|
||||||
Memory::Write_U32(USBV5_VERSION, request.buffer_out);
|
Memory::Write_U32(USBV5_VERSION, request.buffer_out);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
case USB::IOCTL_USBV5_GETDEVICECHANGE:
|
case USB::IOCTL_USBV5_GETDEVICECHANGE:
|
||||||
return GetDeviceChange(request);
|
return GetDeviceChange(request);
|
||||||
case USB::IOCTL_USBV5_SHUTDOWN:
|
case USB::IOCTL_USBV5_SHUTDOWN:
|
||||||
@@ -39,7 +39,7 @@ IPCCommandResult USB_HIDv5::IOCtl(const IOCtlRequest& request)
|
|||||||
return HandleDeviceIOCtl(request,
|
return HandleDeviceIOCtl(request,
|
||||||
[&](USBV5Device& device) { return GetDeviceInfo(device, request); });
|
[&](USBV5Device& device) { return GetDeviceInfo(device, request); });
|
||||||
case USB::IOCTL_USBV5_ATTACHFINISH:
|
case USB::IOCTL_USBV5_ATTACHFINISH:
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
case USB::IOCTL_USBV5_SUSPEND_RESUME:
|
case USB::IOCTL_USBV5_SUSPEND_RESUME:
|
||||||
return HandleDeviceIOCtl(request,
|
return HandleDeviceIOCtl(request,
|
||||||
[&](USBV5Device& device) { return SuspendResume(device, request); });
|
[&](USBV5Device& device) { return SuspendResume(device, request); });
|
||||||
@@ -48,11 +48,11 @@ IPCCommandResult USB_HIDv5::IOCtl(const IOCtlRequest& request)
|
|||||||
[&](USBV5Device& device) { return CancelEndpoint(device, request); });
|
[&](USBV5Device& device) { return CancelEndpoint(device, request); });
|
||||||
default:
|
default:
|
||||||
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_USB, Common::Log::LERROR);
|
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_USB, Common::Log::LERROR);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_HIDv5::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> USB_HIDv5::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_USB);
|
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_USB);
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
@@ -63,12 +63,12 @@ IPCCommandResult USB_HIDv5::IOCtlV(const IOCtlVRequest& request)
|
|||||||
{
|
{
|
||||||
// IOS does not check the number of vectors, but let's do that to avoid out-of-bounds reads.
|
// IOS does not check the number of vectors, but let's do that to avoid out-of-bounds reads.
|
||||||
if (request.in_vectors.size() + request.io_vectors.size() != 2)
|
if (request.in_vectors.size() + request.io_vectors.size() != 2)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
std::lock_guard lock{m_usbv5_devices_mutex};
|
std::lock_guard lock{m_usbv5_devices_mutex};
|
||||||
USBV5Device* device = GetUSBV5Device(request.in_vectors[0].address);
|
USBV5Device* device = GetUSBV5Device(request.in_vectors[0].address);
|
||||||
if (!device)
|
if (!device)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
auto host_device = GetDeviceById(device->host_id);
|
auto host_device = GetDeviceById(device->host_id);
|
||||||
if (request.request == USB::IOCTLV_USBV5_CTRLMSG)
|
if (request.request == USB::IOCTLV_USBV5_CTRLMSG)
|
||||||
host_device->Attach();
|
host_device->Attach();
|
||||||
@@ -78,7 +78,7 @@ IPCCommandResult USB_HIDv5::IOCtlV(const IOCtlVRequest& request)
|
|||||||
[&, this]() { return SubmitTransfer(*device, *host_device, request); });
|
[&, this]() { return SubmitTransfer(*device, *host_device, request); });
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ s32 USB_HIDv5::SubmitTransfer(USBV5Device& device, USB::Device& host_device,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_HIDv5::CancelEndpoint(USBV5Device& device, const IOCtlRequest& request)
|
IPCReply USB_HIDv5::CancelEndpoint(USBV5Device& device, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const u8 value = Memory::Read_U8(request.buffer_in + 8);
|
const u8 value = Memory::Read_U8(request.buffer_in + 8);
|
||||||
u8 endpoint = 0;
|
u8 endpoint = 0;
|
||||||
@@ -130,13 +130,13 @@ IPCCommandResult USB_HIDv5::CancelEndpoint(USBV5Device& device, const IOCtlReque
|
|||||||
}
|
}
|
||||||
|
|
||||||
GetDeviceById(device.host_id)->CancelTransfer(endpoint);
|
GetDeviceById(device.host_id)->CancelTransfer(endpoint);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_HIDv5::GetDeviceInfo(USBV5Device& device, const IOCtlRequest& request)
|
IPCReply USB_HIDv5::GetDeviceInfo(USBV5Device& device, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.buffer_out == 0 || request.buffer_out_size != 0x60)
|
if (request.buffer_out == 0 || request.buffer_out_size != 0x60)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
const std::shared_ptr<USB::Device> host_device = GetDeviceById(device.host_id);
|
const std::shared_ptr<USB::Device> host_device = GetDeviceById(device.host_id);
|
||||||
const u8 alt_setting = Memory::Read_U8(request.buffer_in + 8);
|
const u8 alt_setting = Memory::Read_U8(request.buffer_in + 8);
|
||||||
@@ -161,7 +161,7 @@ IPCCommandResult USB_HIDv5::GetDeviceInfo(USBV5Device& device, const IOCtlReques
|
|||||||
interface.bAlternateSetting == alt_setting;
|
interface.bAlternateSetting == alt_setting;
|
||||||
});
|
});
|
||||||
if (it == interfaces.end())
|
if (it == interfaces.end())
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
it->Swap();
|
it->Swap();
|
||||||
Memory::CopyToEmu(request.buffer_out + 68, &*it, sizeof(*it));
|
Memory::CopyToEmu(request.buffer_out + 68, &*it, sizeof(*it));
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ IPCCommandResult USB_HIDv5::GetDeviceInfo(USBV5Device& device, const IOCtlReques
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USB_HIDv5::ShouldAddDevice(const USB::Device& device) const
|
bool USB_HIDv5::ShouldAddDevice(const USB::Device& device) const
|
||||||
|
@@ -17,12 +17,12 @@ public:
|
|||||||
using USBV5ResourceManager::USBV5ResourceManager;
|
using USBV5ResourceManager::USBV5ResourceManager;
|
||||||
~USB_HIDv5() override;
|
~USB_HIDv5() override;
|
||||||
|
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IPCCommandResult CancelEndpoint(USBV5Device& device, const IOCtlRequest& request);
|
IPCReply CancelEndpoint(USBV5Device& device, const IOCtlRequest& request);
|
||||||
IPCCommandResult GetDeviceInfo(USBV5Device& device, const IOCtlRequest& request);
|
IPCReply GetDeviceInfo(USBV5Device& device, const IOCtlRequest& request);
|
||||||
s32 SubmitTransfer(USBV5Device& device, USB::Device& host_device, const IOCtlVRequest& ioctlv);
|
s32 SubmitTransfer(USBV5Device& device, USB::Device& host_device, const IOCtlVRequest& ioctlv);
|
||||||
|
|
||||||
bool ShouldAddDevice(const USB::Device& device) const override;
|
bool ShouldAddDevice(const USB::Device& device) const override;
|
||||||
|
@@ -188,7 +188,7 @@ USB_KBD::USB_KBD(Kernel& ios, const std::string& device_name) : Device(ios, devi
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_KBD::Open(const OpenRequest& request)
|
std::optional<IPCReply> USB_KBD::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
INFO_LOG_FMT(IOS, "USB_KBD: Open");
|
INFO_LOG_FMT(IOS, "USB_KBD: Open");
|
||||||
IniFile ini;
|
IniFile ini;
|
||||||
@@ -203,13 +203,13 @@ IPCCommandResult USB_KBD::Open(const OpenRequest& request)
|
|||||||
return Device::Open(request);
|
return Device::Open(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_KBD::Write(const ReadWriteRequest& request)
|
std::optional<IPCReply> USB_KBD::Write(const ReadWriteRequest& request)
|
||||||
{
|
{
|
||||||
// Stubbed.
|
// Stubbed.
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_KBD::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> USB_KBD::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (SConfig::GetInstance().m_WiiKeyboard && !Core::WantsDeterminism() &&
|
if (SConfig::GetInstance().m_WiiKeyboard && !Core::WantsDeterminism() &&
|
||||||
ControlReference::GetInputGate() && !m_message_queue.empty())
|
ControlReference::GetInputGate() && !m_message_queue.empty())
|
||||||
@@ -217,7 +217,7 @@ IPCCommandResult USB_KBD::IOCtl(const IOCtlRequest& request)
|
|||||||
Memory::CopyToEmu(request.buffer_out, &m_message_queue.front(), sizeof(MessageData));
|
Memory::CopyToEmu(request.buffer_out, &m_message_queue.front(), sizeof(MessageData));
|
||||||
m_message_queue.pop();
|
m_message_queue.pop();
|
||||||
}
|
}
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USB_KBD::IsKeyPressed(int key) const
|
bool USB_KBD::IsKeyPressed(int key) const
|
||||||
|
@@ -20,9 +20,9 @@ class USB_KBD : public Device
|
|||||||
public:
|
public:
|
||||||
USB_KBD(Kernel& ios, const std::string& device_name);
|
USB_KBD(Kernel& ios, const std::string& device_name);
|
||||||
|
|
||||||
IPCCommandResult Open(const OpenRequest& request) override;
|
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||||
IPCCommandResult Write(const ReadWriteRequest& request) override;
|
std::optional<IPCReply> Write(const ReadWriteRequest& request) override;
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
void Update() override;
|
void Update() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -23,14 +23,14 @@ USB_VEN::~USB_VEN()
|
|||||||
m_scan_thread.Stop();
|
m_scan_thread.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_VEN::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> USB_VEN::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
request.Log(GetDeviceName(), Common::Log::IOS_USB);
|
request.Log(GetDeviceName(), Common::Log::IOS_USB);
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
case USB::IOCTL_USBV5_GETVERSION:
|
case USB::IOCTL_USBV5_GETVERSION:
|
||||||
Memory::Write_U32(USBV5_VERSION, request.buffer_out);
|
Memory::Write_U32(USBV5_VERSION, request.buffer_out);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
case USB::IOCTL_USBV5_GETDEVICECHANGE:
|
case USB::IOCTL_USBV5_GETDEVICECHANGE:
|
||||||
return GetDeviceChange(request);
|
return GetDeviceChange(request);
|
||||||
case USB::IOCTL_USBV5_SHUTDOWN:
|
case USB::IOCTL_USBV5_SHUTDOWN:
|
||||||
@@ -39,7 +39,7 @@ IPCCommandResult USB_VEN::IOCtl(const IOCtlRequest& request)
|
|||||||
return HandleDeviceIOCtl(request,
|
return HandleDeviceIOCtl(request,
|
||||||
[&](USBV5Device& device) { return GetDeviceInfo(device, request); });
|
[&](USBV5Device& device) { return GetDeviceInfo(device, request); });
|
||||||
case USB::IOCTL_USBV5_ATTACHFINISH:
|
case USB::IOCTL_USBV5_ATTACHFINISH:
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
case USB::IOCTL_USBV5_SETALTERNATE:
|
case USB::IOCTL_USBV5_SETALTERNATE:
|
||||||
return HandleDeviceIOCtl(
|
return HandleDeviceIOCtl(
|
||||||
request, [&](USBV5Device& device) { return SetAlternateSetting(device, request); });
|
request, [&](USBV5Device& device) { return SetAlternateSetting(device, request); });
|
||||||
@@ -51,11 +51,11 @@ IPCCommandResult USB_VEN::IOCtl(const IOCtlRequest& request)
|
|||||||
[&](USBV5Device& device) { return CancelEndpoint(device, request); });
|
[&](USBV5Device& device) { return CancelEndpoint(device, request); });
|
||||||
default:
|
default:
|
||||||
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_USB, Common::Log::LERROR);
|
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_USB, Common::Log::LERROR);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_VEN::IOCtlV(const IOCtlVRequest& request)
|
std::optional<IPCReply> USB_VEN::IOCtlV(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
static const std::map<u32, u32> s_num_vectors = {
|
static const std::map<u32, u32> s_num_vectors = {
|
||||||
{USB::IOCTLV_USBV5_CTRLMSG, 2},
|
{USB::IOCTLV_USBV5_CTRLMSG, 2},
|
||||||
@@ -72,12 +72,12 @@ IPCCommandResult USB_VEN::IOCtlV(const IOCtlVRequest& request)
|
|||||||
case USB::IOCTLV_USBV5_ISOMSG:
|
case USB::IOCTLV_USBV5_ISOMSG:
|
||||||
{
|
{
|
||||||
if (request.in_vectors.size() + request.io_vectors.size() != s_num_vectors.at(request.request))
|
if (request.in_vectors.size() + request.io_vectors.size() != s_num_vectors.at(request.request))
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
std::lock_guard lock{m_usbv5_devices_mutex};
|
std::lock_guard lock{m_usbv5_devices_mutex};
|
||||||
USBV5Device* device = GetUSBV5Device(request.in_vectors[0].address);
|
USBV5Device* device = GetUSBV5Device(request.in_vectors[0].address);
|
||||||
if (!device)
|
if (!device)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
auto host_device = GetDeviceById(device->host_id);
|
auto host_device = GetDeviceById(device->host_id);
|
||||||
if (request.request == USB::IOCTLV_USBV5_CTRLMSG)
|
if (request.request == USB::IOCTLV_USBV5_CTRLMSG)
|
||||||
host_device->Attach();
|
host_device->Attach();
|
||||||
@@ -87,7 +87,7 @@ IPCCommandResult USB_VEN::IOCtlV(const IOCtlVRequest& request)
|
|||||||
[&, this]() { return SubmitTransfer(*host_device, request); });
|
[&, this]() { return SubmitTransfer(*host_device, request); });
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,19 +108,19 @@ s32 USB_VEN::SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_VEN::CancelEndpoint(USBV5Device& device, const IOCtlRequest& request)
|
IPCReply USB_VEN::CancelEndpoint(USBV5Device& device, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const u8 endpoint = Memory::Read_U8(request.buffer_in + 8);
|
const u8 endpoint = Memory::Read_U8(request.buffer_in + 8);
|
||||||
// IPC_EINVAL (-4) is returned when no transfer was cancelled.
|
// IPC_EINVAL (-4) is returned when no transfer was cancelled.
|
||||||
if (GetDeviceById(device.host_id)->CancelTransfer(endpoint) < 0)
|
if (GetDeviceById(device.host_id)->CancelTransfer(endpoint) < 0)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USB_VEN::GetDeviceInfo(USBV5Device& device, const IOCtlRequest& request)
|
IPCReply USB_VEN::GetDeviceInfo(USBV5Device& device, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
if (request.buffer_out == 0 || request.buffer_out_size != 0xc0)
|
if (request.buffer_out == 0 || request.buffer_out_size != 0xc0)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
|
|
||||||
const std::shared_ptr<USB::Device> host_device = GetDeviceById(device.host_id);
|
const std::shared_ptr<USB::Device> host_device = GetDeviceById(device.host_id);
|
||||||
const u8 alt_setting = Memory::Read_U8(request.buffer_in + 8);
|
const u8 alt_setting = Memory::Read_U8(request.buffer_in + 8);
|
||||||
@@ -145,7 +145,7 @@ IPCCommandResult USB_VEN::GetDeviceInfo(USBV5Device& device, const IOCtlRequest&
|
|||||||
interface.bAlternateSetting == alt_setting;
|
interface.bAlternateSetting == alt_setting;
|
||||||
});
|
});
|
||||||
if (it == interfaces.end())
|
if (it == interfaces.end())
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return IPCReply(IPC_EINVAL);
|
||||||
it->Swap();
|
it->Swap();
|
||||||
Memory::CopyToEmu(request.buffer_out + 52, &*it, sizeof(*it));
|
Memory::CopyToEmu(request.buffer_out + 52, &*it, sizeof(*it));
|
||||||
|
|
||||||
@@ -157,6 +157,6 @@ IPCCommandResult USB_VEN::GetDeviceInfo(USBV5Device& device, const IOCtlRequest&
|
|||||||
sizeof(endpoints[i]));
|
sizeof(endpoints[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
} // namespace IOS::HLE
|
} // namespace IOS::HLE
|
||||||
|
@@ -17,12 +17,12 @@ public:
|
|||||||
using USBV5ResourceManager::USBV5ResourceManager;
|
using USBV5ResourceManager::USBV5ResourceManager;
|
||||||
~USB_VEN() override;
|
~USB_VEN() override;
|
||||||
|
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IPCCommandResult CancelEndpoint(USBV5Device& device, const IOCtlRequest& request);
|
IPCReply CancelEndpoint(USBV5Device& device, const IOCtlRequest& request);
|
||||||
IPCCommandResult GetDeviceInfo(USBV5Device& device, const IOCtlRequest& request);
|
IPCReply GetDeviceInfo(USBV5Device& device, const IOCtlRequest& request);
|
||||||
|
|
||||||
s32 SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv);
|
s32 SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv);
|
||||||
bool HasInterfaceNumberInIDs() const override { return false; }
|
bool HasInterfaceNumberInIDs() const override { return false; }
|
||||||
|
@@ -124,7 +124,7 @@ void WFSIDevice::FinalizePatchInstall()
|
|||||||
File::CopyDir(WFS::NativePath(patch_dir), WFS::NativePath(current_title_dir), true);
|
File::CopyDir(WFS::NativePath(patch_dir), WFS::NativePath(current_title_dir), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult WFSIDevice::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> WFSIDevice::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
s32 return_error_code = IPC_SUCCESS;
|
s32 return_error_code = IPC_SUCCESS;
|
||||||
|
|
||||||
@@ -546,7 +546,7 @@ IPCCommandResult WFSIDevice::IOCtl(const IOCtlRequest& request)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(return_error_code);
|
return IPCReply(return_error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 WFSIDevice::GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* size) const
|
u32 WFSIDevice::GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* size) const
|
||||||
|
@@ -37,7 +37,7 @@ class WFSIDevice : public Device
|
|||||||
public:
|
public:
|
||||||
WFSIDevice(Kernel& ios, const std::string& device_name);
|
WFSIDevice(Kernel& ios, const std::string& device_name);
|
||||||
|
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* size) const;
|
u32 GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* size) const;
|
||||||
|
@@ -31,7 +31,7 @@ WFSSRVDevice::WFSSRVDevice(Kernel& ios, const std::string& device_name) : Device
|
|||||||
m_device_name = "msc01";
|
m_device_name = "msc01";
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult WFSSRVDevice::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> WFSSRVDevice::IOCtl(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
int return_error_code = IPC_SUCCESS;
|
int return_error_code = IPC_SUCCESS;
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ IPCCommandResult WFSSRVDevice::IOCtl(const IOCtlRequest& request)
|
|||||||
|
|
||||||
// Leave hanging, but we need to acknowledge the request at shutdown time.
|
// Leave hanging, but we need to acknowledge the request at shutdown time.
|
||||||
m_hanging.push_back(request.address);
|
m_hanging.push_back(request.address);
|
||||||
return GetNoReply();
|
return std::nullopt;
|
||||||
|
|
||||||
case IOCTL_WFS_FLUSH:
|
case IOCTL_WFS_FLUSH:
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
@@ -359,7 +359,7 @@ IPCCommandResult WFSSRVDevice::IOCtl(const IOCtlRequest& request)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply(return_error_code);
|
return IPCReply(return_error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 WFSSRVDevice::Rename(std::string source, std::string dest) const
|
s32 WFSSRVDevice::Rename(std::string source, std::string dest) const
|
||||||
|
@@ -34,7 +34,7 @@ class WFSSRVDevice : public Device
|
|||||||
public:
|
public:
|
||||||
WFSSRVDevice(Kernel& ios, const std::string& device_name);
|
WFSSRVDevice(Kernel& ios, const std::string& device_name);
|
||||||
|
|
||||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||||
|
|
||||||
s32 Rename(std::string source, std::string dest) const;
|
s32 Rename(std::string source, std::string dest) const;
|
||||||
void SetHomeDir(const std::string& home_dir);
|
void SetHomeDir(const std::string& home_dir);
|
||||||
|
Reference in New Issue
Block a user