mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-13 07:49:19 +01:00
Merge pull request #9508 from leoetlino/ipc-reply-cleanup
IOS: Clean up the way IPC replies are constructed
This commit is contained in:
commit
effd918837
@ -63,3 +63,12 @@ s64 GetLocalTimeRTCOffset();
|
|||||||
double GetEstimatedEmulationPerformance();
|
double GetEstimatedEmulationPerformance();
|
||||||
|
|
||||||
} // namespace SystemTimers
|
} // namespace SystemTimers
|
||||||
|
|
||||||
|
inline namespace SystemTimersLiterals
|
||||||
|
{
|
||||||
|
/// Converts timebase ticks to clock ticks.
|
||||||
|
constexpr u64 operator""_tbticks(unsigned long long value)
|
||||||
|
{
|
||||||
|
return value * SystemTimers::TIMER_RATIO;
|
||||||
|
}
|
||||||
|
} // namespace SystemTimersLiterals
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user