This commit is contained in:
Nayla Hanegan 2023-05-26 15:52:58 -04:00
commit 871da4e307
No known key found for this signature in database
GPG key ID: BAFE9001DA16CFA2
275 changed files with 33002 additions and 27474 deletions

View file

@ -31,8 +31,6 @@ add_library(common
Crypto/ec.h
Crypto/SHA1.cpp
Crypto/SHA1.h
Debug/CodeTrace.cpp
Debug/CodeTrace.h
Debug/MemoryPatches.cpp
Debug/MemoryPatches.h
Debug/Threads.h
@ -155,7 +153,7 @@ PUBLIC
PRIVATE
${CURL_LIBRARIES}
FatFs
${ICONV_LIBRARIES}
Iconv::Iconv
${spng_target}
${VTUNE_LIBRARIES}
)

View file

@ -30,6 +30,7 @@ public:
void SetCookies(const std::string& cookies);
void UseIPv4();
void FollowRedirects(long max);
s32 GetLastResponseCode();
Response Fetch(const std::string& url, Method method, const Headers& headers, const u8* payload,
size_t size, AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only);
@ -76,6 +77,11 @@ std::string HttpRequest::EscapeComponent(const std::string& string)
return m_impl->EscapeComponent(string);
}
s32 HttpRequest::GetLastResponseCode() const
{
return m_impl->GetLastResponseCode();
}
HttpRequest::Response HttpRequest::Get(const std::string& url, const Headers& headers,
AllowedReturnCodes codes)
{
@ -144,6 +150,13 @@ bool HttpRequest::Impl::IsValid() const
return m_curl != nullptr;
}
s32 HttpRequest::Impl::GetLastResponseCode()
{
s32 response_code{};
curl_easy_getinfo(m_curl.get(), CURLINFO_RESPONSE_CODE, &response_code);
return response_code;
}
void HttpRequest::Impl::SetCookies(const std::string& cookies)
{
curl_easy_setopt(m_curl.get(), CURLOPT_COOKIE, cookies.c_str());

View file

@ -38,6 +38,7 @@ public:
void SetCookies(const std::string& cookies);
void UseIPv4();
void FollowRedirects(long max = 1);
s32 GetLastResponseCode() const;
std::string EscapeComponent(const std::string& string);
Response Get(const std::string& url, const Headers& headers = {},
AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only);

View file

@ -36,7 +36,7 @@ static op_agent_t s_agent = nullptr;
static File::IOFile s_perf_map_file;
namespace JitRegister
namespace Common::JitRegister
{
static bool s_is_enabled = false;
@ -108,4 +108,4 @@ void Register(const void* base_address, u32 code_size, const std::string& symbol
const auto entry = fmt::format("{} {:x} {}\n", fmt::ptr(base_address), code_size, symbol_name);
s_perf_map_file.WriteBytes(entry.data(), entry.size());
}
} // namespace JitRegister
} // namespace Common::JitRegister

View file

@ -9,7 +9,7 @@
#include "Common/CommonTypes.h"
namespace JitRegister
namespace Common::JitRegister
{
void Init(const std::string& perf_dir);
void Shutdown();
@ -30,4 +30,4 @@ inline void Register(const void* start, const void* end, fmt::format_string<Args
u32 code_size = (u32)((const char*)end - (const char*)start);
Register(start, code_size, fmt::format(format, std::forward<Args>(args)...));
}
} // namespace JitRegister
} // namespace Common::JitRegister

View file

@ -4,6 +4,7 @@
#pragma once
#include <cstddef>
#include <string_view>
#include <vector>
#include "Common/CommonTypes.h"
@ -34,8 +35,10 @@ public:
/// CreateView() and ReleaseView(). Used to make a mappable region for emulated memory.
///
/// @param size The amount of bytes that should be allocated in this region.
/// @param base_name A base name for the shared memory region, if applicable for this platform.
/// Will be extended with the process ID.
///
void GrabSHMSegment(size_t size);
void GrabSHMSegment(size_t size, std::string_view base_name);
///
/// Release the memory segment previously allocated with GrabSHMSegment().
@ -113,13 +116,9 @@ private:
void* m_address_VirtualAlloc2 = nullptr;
void* m_address_MapViewOfFile3 = nullptr;
#else
#ifdef ANDROID
int fd;
#else
int m_shm_fd;
void* m_reserved_region;
std::size_t m_reserved_region_size;
#endif
int m_shm_fd = 0;
void* m_reserved_region = nullptr;
std::size_t m_reserved_region_size = 0;
#endif
};

View file

@ -10,6 +10,8 @@
#include <set>
#include <string>
#include <fmt/format.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <linux/ashmem.h>
@ -62,26 +64,36 @@ static int AshmemCreateFileMapping(const char* name, size_t size)
MemArena::MemArena() = default;
MemArena::~MemArena() = default;
void MemArena::GrabSHMSegment(size_t size)
void MemArena::GrabSHMSegment(size_t size, std::string_view base_name)
{
fd = AshmemCreateFileMapping(("dolphin-emu." + std::to_string(getpid())).c_str(), size);
if (fd < 0)
const std::string name = fmt::format("{}.{}", base_name, getpid());
m_shm_fd = AshmemCreateFileMapping(name.c_str(), size);
if (m_shm_fd < 0)
NOTICE_LOG_FMT(MEMMAP, "Ashmem allocation failed");
}
void MemArena::ReleaseSHMSegment()
{
close(fd);
close(m_shm_fd);
}
void* MemArena::CreateView(s64 offset, size_t size)
{
return MapInMemoryRegion(offset, size, nullptr);
void* retval = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, m_shm_fd, offset);
if (retval == MAP_FAILED)
{
NOTICE_LOG_FMT(MEMMAP, "mmap failed");
return nullptr;
}
else
{
return retval;
}
}
void MemArena::ReleaseView(void* view, size_t size)
{
UnmapFromMemoryRegion(view, size);
munmap(view, size);
}
u8* MemArena::ReserveMemoryRegion(size_t memory_size)
@ -96,19 +108,23 @@ u8* MemArena::ReserveMemoryRegion(size_t memory_size)
PanicAlertFmt("Failed to map enough memory space: {}", LastStrerrorString());
return nullptr;
}
munmap(base, memory_size);
m_reserved_region = base;
m_reserved_region_size = memory_size;
return static_cast<u8*>(base);
}
void MemArena::ReleaseMemoryRegion()
{
if (m_reserved_region)
{
munmap(m_reserved_region, m_reserved_region_size);
m_reserved_region = nullptr;
}
}
void* MemArena::MapInMemoryRegion(s64 offset, size_t size, void* base)
{
void* retval = mmap(base, size, PROT_READ | PROT_WRITE,
MAP_SHARED | ((base == nullptr) ? 0 : MAP_FIXED), fd, offset);
void* retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, m_shm_fd, offset);
if (retval == MAP_FAILED)
{
NOTICE_LOG_FMT(MEMMAP, "mmap failed");
@ -122,6 +138,8 @@ void* MemArena::MapInMemoryRegion(s64 offset, size_t size, void* base)
void MemArena::UnmapFromMemoryRegion(void* view, size_t size)
{
munmap(view, size);
void* retval = mmap(view, size, PROT_NONE, MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (retval == MAP_FAILED)
NOTICE_LOG_FMT(MEMMAP, "mmap failed");
}
} // namespace Common

View file

@ -10,6 +10,8 @@
#include <set>
#include <string>
#include <fmt/format.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
@ -25,9 +27,9 @@ namespace Common
MemArena::MemArena() = default;
MemArena::~MemArena() = default;
void MemArena::GrabSHMSegment(size_t size)
void MemArena::GrabSHMSegment(size_t size, std::string_view base_name)
{
const std::string file_name = "/dolphin-emu." + std::to_string(getpid());
const std::string file_name = fmt::format("/{}.{}", base_name, getpid());
m_shm_fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
if (m_shm_fd == -1)
{

View file

@ -8,6 +8,8 @@
#include <cstdlib>
#include <string>
#include <fmt/format.h>
#include <windows.h>
#include "Common/Assert.h"
@ -97,11 +99,22 @@ MemArena::~MemArena()
ReleaseSHMSegment();
}
void MemArena::GrabSHMSegment(size_t size)
static DWORD GetHighDWORD(u64 value)
{
const std::string name = "dolphin-emu." + std::to_string(GetCurrentProcessId());
m_memory_handle = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0,
static_cast<DWORD>(size), UTF8ToTStr(name).c_str());
return static_cast<DWORD>(value >> 32);
}
static DWORD GetLowDWORD(u64 value)
{
return static_cast<DWORD>(value);
}
void MemArena::GrabSHMSegment(size_t size, std::string_view base_name)
{
const std::string name = fmt::format("{}.{}", base_name, GetCurrentProcessId());
m_memory_handle =
CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, GetHighDWORD(size),
GetLowDWORD(size), UTF8ToTStr(name).c_str());
}
void MemArena::ReleaseSHMSegment()
@ -114,8 +127,9 @@ void MemArena::ReleaseSHMSegment()
void* MemArena::CreateView(s64 offset, size_t size)
{
return MapViewOfFileEx(m_memory_handle, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size,
nullptr);
const u64 off = static_cast<u64>(offset);
return MapViewOfFileEx(m_memory_handle, FILE_MAP_ALL_ACCESS, GetHighDWORD(off), GetLowDWORD(off),
size, nullptr);
}
void MemArena::ReleaseView(void* view, size_t size)

View file

@ -77,7 +77,7 @@ std::string HexDump(const u8* data, size_t size)
if (row_start + i < size)
{
char c = static_cast<char>(data[row_start + i]);
out += IsPrintableCharacter(c) ? c : '.';
out += Common::IsPrintableCharacter(c) ? c : '.';
}
}
out += "\n";
@ -547,7 +547,7 @@ std::string CodeTo(const char* tocode, const char* fromcode, std::basic_string_v
while (src_bytes != 0)
{
size_t const iconv_result =
#if defined(__OpenBSD__) || defined(__NetBSD__)
#if defined(__NetBSD__)
iconv(conv_desc, reinterpret_cast<const char**>(&src_buffer), &src_bytes, &dst_buffer,
&dst_bytes);
#else
@ -656,6 +656,8 @@ std::string PathToString(const std::filesystem::path& path)
#endif
}
namespace Common
{
#ifdef _WIN32
std::vector<std::string> CommandLineToUtf8Argv(const wchar_t* command_line)
{
@ -693,8 +695,6 @@ std::string GetEscapedHtml(std::string html)
return html;
}
namespace Common
{
void ToLower(std::string* str)
{
std::transform(str->begin(), str->end(), str->begin(), [](char c) { return Common::ToLower(c); });

View file

@ -211,6 +211,34 @@ inline std::string UTF8ToTStr(std::string_view str)
std::filesystem::path StringToPath(std::string_view path);
std::string PathToString(const std::filesystem::path& path);
namespace Common
{
/// Returns whether a character is printable, i.e. whether 0x20 <= c <= 0x7e is true.
/// Use this instead of calling std::isprint directly to ensure
/// the C locale is being used and to avoid possibly undefined behaviour.
inline bool IsPrintableCharacter(char c)
{
return std::isprint(c, std::locale::classic());
}
/// Returns whether a character is a letter, i.e. whether 'a' <= c <= 'z' || 'A' <= c <= 'Z'
/// is true. Use this instead of calling std::isalpha directly to ensure
/// the C locale is being used and to avoid possibly undefined behaviour.
inline bool IsAlpha(char c)
{
return std::isalpha(c, std::locale::classic());
}
inline char ToLower(char ch)
{
return std::tolower(ch, std::locale::classic());
}
inline char ToUpper(char ch)
{
return std::toupper(ch, std::locale::classic());
}
// Thousand separator. Turns 12345678 into 12,345,678
template <typename I>
std::string ThousandSeparate(I value, int spaces = 0)
@ -230,38 +258,12 @@ std::string ThousandSeparate(I value, int spaces = 0)
#endif
}
/// Returns whether a character is printable, i.e. whether 0x20 <= c <= 0x7e is true.
/// Use this instead of calling std::isprint directly to ensure
/// the C locale is being used and to avoid possibly undefined behaviour.
inline bool IsPrintableCharacter(char c)
{
return std::isprint(c, std::locale::classic());
}
/// Returns whether a character is a letter, i.e. whether 'a' <= c <= 'z' || 'A' <= c <= 'Z'
/// is true. Use this instead of calling std::isalpha directly to ensure
/// the C locale is being used and to avoid possibly undefined behaviour.
inline bool IsAlpha(char c)
{
return std::isalpha(c, std::locale::classic());
}
#ifdef _WIN32
std::vector<std::string> CommandLineToUtf8Argv(const wchar_t* command_line);
#endif
std::string GetEscapedHtml(std::string html);
namespace Common
{
inline char ToLower(char ch)
{
return std::tolower(ch, std::locale::classic());
}
inline char ToUpper(char ch)
{
return std::toupper(ch, std::locale::classic());
}
void ToLower(std::string* str);
void ToUpper(std::string* str);
bool CaseInsensitiveEquals(std::string_view a, std::string_view b);

View file

@ -37,6 +37,9 @@ struct Symbol
Data,
};
Symbol() = default;
explicit Symbol(const std::string& name) { Rename(name); }
void Rename(const std::string& symbol_name);
std::string name;

View file

@ -200,8 +200,8 @@ std::tuple<void*, size_t> GetCurrentThreadStack()
stack_t stack;
pthread_stackseg_np(self, &stack);
stack_addr = reinterpret_cast<u8*>(stack->ss_sp) - stack->ss_size;
stack_size = stack->ss_size;
stack_addr = reinterpret_cast<u8*>(stack.ss_sp) - stack.ss_size;
stack_size = stack.ss_size;
#else
pthread_attr_t attr;

View file

@ -12,6 +12,8 @@
#include "Common/Random.h"
#include "Core/NetPlayProto.h"
namespace Common
{
TraversalClient::TraversalClient(ENetHost* netHost, const std::string& server, const u16 port)
: m_NetHost(netHost), m_Server(server), m_port(port)
{
@ -304,7 +306,7 @@ int ENET_CALLBACK TraversalClient::InterceptCallback(ENetHost* host, ENetEvent*
}
std::unique_ptr<TraversalClient> g_TraversalClient;
Common::ENet::ENetHostPtr g_MainNetHost;
ENet::ENetHostPtr g_MainNetHost;
// The settings at the previous TraversalClient reset - notably, we
// need to know not just what port it's on, but whether it was
@ -348,3 +350,4 @@ void ReleaseTraversalClient()
g_TraversalClient.reset();
g_MainNetHost.reset();
}
} // namespace Common

View file

@ -15,6 +15,8 @@
#include "Common/Thread.h"
#include "Common/TraversalProto.h"
namespace Common
{
class TraversalClientClient
{
public:
@ -90,9 +92,12 @@ private:
u16 m_port;
u32 m_PingTime = 0;
};
extern std::unique_ptr<TraversalClient> g_TraversalClient;
// the NetHost connected to the TraversalClient.
extern Common::ENet::ENetHostPtr g_MainNetHost;
extern ENet::ENetHostPtr g_MainNetHost;
// Create g_TraversalClient and g_MainNetHost if necessary.
bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 listen_port = 0);
void ReleaseTraversalClient();
} // namespace Common

View file

@ -6,6 +6,8 @@
#include <cstddef>
#include "Common/CommonTypes.h"
namespace Common
{
constexpr size_t NETPLAY_CODE_SIZE = 8;
using TraversalHostId = std::array<char, NETPLAY_CODE_SIZE>;
using TraversalRequestId = u64;
@ -92,3 +94,4 @@ struct TraversalPacket
};
};
#pragma pack(pop)
} // namespace Common

View file

@ -31,8 +31,8 @@ static u64 currentTime;
struct OutgoingPacketInfo
{
TraversalPacket packet;
TraversalRequestId misc;
Common::TraversalPacket packet;
Common::TraversalRequestId misc;
sockaddr_in6 dest;
int tries;
u64 sendTime;
@ -104,9 +104,9 @@ V* EvictSet(std::unordered_map<K, EvictEntry<V>>& map, const K& key)
namespace std
{
template <>
struct hash<TraversalHostId>
struct hash<Common::TraversalHostId>
{
size_t operator()(const TraversalHostId& id) const
size_t operator()(const Common::TraversalHostId& id) const noexcept
{
auto p = (u32*)id.data();
return p[0] ^ ((p[1] << 13) | (p[1] >> 19));
@ -114,11 +114,15 @@ struct hash<TraversalHostId>
};
} // namespace std
static int sock;
static std::unordered_map<TraversalRequestId, OutgoingPacketInfo> outgoingPackets;
static std::unordered_map<TraversalHostId, EvictEntry<TraversalInetAddress>> connectedClients;
using ConnectedClients =
std::unordered_map<Common::TraversalHostId, EvictEntry<Common::TraversalInetAddress>>;
using OutgoingPackets = std::unordered_map<Common::TraversalRequestId, OutgoingPacketInfo>;
static TraversalInetAddress MakeInetAddress(const sockaddr_in6& addr)
static int sock;
static OutgoingPackets outgoingPackets;
static ConnectedClients connectedClients;
static Common::TraversalInetAddress MakeInetAddress(const sockaddr_in6& addr)
{
if (addr.sin6_family != AF_INET6)
{
@ -126,7 +130,7 @@ static TraversalInetAddress MakeInetAddress(const sockaddr_in6& addr)
exit(1);
}
u32* words = (u32*)addr.sin6_addr.s6_addr;
TraversalInetAddress result = {0};
Common::TraversalInetAddress result = {};
if (words[0] == 0 && words[1] == 0 && words[2] == 0xffff0000)
{
result.isIPV6 = false;
@ -141,7 +145,7 @@ static TraversalInetAddress MakeInetAddress(const sockaddr_in6& addr)
return result;
}
static sockaddr_in6 MakeSinAddr(const TraversalInetAddress& addr)
static sockaddr_in6 MakeSinAddr(const Common::TraversalInetAddress& addr)
{
sockaddr_in6 result;
#ifdef SIN6_LEN
@ -166,7 +170,7 @@ static sockaddr_in6 MakeSinAddr(const TraversalInetAddress& addr)
return result;
}
static void GetRandomHostId(TraversalHostId* hostId)
static void GetRandomHostId(Common::TraversalHostId* hostId)
{
char buf[9];
const u32 num = Common::Random::GenerateValue<u32>();
@ -185,7 +189,7 @@ static const char* SenderName(sockaddr_in6* addr)
static void TrySend(const void* buffer, size_t size, sockaddr_in6* addr)
{
#if DEBUG
const auto* packet = static_cast<const TraversalPacket*>(buffer);
const auto* packet = static_cast<const Common::TraversalPacket*>(buffer);
printf("-> %d %llu %s\n", static_cast<int>(packet->type),
static_cast<long long>(packet->requestId), SenderName(addr));
#endif
@ -195,16 +199,17 @@ static void TrySend(const void* buffer, size_t size, sockaddr_in6* addr)
}
}
static TraversalPacket* AllocPacket(const sockaddr_in6& dest, TraversalRequestId misc = 0)
static Common::TraversalPacket* AllocPacket(const sockaddr_in6& dest,
Common::TraversalRequestId misc = 0)
{
TraversalRequestId requestId;
Common::TraversalRequestId requestId{};
Common::Random::Generate(&requestId, sizeof(requestId));
OutgoingPacketInfo* info = &outgoingPackets[requestId];
info->dest = dest;
info->misc = misc;
info->tries = 0;
info->sendTime = currentTime;
TraversalPacket* result = &info->packet;
Common::TraversalPacket* result = &info->packet;
memset(result, 0, sizeof(*result));
result->requestId = requestId;
return result;
@ -219,7 +224,7 @@ static void SendPacket(OutgoingPacketInfo* info)
static void ResendPackets()
{
std::vector<std::pair<TraversalInetAddress, TraversalRequestId>> todoFailures;
std::vector<std::pair<Common::TraversalInetAddress, Common::TraversalRequestId>> todoFailures;
todoFailures.clear();
for (auto it = outgoingPackets.begin(); it != outgoingPackets.end();)
{
@ -228,7 +233,7 @@ static void ResendPackets()
{
if (info->tries >= NUMBER_OF_TRIES)
{
if (info->packet.type == TraversalPacketType::PleaseSendPacket)
if (info->packet.type == Common::TraversalPacketType::PleaseSendPacket)
{
todoFailures.push_back(std::make_pair(info->packet.pleaseSendPacket.address, info->misc));
}
@ -245,14 +250,14 @@ static void ResendPackets()
for (const auto& p : todoFailures)
{
TraversalPacket* fail = AllocPacket(MakeSinAddr(p.first));
fail->type = TraversalPacketType::ConnectFailed;
Common::TraversalPacket* fail = AllocPacket(MakeSinAddr(p.first));
fail->type = Common::TraversalPacketType::ConnectFailed;
fail->connectFailed.requestId = p.second;
fail->connectFailed.reason = TraversalConnectFailedReason::ClientDidntRespond;
fail->connectFailed.reason = Common::TraversalConnectFailedReason::ClientDidntRespond;
}
}
static void HandlePacket(TraversalPacket* packet, sockaddr_in6* addr)
static void HandlePacket(Common::TraversalPacket* packet, sockaddr_in6* addr)
{
#if DEBUG
printf("<- %d %llu %s\n", static_cast<int>(packet->type),
@ -261,7 +266,7 @@ static void HandlePacket(TraversalPacket* packet, sockaddr_in6* addr)
bool packetOk = true;
switch (packet->type)
{
case TraversalPacketType::Ack:
case Common::TraversalPacketType::Ack:
{
auto it = outgoingPackets.find(packet->requestId);
if (it == outgoingPackets.end())
@ -269,42 +274,42 @@ static void HandlePacket(TraversalPacket* packet, sockaddr_in6* addr)
OutgoingPacketInfo* info = &it->second;
if (info->packet.type == TraversalPacketType::PleaseSendPacket)
if (info->packet.type == Common::TraversalPacketType::PleaseSendPacket)
{
TraversalPacket* ready = AllocPacket(MakeSinAddr(info->packet.pleaseSendPacket.address));
auto* ready = AllocPacket(MakeSinAddr(info->packet.pleaseSendPacket.address));
if (packet->ack.ok)
{
ready->type = TraversalPacketType::ConnectReady;
ready->type = Common::TraversalPacketType::ConnectReady;
ready->connectReady.requestId = info->misc;
ready->connectReady.address = MakeInetAddress(info->dest);
}
else
{
ready->type = TraversalPacketType::ConnectFailed;
ready->type = Common::TraversalPacketType::ConnectFailed;
ready->connectFailed.requestId = info->misc;
ready->connectFailed.reason = TraversalConnectFailedReason::ClientFailure;
ready->connectFailed.reason = Common::TraversalConnectFailedReason::ClientFailure;
}
}
outgoingPackets.erase(it);
break;
}
case TraversalPacketType::Ping:
case Common::TraversalPacketType::Ping:
{
auto r = EvictFind(connectedClients, packet->ping.hostId, true);
packetOk = r.found;
break;
}
case TraversalPacketType::HelloFromClient:
case Common::TraversalPacketType::HelloFromClient:
{
u8 ok = packet->helloFromClient.protoVersion <= TraversalProtoVersion;
TraversalPacket* reply = AllocPacket(*addr);
reply->type = TraversalPacketType::HelloFromServer;
u8 ok = packet->helloFromClient.protoVersion <= Common::TraversalProtoVersion;
Common::TraversalPacket* reply = AllocPacket(*addr);
reply->type = Common::TraversalPacketType::HelloFromServer;
reply->helloFromServer.ok = ok;
if (ok)
{
TraversalHostId hostId;
TraversalInetAddress* iaddr;
Common::TraversalHostId hostId{};
Common::TraversalInetAddress* iaddr{};
// not that there is any significant change of
// duplication, but...
GetRandomHostId(&hostId);
@ -325,21 +330,21 @@ static void HandlePacket(TraversalPacket* packet, sockaddr_in6* addr)
}
break;
}
case TraversalPacketType::ConnectPlease:
case Common::TraversalPacketType::ConnectPlease:
{
TraversalHostId& hostId = packet->connectPlease.hostId;
Common::TraversalHostId& hostId = packet->connectPlease.hostId;
auto r = EvictFind(connectedClients, hostId);
if (!r.found)
{
TraversalPacket* reply = AllocPacket(*addr);
reply->type = TraversalPacketType::ConnectFailed;
Common::TraversalPacket* reply = AllocPacket(*addr);
reply->type = Common::TraversalPacketType::ConnectFailed;
reply->connectFailed.requestId = packet->requestId;
reply->connectFailed.reason = TraversalConnectFailedReason::NoSuchClient;
reply->connectFailed.reason = Common::TraversalConnectFailedReason::NoSuchClient;
}
else
{
TraversalPacket* please = AllocPacket(MakeSinAddr(*r.value), packet->requestId);
please->type = TraversalPacketType::PleaseSendPacket;
Common::TraversalPacket* please = AllocPacket(MakeSinAddr(*r.value), packet->requestId);
please->type = Common::TraversalPacketType::PleaseSendPacket;
please->pleaseSendPacket.address = MakeInetAddress(*addr);
}
break;
@ -349,10 +354,10 @@ static void HandlePacket(TraversalPacket* packet, sockaddr_in6* addr)
SenderName(addr));
break;
}
if (packet->type != TraversalPacketType::Ack)
if (packet->type != Common::TraversalPacketType::Ack)
{
TraversalPacket ack = {};
ack.type = TraversalPacketType::Ack;
Common::TraversalPacket ack = {};
ack.type = Common::TraversalPacketType::Ack;
ack.requestId = packet->requestId;
ack.ack.ok = packetOk;
TrySend(&ack, sizeof(ack), addr);
@ -411,7 +416,7 @@ int main()
{
sockaddr_in6 raddr;
socklen_t addrLen = sizeof(raddr);
TraversalPacket packet;
Common::TraversalPacket packet{};
// note: switch to recvmmsg (yes, mmsg) if this becomes
// expensive
rv = recvfrom(sock, &packet, sizeof(packet), 0, (sockaddr*)&raddr, &addrLen);

View file

@ -19,5 +19,5 @@ OSMinimumVersionWin11=10.0.22000.0
// VCToolsVersion=14.33.31629
// We're really looking for "14.32.31332.0" (because that's what will appear in the registry once
// installed), NOT the other values!
VCToolsVersion=14.34.31931.0
VCToolsVersion=${VC_TOOLS_VERSION}
VCToolsUpdateURL=https://aka.ms/vs/17/release/vc_redist.x64.exe

View file

@ -5,14 +5,16 @@
#include "Core/AchievementManager.h"
#include <array>
#include <rcheevos/include/rc_hash.h>
#include "Common/HttpRequest.h"
#include "Common/WorkQueueThread.h"
#include "Config/AchievementSettings.h"
#include "Core/Config/AchievementSettings.h"
#include "Core/Core.h"
#include "Core/PowerPC/MMU.h"
#include "Core/System.h"
#include "DiscIO/Volume.h"
#include "VideoCommon/VideoEvents.h"
static constexpr bool hardcore_mode_enabled = false;
@ -63,6 +65,7 @@ void AchievementManager::LoadGameByFilenameAsync(const std::string& iso_path,
callback(AchievementManager::ResponseType::MANAGER_NOT_INITIALIZED);
return;
}
m_system = &Core::System::GetInstance();
struct FilereaderState
{
int64_t position = 0;
@ -113,11 +116,10 @@ void AchievementManager::LoadGameByFilenameAsync(const std::string& iso_path,
},
.close = [](void* file_handle) { delete reinterpret_cast<FilereaderState*>(file_handle); }};
rc_hash_init_custom_filereader(&volume_reader);
std::array<char, HASH_LENGTH> game_hash;
if (!rc_hash_generate_from_file(game_hash.data(), RC_CONSOLE_GAMECUBE, iso_path.c_str()))
if (!rc_hash_generate_from_file(m_game_hash.data(), RC_CONSOLE_GAMECUBE, iso_path.c_str()))
return;
m_queue.EmplaceItem([this, callback, game_hash] {
const auto resolve_hash_response = ResolveHash(game_hash);
m_queue.EmplaceItem([this, callback] {
const auto resolve_hash_response = ResolveHash(this->m_game_hash);
if (resolve_hash_response != ResponseType::SUCCESS || m_game_id == 0)
{
callback(resolve_hash_response);
@ -204,12 +206,76 @@ void AchievementManager::ActivateDeactivateRichPresence()
nullptr, 0);
}
void AchievementManager::DoFrame()
{
if (!m_is_game_loaded)
return;
Core::RunAsCPUThread([&] {
rc_runtime_do_frame(
&m_runtime,
[](const rc_runtime_event_t* runtime_event) {
AchievementManager::GetInstance()->AchievementEventHandler(runtime_event);
},
[](unsigned address, unsigned num_bytes, void* ud) {
return static_cast<AchievementManager*>(ud)->MemoryPeeker(address, num_bytes, ud);
},
this, nullptr);
});
if (!m_system)
return;
u64 current_time = m_system->GetCoreTiming().GetTicks();
if (current_time - m_last_ping_time > SystemTimers::GetTicksPerSecond() * 120)
m_queue.EmplaceItem([this] { PingRichPresence(GenerateRichPresence()); });
}
u32 AchievementManager::MemoryPeeker(u32 address, u32 num_bytes, void* ud)
{
if (!m_system)
return 0u;
Core::CPUThreadGuard threadguard(*m_system);
switch (num_bytes)
{
case 1:
return m_system->GetMMU()
.HostTryReadU8(threadguard, address)
.value_or(PowerPC::ReadResult<u8>(false, 0u))
.value;
case 2:
return m_system->GetMMU()
.HostTryReadU16(threadguard, address)
.value_or(PowerPC::ReadResult<u16>(false, 0u))
.value;
case 4:
return m_system->GetMMU()
.HostTryReadU32(threadguard, address)
.value_or(PowerPC::ReadResult<u32>(false, 0u))
.value;
default:
ASSERT(false);
return 0u;
}
}
void AchievementManager::AchievementEventHandler(const rc_runtime_event_t* runtime_event)
{
switch (runtime_event->type)
{
case RC_RUNTIME_EVENT_ACHIEVEMENT_TRIGGERED:
HandleAchievementTriggeredEvent(runtime_event);
break;
case RC_RUNTIME_EVENT_LBOARD_TRIGGERED:
HandleLeaderboardTriggeredEvent(runtime_event);
break;
}
}
void AchievementManager::CloseGame()
{
m_is_game_loaded = false;
m_game_id = 0;
m_queue.Cancel();
m_unlock_map.clear();
m_system = nullptr;
ActivateDeactivateAchievements();
ActivateDeactivateLeaderboards();
ActivateDeactivateRichPresence();
@ -366,6 +432,91 @@ void AchievementManager::ActivateDeactivateAchievement(AchievementId id, bool en
rc_runtime_deactivate_achievement(&m_runtime, id);
}
RichPresence AchievementManager::GenerateRichPresence()
{
RichPresence rp_buffer;
Core::RunAsCPUThread([&] {
rc_runtime_get_richpresence(
&m_runtime, rp_buffer.data(), RP_SIZE,
[](unsigned address, unsigned num_bytes, void* ud) {
return static_cast<AchievementManager*>(ud)->MemoryPeeker(address, num_bytes, ud);
},
this, nullptr);
});
return rp_buffer;
}
AchievementManager::ResponseType AchievementManager::AwardAchievement(AchievementId achievement_id)
{
std::string username = Config::Get(Config::RA_USERNAME);
std::string api_token = Config::Get(Config::RA_API_TOKEN);
rc_api_award_achievement_request_t award_request = {.username = username.c_str(),
.api_token = api_token.c_str(),
.achievement_id = achievement_id,
.hardcore = hardcore_mode_enabled,
.game_hash = m_game_hash.data()};
rc_api_award_achievement_response_t award_response = {};
ResponseType r_type =
Request<rc_api_award_achievement_request_t, rc_api_award_achievement_response_t>(
award_request, &award_response, rc_api_init_award_achievement_request,
rc_api_process_award_achievement_response);
rc_api_destroy_award_achievement_response(&award_response);
return r_type;
}
AchievementManager::ResponseType AchievementManager::SubmitLeaderboard(AchievementId leaderboard_id,
int value)
{
std::string username = Config::Get(Config::RA_USERNAME);
std::string api_token = Config::Get(Config::RA_API_TOKEN);
rc_api_submit_lboard_entry_request_t submit_request = {.username = username.c_str(),
.api_token = api_token.c_str(),
.leaderboard_id = leaderboard_id,
.score = value,
.game_hash = m_game_hash.data()};
rc_api_submit_lboard_entry_response_t submit_response = {};
ResponseType r_type =
Request<rc_api_submit_lboard_entry_request_t, rc_api_submit_lboard_entry_response_t>(
submit_request, &submit_response, rc_api_init_submit_lboard_entry_request,
rc_api_process_submit_lboard_entry_response);
rc_api_destroy_submit_lboard_entry_response(&submit_response);
return r_type;
}
AchievementManager::ResponseType
AchievementManager::PingRichPresence(const RichPresence& rich_presence)
{
std::string username = Config::Get(Config::RA_USERNAME);
std::string api_token = Config::Get(Config::RA_API_TOKEN);
rc_api_ping_request_t ping_request = {.username = username.c_str(),
.api_token = api_token.c_str(),
.game_id = m_game_id,
.rich_presence = rich_presence.data()};
rc_api_ping_response_t ping_response = {};
ResponseType r_type = Request<rc_api_ping_request_t, rc_api_ping_response_t>(
ping_request, &ping_response, rc_api_init_ping_request, rc_api_process_ping_response);
rc_api_destroy_ping_response(&ping_response);
return r_type;
}
void AchievementManager::HandleAchievementTriggeredEvent(const rc_runtime_event_t* runtime_event)
{
auto it = m_unlock_map.find(runtime_event->id);
if (it == m_unlock_map.end())
return;
it->second.session_unlock_count++;
m_queue.EmplaceItem([this, runtime_event] { AwardAchievement(runtime_event->id); });
ActivateDeactivateAchievement(runtime_event->id, Config::Get(Config::RA_ACHIEVEMENTS_ENABLED),
Config::Get(Config::RA_UNOFFICIAL_ENABLED),
Config::Get(Config::RA_ENCORE_ENABLED));
}
void AchievementManager::HandleLeaderboardTriggeredEvent(const rc_runtime_event_t* runtime_event)
{
m_queue.EmplaceItem(
[this, runtime_event] { SubmitLeaderboard(runtime_event->id, runtime_event->value); });
}
// Every RetroAchievements API call, with only a partial exception for fetch_image, follows
// the same design pattern (here, X is the name of the call):
// Create a specific rc_api_X_request_t struct and populate with the necessary values
@ -384,6 +535,8 @@ AchievementManager::ResponseType AchievementManager::Request(
rc_api_request_t api_request;
Common::HttpRequest http_request;
init_request(&api_request, &rc_request);
if (!api_request.post_data)
return ResponseType::INVALID_REQUEST;
auto http_response = http_request.Post(api_request.url, api_request.post_data);
rc_api_destroy_request(&api_request);
if (http_response.has_value() && http_response->size() > 0)

View file

@ -4,6 +4,7 @@
#pragma once
#ifdef USE_RETRO_ACHIEVEMENTS
#include <array>
#include <functional>
#include <mutex>
#include <string>
@ -18,6 +19,13 @@
#include "Common/WorkQueueThread.h"
using AchievementId = u32;
constexpr size_t RP_SIZE = 256;
using RichPresence = std::array<char, RP_SIZE>;
namespace Core
{
class System;
}
class AchievementManager
{
@ -26,6 +34,7 @@ public:
{
SUCCESS,
MANAGER_NOT_INITIALIZED,
INVALID_REQUEST,
INVALID_CREDENTIALS,
CONNECTION_FAILED,
UNKNOWN_FAILURE
@ -44,6 +53,10 @@ public:
void ActivateDeactivateLeaderboards();
void ActivateDeactivateRichPresence();
void DoFrame();
u32 MemoryPeeker(u32 address, u32 num_bytes, void* ud);
void AchievementEventHandler(const rc_runtime_event_t* runtime_event);
void CloseGame();
void Logout();
void Shutdown();
@ -60,6 +73,14 @@ private:
ResponseType FetchUnlockData(bool hardcore);
void ActivateDeactivateAchievement(AchievementId id, bool enabled, bool unofficial, bool encore);
RichPresence GenerateRichPresence();
ResponseType AwardAchievement(AchievementId achievement_id);
ResponseType SubmitLeaderboard(AchievementId leaderboard_id, int value);
ResponseType PingRichPresence(const RichPresence& rich_presence);
void HandleAchievementTriggeredEvent(const rc_runtime_event_t* runtime_event);
void HandleLeaderboardTriggeredEvent(const rc_runtime_event_t* runtime_event);
template <typename RcRequest, typename RcResponse>
ResponseType Request(RcRequest rc_request, RcResponse* rc_response,
@ -67,10 +88,13 @@ private:
const std::function<int(RcResponse*, const char*)>& process_response);
rc_runtime_t m_runtime{};
Core::System* m_system{};
bool m_is_runtime_initialized = false;
unsigned int m_game_id = 0;
std::array<char, HASH_LENGTH> m_game_hash{};
u32 m_game_id = 0;
rc_api_fetch_game_data_response_t m_game_data{};
bool m_is_game_loaded = false;
u64 m_last_ping_time = 0;
struct UnlockStatus
{

View file

@ -690,8 +690,8 @@ void UpdateStateFlags(std::function<void(StateFlags*)> update_function)
void CreateSystemMenuTitleDirs()
{
const auto es = IOS::HLE::GetIOS()->GetES();
es->CreateTitleDirectories(Titles::SYSTEM_MENU, IOS::SYSMENU_GID);
const auto& es = IOS::HLE::GetIOS()->GetESCore();
es.CreateTitleDirectories(Titles::SYSTEM_MENU, IOS::SYSMENU_GID);
}
void AddRiivolutionPatches(BootParameters* boot_params,

View file

@ -595,7 +595,7 @@ bool CBoot::EmulatedBS2_Wii(Core::System& system, const Core::CPUThreadGuard& gu
// Warning: This call will set incorrect running game metadata if our volume parameter
// doesn't point to the same disc as the one that's inserted in the emulated disc drive!
IOS::HLE::GetIOS()->GetES()->DIVerify(tmd, volume.GetTicket(partition));
IOS::HLE::GetIOS()->GetESDevice()->DIVerify(tmd, volume.GetTicket(partition));
return true;
}

View file

@ -21,8 +21,8 @@ bool CBoot::BootNANDTitle(Core::System& system, const u64 title_id)
state->type = 0x04; // TYPE_NANDBOOT
});
auto es = IOS::HLE::GetIOS()->GetES();
const IOS::ES::TicketReader ticket = es->FindSignedTicket(title_id);
auto es = IOS::HLE::GetIOS()->GetESDevice();
const IOS::ES::TicketReader ticket = es->GetCore().FindSignedTicket(title_id);
auto console_type = IOS::HLE::IOSC::ConsoleType::Retail;
if (ticket.IsValid())
console_type = ticket.GetConsoleType();

View file

@ -59,6 +59,8 @@ add_library(core
Core.h
CoreTiming.cpp
CoreTiming.h
Debugger/CodeTrace.cpp
Debugger/CodeTrace.h
Debugger/Debugger_SymbolMap.cpp
Debugger/Debugger_SymbolMap.h
Debugger/Dump.cpp
@ -403,6 +405,8 @@ add_library(core
IOS/USB/Bluetooth/WiimoteHIDAttr.h
IOS/USB/Common.cpp
IOS/USB/Common.h
IOS/USB/Emulated/Infinity.cpp
IOS/USB/Emulated/Infinity.h
IOS/USB/Emulated/Skylander.cpp
IOS/USB/Emulated/Skylander.h
IOS/USB/Host.cpp

View file

@ -555,6 +555,9 @@ void SetUSBDeviceWhitelist(const std::set<std::pair<u16, u16>>& devices)
const Info<bool> MAIN_EMULATE_SKYLANDER_PORTAL{
{System::Main, "EmulatedUSBDevices", "EmulateSkylanderPortal"}, false};
const Info<bool> MAIN_EMULATE_INFINITY_BASE{
{System::Main, "EmulatedUSBDevices", "EmulateInfinityBase"}, false};
// The reason we need this function is because some memory card code
// expects to get a non-NTSC-K region even if we're emulating an NTSC-K Wii.
DiscIO::Region ToGameCubeRegion(DiscIO::Region region)

View file

@ -344,6 +344,7 @@ void SetUSBDeviceWhitelist(const std::set<std::pair<u16, u16>>& devices);
// Main.EmulatedUSBDevices
extern const Info<bool> MAIN_EMULATE_SKYLANDER_PORTAL;
extern const Info<bool> MAIN_EMULATE_INFINITY_BASE;
// GameCube path utility functions

View file

@ -286,7 +286,7 @@ struct SetGameMetadata
bool operator()(const BootParameters::NANDTitle& nand_title) const
{
IOS::HLE::Kernel ios;
const IOS::ES::TMDReader tmd = ios.GetES()->FindInstalledTMD(nand_title.id);
const IOS::ES::TMDReader tmd = ios.GetESCore().FindInstalledTMD(nand_title.id);
if (!tmd.IsValid() || !IOS::ES::IsChannel(nand_title.id))
{
PanicAlertFmtT("This title cannot be booted.");
@ -433,3 +433,38 @@ Common::IniFile SConfig::LoadGameIni(const std::string& id, std::optional<u16> r
game_ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true);
return game_ini;
}
std::string SConfig::GetGameTDBImageRegionCode(bool wii, DiscIO::Region region) const
{
switch (region)
{
case DiscIO::Region::NTSC_J:
return "JA";
case DiscIO::Region::NTSC_U:
return "US";
case DiscIO::Region::NTSC_K:
return "KO";
case DiscIO::Region::PAL:
{
const auto user_lang = GetCurrentLanguage(wii);
switch (user_lang)
{
case DiscIO::Language::German:
return "DE";
case DiscIO::Language::French:
return "FR";
case DiscIO::Language::Spanish:
return "ES";
case DiscIO::Language::Italian:
return "IT";
case DiscIO::Language::Dutch:
return "NL";
case DiscIO::Language::English:
default:
return "EN";
}
}
default:
return "EN";
}
}

View file

@ -83,6 +83,7 @@ struct SConfig
bool SetPathsAndGameMetadata(const BootParameters& boot);
DiscIO::Language GetCurrentLanguage(bool wii) const;
DiscIO::Language GetLanguageAdjustedForRegion(bool wii, DiscIO::Region region) const;
std::string GetGameTDBImageRegionCode(bool wii, DiscIO::Region region) const;
Common::IniFile LoadDefaultGameIni() const;
Common::IniFile LoadLocalGameIni() const;

View file

@ -193,7 +193,7 @@ void DisplayMessage(std::string message, int time_in_ms)
return;
// Actually displaying non-ASCII could cause things to go pear-shaped
if (!std::all_of(message.begin(), message.end(), IsPrintableCharacter))
if (!std::all_of(message.begin(), message.end(), Common::IsPrintableCharacter))
return;
OSD::AddMessage(std::move(message), time_in_ms);

View file

@ -1,7 +1,7 @@
// Copyright 2022 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Common/Debug/CodeTrace.h"
#include "Core/Debugger/CodeTrace.h"
#include <algorithm>
#include <chrono>

View file

@ -136,7 +136,7 @@ void DolphinAnalytics::ReportGameStart()
}
// Keep in sync with enum class GameQuirk definition.
constexpr std::array<const char*, 27> GAME_QUIRKS_NAMES{
constexpr std::array<const char*, 28> GAME_QUIRKS_NAMES{
"directly-reads-wiimote-input",
"uses-DVDLowStopLaser",
"uses-DVDLowOffset",
@ -164,6 +164,7 @@ constexpr std::array<const char*, 27> GAME_QUIRKS_NAMES{
"mismatched-gpu-normals-between-cp-and-xf",
"mismatched-gpu-tex-coords-between-cp-and-xf",
"mismatched-gpu-matrix-indices-between-cp-and-xf",
"reads-bounding-box",
};
static_assert(GAME_QUIRKS_NAMES.size() == static_cast<u32>(GameQuirk::COUNT),
"Game quirks names and enum definition are out of sync.");

View file

@ -89,6 +89,11 @@ enum class GameQuirk
// but testing is needed to find out which of these is actually used for what.
MISMATCHED_GPU_MATRIX_INDICES_BETWEEN_CP_AND_XF,
// Only a few games use the Bounding Box feature. Note that every game initializes the bounding
// box registers (using BPMEM_CLEARBBOX1/BPMEM_CLEARBBOX2) on startup, as part of the SDK, but
// only a few read them (from PE_BBOX_LEFT etc.)
READS_BOUNDING_BOX,
COUNT,
};

View file

@ -1355,9 +1355,7 @@ void ZeldaAudioRenderer::FetchVPB(u16 voice_id, VPB* vpb)
void ZeldaAudioRenderer::StoreVPB(u16 voice_id, VPB* vpb)
{
u16* vpb_words = (u16*)vpb;
// volatile is a workaround for msvc optimizer bug, see
// https://developercommunity.visualstudio.com/t/VS-175-bad-codegen-optimizing-loop-with/10291620
volatile u16* ram_vpbs = (u16*)HLEMemory_Get_Pointer(m_vpb_base_addr);
u16* ram_vpbs = (u16*)HLEMemory_Get_Pointer(m_vpb_base_addr);
size_t vpb_size = (m_flags & TINY_VPB) ? 0x80 : 0xC0;
size_t base_idx = voice_id * vpb_size;

View file

@ -77,7 +77,7 @@ void FileLogger::Log(const DiscIO::Volume& volume, const DiscIO::Partition& part
if (m_previous_partition == partition && m_previous_file_offset == file_offset)
return;
const std::string size_string = ThousandSeparate(file_info->GetSize() / 1000, 7);
const std::string size_string = Common::ThousandSeparate(file_info->GetSize() / 1000, 7);
const std::string path = file_info->GetPath();
const std::string log_string = fmt::format("{} kB {}", size_string, path);
if (IsSoundFile(path))

View file

@ -121,7 +121,7 @@ void MemoryManager::Init()
region.active = true;
mem_size += region.size;
}
m_arena.GrabSHMSegment(mem_size);
m_arena.GrabSHMSegment(mem_size, "dolphin-emu");
m_physical_page_mappings.fill(nullptr);

View file

@ -553,7 +553,7 @@ CopyResult Import(const std::string& data_bin_path, std::function<bool()> can_ov
return CopyResult::CorruptedSource;
}
if (!WiiUtils::EnsureTMDIsImported(*ios.GetFS(), *ios.GetES(), header->tid))
if (!WiiUtils::EnsureTMDIsImported(*ios.GetFS(), ios.GetESCore(), header->tid))
{
ERROR_LOG_FMT(CORE, "WiiSave::Import: Failed to find or import TMD for title {:16x}",
header->tid);
@ -585,7 +585,7 @@ size_t ExportAll(std::string_view export_path)
{
IOS::HLE::Kernel ios;
size_t exported_save_count = 0;
for (const u64 title : ios.GetES()->GetInstalledTitles())
for (const u64 title : ios.GetESCore().GetInstalledTitles())
{
if (Export(title, export_path, &ios) == CopyResult::Success)
++exported_save_count;

View file

@ -41,7 +41,8 @@ namespace IOS::HLE
{
CoreTiming::EventType* DIDevice::s_finish_executing_di_command;
DIDevice::DIDevice(Kernel& ios, const std::string& device_name) : Device(ios, device_name)
DIDevice::DIDevice(EmulationKernel& ios, const std::string& device_name)
: EmulationDevice(ios, device_name)
{
}
@ -70,7 +71,7 @@ std::optional<IPCReply> DIDevice::IOCtl(const IOCtlRequest& request)
// asynchronously. The rest are also treated as async to match this. Only one command can be
// executed at a time, so commands are queued until DVDInterface is ready to handle them.
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u8 command = memory.Read_U8(request.buffer_in);
if (request.request != command)
@ -105,12 +106,13 @@ void DIDevice::ProcessQueuedIOCtl()
m_executing_command = {m_commands_to_execute.front()};
m_commands_to_execute.pop_front();
IOCtlRequest request{m_executing_command->m_request_address};
auto& system = GetSystem();
IOCtlRequest request{system, m_executing_command->m_request_address};
auto finished = StartIOCtl(request);
if (finished)
{
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(
IPC_OVERHEAD_TICKS, s_finish_executing_di_command, static_cast<u64>(finished.value()));
system.GetCoreTiming().ScheduleEvent(IPC_OVERHEAD_TICKS, s_finish_executing_di_command,
static_cast<u64>(finished.value()));
return;
}
}
@ -124,7 +126,7 @@ std::optional<DIDevice::DIResult> DIDevice::WriteIfFits(const IOCtlRequest& requ
}
else
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(value, request.buffer_out);
return DIResult::Success;
@ -150,7 +152,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
return DIResult::SecurityError;
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
auto* mmio = memory.GetMMIOMapping();
@ -561,7 +563,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartDMATransfer(u32 command_length,
return DIResult::BadArgument;
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto* mmio = system.GetMemory().GetMMIOMapping();
mmio->Write<u32>(ADDRESS_DIMAR, request.buffer_out);
m_last_length = command_length;
@ -585,7 +587,8 @@ std::optional<DIDevice::DIResult> DIDevice::StartImmediateTransfer(const IOCtlRe
m_executing_command->m_copy_diimmbuf = write_to_buf;
Core::System::GetInstance().GetDVDInterface().ExecuteCommand(DVD::ReplyType::IOS);
auto& system = GetSystem();
system.GetDVDInterface().ExecuteCommand(DVD::ReplyType::IOS);
// Reply will be posted when done by FinishIOCtl.
return {};
}
@ -649,15 +652,15 @@ void DIDevice::FinishDICommand(DIResult result)
return;
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
auto* mmio = memory.GetMMIOMapping();
IOCtlRequest request{m_executing_command->m_request_address};
IOCtlRequest request{system, m_executing_command->m_request_address};
if (m_executing_command->m_copy_diimmbuf)
memory.Write_U32(mmio->Read<u32>(ADDRESS_DIIMMBUF), request.buffer_out);
m_ios.EnqueueIPCReply(request, static_cast<s32>(result));
GetEmulationKernel().EnqueueIPCReply(request, static_cast<s32>(result));
m_executing_command.reset();
@ -683,7 +686,7 @@ std::optional<IPCReply> DIDevice::IOCtlV(const IOCtlVRequest& request)
return IPCReply{static_cast<s32>(DIResult::BadArgument)};
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u8 command = memory.Read_U8(request.in_vectors[0].address);
@ -733,7 +736,8 @@ std::optional<IPCReply> DIDevice::IOCtlV(const IOCtlVRequest& request)
const std::vector<u8>& raw_tmd = tmd.GetBytes();
memory.CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size());
ReturnCode es_result = m_ios.GetES()->DIVerify(tmd, dvd_thread.GetTicket(m_current_partition));
ReturnCode es_result = GetEmulationKernel().GetESDevice()->DIVerify(
tmd, dvd_thread.GetTicket(m_current_partition));
memory.Write_U32(es_result, request.io_vectors[1].address);
return_value = DIResult::Success;
@ -742,17 +746,17 @@ std::optional<IPCReply> DIDevice::IOCtlV(const IOCtlVRequest& request)
case DIIoctl::DVDLowGetNoDiscOpenPartitionParams:
ERROR_LOG_FMT(IOS_DI, "DVDLowGetNoDiscOpenPartitionParams - dummied out");
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_DIFFERENT_PARTITION_COMMAND);
request.DumpUnknown(GetDeviceName(), Common::Log::LogType::IOS_DI);
request.DumpUnknown(system, GetDeviceName(), Common::Log::LogType::IOS_DI);
break;
case DIIoctl::DVDLowNoDiscOpenPartition:
ERROR_LOG_FMT(IOS_DI, "DVDLowNoDiscOpenPartition - dummied out");
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_DIFFERENT_PARTITION_COMMAND);
request.DumpUnknown(GetDeviceName(), Common::Log::LogType::IOS_DI);
request.DumpUnknown(system, GetDeviceName(), Common::Log::LogType::IOS_DI);
break;
case DIIoctl::DVDLowGetNoDiscBufferSizes:
ERROR_LOG_FMT(IOS_DI, "DVDLowGetNoDiscBufferSizes - dummied out");
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_DIFFERENT_PARTITION_COMMAND);
request.DumpUnknown(GetDeviceName(), Common::Log::LogType::IOS_DI);
request.DumpUnknown(system, GetDeviceName(), Common::Log::LogType::IOS_DI);
break;
case DIIoctl::DVDLowOpenPartitionWithTmdAndTicket:
ERROR_LOG_FMT(IOS_DI, "DVDLowOpenPartitionWithTmdAndTicket - not implemented");
@ -764,7 +768,7 @@ std::optional<IPCReply> DIDevice::IOCtlV(const IOCtlVRequest& request)
break;
default:
ERROR_LOG_FMT(IOS_DI, "Unknown ioctlv {:#04x}", request.request);
request.DumpUnknown(GetDeviceName(), Common::Log::LogType::IOS_DI);
request.DumpUnknown(system, GetDeviceName(), Common::Log::LogType::IOS_DI);
}
return IPCReply{static_cast<s32>(return_value)};
}
@ -804,7 +808,7 @@ void DIDevice::ResetDIRegisters()
{
// Clear transfer complete and error interrupts (normally r/z, but here we just directly write
// zero)
auto& di = Core::System::GetInstance().GetDVDInterface();
auto& di = GetSystem().GetDVDInterface();
di.ClearInterrupt(DVD::DIInterruptType::TCINT);
di.ClearInterrupt(DVD::DIInterruptType::DEINT);
// Enable transfer complete and error interrupts, and disable cover interrupt

View file

@ -35,10 +35,10 @@ void Init();
namespace IOS::HLE
{
class DIDevice : public Device
class DIDevice : public EmulationDevice
{
public:
DIDevice(Kernel& ios, const std::string& device_name);
DIDevice(EmulationKernel& ios, const std::string& device_name);
static void InterruptFromDVDInterface(DVD::DIInterruptType interrupt_type);
static DiscIO::Partition GetCurrentPartition();

View file

@ -16,21 +16,19 @@
namespace IOS::HLE
{
Request::Request(const u32 address_) : address(address_)
Request::Request(Core::System& system, const u32 address_) : address(address_)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
command = static_cast<IPCCommandType>(memory.Read_U32(address));
fd = memory.Read_U32(address + 8);
}
OpenRequest::OpenRequest(const u32 address_) : Request(address_)
OpenRequest::OpenRequest(Core::System& system, const u32 address_) : Request(system, address_)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
path = memory.GetString(memory.Read_U32(address + 0xc));
flags = static_cast<OpenMode>(memory.Read_U32(address + 0x10));
const Kernel* ios = GetIOS();
const EmulationKernel* ios = GetIOS();
if (ios)
{
uid = ios->GetUidForPPC();
@ -38,25 +36,23 @@ OpenRequest::OpenRequest(const u32 address_) : Request(address_)
}
}
ReadWriteRequest::ReadWriteRequest(const u32 address_) : Request(address_)
ReadWriteRequest::ReadWriteRequest(Core::System& system, const u32 address_)
: Request(system, address_)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
buffer = memory.Read_U32(address + 0xc);
size = memory.Read_U32(address + 0x10);
}
SeekRequest::SeekRequest(const u32 address_) : Request(address_)
SeekRequest::SeekRequest(Core::System& system, const u32 address_) : Request(system, address_)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
offset = memory.Read_U32(address + 0xc);
mode = static_cast<SeekMode>(memory.Read_U32(address + 0x10));
}
IOCtlRequest::IOCtlRequest(const u32 address_) : Request(address_)
IOCtlRequest::IOCtlRequest(Core::System& system, const u32 address_) : Request(system, address_)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
request = memory.Read_U32(address + 0x0c);
buffer_in = memory.Read_U32(address + 0x10);
@ -65,9 +61,8 @@ IOCtlRequest::IOCtlRequest(const u32 address_) : Request(address_)
buffer_out_size = memory.Read_U32(address + 0x1c);
}
IOCtlVRequest::IOCtlVRequest(const u32 address_) : Request(address_)
IOCtlVRequest::IOCtlVRequest(Core::System& system, const u32 address_) : Request(system, address_)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
request = memory.Read_U32(address + 0x0c);
const u32 in_number = memory.Read_U32(address + 0x10);
@ -114,10 +109,9 @@ void IOCtlRequest::Log(std::string_view device_name, Common::Log::LogType type,
device_name, fd, request, buffer_in_size, buffer_out_size);
}
void IOCtlRequest::Dump(const std::string& description, Common::Log::LogType type,
Common::Log::LogLevel level) const
void IOCtlRequest::Dump(Core::System& system, const std::string& description,
Common::Log::LogType type, Common::Log::LogLevel level) const
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
Log("===== " + description, type, level);
@ -127,16 +121,15 @@ void IOCtlRequest::Dump(const std::string& description, Common::Log::LogType typ
HexDump(memory.GetPointer(buffer_out), buffer_out_size));
}
void IOCtlRequest::DumpUnknown(const std::string& description, Common::Log::LogType type,
Common::Log::LogLevel level) const
void IOCtlRequest::DumpUnknown(Core::System& system, const std::string& description,
Common::Log::LogType type, Common::Log::LogLevel level) const
{
Dump("Unknown IOCtl - " + description, type, level);
Dump(system, "Unknown IOCtl - " + description, type, level);
}
void IOCtlVRequest::Dump(std::string_view description, Common::Log::LogType type,
Common::Log::LogLevel level) const
void IOCtlVRequest::Dump(Core::System& system, std::string_view description,
Common::Log::LogType type, Common::Log::LogLevel level) const
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
GENERIC_LOG_FMT(type, level, "===== {} (fd {}) - IOCtlV {:#x} ({} in, {} io)", description, fd,
@ -154,10 +147,10 @@ void IOCtlVRequest::Dump(std::string_view description, Common::Log::LogType type
GENERIC_LOG_FMT(type, level, "io[{}] (size={:#x})", i++, vector.size);
}
void IOCtlVRequest::DumpUnknown(const std::string& description, Common::Log::LogType type,
Common::Log::LogLevel level) const
void IOCtlVRequest::DumpUnknown(Core::System& system, const std::string& description,
Common::Log::LogType type, Common::Log::LogLevel level) const
{
Dump("Unknown IOCtlV - " + description, type, level);
Dump(system, "Unknown IOCtlV - " + description, type, level);
}
Device::Device(Kernel& ios, const std::string& device_name, const DeviceType type)

View file

@ -13,6 +13,11 @@
#include "Common/Logging/Log.h"
#include "Core/IOS/IOS.h"
namespace Core
{
class System;
}
namespace IOS::HLE
{
enum ReturnCode : s32
@ -77,7 +82,7 @@ struct Request
u32 address = 0;
IPCCommandType command = IPC_CMD_OPEN;
u32 fd = 0;
explicit Request(u32 address);
Request(Core::System& system, u32 address);
virtual ~Request() = default;
};
@ -97,14 +102,14 @@ struct OpenRequest final : Request
// but they are set after they reach IOS and are dispatched to the appropriate module.
u32 uid = 0;
u16 gid = 0;
explicit OpenRequest(u32 address);
OpenRequest(Core::System& system, u32 address);
};
struct ReadWriteRequest final : Request
{
u32 buffer = 0;
u32 size = 0;
explicit ReadWriteRequest(u32 address);
ReadWriteRequest(Core::System& system, u32 address);
};
enum SeekMode : s32
@ -118,7 +123,7 @@ struct SeekRequest final : Request
{
u32 offset = 0;
SeekMode mode = IOS_SEEK_SET;
explicit SeekRequest(u32 address);
SeekRequest(Core::System& system, u32 address);
};
struct IOCtlRequest final : Request
@ -129,12 +134,13 @@ struct IOCtlRequest final : Request
// Contrary to the name, the output buffer can also be used for input.
u32 buffer_out = 0;
u32 buffer_out_size = 0;
explicit IOCtlRequest(u32 address);
IOCtlRequest(Core::System& system, u32 address);
void Log(std::string_view description, Common::Log::LogType type = Common::Log::LogType::IOS,
Common::Log::LogLevel level = Common::Log::LogLevel::LINFO) const;
void Dump(const std::string& description, Common::Log::LogType type = Common::Log::LogType::IOS,
void Dump(Core::System& system, const std::string& description,
Common::Log::LogType type = Common::Log::LogType::IOS,
Common::Log::LogLevel level = Common::Log::LogLevel::LINFO) const;
void DumpUnknown(const std::string& description,
void DumpUnknown(Core::System& system, const std::string& description,
Common::Log::LogType type = Common::Log::LogType::IOS,
Common::Log::LogLevel level = Common::Log::LogLevel::LERROR) const;
};
@ -159,11 +165,12 @@ struct IOCtlVRequest final : Request
/// Returns the specified vector or nullptr if the index is out of bounds.
const IOVector* GetVector(size_t index) const;
explicit IOCtlVRequest(u32 address);
IOCtlVRequest(Core::System& system, u32 address);
bool HasNumberOfValidVectors(size_t in_count, size_t io_count) const;
void Dump(std::string_view description, Common::Log::LogType type = Common::Log::LogType::IOS,
void Dump(Core::System& system, std::string_view description,
Common::Log::LogType type = Common::Log::LogType::IOS,
Common::Log::LogLevel level = Common::Log::LogLevel::LINFO) const;
void DumpUnknown(const std::string& description,
void DumpUnknown(Core::System& system, const std::string& description,
Common::Log::LogType type = Common::Log::LogType::IOS,
Common::Log::LogLevel level = Common::Log::LogLevel::LERROR) const;
};
@ -214,4 +221,22 @@ protected:
private:
std::optional<IPCReply> Unsupported(const Request& request);
};
// Helper class for Devices that we know are only ever instantiated under an EmulationKernel.
// Deriving a Device from this allows it to access EmulationKernel-only features without runtime
// overhead, since it will know that the m_ios instance is an EmulationKernel.
class EmulationDevice : public Device
{
public:
EmulationDevice(EmulationKernel& ios, const std::string& device_name,
DeviceType type = DeviceType::Static)
: Device(ios, device_name, type)
{
}
protected:
EmulationKernel& GetEmulationKernel() const { return static_cast<EmulationKernel&>(m_ios); }
Core::System& GetSystem() const { return GetEmulationKernel().GetSystem(); }
};
} // namespace IOS::HLE

View file

@ -40,7 +40,7 @@ enum
};
IPCReply GetVersion(const IOCtlVRequest& request)
IPCReply GetVersion(Core::System& system, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1))
{
@ -49,7 +49,6 @@ IPCReply GetVersion(const IOCtlVRequest& request)
const auto length = std::min(size_t(request.io_vectors[0].size), Common::GetScmDescStr().size());
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
memory.Memset(request.io_vectors[0].address, 0, request.io_vectors[0].size);
memory.CopyToEmu(request.io_vectors[0].address, Common::GetScmDescStr().data(), length);
@ -57,7 +56,7 @@ IPCReply GetVersion(const IOCtlVRequest& request)
return IPCReply(IPC_SUCCESS);
}
IPCReply GetCPUSpeed(const IOCtlVRequest& request)
IPCReply GetCPUSpeed(Core::System& system, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1))
{
@ -74,14 +73,13 @@ IPCReply GetCPUSpeed(const IOCtlVRequest& request)
const u32 core_clock = u32(float(SystemTimers::GetTicksPerSecond()) * oc);
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
memory.Write_U32(core_clock, request.io_vectors[0].address);
return IPCReply(IPC_SUCCESS);
}
IPCReply GetSpeedLimit(const IOCtlVRequest& request)
IPCReply GetSpeedLimit(Core::System& system, const IOCtlVRequest& request)
{
// get current speed limit
if (!request.HasNumberOfValidVectors(0, 1))
@ -96,14 +94,13 @@ IPCReply GetSpeedLimit(const IOCtlVRequest& request)
const u32 speed_percent = Config::Get(Config::MAIN_EMULATION_SPEED) * 100;
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
memory.Write_U32(speed_percent, request.io_vectors[0].address);
return IPCReply(IPC_SUCCESS);
}
IPCReply SetSpeedLimit(const IOCtlVRequest& request)
IPCReply SetSpeedLimit(Core::System& system, const IOCtlVRequest& request)
{
// set current speed limit
if (!request.HasNumberOfValidVectors(1, 0))
@ -116,7 +113,6 @@ IPCReply SetSpeedLimit(const IOCtlVRequest& request)
return IPCReply(IPC_EINVAL);
}
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
const float speed = float(memory.Read_U32(request.in_vectors[0].address)) / 100.0f;
Config::SetCurrent(Config::MAIN_EMULATION_SPEED, speed);
@ -124,7 +120,7 @@ IPCReply SetSpeedLimit(const IOCtlVRequest& request)
return IPCReply(IPC_SUCCESS);
}
IPCReply GetRealProductCode(const IOCtlVRequest& request)
IPCReply GetRealProductCode(Core::System& system, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1))
{
@ -150,14 +146,13 @@ IPCReply GetRealProductCode(const IOCtlVRequest& request)
if (length == 0)
return IPCReply(IPC_ENOENT);
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
memory.Memset(request.io_vectors[0].address, 0, request.io_vectors[0].size);
memory.CopyToEmu(request.io_vectors[0].address, code.c_str(), length);
return IPCReply(IPC_SUCCESS);
}
IPCReply SetDiscordClient(const IOCtlVRequest& request)
IPCReply SetDiscordClient(Core::System& system, const IOCtlVRequest& request)
{
if (!Config::Get(Config::MAIN_USE_DISCORD_PRESENCE))
return IPCReply(IPC_EACCES);
@ -165,7 +160,6 @@ IPCReply SetDiscordClient(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 0))
return IPCReply(IPC_EINVAL);
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
std::string new_client_id =
memory.GetString(request.in_vectors[0].address, request.in_vectors[0].size);
@ -175,7 +169,7 @@ IPCReply SetDiscordClient(const IOCtlVRequest& request)
return IPCReply(IPC_SUCCESS);
}
IPCReply SetDiscordPresence(const IOCtlVRequest& request)
IPCReply SetDiscordPresence(Core::System& system, const IOCtlVRequest& request)
{
if (!Config::Get(Config::MAIN_USE_DISCORD_PRESENCE))
return IPCReply(IPC_EACCES);
@ -183,7 +177,6 @@ IPCReply SetDiscordPresence(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(10, 0))
return IPCReply(IPC_EINVAL);
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
std::string details = memory.GetString(request.in_vectors[0].address, request.in_vectors[0].size);
@ -242,7 +235,7 @@ IPCReply DolphinDevice::GetElapsedTime(const IOCtlVRequest& request) const
// have issues.
const u32 milliseconds = static_cast<u32>(m_timer.ElapsedMs());
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(milliseconds, request.io_vectors[0].address);
@ -261,7 +254,7 @@ IPCReply DolphinDevice::GetSystemTime(const IOCtlVRequest& request) const
return IPCReply(IPC_EINVAL);
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
// Write Unix timestamp in milliseconds to memory address
@ -272,7 +265,8 @@ IPCReply DolphinDevice::GetSystemTime(const IOCtlVRequest& request) const
return IPCReply(IPC_SUCCESS);
}
DolphinDevice::DolphinDevice(Kernel& ios, const std::string& device_name) : Device(ios, device_name)
DolphinDevice::DolphinDevice(EmulationKernel& ios, const std::string& device_name)
: EmulationDevice(ios, device_name)
{
m_timer.Start();
}
@ -287,19 +281,19 @@ std::optional<IPCReply> DolphinDevice::IOCtlV(const IOCtlVRequest& request)
case IOCTL_DOLPHIN_GET_ELAPSED_TIME:
return GetElapsedTime(request);
case IOCTL_DOLPHIN_GET_VERSION:
return GetVersion(request);
return GetVersion(GetSystem(), request);
case IOCTL_DOLPHIN_GET_SPEED_LIMIT:
return GetSpeedLimit(request);
return GetSpeedLimit(GetSystem(), request);
case IOCTL_DOLPHIN_SET_SPEED_LIMIT:
return SetSpeedLimit(request);
return SetSpeedLimit(GetSystem(), request);
case IOCTL_DOLPHIN_GET_CPU_SPEED:
return GetCPUSpeed(request);
return GetCPUSpeed(GetSystem(), request);
case IOCTL_DOLPHIN_GET_REAL_PRODUCTCODE:
return GetRealProductCode(request);
return GetRealProductCode(GetSystem(), request);
case IOCTL_DOLPHIN_DISCORD_SET_CLIENT:
return SetDiscordClient(request);
return SetDiscordClient(GetSystem(), request);
case IOCTL_DOLPHIN_DISCORD_SET_PRESENCE:
return SetDiscordPresence(request);
return SetDiscordPresence(GetSystem(), request);
case IOCTL_DOLPHIN_DISCORD_RESET:
return ResetDiscord(request);
case IOCTL_DOLPHIN_GET_SYSTEM_TIME:

View file

@ -8,10 +8,10 @@
namespace IOS::HLE
{
class DolphinDevice final : public Device
class DolphinDevice final : public EmulationDevice
{
public:
DolphinDevice(Kernel& ios, const std::string& device_name);
DolphinDevice(EmulationKernel& ios, const std::string& device_name);
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
private:

View file

@ -81,7 +81,7 @@ constexpr SystemTimers::TimeBaseTick GetESBootTicks(u32 ios_version)
}
} // namespace
ESDevice::ESDevice(Kernel& ios, const std::string& device_name) : Device(ios, device_name)
ESCore::ESCore(Kernel& ios) : m_ios(ios)
{
for (const auto& directory : s_directories_to_create)
{
@ -101,13 +101,19 @@ ESDevice::ESDevice(Kernel& ios, const std::string& device_name) : Device(ios, de
}
FinishAllStaleImports();
}
ESCore::~ESCore() = default;
ESDevice::ESDevice(EmulationKernel& ios, ESCore& core, const std::string& device_name)
: EmulationDevice(ios, device_name), m_core(core)
{
if (Core::IsRunningAndStarted())
{
auto& system = Core::System::GetInstance();
auto& system = ios.GetSystem();
auto& core_timing = system.GetCoreTiming();
core_timing.RemoveEvent(s_finish_init_event);
core_timing.ScheduleEvent(GetESBootTicks(m_ios.GetVersion()), s_finish_init_event);
core_timing.ScheduleEvent(GetESBootTicks(ios.GetVersion()), s_finish_init_event);
}
else
{
@ -115,19 +121,23 @@ ESDevice::ESDevice(Kernel& ios, const std::string& device_name) : Device(ios, de
}
}
ESDevice::~ESDevice() = default;
void ESDevice::InitializeEmulationState()
{
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
s_finish_init_event = core_timing.RegisterEvent(
"IOS-ESFinishInit", [](Core::System& system_, u64, s64) { GetIOS()->GetES()->FinishInit(); });
s_finish_init_event =
core_timing.RegisterEvent("IOS-ESFinishInit", [](Core::System& system_, u64, s64) {
GetIOS()->GetESDevice()->FinishInit();
});
s_reload_ios_for_ppc_launch_event = core_timing.RegisterEvent(
"IOS-ESReloadIOSForPPCLaunch", [](Core::System& system_, u64 ios_id, s64) {
GetIOS()->GetES()->LaunchTitle(ios_id, HangPPC::Yes);
GetIOS()->GetESDevice()->LaunchTitle(ios_id, HangPPC::Yes);
});
s_bootstrap_ppc_for_launch_event =
core_timing.RegisterEvent("IOS-ESBootstrapPPCForLaunch", [](Core::System& system_, u64, s64) {
GetIOS()->GetES()->BootstrapPPC();
GetIOS()->GetESDevice()->BootstrapPPC();
});
}
@ -140,13 +150,13 @@ void ESDevice::FinalizeEmulationState()
void ESDevice::FinishInit()
{
m_ios.InitIPC();
GetEmulationKernel().InitIPC();
std::optional<u64> pending_launch_title_id;
{
const auto launch_file =
m_ios.GetFS()->OpenFile(PID_KERNEL, PID_KERNEL, LAUNCH_FILE_PATH, FS::Mode::Read);
const auto launch_file = GetEmulationKernel().GetFS()->OpenFile(
PID_KERNEL, PID_KERNEL, LAUNCH_FILE_PATH, FS::Mode::Read);
if (launch_file)
{
u64 id;
@ -202,7 +212,7 @@ IPCReply ESDevice::GetTitleDirectory(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 1))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
@ -215,7 +225,7 @@ IPCReply ESDevice::GetTitleDirectory(const IOCtlVRequest& request)
return IPCReply(IPC_SUCCESS);
}
ReturnCode ESDevice::GetTitleId(u64* title_id) const
ReturnCode ESCore::GetTitleId(u64* title_id) const
{
if (!m_title_context.active)
return ES_EINVAL;
@ -229,11 +239,11 @@ IPCReply ESDevice::GetTitleId(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
u64 title_id;
const ReturnCode ret = GetTitleId(&title_id);
const ReturnCode ret = m_core.GetTitleId(&title_id);
if (ret != IPC_SUCCESS)
return IPCReply(ret);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U64(title_id, request.io_vectors[0].address);
@ -242,9 +252,9 @@ IPCReply ESDevice::GetTitleId(const IOCtlVRequest& request)
return IPCReply(IPC_SUCCESS);
}
static bool UpdateUIDAndGID(Kernel& kernel, const ES::TMDReader& tmd)
static bool UpdateUIDAndGID(EmulationKernel& kernel, const ES::TMDReader& tmd)
{
ES::UIDSys uid_sys{kernel.GetFSDevice()};
ES::UIDSys uid_sys{kernel.GetFSCore()};
const u64 title_id = tmd.GetTitleId();
const u32 uid = uid_sys.GetOrInsertUIDForTitle(title_id);
if (uid == 0)
@ -257,10 +267,10 @@ static bool UpdateUIDAndGID(Kernel& kernel, const ES::TMDReader& tmd)
return true;
}
static ReturnCode CheckIsAllowedToSetUID(Kernel& kernel, const u32 caller_uid,
static ReturnCode CheckIsAllowedToSetUID(EmulationKernel& kernel, const u32 caller_uid,
const ES::TMDReader& active_tmd)
{
ES::UIDSys uid_map{kernel.GetFSDevice()};
ES::UIDSys uid_map{kernel.GetFSCore()};
const u32 system_menu_uid = uid_map.GetOrInsertUIDForTitle(Titles::SYSTEM_MENU);
if (!system_menu_uid)
return ES_SHORT_READ;
@ -284,23 +294,23 @@ IPCReply ESDevice::SetUID(u32 uid, const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 8)
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const s32 ret = CheckIsAllowedToSetUID(m_ios, uid, m_title_context.tmd);
const s32 ret = CheckIsAllowedToSetUID(GetEmulationKernel(), uid, m_core.m_title_context.tmd);
if (ret < 0)
{
ERROR_LOG_FMT(IOS_ES, "SetUID: Permission check failed with error {}", ret);
return IPCReply(ret);
}
const auto tmd = FindInstalledTMD(title_id);
const auto tmd = m_core.FindInstalledTMD(title_id);
if (!tmd.IsValid())
return IPCReply(FS_ENOENT);
if (!UpdateUIDAndGID(m_ios, tmd))
if (!UpdateUIDAndGID(GetEmulationKernel(), tmd))
{
ERROR_LOG_FMT(IOS_ES, "SetUID: Failed to get UID for title {:016x}", title_id);
return IPCReply(ES_SHORT_READ);
@ -311,13 +321,13 @@ IPCReply ESDevice::SetUID(u32 uid, const IOCtlVRequest& request)
bool ESDevice::LaunchTitle(u64 title_id, HangPPC hang_ppc)
{
m_title_context.Clear();
m_core.m_title_context.Clear();
INFO_LOG_FMT(IOS_ES, "ES_Launch: Title context changed: (none)");
NOTICE_LOG_FMT(IOS_ES, "Launching title {:016x}...", title_id);
if ((title_id == Titles::SHOP || title_id == Titles::KOREAN_SHOP) &&
m_ios.GetIOSC().IsUsingDefaultId())
GetEmulationKernel().GetIOSC().IsUsingDefaultId())
{
ERROR_LOG_FMT(IOS_ES, "Refusing to launch the shop channel with default device credentials");
CriticalAlertFmtT(
@ -358,12 +368,12 @@ bool ESDevice::LaunchIOS(u64 ios_title_id, HangPPC hang_ppc)
// so only have this check for MIOS (for which having the binary is *required*).
if (ios_title_id == Titles::MIOS)
{
const ES::TMDReader tmd = FindInstalledTMD(ios_title_id);
const ES::TicketReader ticket = FindSignedTicket(ios_title_id);
const ES::TMDReader tmd = m_core.FindInstalledTMD(ios_title_id);
const ES::TicketReader ticket = m_core.FindSignedTicket(ios_title_id);
ES::Content content;
if (!tmd.IsValid() || !ticket.IsValid() || !tmd.GetContent(tmd.GetBootIndex(), &content) ||
!m_ios.BootIOS(Core::System::GetInstance(), ios_title_id, hang_ppc,
GetContentPath(ios_title_id, content)))
!GetEmulationKernel().BootIOS(GetSystem(), ios_title_id, hang_ppc,
m_core.GetContentPath(ios_title_id, content)))
{
PanicAlertFmtT("Could not launch IOS {0:016x} because it is missing from the NAND.\n"
"The emulated software will likely hang now.",
@ -373,12 +383,12 @@ bool ESDevice::LaunchIOS(u64 ios_title_id, HangPPC hang_ppc)
return true;
}
return m_ios.BootIOS(Core::System::GetInstance(), ios_title_id, hang_ppc);
return GetEmulationKernel().BootIOS(GetSystem(), ios_title_id, hang_ppc);
}
s32 ESDevice::WriteLaunchFile(const ES::TMDReader& tmd, Ticks ticks)
{
m_ios.GetFSDevice()->DeleteFile(PID_KERNEL, PID_KERNEL, SPACE_FILE_PATH, ticks);
GetEmulationKernel().GetFSCore().DeleteFile(PID_KERNEL, PID_KERNEL, SPACE_FILE_PATH, ticks);
std::vector<u8> launch_data(sizeof(u64) + sizeof(ES::TicketView));
const u64 title_id = tmd.GetTitleId();
@ -393,8 +403,8 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
{
u64 ticks = 0;
const ES::TMDReader tmd = FindInstalledTMD(title_id, &ticks);
const ES::TicketReader ticket = FindSignedTicket(title_id);
const ES::TMDReader tmd = m_core.FindInstalledTMD(title_id, &ticks);
const ES::TicketReader ticket = m_core.FindSignedTicket(title_id);
if (!tmd.IsValid() || !ticket.IsValid())
{
@ -412,7 +422,7 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
return false;
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& core_timing = system.GetCoreTiming();
// Before launching a title, IOS first reads the TMD and reloads into the specified IOS version,
@ -422,7 +432,7 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
// To keep track of the PPC title launch, a temporary launch file (LAUNCH_FILE_PATH) is used
// to store the title ID of the title to launch and its TMD.
// The launch file not existing means an IOS reload is required.
if (const auto launch_file_fd = m_ios.GetFSDevice()->Open(
if (const auto launch_file_fd = GetEmulationKernel().GetFSCore().Open(
PID_KERNEL, PID_KERNEL, LAUNCH_FILE_PATH, FS::Mode::Read, {}, &ticks);
launch_file_fd.Get() < 0)
{
@ -442,17 +452,17 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
// Otherwise, assume that the PPC title can now be launched directly.
// Unlike IOS, we won't bother checking the title ID in the launch file. (It's not useful.)
m_ios.GetFSDevice()->DeleteFile(PID_KERNEL, PID_KERNEL, LAUNCH_FILE_PATH, &ticks);
GetEmulationKernel().GetFSCore().DeleteFile(PID_KERNEL, PID_KERNEL, LAUNCH_FILE_PATH, &ticks);
WriteSystemFile(SPACE_FILE_PATH, std::vector<u8>(SPACE_FILE_SIZE), &ticks);
m_title_context.Update(tmd, ticket, DiscIO::Platform::WiiWAD);
m_core.m_title_context.Update(tmd, ticket, DiscIO::Platform::WiiWAD);
INFO_LOG_FMT(IOS_ES, "LaunchPPCTitle: Title context changed: {:016x}", tmd.GetTitleId());
// Note: the UID/GID is also updated for IOS titles, but since we have no guarantee IOS titles
// are installed, we can only do this for PPC titles.
if (!UpdateUIDAndGID(m_ios, m_title_context.tmd))
if (!UpdateUIDAndGID(GetEmulationKernel(), m_core.m_title_context.tmd))
{
m_title_context.Clear();
m_core.m_title_context.Clear();
INFO_LOG_FMT(IOS_ES, "LaunchPPCTitle: Title context changed: (none)");
return false;
}
@ -461,7 +471,7 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
if (!tmd.GetContent(tmd.GetBootIndex(), &content))
return false;
m_pending_ppc_boot_content_path = GetContentPath(tmd.GetTitleId(), content);
m_pending_ppc_boot_content_path = m_core.GetContentPath(tmd.GetTitleId(), content);
if (!Core::IsRunningAndStarted())
return BootstrapPPC();
@ -473,12 +483,12 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
bool ESDevice::BootstrapPPC()
{
const bool result =
m_ios.BootstrapPPC(Core::System::GetInstance(), m_pending_ppc_boot_content_path);
GetEmulationKernel().BootstrapPPC(GetSystem(), m_pending_ppc_boot_content_path);
m_pending_ppc_boot_content_path = {};
return result;
}
void ESDevice::Context::DoState(PointerWrap& p)
void ESCore::Context::DoState(PointerWrap& p)
{
p.Do(uid);
p.Do(gid);
@ -492,7 +502,7 @@ void ESDevice::DoState(PointerWrap& p)
{
Device::DoState(p);
for (auto& entry : m_content_table)
for (auto& entry : m_core.m_content_table)
{
p.Do(entry.m_opened);
p.Do(entry.m_title_id);
@ -501,7 +511,7 @@ void ESDevice::DoState(PointerWrap& p)
p.Do(entry.m_uid);
}
m_title_context.DoState(p);
m_core.m_title_context.DoState(p);
for (auto& context : m_contexts)
context.DoState(p);
@ -702,7 +712,7 @@ std::optional<IPCReply> ESDevice::IOCtlV(const IOCtlVRequest& request)
case IOCTL_ES_UNKNOWN_42:
PanicAlertFmt("IOS-ES: Unimplemented ioctlv {:#x} ({} in vectors, {} io vectors)",
request.request, request.in_vectors.size(), request.io_vectors.size());
request.DumpUnknown(GetDeviceName(), Common::Log::LogType::IOS_ES,
request.DumpUnknown(GetSystem(), GetDeviceName(), Common::Log::LogType::IOS_ES,
Common::Log::LogLevel::LERROR);
return IPCReply(IPC_EINVAL);
@ -718,7 +728,7 @@ IPCReply ESDevice::GetConsumption(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
// This is at least what crediar's ES module does
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(0, request.io_vectors[1].address);
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETCONSUMPTION");
@ -730,7 +740,7 @@ std::optional<IPCReply> ESDevice::Launch(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(2, 0))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
@ -765,7 +775,7 @@ std::optional<IPCReply> ESDevice::LaunchBC(const IOCtlVRequest& request)
// 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.
if (m_ios.GetVersion() == 0x101)
if (GetEmulationKernel().GetVersion() == 0x101)
return IPCReply(ES_EINVAL);
if (!LaunchTitle(0x0000000100000100))
@ -808,7 +818,7 @@ static ReturnCode WriteTmdForDiVerify(FS::FileSystem* fs, const ES::TMDReader& t
ReturnCode ESDevice::DIVerify(const ES::TMDReader& tmd, const ES::TicketReader& ticket)
{
m_title_context.Clear();
m_core.m_title_context.Clear();
INFO_LOG_FMT(IOS_ES, "ES_DIVerify: Title context changed: (none)");
if (!tmd.IsValid() || !ticket.IsValid())
@ -817,14 +827,14 @@ ReturnCode ESDevice::DIVerify(const ES::TMDReader& tmd, const ES::TicketReader&
if (tmd.GetTitleId() != ticket.GetTitleId())
return ES_EINVAL;
m_title_context.Update(tmd, ticket, DiscIO::Platform::WiiDisc);
m_core.m_title_context.Update(tmd, ticket, DiscIO::Platform::WiiDisc);
INFO_LOG_FMT(IOS_ES, "ES_DIVerify: Title context changed: {:016x}", tmd.GetTitleId());
// XXX: We are supposed to verify the TMD and ticket here, but cannot because
// this may cause issues with custom/patched games.
const auto fs = m_ios.GetFS();
if (!FindInstalledTMD(tmd.GetTitleId()).IsValid())
const auto fs = GetEmulationKernel().GetFS();
if (!m_core.FindInstalledTMD(tmd.GetTitleId()).IsValid())
{
if (const ReturnCode ret = WriteTmdForDiVerify(fs.get(), tmd))
{
@ -833,7 +843,7 @@ ReturnCode ESDevice::DIVerify(const ES::TMDReader& tmd, const ES::TicketReader&
}
}
if (!UpdateUIDAndGID(*GetIOS(), m_title_context.tmd))
if (!UpdateUIDAndGID(GetEmulationKernel(), m_core.m_title_context.tmd))
{
return ES_SHORT_READ;
}
@ -842,12 +852,12 @@ ReturnCode ESDevice::DIVerify(const ES::TMDReader& tmd, const ES::TicketReader&
// Might already exist, so we only need to check whether the second operation succeeded.
constexpr FS::Modes data_dir_modes{FS::Mode::ReadWrite, FS::Mode::None, FS::Mode::None};
fs->CreateDirectory(PID_KERNEL, PID_KERNEL, data_dir, 0, data_dir_modes);
return FS::ConvertResult(
fs->SetMetadata(0, data_dir, m_ios.GetUidForPPC(), m_ios.GetGidForPPC(), 0, data_dir_modes));
return FS::ConvertResult(fs->SetMetadata(0, data_dir, GetEmulationKernel().GetUidForPPC(),
GetEmulationKernel().GetGidForPPC(), 0, data_dir_modes));
}
ReturnCode ESDevice::CheckStreamKeyPermissions(const u32 uid, const u8* ticket_view,
const ES::TMDReader& tmd) const
ReturnCode ESCore::CheckStreamKeyPermissions(const u32 uid, const u8* ticket_view,
const ES::TMDReader& tmd) const
{
const u32 title_flags = tmd.GetTitleFlags();
// Only allow using this function with some titles (WFS titles).
@ -889,8 +899,8 @@ ReturnCode ESDevice::CheckStreamKeyPermissions(const u32 uid, const u8* ticket_v
return IPC_SUCCESS;
}
ReturnCode ESDevice::SetUpStreamKey(const u32 uid, const u8* ticket_view, const ES::TMDReader& tmd,
u32* handle)
ReturnCode ESCore::SetUpStreamKey(const u32 uid, const u8* ticket_view, const ES::TMDReader& tmd,
u32* handle)
{
ReturnCode ret = CheckStreamKeyPermissions(uid, ticket_view, tmd);
if (ret != IPC_SUCCESS)
@ -952,7 +962,7 @@ IPCReply ESDevice::SetUpStreamKey(const Context& context, const IOCtlVRequest& r
return IPCReply(ES_EINVAL);
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
std::vector<u8> tmd_bytes(request.in_vectors[1].size);
@ -963,8 +973,8 @@ IPCReply ESDevice::SetUpStreamKey(const Context& context, const IOCtlVRequest& r
return IPCReply(ES_EINVAL);
u32 handle;
const ReturnCode ret =
SetUpStreamKey(context.uid, memory.GetPointer(request.in_vectors[0].address), tmd, &handle);
const ReturnCode ret = m_core.SetUpStreamKey(
context.uid, memory.GetPointer(request.in_vectors[0].address), tmd, &handle);
memory.Write_U32(handle, request.io_vectors[0].address);
return IPCReply(ret);
}
@ -974,13 +984,13 @@ IPCReply ESDevice::DeleteStreamKey(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 handle = memory.Read_U32(request.in_vectors[0].address);
return IPCReply(m_ios.GetIOSC().DeleteObject(handle, PID_ES));
return IPCReply(GetEmulationKernel().GetIOSC().DeleteObject(handle, PID_ES));
}
bool ESDevice::IsActiveTitlePermittedByTicket(const u8* ticket_view) const
bool ESCore::IsActiveTitlePermittedByTicket(const u8* ticket_view) const
{
if (!m_title_context.active)
return false;
@ -993,7 +1003,7 @@ bool ESDevice::IsActiveTitlePermittedByTicket(const u8* ticket_view) const
return title_identifier && (title_identifier & ~permitted_title_mask) == permitted_title_id;
}
bool ESDevice::IsIssuerCorrect(VerifyContainerType type, const ES::CertReader& issuer_cert) const
bool ESCore::IsIssuerCorrect(VerifyContainerType type, const ES::CertReader& issuer_cert) const
{
switch (type)
{
@ -1010,7 +1020,7 @@ bool ESDevice::IsIssuerCorrect(VerifyContainerType type, const ES::CertReader& i
static const std::string CERT_STORE_PATH = "/sys/cert.sys";
ReturnCode ESDevice::ReadCertStore(std::vector<u8>* buffer) const
ReturnCode ESCore::ReadCertStore(std::vector<u8>* buffer) const
{
const auto store_file =
m_ios.GetFS()->OpenFile(PID_KERNEL, PID_KERNEL, CERT_STORE_PATH, FS::Mode::Read);
@ -1023,7 +1033,7 @@ ReturnCode ESDevice::ReadCertStore(std::vector<u8>* buffer) const
return IPC_SUCCESS;
}
ReturnCode ESDevice::WriteNewCertToStore(const ES::CertReader& cert)
ReturnCode ESCore::WriteNewCertToStore(const ES::CertReader& cert)
{
// Read the current store to determine if the new cert needs to be written.
std::vector<u8> current_store;
@ -1048,9 +1058,9 @@ ReturnCode ESDevice::WriteNewCertToStore(const ES::CertReader& cert)
return IPC_SUCCESS;
}
ReturnCode ESDevice::VerifyContainer(VerifyContainerType type, VerifyMode mode,
const ES::SignedBlobReader& signed_blob,
const std::vector<u8>& cert_chain, u32* issuer_handle_out)
ReturnCode ESCore::VerifyContainer(VerifyContainerType type, VerifyMode mode,
const ES::SignedBlobReader& signed_blob,
const std::vector<u8>& cert_chain, u32* issuer_handle_out)
{
if (!signed_blob.IsSignatureValid())
return ES_EINVAL;
@ -1144,9 +1154,9 @@ ReturnCode ESDevice::VerifyContainer(VerifyContainerType type, VerifyMode mode,
return ret;
}
ReturnCode ESDevice::VerifyContainer(VerifyContainerType type, VerifyMode mode,
const ES::CertReader& cert, const std::vector<u8>& cert_chain,
u32 certificate_iosc_handle)
ReturnCode ESCore::VerifyContainer(VerifyContainerType type, VerifyMode mode,
const ES::CertReader& cert, const std::vector<u8>& cert_chain,
u32 certificate_iosc_handle)
{
IOSC::Handle issuer_handle;
ReturnCode ret = VerifyContainer(type, mode, cert, cert_chain, &issuer_handle);

View file

@ -37,22 +37,17 @@ struct TitleContext
bool first_change = true;
};
class ESDevice final : public Device
class ESDevice;
class ESCore final
{
public:
ESDevice(Kernel& ios, const std::string& device_name);
static void InitializeEmulationState();
static void FinalizeEmulationState();
ReturnCode DIVerify(const ES::TMDReader& tmd, const ES::TicketReader& ticket);
bool LaunchTitle(u64 title_id, HangPPC hang_ppc = HangPPC::No);
void DoState(PointerWrap& p) override;
std::optional<IPCReply> Open(const OpenRequest& request) override;
std::optional<IPCReply> Close(u32 fd) override;
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
explicit ESCore(Kernel& ios);
ESCore(const ESCore& other) = delete;
ESCore(ESCore&& other) = delete;
ESCore& operator=(const ESCore& other) = delete;
ESCore& operator=(ESCore&& other) = delete;
~ESCore();
struct TitleImportExportContext
{
@ -83,12 +78,6 @@ public:
s32 ipc_fd = -1;
};
enum class CheckContentHashes : bool
{
Yes = true,
No = false,
};
ES::TMDReader FindImportTMD(u64 title_id, Ticks ticks = {}) const;
ES::TMDReader FindInstalledTMD(u64 title_id, Ticks ticks = {}) const;
ES::TicketReader FindSignedTicket(u64 title_id,
@ -101,6 +90,12 @@ public:
// Get titles for which there is a ticket (in /ticket).
std::vector<u64> GetTitlesWithTickets() const;
enum class CheckContentHashes : bool
{
Yes = true,
No = false,
};
std::vector<ES::Content>
GetStoredContentsFromTMD(const ES::TMDReader& tmd,
CheckContentHashes check_content_hashes = CheckContentHashes::No) const;
@ -186,6 +181,71 @@ public:
const ES::CertReader& certificate, const std::vector<u8>& cert_chain,
u32 certificate_iosc_handle);
private:
// Start a title import.
bool InitImport(const ES::TMDReader& tmd);
// Clean up the import content directory and move it back to /title.
bool FinishImport(const ES::TMDReader& tmd);
// Write a TMD for a title in /import atomically.
bool WriteImportTMD(const ES::TMDReader& tmd);
// Finish stale imports and clear the import directory.
void FinishStaleImport(u64 title_id);
void FinishAllStaleImports();
std::string GetContentPath(u64 title_id, const ES::Content& content, Ticks ticks = {}) const;
bool IsActiveTitlePermittedByTicket(const u8* ticket_view) const;
bool IsIssuerCorrect(VerifyContainerType type, const ES::CertReader& issuer_cert) const;
ReturnCode ReadCertStore(std::vector<u8>* buffer) const;
ReturnCode WriteNewCertToStore(const ES::CertReader& cert);
ReturnCode CheckStreamKeyPermissions(u32 uid, const u8* ticket_view,
const ES::TMDReader& tmd) const;
struct OpenedContent
{
bool m_opened = false;
u64 m_fd = 0;
u64 m_title_id = 0;
ES::Content m_content{};
u32 m_uid = 0;
};
Kernel& m_ios;
using ContentTable = std::array<OpenedContent, 16>;
ContentTable m_content_table;
TitleContext m_title_context{};
friend class ESDevice;
};
class ESDevice final : public EmulationDevice
{
public:
ESDevice(EmulationKernel& ios, ESCore& core, const std::string& device_name);
ESDevice(const ESDevice& other) = delete;
ESDevice(ESDevice&& other) = delete;
ESDevice& operator=(const ESDevice& other) = delete;
ESDevice& operator=(ESDevice&& other) = delete;
~ESDevice();
static void InitializeEmulationState();
static void FinalizeEmulationState();
ReturnCode DIVerify(const ES::TMDReader& tmd, const ES::TicketReader& ticket);
bool LaunchTitle(u64 title_id, HangPPC hang_ppc = HangPPC::No);
void DoState(PointerWrap& p) override;
std::optional<IPCReply> Open(const OpenRequest& request) override;
std::optional<IPCReply> Close(u32 fd) override;
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
ESCore& GetCore() const { return m_core; }
private:
enum
{
@ -261,6 +321,7 @@ private:
};
// ES can only have 3 contexts at one time.
using Context = ESCore::Context;
using ContextArray = std::array<Context, 3>;
// Title management
@ -348,47 +409,15 @@ private:
bool LaunchIOS(u64 ios_title_id, HangPPC hang_ppc);
bool LaunchPPCTitle(u64 title_id);
bool IsActiveTitlePermittedByTicket(const u8* ticket_view) const;
ReturnCode CheckStreamKeyPermissions(u32 uid, const u8* ticket_view,
const ES::TMDReader& tmd) const;
bool IsIssuerCorrect(VerifyContainerType type, const ES::CertReader& issuer_cert) const;
ReturnCode ReadCertStore(std::vector<u8>* buffer) const;
ReturnCode WriteNewCertToStore(const ES::CertReader& cert);
// Start a title import.
bool InitImport(const ES::TMDReader& tmd);
// Clean up the import content directory and move it back to /title.
bool FinishImport(const ES::TMDReader& tmd);
// Write a TMD for a title in /import atomically.
bool WriteImportTMD(const ES::TMDReader& tmd);
// Finish stale imports and clear the import directory.
void FinishStaleImport(u64 title_id);
void FinishAllStaleImports();
void FinishInit();
std::string GetContentPath(u64 title_id, const ES::Content& content, Ticks ticks = {}) const;
s32 WriteSystemFile(const std::string& path, const std::vector<u8>& data, Ticks ticks = {});
s32 WriteLaunchFile(const ES::TMDReader& tmd, Ticks ticks = {});
bool BootstrapPPC();
struct OpenedContent
{
bool m_opened = false;
u64 m_fd = 0;
u64 m_title_id = 0;
ES::Content m_content{};
u32 m_uid = 0;
};
using ContentTable = std::array<OpenedContent, 16>;
ContentTable m_content_table;
ESCore& m_core;
ContextArray m_contexts;
TitleContext m_title_context{};
std::string m_pending_ppc_boot_content_path;
};
} // namespace IOS::HLE

View file

@ -302,7 +302,7 @@ std::string TMDReader::GetGameID() const
std::memcpy(game_id, m_bytes.data() + offsetof(TMDHeader, title_id) + 4, 4);
std::memcpy(game_id + 4, m_bytes.data() + offsetof(TMDHeader, group_id), 2);
if (std::all_of(std::begin(game_id), std::end(game_id), IsPrintableCharacter))
if (std::all_of(std::begin(game_id), std::end(game_id), Common::IsPrintableCharacter))
return std::string(game_id, sizeof(game_id));
return fmt::format("{:016x}", GetTitleId());
@ -313,7 +313,7 @@ std::string TMDReader::GetGameTDBID() const
const u8* begin = m_bytes.data() + offsetof(TMDHeader, title_id) + 4;
const u8* end = begin + 4;
if (std::all_of(begin, end, IsPrintableCharacter))
if (std::all_of(begin, end, Common::IsPrintableCharacter))
return std::string(begin, end);
return fmt::format("{:016x}", GetTitleId());
@ -554,17 +554,16 @@ struct SharedContentMap::Entry
};
constexpr char CONTENT_MAP_PATH[] = "/shared1/content.map";
SharedContentMap::SharedContentMap(std::shared_ptr<HLE::FSDevice> fs)
: m_fs_device{fs}, m_fs{fs->GetFS()}
SharedContentMap::SharedContentMap(HLE::FSCore& fs_core) : m_fs_core{fs_core}, m_fs{fs_core.GetFS()}
{
static_assert(sizeof(Entry) == 28, "SharedContentMap::Entry has the wrong size");
Entry entry;
const auto fd =
fs->Open(PID_KERNEL, PID_KERNEL, CONTENT_MAP_PATH, HLE::FS::Mode::Read, {}, &m_ticks);
fs_core.Open(PID_KERNEL, PID_KERNEL, CONTENT_MAP_PATH, HLE::FS::Mode::Read, {}, &m_ticks);
if (fd.Get() < 0)
return;
while (fs->Read(fd.Get(), &entry, 1, &m_ticks) == sizeof(entry))
while (fs_core.Read(fd.Get(), &entry, 1, &m_ticks) == sizeof(entry))
{
m_entries.push_back(entry);
m_last_id++;
@ -637,7 +636,7 @@ bool SharedContentMap::WriteEntries() const
HLE::FS::ResultCode::Success;
}
static std::pair<u32, u64> ReadUidSysEntry(HLE::FSDevice& fs, u64 fd, u64* ticks)
static std::pair<u32, u64> ReadUidSysEntry(HLE::FSCore& fs, u64 fd, u64* ticks)
{
u64 title_id = 0;
if (fs.Read(fd, &title_id, 1, ticks) != sizeof(title_id))
@ -651,15 +650,15 @@ static std::pair<u32, u64> ReadUidSysEntry(HLE::FSDevice& fs, u64 fd, u64* ticks
}
constexpr char UID_MAP_PATH[] = "/sys/uid.sys";
UIDSys::UIDSys(std::shared_ptr<HLE::FSDevice> fs) : m_fs_device{fs}, m_fs{fs->GetFS()}
UIDSys::UIDSys(HLE::FSCore& fs_core) : m_fs_core{fs_core}, m_fs{fs_core.GetFS()}
{
if (const auto fd =
fs->Open(PID_KERNEL, PID_KERNEL, UID_MAP_PATH, HLE::FS::Mode::Read, {}, &m_ticks);
fs_core.Open(PID_KERNEL, PID_KERNEL, UID_MAP_PATH, HLE::FS::Mode::Read, {}, &m_ticks);
fd.Get() >= 0)
{
while (true)
{
std::pair<u32, u64> entry = ReadUidSysEntry(*fs, fd.Get(), &m_ticks);
std::pair<u32, u64> entry = ReadUidSysEntry(fs_core, fd.Get(), &m_ticks);
if (!entry.first && !entry.second)
break;

View file

@ -280,7 +280,7 @@ public:
class SharedContentMap final
{
public:
explicit SharedContentMap(std::shared_ptr<HLE::FSDevice> fs);
explicit SharedContentMap(HLE::FSCore& fs_core);
~SharedContentMap();
std::optional<std::string> GetFilenameFromSHA1(const std::array<u8, 20>& sha1) const;
@ -296,7 +296,7 @@ private:
struct Entry;
u32 m_last_id = 0;
std::vector<Entry> m_entries;
std::shared_ptr<HLE::FSDevice> m_fs_device;
HLE::FSCore& m_fs_core;
std::shared_ptr<HLE::FS::FileSystem> m_fs;
u64 m_ticks = 0;
};
@ -304,7 +304,7 @@ private:
class UIDSys final
{
public:
explicit UIDSys(std::shared_ptr<HLE::FSDevice> fs);
explicit UIDSys(HLE::FSCore& fs_core);
u32 GetUIDFromTitle(u64 title_id) const;
u32 GetOrInsertUIDForTitle(u64 title_id);
@ -313,7 +313,7 @@ public:
u64 GetTicks() const { return m_ticks; }
private:
std::shared_ptr<HLE::FSDevice> m_fs_device;
HLE::FSCore& m_fs_core;
std::shared_ptr<HLE::FS::FileSystem> m_fs;
std::map<u32, u64> m_entries;
u64 m_ticks = 0;

View file

@ -19,7 +19,7 @@
namespace IOS::HLE
{
ReturnCode ESDevice::GetDeviceId(u32* device_id) const
ReturnCode ESCore::GetDeviceId(u32* device_id) const
{
*device_id = m_ios.GetIOSC().GetDeviceId();
INFO_LOG_FMT(IOS_ES, "GetDeviceId: {:08X}", *device_id);
@ -32,11 +32,11 @@ IPCReply ESDevice::GetDeviceId(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
u32 device_id;
const ReturnCode ret = GetDeviceId(&device_id);
const ReturnCode ret = m_core.GetDeviceId(&device_id);
if (ret != IPC_SUCCESS)
return IPCReply(ret);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(device_id, request.io_vectors[0].address);
return IPCReply(IPC_SUCCESS);
@ -47,7 +47,7 @@ IPCReply ESDevice::Encrypt(u32 uid, const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(3, 2))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 keyIndex = memory.Read_U32(request.in_vectors[0].address);
u8* source = memory.GetPointer(request.in_vectors[2].address);
@ -57,7 +57,8 @@ IPCReply ESDevice::Encrypt(u32 uid, const IOCtlVRequest& request)
// 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 =
GetEmulationKernel().GetIOSC().Encrypt(keyIndex, iv, source, size, destination, PID_ES);
return IPCReply(ret);
}
@ -66,7 +67,7 @@ IPCReply ESDevice::Decrypt(u32 uid, const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(3, 2))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 keyIndex = memory.Read_U32(request.in_vectors[0].address);
u8* source = memory.GetPointer(request.in_vectors[2].address);
@ -76,7 +77,8 @@ IPCReply ESDevice::Decrypt(u32 uid, const IOCtlVRequest& request)
// 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 =
GetEmulationKernel().GetIOSC().Decrypt(keyIndex, iv, source, size, destination, PID_ES);
return IPCReply(ret);
}
@ -100,9 +102,9 @@ IPCReply ESDevice::GetDeviceCertificate(const IOCtlVRequest& request)
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETDEVICECERT");
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const IOS::CertECC cert = m_ios.GetIOSC().GetDeviceCertificate();
const IOS::CertECC cert = GetEmulationKernel().GetIOSC().GetDeviceCertificate();
memory.CopyToEmu(request.io_vectors[0].address, &cert, sizeof(cert));
return IPCReply(IPC_SUCCESS);
}
@ -113,22 +115,23 @@ IPCReply ESDevice::Sign(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_SIGN");
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u8* ap_cert_out = memory.GetPointer(request.io_vectors[1].address);
u8* data = memory.GetPointer(request.in_vectors[0].address);
u32 data_size = request.in_vectors[0].size;
u8* sig_out = memory.GetPointer(request.io_vectors[0].address);
if (!m_title_context.active)
if (!m_core.m_title_context.active)
return IPCReply(ES_EINVAL);
m_ios.GetIOSC().Sign(sig_out, ap_cert_out, m_title_context.tmd.GetTitleId(), data, data_size);
GetEmulationKernel().GetIOSC().Sign(sig_out, ap_cert_out, m_core.m_title_context.tmd.GetTitleId(),
data, data_size);
return IPCReply(IPC_SUCCESS);
}
ReturnCode ESDevice::VerifySign(const std::vector<u8>& hash, const std::vector<u8>& ecc_signature,
const std::vector<u8>& certs_bytes)
ReturnCode ESCore::VerifySign(const std::vector<u8>& hash, const std::vector<u8>& ecc_signature,
const std::vector<u8>& certs_bytes)
{
const std::map<std::string, ES::CertReader> certs = ES::ParseCertChain(certs_bytes);
if (certs.empty())
@ -205,7 +208,7 @@ IPCReply ESDevice::VerifySign(const IOCtlVRequest& request)
if (request.in_vectors[1].size != sizeof(Common::ec::Signature))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
std::vector<u8> hash(request.in_vectors[0].size);
@ -217,6 +220,6 @@ IPCReply ESDevice::VerifySign(const IOCtlVRequest& request)
std::vector<u8> certs(request.in_vectors[2].size);
memory.CopyFromEmu(certs.data(), request.in_vectors[2].address, certs.size());
return IPCReply(VerifySign(hash, ecc_signature, certs));
return IPCReply(m_core.VerifySign(hash, ecc_signature, certs));
}
} // namespace IOS::HLE

View file

@ -25,7 +25,7 @@
namespace IOS::HLE
{
static ES::TMDReader FindTMD(FSDevice& fs, const std::string& tmd_path, Ticks ticks)
static ES::TMDReader FindTMD(FSCore& fs, const std::string& tmd_path, Ticks ticks)
{
const auto fd = fs.Open(PID_KERNEL, PID_KERNEL, tmd_path, FS::Mode::Read, {}, ticks);
if (fd.Get() < 0)
@ -38,18 +38,18 @@ static ES::TMDReader FindTMD(FSDevice& fs, const std::string& tmd_path, Ticks ti
return ES::TMDReader{std::move(tmd_bytes)};
}
ES::TMDReader ESDevice::FindImportTMD(u64 title_id, Ticks ticks) const
ES::TMDReader ESCore::FindImportTMD(u64 title_id, Ticks ticks) const
{
return FindTMD(*m_ios.GetFSDevice(), Common::GetImportTitlePath(title_id) + "/content/title.tmd",
return FindTMD(m_ios.GetFSCore(), Common::GetImportTitlePath(title_id) + "/content/title.tmd",
ticks);
}
ES::TMDReader ESDevice::FindInstalledTMD(u64 title_id, Ticks ticks) const
ES::TMDReader ESCore::FindInstalledTMD(u64 title_id, Ticks ticks) const
{
return FindTMD(*m_ios.GetFSDevice(), Common::GetTMDFileName(title_id), ticks);
return FindTMD(m_ios.GetFSCore(), Common::GetTMDFileName(title_id), ticks);
}
ES::TicketReader ESDevice::FindSignedTicket(u64 title_id, std::optional<u8> desired_version) const
ES::TicketReader ESCore::FindSignedTicket(u64 title_id, std::optional<u8> desired_version) const
{
std::string path = desired_version == 1 ? Common::GetV1TicketFileName(title_id) :
Common::GetTicketFileName(title_id);
@ -125,17 +125,17 @@ static std::vector<u64> GetTitlesInTitleOrImport(FS::FileSystem* fs, const std::
return title_ids;
}
std::vector<u64> ESDevice::GetInstalledTitles() const
std::vector<u64> ESCore::GetInstalledTitles() const
{
return GetTitlesInTitleOrImport(m_ios.GetFS().get(), "/title");
}
std::vector<u64> ESDevice::GetTitleImports() const
std::vector<u64> ESCore::GetTitleImports() const
{
return GetTitlesInTitleOrImport(m_ios.GetFS().get(), "/import");
}
std::vector<u64> ESDevice::GetTitlesWithTickets() const
std::vector<u64> ESCore::GetTitlesWithTickets() const
{
const auto fs = m_ios.GetFS();
const auto entries = fs->ReadDirectory(PID_KERNEL, PID_KERNEL, "/ticket");
@ -179,8 +179,8 @@ std::vector<u64> ESDevice::GetTitlesWithTickets() const
}
std::vector<ES::Content>
ESDevice::GetStoredContentsFromTMD(const ES::TMDReader& tmd,
CheckContentHashes check_content_hashes) const
ESCore::GetStoredContentsFromTMD(const ES::TMDReader& tmd,
CheckContentHashes check_content_hashes) const
{
if (!tmd.IsValid())
return {};
@ -216,7 +216,7 @@ ESDevice::GetStoredContentsFromTMD(const ES::TMDReader& tmd,
return stored_contents;
}
u32 ESDevice::GetSharedContentsCount() const
u32 ESCore::GetSharedContentsCount() const
{
const auto entries = m_ios.GetFS()->ReadDirectory(PID_KERNEL, PID_KERNEL, "/shared1");
return static_cast<u32>(
@ -226,9 +226,9 @@ u32 ESDevice::GetSharedContentsCount() const
}));
}
std::vector<std::array<u8, 20>> ESDevice::GetSharedContents() const
std::vector<std::array<u8, 20>> ESCore::GetSharedContents() const
{
const ES::SharedContentMap map{m_ios.GetFSDevice()};
const ES::SharedContentMap map{m_ios.GetFSCore()};
return map.GetHashes();
}
@ -253,7 +253,7 @@ constexpr FS::Modes title_dir_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS
constexpr FS::Modes content_dir_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None};
constexpr FS::Modes data_dir_modes{FS::Mode::ReadWrite, FS::Mode::None, FS::Mode::None};
bool ESDevice::CreateTitleDirectories(u64 title_id, u16 group_id) const
bool ESCore::CreateTitleDirectories(u64 title_id, u16 group_id) const
{
const auto fs = m_ios.GetFS();
@ -278,7 +278,7 @@ bool ESDevice::CreateTitleDirectories(u64 title_id, u16 group_id) const
return false;
}
ES::UIDSys uid_sys{m_ios.GetFSDevice()};
ES::UIDSys uid_sys{m_ios.GetFSCore()};
const u32 uid = uid_sys.GetOrInsertUIDForTitle(title_id);
if (fs->SetMetadata(0, data_dir, uid, group_id, 0, data_dir_modes) != FS::ResultCode::Success)
{
@ -289,7 +289,7 @@ bool ESDevice::CreateTitleDirectories(u64 title_id, u16 group_id) const
return true;
}
bool ESDevice::InitImport(const ES::TMDReader& tmd)
bool ESCore::InitImport(const ES::TMDReader& tmd)
{
if (!CreateTitleDirectories(tmd.GetTitleId(), tmd.GetGroupId()))
return false;
@ -321,7 +321,7 @@ bool ESDevice::InitImport(const ES::TMDReader& tmd)
return true;
}
bool ESDevice::FinishImport(const ES::TMDReader& tmd)
bool ESCore::FinishImport(const ES::TMDReader& tmd)
{
const auto fs = m_ios.GetFS();
const u64 title_id = tmd.GetTitleId();
@ -354,7 +354,7 @@ bool ESDevice::FinishImport(const ES::TMDReader& tmd)
return true;
}
bool ESDevice::WriteImportTMD(const ES::TMDReader& tmd)
bool ESCore::WriteImportTMD(const ES::TMDReader& tmd)
{
const auto fs = m_ios.GetFS();
const std::string tmd_path = "/tmp/title.tmd";
@ -369,7 +369,7 @@ bool ESDevice::WriteImportTMD(const ES::TMDReader& tmd)
return fs->Rename(PID_KERNEL, PID_KERNEL, tmd_path, dest) == FS::ResultCode::Success;
}
void ESDevice::FinishStaleImport(u64 title_id)
void ESCore::FinishStaleImport(u64 title_id)
{
const auto fs = m_ios.GetFS();
const auto import_tmd = FindImportTMD(title_id);
@ -385,19 +385,19 @@ void ESDevice::FinishStaleImport(u64 title_id)
}
}
void ESDevice::FinishAllStaleImports()
void ESCore::FinishAllStaleImports()
{
const std::vector<u64> titles = GetTitleImports();
for (const u64& title_id : titles)
FinishStaleImport(title_id);
}
std::string ESDevice::GetContentPath(const u64 title_id, const ES::Content& content,
Ticks ticks) const
std::string ESCore::GetContentPath(const u64 title_id, const ES::Content& content,
Ticks ticks) const
{
if (content.IsShared())
{
ES::SharedContentMap content_map{m_ios.GetFSDevice()};
ES::SharedContentMap content_map{m_ios.GetFSCore()};
ticks.Add(content_map.GetTicks());
return content_map.GetFilenameFromSHA1(content.sha1).value_or("");
}
@ -406,7 +406,7 @@ std::string ESDevice::GetContentPath(const u64 title_id, const ES::Content& cont
s32 ESDevice::WriteSystemFile(const std::string& path, const std::vector<u8>& data, Ticks ticks)
{
auto& fs = *m_ios.GetFSDevice();
auto& fs = GetEmulationKernel().GetFSCore();
const std::string tmp_path = "/tmp/" + PathToFileName(path);
auto result = fs.CreateFile(PID_KERNEL, PID_KERNEL, tmp_path, {},

View file

@ -14,7 +14,7 @@
namespace IOS::HLE
{
s32 ESDevice::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid, Ticks ticks)
s32 ESCore::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid, Ticks ticks)
{
const u64 title_id = tmd.GetTitleId();
@ -29,7 +29,7 @@ s32 ESDevice::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid,
continue;
const std::string path = GetContentPath(title_id, content, ticks);
auto fd = m_ios.GetFSDevice()->Open(PID_KERNEL, PID_KERNEL, path, FS::Mode::Read, {}, ticks);
auto fd = m_ios.GetFSCore().Open(PID_KERNEL, PID_KERNEL, path, FS::Mode::Read, {}, ticks);
if (fd.Get() < 0)
return fd.Get();
@ -57,17 +57,17 @@ IPCReply ESDevice::OpenContent(u32 uid, const IOCtlVRequest& request)
return ES_EINVAL;
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const u32 content_index = memory.Read_U32(request.in_vectors[2].address);
// TODO: check the ticket view, check permissions.
const auto tmd = FindInstalledTMD(title_id, ticks);
const auto tmd = m_core.FindInstalledTMD(title_id, ticks);
if (!tmd.IsValid())
return FS_ENOENT;
return OpenContent(tmd, content_index, uid, ticks);
return m_core.OpenContent(tmd, content_index, uid, ticks);
});
}
@ -77,24 +77,24 @@ IPCReply ESDevice::OpenActiveTitleContent(u32 caller_uid, const IOCtlVRequest& r
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
return ES_EINVAL;
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 content_index = memory.Read_U32(request.in_vectors[0].address);
if (!m_title_context.active)
if (!m_core.m_title_context.active)
return ES_EINVAL;
ES::UIDSys uid_map{m_ios.GetFSDevice()};
const u32 uid = uid_map.GetOrInsertUIDForTitle(m_title_context.tmd.GetTitleId());
ES::UIDSys uid_map{GetEmulationKernel().GetFSCore()};
const u32 uid = uid_map.GetOrInsertUIDForTitle(m_core.m_title_context.tmd.GetTitleId());
ticks.Add(uid_map.GetTicks());
if (caller_uid != 0 && caller_uid != uid)
return ES_EACCES;
return OpenContent(m_title_context.tmd, content_index, caller_uid, ticks);
return m_core.OpenContent(m_core.m_title_context.tmd, content_index, caller_uid, ticks);
});
}
s32 ESDevice::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid, Ticks ticks)
s32 ESCore::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid, Ticks ticks)
{
if (cfd >= m_content_table.size())
return ES_EINVAL;
@ -105,7 +105,7 @@ s32 ESDevice::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid, Ticks ticks)
if (!entry.m_opened)
return IPC_EINVAL;
return m_ios.GetFSDevice()->Read(entry.m_fd, buffer, size, {}, ticks);
return m_ios.GetFSCore().Read(entry.m_fd, buffer, size, {}, ticks);
}
IPCReply ESDevice::ReadContent(u32 uid, const IOCtlVRequest& request)
@ -114,7 +114,7 @@ IPCReply ESDevice::ReadContent(u32 uid, const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
return ES_EINVAL;
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 cfd = memory.Read_U32(request.in_vectors[0].address);
const u32 size = request.io_vectors[0].size;
@ -122,11 +122,11 @@ IPCReply ESDevice::ReadContent(u32 uid, const IOCtlVRequest& request)
INFO_LOG_FMT(IOS_ES, "ReadContent(uid={:#x}, cfd={}, size={}, addr={:08x})", uid, cfd, size,
addr);
return ReadContent(cfd, memory.GetPointer(addr), size, uid, ticks);
return m_core.ReadContent(cfd, memory.GetPointer(addr), size, uid, ticks);
});
}
s32 ESDevice::CloseContent(u32 cfd, u32 uid, Ticks ticks)
s32 ESCore::CloseContent(u32 cfd, u32 uid, Ticks ticks)
{
if (cfd >= m_content_table.size())
return ES_EINVAL;
@ -137,7 +137,7 @@ s32 ESDevice::CloseContent(u32 cfd, u32 uid, Ticks ticks)
if (!entry.m_opened)
return IPC_EINVAL;
m_ios.GetFSDevice()->Close(entry.m_fd, ticks);
m_ios.GetFSCore().Close(entry.m_fd, ticks);
entry = {};
INFO_LOG_FMT(IOS_ES, "CloseContent: CFD {}", cfd);
return IPC_SUCCESS;
@ -149,14 +149,14 @@ IPCReply ESDevice::CloseContent(u32 uid, const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
return ES_EINVAL;
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 cfd = memory.Read_U32(request.in_vectors[0].address);
return CloseContent(cfd, uid, ticks);
return m_core.CloseContent(cfd, uid, ticks);
});
}
s32 ESDevice::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid, Ticks ticks)
s32 ESCore::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid, Ticks ticks)
{
if (cfd >= m_content_table.size())
return ES_EINVAL;
@ -167,7 +167,7 @@ s32 ESDevice::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid, Ticks tic
if (!entry.m_opened)
return IPC_EINVAL;
return m_ios.GetFSDevice()->Seek(entry.m_fd, offset, static_cast<FS::SeekMode>(mode), ticks);
return m_ios.GetFSCore().Seek(entry.m_fd, offset, static_cast<FS::SeekMode>(mode), ticks);
}
IPCReply ESDevice::SeekContent(u32 uid, const IOCtlVRequest& request)
@ -176,13 +176,13 @@ IPCReply ESDevice::SeekContent(u32 uid, const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(3, 0))
return ES_EINVAL;
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 cfd = memory.Read_U32(request.in_vectors[0].address);
const u32 offset = memory.Read_U32(request.in_vectors[1].address);
const auto mode = static_cast<SeekMode>(memory.Read_U32(request.in_vectors[2].address));
return SeekContent(cfd, offset, mode, uid, ticks);
return m_core.SeekContent(cfd, offset, mode, uid, ticks);
});
}
} // namespace IOS::HLE

View file

@ -21,8 +21,8 @@ IPCReply ESDevice::GetStoredContentsCount(const ES::TMDReader& tmd, const IOCtlV
if (request.io_vectors[0].size != sizeof(u32) || !tmd.IsValid())
return IPCReply(ES_EINVAL);
const u16 num_contents = static_cast<u16>(GetStoredContentsFromTMD(tmd).size());
auto& system = Core::System::GetInstance();
const u16 num_contents = static_cast<u16>(m_core.GetStoredContentsFromTMD(tmd).size());
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(num_contents, request.io_vectors[0].address);
@ -38,7 +38,7 @@ IPCReply ESDevice::GetStoredContents(const ES::TMDReader& tmd, const IOCtlVReque
if (!tmd.IsValid())
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
if (request.in_vectors[1].size != sizeof(u32) ||
request.io_vectors[0].size != memory.Read_U32(request.in_vectors[1].address) * sizeof(u32))
@ -46,7 +46,7 @@ IPCReply ESDevice::GetStoredContents(const ES::TMDReader& tmd, const IOCtlVReque
return IPCReply(ES_EINVAL);
}
const auto contents = GetStoredContentsFromTMD(tmd);
const auto contents = m_core.GetStoredContentsFromTMD(tmd);
const u32 max_content_count = memory.Read_U32(request.in_vectors[1].address);
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));
@ -59,10 +59,10 @@ IPCReply ESDevice::GetStoredContentsCount(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u64))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
const ES::TMDReader tmd = m_core.FindInstalledTMD(title_id);
if (!tmd.IsValid())
return IPCReply(FS_ENOENT);
return GetStoredContentsCount(tmd, request);
@ -73,10 +73,10 @@ IPCReply ESDevice::GetStoredContents(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(2, 1) || request.in_vectors[0].size != sizeof(u64))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
const ES::TMDReader tmd = m_core.FindInstalledTMD(title_id);
if (!tmd.IsValid())
return IPCReply(FS_ENOENT);
return GetStoredContents(tmd, request);
@ -88,7 +88,7 @@ IPCReply ESDevice::GetTMDStoredContentsCount(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
std::vector<u8> tmd_bytes(request.in_vectors[0].size);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size());
return GetStoredContentsCount(ES::TMDReader{std::move(tmd_bytes)}, request);
@ -100,7 +100,7 @@ IPCReply ESDevice::GetTMDStoredContents(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
std::vector<u8> tmd_bytes(request.in_vectors[0].size);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size());
@ -109,11 +109,12 @@ IPCReply ESDevice::GetTMDStoredContents(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
std::vector<u8> cert_store;
ReturnCode ret = ReadCertStore(&cert_store);
ReturnCode ret = m_core.ReadCertStore(&cert_store);
if (ret != IPC_SUCCESS)
return IPCReply(ret);
ret = VerifyContainer(VerifyContainerType::TMD, VerifyMode::UpdateCertStore, tmd, cert_store);
ret = m_core.VerifyContainer(ESCore::VerifyContainerType::TMD,
ESCore::VerifyMode::UpdateCertStore, tmd, cert_store);
if (ret != IPC_SUCCESS)
return IPCReply(ret);
@ -125,7 +126,7 @@ IPCReply ESDevice::GetTitleCount(const std::vector<u64>& titles, const IOCtlVReq
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 4)
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(static_cast<u32>(titles.size()), request.io_vectors[0].address);
@ -137,7 +138,7 @@ IPCReply ESDevice::GetTitles(const std::vector<u64>& titles, const IOCtlVRequest
if (!request.HasNumberOfValidVectors(1, 1))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
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++)
@ -150,14 +151,14 @@ IPCReply ESDevice::GetTitles(const std::vector<u64>& titles, const IOCtlVRequest
IPCReply ESDevice::GetTitleCount(const IOCtlVRequest& request)
{
const std::vector<u64> titles = GetInstalledTitles();
const std::vector<u64> titles = m_core.GetInstalledTitles();
INFO_LOG_FMT(IOS_ES, "GetTitleCount: {} titles", titles.size());
return GetTitleCount(titles, request);
}
IPCReply ESDevice::GetTitles(const IOCtlVRequest& request)
{
return GetTitles(GetInstalledTitles(), request);
return GetTitles(m_core.GetInstalledTitles(), request);
}
IPCReply ESDevice::GetStoredTMDSize(const IOCtlVRequest& request)
@ -165,10 +166,10 @@ IPCReply ESDevice::GetStoredTMDSize(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 1))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
const ES::TMDReader tmd = m_core.FindInstalledTMD(title_id);
if (!tmd.IsValid())
return IPCReply(FS_ENOENT);
@ -185,10 +186,10 @@ IPCReply ESDevice::GetStoredTMD(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(2, 1))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
const ES::TMDReader tmd = m_core.FindInstalledTMD(title_id);
if (!tmd.IsValid())
return IPCReply(FS_ENOENT);
@ -207,14 +208,14 @@ IPCReply ESDevice::GetStoredTMD(const IOCtlVRequest& request)
IPCReply ESDevice::GetOwnedTitleCount(const IOCtlVRequest& request)
{
const std::vector<u64> titles = GetTitlesWithTickets();
const std::vector<u64> titles = m_core.GetTitlesWithTickets();
INFO_LOG_FMT(IOS_ES, "GetOwnedTitleCount: {} titles", titles.size());
return GetTitleCount(titles, request);
}
IPCReply ESDevice::GetOwnedTitles(const IOCtlVRequest& request)
{
return GetTitles(GetTitlesWithTickets(), request);
return GetTitles(m_core.GetTitlesWithTickets(), request);
}
IPCReply ESDevice::GetBoot2Version(const IOCtlVRequest& request)
@ -225,7 +226,7 @@ IPCReply ESDevice::GetBoot2Version(const IOCtlVRequest& request)
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETBOOT2VERSION");
// as of 26/02/2012, this was latest bootmii version
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(4, request.io_vectors[0].address);
return IPCReply(IPC_SUCCESS);
@ -236,8 +237,8 @@ IPCReply ESDevice::GetSharedContentsCount(const IOCtlVRequest& request) const
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
return IPCReply(ES_EINVAL);
const u32 count = GetSharedContentsCount();
auto& system = Core::System::GetInstance();
const u32 count = m_core.GetSharedContentsCount();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(count, request.io_vectors[0].address);
@ -250,13 +251,13 @@ IPCReply ESDevice::GetSharedContents(const IOCtlVRequest& request) const
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 max_count = memory.Read_U32(request.in_vectors[0].address);
if (request.io_vectors[0].size != 20 * max_count)
return IPCReply(ES_EINVAL);
const std::vector<std::array<u8, 20>> hashes = GetSharedContents();
const std::vector<std::array<u8, 20>> hashes = m_core.GetSharedContents();
const u32 count = std::min(static_cast<u32>(hashes.size()), max_count);
memory.CopyToEmu(request.io_vectors[0].address, hashes.data(), 20 * count);

View file

@ -39,7 +39,7 @@ static ReturnCode WriteTicket(FS::FileSystem* fs, const ES::TicketReader& ticket
return file->Write(raw_ticket.data(), raw_ticket.size()) ? IPC_SUCCESS : ES_EIO;
}
void ESDevice::TitleImportExportContext::DoState(PointerWrap& p)
void ESCore::TitleImportExportContext::DoState(PointerWrap& p)
{
p.Do(valid);
p.Do(key_handle);
@ -50,9 +50,9 @@ void ESDevice::TitleImportExportContext::DoState(PointerWrap& p)
p.Do(content.buffer);
}
ReturnCode ESDevice::ImportTicket(const std::vector<u8>& ticket_bytes,
const std::vector<u8>& cert_chain, TicketImportType type,
VerifySignature verify_signature)
ReturnCode ESCore::ImportTicket(const std::vector<u8>& ticket_bytes,
const std::vector<u8>& cert_chain, TicketImportType type,
VerifySignature verify_signature)
{
ES::TicketReader ticket{ticket_bytes};
if (!ticket.IsValid())
@ -98,14 +98,14 @@ IPCReply ESDevice::ImportTicket(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(3, 0))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
std::vector<u8> bytes(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);
memory.CopyFromEmu(cert_chain.data(), request.in_vectors[1].address, request.in_vectors[1].size);
return IPCReply(ImportTicket(bytes, cert_chain));
return IPCReply(m_core.ImportTicket(bytes, cert_chain));
}
constexpr std::array<u8, 16> NULL_KEY{};
@ -132,15 +132,15 @@ static ReturnCode InitBackupKey(u64 tid, u32 title_flags, IOSC& iosc, IOSC::Hand
return ret == IPC_SUCCESS ? iosc.ImportSecretKey(*key, NULL_KEY.data(), PID_ES) : ret;
}
static void ResetTitleImportContext(ESDevice::Context* context, IOSC& iosc)
static void ResetTitleImportContext(ESCore::Context* context, IOSC& iosc)
{
if (context->title_import_export.key_handle)
iosc.DeleteObject(context->title_import_export.key_handle, PID_ES);
context->title_import_export = {};
}
ReturnCode ESDevice::ImportTmd(Context& context, const std::vector<u8>& tmd_bytes,
u64 caller_title_id, u32 caller_title_flags)
ReturnCode ESCore::ImportTmd(Context& context, const std::vector<u8>& tmd_bytes,
u64 caller_title_id, u32 caller_title_flags)
{
INFO_LOG_FMT(IOS_ES, "ImportTmd");
@ -191,13 +191,13 @@ IPCReply ESDevice::ImportTmd(Context& context, const IOCtlVRequest& request)
if (!ES::IsValidTMDSize(request.in_vectors[0].size))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
std::vector<u8> tmd(request.in_vectors[0].size);
memory.CopyFromEmu(tmd.data(), request.in_vectors[0].address, request.in_vectors[0].size);
return IPCReply(ImportTmd(context, tmd, m_title_context.tmd.GetTitleId(),
m_title_context.tmd.GetTitleFlags()));
return IPCReply(m_core.ImportTmd(context, tmd, m_core.m_title_context.tmd.GetTitleId(),
m_core.m_title_context.tmd.GetTitleFlags()));
}
static ReturnCode InitTitleImportKey(const std::vector<u8>& ticket_bytes, IOSC& iosc,
@ -217,9 +217,9 @@ static ReturnCode InitTitleImportKey(const std::vector<u8>& ticket_bytes, IOSC&
&ticket_bytes[offsetof(ES::Ticket, title_key)], PID_ES);
}
ReturnCode ESDevice::ImportTitleInit(Context& context, const std::vector<u8>& tmd_bytes,
const std::vector<u8>& cert_chain,
VerifySignature verify_signature)
ReturnCode ESCore::ImportTitleInit(Context& context, const std::vector<u8>& tmd_bytes,
const std::vector<u8>& cert_chain,
VerifySignature verify_signature)
{
INFO_LOG_FMT(IOS_ES, "ImportTitleInit");
ResetTitleImportContext(&context, m_ios.GetIOSC());
@ -280,17 +280,17 @@ IPCReply ESDevice::ImportTitleInit(Context& context, const IOCtlVRequest& reques
if (!ES::IsValidTMDSize(request.in_vectors[0].size))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
std::vector<u8> tmd(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);
memory.CopyFromEmu(certs.data(), request.in_vectors[1].address, request.in_vectors[1].size);
return IPCReply(ImportTitleInit(context, tmd, certs));
return IPCReply(m_core.ImportTitleInit(context, tmd, certs));
}
ReturnCode ESDevice::ImportContentBegin(Context& context, u64 title_id, u32 content_id)
ReturnCode ESCore::ImportContentBegin(Context& context, u64 title_id, u32 content_id)
{
if (context.title_import_export.content.valid)
{
@ -338,16 +338,16 @@ IPCReply ESDevice::ImportContentBegin(Context& context, const IOCtlVRequest& req
if (!request.HasNumberOfValidVectors(2, 0))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u64 title_id = memory.Read_U64(request.in_vectors[0].address);
u32 content_id = memory.Read_U32(request.in_vectors[1].address);
return IPCReply(ImportContentBegin(context, title_id, content_id));
return IPCReply(m_core.ImportContentBegin(context, title_id, content_id));
}
ReturnCode ESDevice::ImportContentData(Context& context, u32 content_fd, const u8* data,
u32 data_size)
ReturnCode ESCore::ImportContentData(Context& context, u32 content_fd, const u8* data,
u32 data_size)
{
INFO_LOG_FMT(IOS_ES, "ImportContentData: content fd {:08x}, size {}", content_fd, data_size);
context.title_import_export.content.buffer.insert(
@ -360,12 +360,13 @@ IPCReply ESDevice::ImportContentData(Context& context, const IOCtlVRequest& requ
if (!request.HasNumberOfValidVectors(2, 0))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 content_fd = memory.Read_U32(request.in_vectors[0].address);
u8* data_start = memory.GetPointer(request.in_vectors[1].address);
return IPCReply(ImportContentData(context, content_fd, data_start, request.in_vectors[1].size));
return IPCReply(
m_core.ImportContentData(context, content_fd, data_start, request.in_vectors[1].size));
}
static bool CheckIfContentHashMatches(const std::vector<u8>& content, const ES::Content& info)
@ -378,7 +379,7 @@ static std::string GetImportContentPath(u64 title_id, u32 content_id)
return fmt::format("{}/content/{:08x}.app", Common::GetImportTitlePath(title_id), content_id);
}
ReturnCode ESDevice::ImportContentEnd(Context& context, u32 content_fd)
ReturnCode ESCore::ImportContentEnd(Context& context, u32 content_fd)
{
INFO_LOG_FMT(IOS_ES, "ImportContentEnd: content fd {:08x}", content_fd);
@ -407,7 +408,7 @@ ReturnCode ESDevice::ImportContentEnd(Context& context, u32 content_fd)
std::string content_path;
if (content_info.IsShared())
{
ES::SharedContentMap shared_content{m_ios.GetFSDevice()};
ES::SharedContentMap shared_content{m_ios.GetFSCore()};
content_path = shared_content.AddSharedContent(content_info.sha1);
}
else
@ -446,18 +447,18 @@ IPCReply ESDevice::ImportContentEnd(Context& context, const IOCtlVRequest& reque
if (!request.HasNumberOfValidVectors(1, 0))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 content_fd = memory.Read_U32(request.in_vectors[0].address);
return IPCReply(ImportContentEnd(context, content_fd));
return IPCReply(m_core.ImportContentEnd(context, content_fd));
}
static bool HasAllRequiredContents(Kernel& ios, const ES::TMDReader& tmd)
{
const u64 title_id = tmd.GetTitleId();
const std::vector<ES::Content> contents = tmd.GetContents();
const ES::SharedContentMap shared_content_map{ios.GetFSDevice()};
const ES::SharedContentMap shared_content_map{ios.GetFSCore()};
return std::all_of(contents.cbegin(), contents.cend(), [&](const ES::Content& content) {
if (content.IsOptional())
return true;
@ -472,7 +473,7 @@ static bool HasAllRequiredContents(Kernel& ios, const ES::TMDReader& tmd)
});
}
ReturnCode ESDevice::ImportTitleDone(Context& context)
ReturnCode ESCore::ImportTitleDone(Context& context)
{
if (!context.title_import_export.valid || context.title_import_export.content.valid)
{
@ -512,10 +513,10 @@ IPCReply ESDevice::ImportTitleDone(Context& context, const IOCtlVRequest& reques
if (!request.HasNumberOfValidVectors(0, 0))
return IPCReply(ES_EINVAL);
return IPCReply(ImportTitleDone(context));
return IPCReply(m_core.ImportTitleDone(context));
}
ReturnCode ESDevice::ImportTitleCancel(Context& context)
ReturnCode ESCore::ImportTitleCancel(Context& context)
{
// The TMD buffer can exist without a valid title import context.
if (context.title_import_export.tmd.GetBytes().empty() ||
@ -538,7 +539,7 @@ IPCReply ESDevice::ImportTitleCancel(Context& context, const IOCtlVRequest& requ
if (!request.HasNumberOfValidVectors(0, 0))
return IPCReply(ES_EINVAL);
return IPCReply(ImportTitleCancel(context));
return IPCReply(m_core.ImportTitleCancel(context));
}
static bool CanDeleteTitle(u64 title_id)
@ -547,7 +548,7 @@ static bool CanDeleteTitle(u64 title_id)
return static_cast<u32>(title_id >> 32) != 0x00000001 || static_cast<u32>(title_id) > 0x101;
}
ReturnCode ESDevice::DeleteTitle(u64 title_id)
ReturnCode ESCore::DeleteTitle(u64 title_id)
{
if (!CanDeleteTitle(title_id))
return ES_EINVAL;
@ -561,14 +562,14 @@ IPCReply ESDevice::DeleteTitle(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 8)
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
return IPCReply(DeleteTitle(title_id));
return IPCReply(m_core.DeleteTitle(title_id));
}
ReturnCode ESDevice::DeleteTicket(const u8* ticket_view)
ReturnCode ESCore::DeleteTicket(const u8* ticket_view)
{
const auto fs = m_ios.GetFS();
const u64 title_id = Common::swap64(ticket_view + offsetof(ES::TicketView, title_id));
@ -622,12 +623,12 @@ IPCReply ESDevice::DeleteTicket(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
return IPCReply(DeleteTicket(memory.GetPointer(request.in_vectors[0].address)));
return IPCReply(m_core.DeleteTicket(memory.GetPointer(request.in_vectors[0].address)));
}
ReturnCode ESDevice::DeleteTitleContent(u64 title_id) const
ReturnCode ESCore::DeleteTitleContent(u64 title_id) const
{
if (!CanDeleteTitle(title_id))
return ES_EINVAL;
@ -651,12 +652,12 @@ IPCReply ESDevice::DeleteTitleContent(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u64))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
return IPCReply(DeleteTitleContent(memory.Read_U64(request.in_vectors[0].address)));
return IPCReply(m_core.DeleteTitleContent(memory.Read_U64(request.in_vectors[0].address)));
}
ReturnCode ESDevice::DeleteContent(u64 title_id, u32 content_id) const
ReturnCode ESCore::DeleteContent(u64 title_id, u32 content_id) const
{
if (!CanDeleteTitle(title_id))
return ES_EINVAL;
@ -682,14 +683,14 @@ IPCReply ESDevice::DeleteContent(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
return IPCReply(DeleteContent(memory.Read_U64(request.in_vectors[0].address),
memory.Read_U32(request.in_vectors[1].address)));
return IPCReply(m_core.DeleteContent(memory.Read_U64(request.in_vectors[0].address),
memory.Read_U32(request.in_vectors[1].address)));
}
ReturnCode ESDevice::ExportTitleInit(Context& context, u64 title_id, u8* tmd_bytes, u32 tmd_size,
u64 caller_title_id, u32 caller_title_flags)
ReturnCode ESCore::ExportTitleInit(Context& context, u64 title_id, u8* tmd_bytes, u32 tmd_size,
u64 caller_title_id, u32 caller_title_flags)
{
// No concurrent title import/export is allowed.
if (context.title_import_export.valid)
@ -722,19 +723,19 @@ IPCReply ESDevice::ExportTitleInit(Context& context, const IOCtlVRequest& reques
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != 8)
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
u8* tmd_bytes = memory.GetPointer(request.io_vectors[0].address);
const u32 tmd_size = request.io_vectors[0].size;
return IPCReply(ExportTitleInit(context, title_id, tmd_bytes, tmd_size,
m_title_context.tmd.GetTitleId(),
m_title_context.tmd.GetTitleFlags()));
return IPCReply(m_core.ExportTitleInit(context, title_id, tmd_bytes, tmd_size,
m_core.m_title_context.tmd.GetTitleId(),
m_core.m_title_context.tmd.GetTitleFlags()));
}
ReturnCode ESDevice::ExportContentBegin(Context& context, u64 title_id, u32 content_id)
ReturnCode ESCore::ExportContentBegin(Context& context, u64 title_id, u32 content_id)
{
context.title_import_export.content = {};
if (!context.title_import_export.valid ||
@ -771,16 +772,16 @@ IPCReply ESDevice::ExportContentBegin(Context& context, const IOCtlVRequest& req
request.in_vectors[1].size != 4)
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const u32 content_id = memory.Read_U32(request.in_vectors[1].address);
return IPCReply(ExportContentBegin(context, title_id, content_id));
return IPCReply(m_core.ExportContentBegin(context, title_id, content_id));
}
ReturnCode ESDevice::ExportContentData(Context& context, u32 content_fd, u8* data, u32 data_size)
ReturnCode ESCore::ExportContentData(Context& context, u32 content_fd, u8* data, u32 data_size)
{
if (!context.title_import_export.valid || !context.title_import_export.content.valid || !data ||
data_size == 0)
@ -822,17 +823,17 @@ IPCReply ESDevice::ExportContentData(Context& context, const IOCtlVRequest& requ
return IPCReply(ES_EINVAL);
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 content_fd = memory.Read_U32(request.in_vectors[0].address);
u8* data = memory.GetPointer(request.io_vectors[0].address);
const u32 bytes_to_read = request.io_vectors[0].size;
return IPCReply(ExportContentData(context, content_fd, data, bytes_to_read));
return IPCReply(m_core.ExportContentData(context, content_fd, data, bytes_to_read));
}
ReturnCode ESDevice::ExportContentEnd(Context& context, u32 content_fd)
ReturnCode ESCore::ExportContentEnd(Context& context, u32 content_fd)
{
if (!context.title_import_export.valid || !context.title_import_export.content.valid)
return ES_EINVAL;
@ -844,14 +845,14 @@ IPCReply ESDevice::ExportContentEnd(Context& context, const IOCtlVRequest& reque
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 4)
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 content_fd = memory.Read_U32(request.in_vectors[0].address);
return IPCReply(ExportContentEnd(context, content_fd));
return IPCReply(m_core.ExportContentEnd(context, content_fd));
}
ReturnCode ESDevice::ExportTitleDone(Context& context)
ReturnCode ESCore::ExportTitleDone(Context& context)
{
ResetTitleImportContext(&context, m_ios.GetIOSC());
return IPC_SUCCESS;
@ -859,12 +860,12 @@ ReturnCode ESDevice::ExportTitleDone(Context& context)
IPCReply ESDevice::ExportTitleDone(Context& context, const IOCtlVRequest& request)
{
return IPCReply(ExportTitleDone(context));
return IPCReply(m_core.ExportTitleDone(context));
}
ReturnCode ESDevice::DeleteSharedContent(const std::array<u8, 20>& sha1) const
ReturnCode ESCore::DeleteSharedContent(const std::array<u8, 20>& sha1) const
{
ES::SharedContentMap map{m_ios.GetFSDevice()};
ES::SharedContentMap map{m_ios.GetFSCore()};
const auto content_path = map.GetFilenameFromSHA1(sha1);
if (!content_path)
return ES_EINVAL;
@ -905,10 +906,10 @@ IPCReply ESDevice::DeleteSharedContent(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sha1.size())
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.CopyFromEmu(sha1.data(), request.in_vectors[0].address, request.in_vectors[0].size);
return IPCReply(DeleteSharedContent(sha1));
return IPCReply(m_core.DeleteSharedContent(sha1));
}
} // namespace IOS::HLE

View file

@ -41,12 +41,12 @@ IPCReply ESDevice::GetTicketViewCount(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 1))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 TitleID = memory.Read_U64(request.in_vectors[0].address);
const ES::TicketReader ticket = FindSignedTicket(TitleID);
const ES::TicketReader ticket = m_core.FindSignedTicket(TitleID);
u32 view_count = ticket.IsValid() ? static_cast<u32>(ticket.GetNumberOfTickets()) : 0;
if (!IsEmulated(TitleID))
@ -54,7 +54,7 @@ IPCReply ESDevice::GetTicketViewCount(const IOCtlVRequest& request)
view_count = 0;
ERROR_LOG_FMT(IOS_ES, "GetViewCount: Dolphin doesn't emulate IOS title {:016x}", TitleID);
}
else if (ShouldReturnFakeViewsForIOSes(TitleID, m_title_context))
else if (ShouldReturnFakeViewsForIOSes(TitleID, m_core.m_title_context))
{
view_count = 1;
WARN_LOG_FMT(IOS_ES, "GetViewCount: Faking IOS title {:016x} being present", TitleID);
@ -72,13 +72,13 @@ IPCReply ESDevice::GetTicketViews(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(2, 1))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 TitleID = memory.Read_U64(request.in_vectors[0].address);
const u32 maxViews = memory.Read_U32(request.in_vectors[1].address);
const ES::TicketReader ticket = FindSignedTicket(TitleID);
const ES::TicketReader ticket = m_core.FindSignedTicket(TitleID);
if (!IsEmulated(TitleID))
{
@ -94,7 +94,7 @@ IPCReply ESDevice::GetTicketViews(const IOCtlVRequest& request)
ticket_view.data(), ticket_view.size());
}
}
else if (ShouldReturnFakeViewsForIOSes(TitleID, m_title_context))
else if (ShouldReturnFakeViewsForIOSes(TitleID, m_core.m_title_context))
{
memory.Memset(request.io_vectors[0].address, 0, sizeof(ES::TicketView));
WARN_LOG_FMT(IOS_ES, "GetViews: Faking IOS title {:016x} being present", TitleID);
@ -105,8 +105,8 @@ IPCReply ESDevice::GetTicketViews(const IOCtlVRequest& request)
return IPCReply(IPC_SUCCESS);
}
ReturnCode ESDevice::GetTicketFromView(const u8* ticket_view, u8* ticket, u32* ticket_size,
std::optional<u8> desired_version) const
ReturnCode ESCore::GetTicketFromView(const u8* ticket_view, u8* ticket, u32* ticket_size,
std::optional<u8> desired_version) const
{
const u64 title_id = Common::swap64(&ticket_view[offsetof(ES::TicketView, title_id)]);
const u64 ticket_id = Common::swap64(&ticket_view[offsetof(ES::TicketView, ticket_id)]);
@ -160,10 +160,11 @@ IPCReply ESDevice::GetV0TicketFromView(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
return IPCReply(GetTicketFromView(memory.GetPointer(request.in_vectors[0].address),
memory.GetPointer(request.io_vectors[0].address), nullptr, 0));
return IPCReply(m_core.GetTicketFromView(memory.GetPointer(request.in_vectors[0].address),
memory.GetPointer(request.io_vectors[0].address),
nullptr, 0));
}
IPCReply ESDevice::GetTicketSizeFromView(const IOCtlVRequest& request)
@ -176,10 +177,10 @@ IPCReply ESDevice::GetTicketSizeFromView(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const ReturnCode ret = GetTicketFromView(memory.GetPointer(request.in_vectors[0].address),
nullptr, &ticket_size, std::nullopt);
const ReturnCode ret = m_core.GetTicketFromView(memory.GetPointer(request.in_vectors[0].address),
nullptr, &ticket_size, std::nullopt);
memory.Write_U32(ticket_size, request.io_vectors[0].address);
return IPCReply(ret);
}
@ -193,16 +194,16 @@ IPCReply ESDevice::GetTicketFromView(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 ticket_size = memory.Read_U32(request.in_vectors[1].address);
if (ticket_size != request.io_vectors[0].size)
return IPCReply(ES_EINVAL);
return IPCReply(GetTicketFromView(memory.GetPointer(request.in_vectors[0].address),
memory.GetPointer(request.io_vectors[0].address), &ticket_size,
std::nullopt));
return IPCReply(m_core.GetTicketFromView(memory.GetPointer(request.in_vectors[0].address),
memory.GetPointer(request.io_vectors[0].address),
&ticket_size, std::nullopt));
}
IPCReply ESDevice::GetTMDViewSize(const IOCtlVRequest& request)
@ -210,11 +211,11 @@ IPCReply ESDevice::GetTMDViewSize(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 1))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 TitleID = memory.Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(TitleID);
const ES::TMDReader tmd = m_core.FindInstalledTMD(TitleID);
if (!tmd.IsValid())
return IPCReply(FS_ENOENT);
@ -228,7 +229,7 @@ IPCReply ESDevice::GetTMDViewSize(const IOCtlVRequest& request)
IPCReply ESDevice::GetTMDViews(const IOCtlVRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
if (!request.HasNumberOfValidVectors(2, 1) ||
@ -240,7 +241,7 @@ IPCReply ESDevice::GetTMDViews(const IOCtlVRequest& request)
}
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
const ES::TMDReader tmd = m_core.FindInstalledTMD(title_id);
if (!tmd.IsValid())
return IPCReply(FS_ENOENT);
@ -267,7 +268,7 @@ IPCReply ESDevice::DIGetTMDViewSize(const IOCtlVRequest& request)
if (request.io_vectors[0].size != sizeof(u32))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const bool has_tmd = request.in_vectors[0].size != 0;
@ -289,10 +290,10 @@ IPCReply ESDevice::DIGetTMDViewSize(const IOCtlVRequest& request)
else
{
// If no TMD was passed in and no title is active, IOS returns -1017.
if (!m_title_context.active)
if (!m_core.m_title_context.active)
return IPCReply(ES_EINVAL);
tmd_view_size = m_title_context.tmd.GetRawView().size();
tmd_view_size = m_core.m_title_context.tmd.GetRawView().size();
}
memory.Write_U32(static_cast<u32>(tmd_view_size), request.io_vectors[0].address);
@ -308,7 +309,7 @@ IPCReply ESDevice::DIGetTMDView(const IOCtlVRequest& request)
if (request.in_vectors[0].size >= 4 * 1024 * 1024)
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
// Check whether the TMD view size is consistent.
@ -335,10 +336,10 @@ IPCReply ESDevice::DIGetTMDView(const IOCtlVRequest& request)
else
{
// If no TMD was passed in and no title is active, IOS returns -1017.
if (!m_title_context.active)
if (!m_core.m_title_context.active)
return IPCReply(ES_EINVAL);
tmd_view = m_title_context.tmd.GetRawView();
tmd_view = m_core.m_title_context.tmd.GetRawView();
}
if (tmd_view.size() > request.io_vectors[0].size)
@ -362,7 +363,7 @@ IPCReply ESDevice::DIGetTicketView(const IOCtlVRequest& request)
if (!has_ticket_vector && request.in_vectors[0].size != 0)
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
std::vector<u8> view;
@ -371,10 +372,10 @@ IPCReply ESDevice::DIGetTicketView(const IOCtlVRequest& request)
// Of course, this returns -1017 if no title is active and no ticket is passed.
if (!has_ticket_vector)
{
if (!m_title_context.active)
if (!m_core.m_title_context.active)
return IPCReply(ES_EINVAL);
view = m_title_context.ticket.GetRawTicketView(0);
view = m_core.m_title_context.ticket.GetRawTicketView(0);
}
else
{
@ -394,12 +395,12 @@ IPCReply ESDevice::DIGetTMDSize(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
return IPCReply(ES_EINVAL);
if (!m_title_context.active)
if (!m_core.m_title_context.active)
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(static_cast<u32>(m_title_context.tmd.GetBytes().size()),
memory.Write_U32(static_cast<u32>(m_core.m_title_context.tmd.GetBytes().size()),
request.io_vectors[0].address);
return IPCReply(IPC_SUCCESS);
}
@ -409,17 +410,17 @@ IPCReply ESDevice::DIGetTMD(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 tmd_size = memory.Read_U32(request.in_vectors[0].address);
if (tmd_size != request.io_vectors[0].size)
return IPCReply(ES_EINVAL);
if (!m_title_context.active)
if (!m_core.m_title_context.active)
return IPCReply(ES_EINVAL);
const std::vector<u8>& tmd_bytes = m_title_context.tmd.GetBytes();
const std::vector<u8>& tmd_bytes = m_core.m_title_context.tmd.GetBytes();
if (static_cast<u32>(tmd_bytes.size()) > tmd_size)
return IPCReply(ES_EINVAL);

View file

@ -83,7 +83,7 @@ constexpr SystemTimers::TimeBaseTick GetFreeClusterCheckTbTicks()
constexpr size_t CLUSTER_DATA_SIZE = 0x4000;
FSDevice::FSDevice(Kernel& ios, const std::string& device_name) : Device(ios, device_name)
FSCore::FSCore(Kernel& ios) : m_ios(ios)
{
if (ios.GetFS()->Delete(PID_KERNEL, PID_KERNEL, "/tmp") == ResultCode::Success)
{
@ -92,14 +92,23 @@ FSDevice::FSDevice(Kernel& ios, const std::string& device_name) : Device(ios, de
}
}
FSCore::~FSCore() = default;
FSDevice::FSDevice(EmulationKernel& ios, FSCore& core, const std::string& device_name)
: EmulationDevice(ios, device_name), m_core(core)
{
}
FSDevice::~FSDevice() = default;
void FSDevice::DoState(PointerWrap& p)
{
Device::DoState(p);
p.Do(m_dirty_cache);
p.Do(m_cache_chain_index);
p.Do(m_cache_fd);
p.Do(m_next_fd);
p.Do(m_fd_map);
p.Do(m_core.m_dirty_cache);
p.Do(m_core.m_cache_chain_index);
p.Do(m_core.m_cache_fd);
p.Do(m_core.m_next_fd);
p.Do(m_core.m_fd_map);
}
template <typename... Args>
@ -161,14 +170,15 @@ static IPCReply GetReplyForSuperblockOperation(int ios_version, ResultCode resul
std::optional<IPCReply> FSDevice::Open(const OpenRequest& request)
{
return MakeIPCReply([&](Ticks t) {
return Open(request.uid, request.gid, request.path, static_cast<Mode>(request.flags & 3),
request.fd, t)
return m_core
.Open(request.uid, request.gid, request.path, static_cast<Mode>(request.flags & 3),
request.fd, t)
.Release();
});
}
FSDevice::ScopedFd FSDevice::Open(FS::Uid uid, FS::Gid gid, const std::string& path, FS::Mode mode,
std::optional<u32> ipc_fd, Ticks ticks)
FSCore::ScopedFd FSCore::Open(FS::Uid uid, FS::Gid gid, const std::string& path, FS::Mode mode,
std::optional<u32> ipc_fd, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);
@ -200,10 +210,10 @@ FSDevice::ScopedFd FSDevice::Open(FS::Uid uid, FS::Gid gid, const std::string& p
std::optional<IPCReply> FSDevice::Close(u32 fd)
{
return MakeIPCReply([&](Ticks t) { return Close(static_cast<u64>(fd), t); });
return MakeIPCReply([&](Ticks t) { return m_core.Close(static_cast<u64>(fd), t); });
}
s32 FSDevice::Close(u64 fd, Ticks ticks)
s32 FSCore::Close(u64 fd, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);
@ -232,7 +242,7 @@ s32 FSDevice::Close(u64 fd, Ticks ticks)
return IPC_SUCCESS;
}
u64 FSDevice::SimulatePopulateFileCache(u64 fd, u32 offset, u32 file_size)
u64 FSCore::SimulatePopulateFileCache(u64 fd, u32 offset, u32 file_size)
{
if (HasCacheForFile(fd, offset))
return 0;
@ -246,7 +256,7 @@ u64 FSDevice::SimulatePopulateFileCache(u64 fd, u32 offset, u32 file_size)
return ticks;
}
u64 FSDevice::SimulateFlushFileCache()
u64 FSCore::SimulateFlushFileCache()
{
if (!m_cache_fd.has_value() || !m_dirty_cache)
return 0;
@ -256,8 +266,8 @@ u64 FSDevice::SimulateFlushFileCache()
}
// Simulate parts of the FS read/write logic to estimate ticks for file operations correctly.
u64 FSDevice::EstimateTicksForReadWrite(const Handle& handle, u64 fd, IPCCommandType command,
u32 size)
u64 FSCore::EstimateTicksForReadWrite(const Handle& handle, u64 fd, IPCCommandType command,
u32 size)
{
u64 ticks = 0;
@ -304,7 +314,7 @@ u64 FSDevice::EstimateTicksForReadWrite(const Handle& handle, u64 fd, IPCCommand
return ticks;
}
bool FSDevice::HasCacheForFile(u64 fd, u32 offset) const
bool FSCore::HasCacheForFile(u64 fd, u32 offset) const
{
const u16 chain_index = static_cast<u16>(offset / CLUSTER_DATA_SIZE);
return m_cache_fd == fd && m_cache_chain_index == chain_index;
@ -313,13 +323,14 @@ bool FSDevice::HasCacheForFile(u64 fd, u32 offset) const
std::optional<IPCReply> FSDevice::Read(const ReadWriteRequest& request)
{
return MakeIPCReply([&](Ticks t) {
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
return Read(request.fd, memory.GetPointer(request.buffer), request.size, request.buffer, t);
return m_core.Read(request.fd, memory.GetPointer(request.buffer), request.size, request.buffer,
t);
});
}
s32 FSDevice::Read(u64 fd, u8* data, u32 size, std::optional<u32> ipc_buffer_addr, Ticks ticks)
s32 FSCore::Read(u64 fd, u8* data, u32 size, std::optional<u32> ipc_buffer_addr, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);
@ -343,14 +354,14 @@ s32 FSDevice::Read(u64 fd, u8* data, u32 size, std::optional<u32> ipc_buffer_add
std::optional<IPCReply> FSDevice::Write(const ReadWriteRequest& request)
{
return MakeIPCReply([&](Ticks t) {
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
return Write(request.fd, memory.GetPointer(request.buffer), request.size, request.buffer, t);
return m_core.Write(request.fd, memory.GetPointer(request.buffer), request.size, request.buffer,
t);
});
}
s32 FSDevice::Write(u64 fd, const u8* data, u32 size, std::optional<u32> ipc_buffer_addr,
Ticks ticks)
s32 FSCore::Write(u64 fd, const u8* data, u32 size, std::optional<u32> ipc_buffer_addr, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);
@ -374,11 +385,11 @@ s32 FSDevice::Write(u64 fd, const u8* data, u32 size, std::optional<u32> ipc_buf
std::optional<IPCReply> FSDevice::Seek(const SeekRequest& request)
{
return MakeIPCReply([&](Ticks t) {
return Seek(request.fd, request.offset, HLE::FS::SeekMode(request.mode), t);
return m_core.Seek(request.fd, request.offset, HLE::FS::SeekMode(request.mode), t);
});
}
s32 FSDevice::Seek(u64 fd, u32 offset, FS::SeekMode mode, Ticks ticks)
s32 FSCore::Seek(u64 fd, u32 offset, FS::SeekMode mode, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);
@ -422,14 +433,11 @@ struct ISFSFileStats
#pragma pack(pop)
template <typename T>
static Result<T> GetParams(const IOCtlRequest& request)
static Result<T> GetParams(Memory::MemoryManager& memory, const IOCtlRequest& request)
{
if (request.buffer_in_size < sizeof(T))
return ResultCode::Invalid;
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
T params;
memory.CopyFromEmu(&params, request.buffer_in, sizeof(params));
return params;
@ -437,8 +445,8 @@ static Result<T> GetParams(const IOCtlRequest& request)
std::optional<IPCReply> FSDevice::IOCtl(const IOCtlRequest& request)
{
const auto it = m_fd_map.find(request.fd);
if (it == m_fd_map.end())
const auto it = m_core.m_fd_map.find(request.fd);
if (it == m_core.m_fd_map.end())
return IPCReply(ConvertResult(ResultCode::Invalid));
switch (request.request)
@ -472,8 +480,8 @@ std::optional<IPCReply> FSDevice::IOCtl(const IOCtlRequest& request)
std::optional<IPCReply> FSDevice::IOCtlV(const IOCtlVRequest& request)
{
const auto it = m_fd_map.find(request.fd);
if (it == m_fd_map.end())
const auto it = m_core.m_fd_map.find(request.fd);
if (it == m_core.m_fd_map.end())
return IPCReply(ConvertResult(ResultCode::Invalid));
switch (request.request)
@ -506,7 +514,7 @@ IPCReply FSDevice::GetStats(const Handle& handle, const IOCtlRequest& request)
if (!stats)
return IPCReply(ConvertResult(stats.Error()));
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
ISFSNandStats out;
@ -523,7 +531,7 @@ IPCReply FSDevice::GetStats(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>(GetSystem().GetMemory(), request);
if (!params)
return GetFSReply(ConvertResult(params.Error()));
@ -541,7 +549,7 @@ IPCReply FSDevice::ReadDirectory(const Handle& handle, const IOCtlVRequest& requ
return GetFSReply(ConvertResult(ResultCode::Invalid));
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 file_list_address, file_count_address, max_count;
@ -592,7 +600,7 @@ IPCReply FSDevice::ReadDirectory(const Handle& handle, const IOCtlVRequest& requ
IPCReply FSDevice::SetAttribute(const Handle& handle, const IOCtlRequest& request)
{
const auto params = GetParams<ISFSParams>(request);
const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request);
if (!params)
return GetFSReply(ConvertResult(params.Error()));
@ -607,7 +615,7 @@ IPCReply FSDevice::GetAttribute(const Handle& handle, const IOCtlRequest& reques
if (request.buffer_in_size < 64 || request.buffer_out_size < sizeof(ISFSParams))
return GetFSReply(ConvertResult(ResultCode::Invalid));
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const std::string path = memory.GetString(request.buffer_in, 64);
@ -629,7 +637,7 @@ IPCReply FSDevice::GetAttribute(const Handle& handle, const IOCtlRequest& reques
return GetFSReply(IPC_SUCCESS, ticks);
}
FS::ResultCode FSDevice::DeleteFile(FS::Uid uid, FS::Gid gid, const std::string& path, Ticks ticks)
FS::ResultCode FSCore::DeleteFile(FS::Uid uid, FS::Gid gid, const std::string& path, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);
@ -644,16 +652,17 @@ IPCReply FSDevice::DeleteFile(const Handle& handle, const IOCtlRequest& request)
if (request.buffer_in_size < 64)
return GetFSReply(ConvertResult(ResultCode::Invalid));
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const std::string path = memory.GetString(request.buffer_in, 64);
return MakeIPCReply(
[&](Ticks ticks) { return ConvertResult(DeleteFile(handle.uid, handle.gid, path, ticks)); });
return MakeIPCReply([&](Ticks ticks) {
return ConvertResult(m_core.DeleteFile(handle.uid, handle.gid, path, ticks));
});
}
FS::ResultCode FSDevice::RenameFile(FS::Uid uid, FS::Gid gid, const std::string& old_path,
const std::string& new_path, Ticks ticks)
FS::ResultCode FSCore::RenameFile(FS::Uid uid, FS::Gid gid, const std::string& old_path,
const std::string& new_path, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);
@ -668,18 +677,18 @@ IPCReply FSDevice::RenameFile(const Handle& handle, const IOCtlRequest& request)
if (request.buffer_in_size < 64 * 2)
return GetFSReply(ConvertResult(ResultCode::Invalid));
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const std::string old_path = memory.GetString(request.buffer_in, 64);
const std::string new_path = memory.GetString(request.buffer_in + 64, 64);
return MakeIPCReply([&](Ticks ticks) {
return ConvertResult(RenameFile(handle.uid, handle.gid, old_path, new_path, ticks));
return ConvertResult(m_core.RenameFile(handle.uid, handle.gid, old_path, new_path, ticks));
});
}
FS::ResultCode FSDevice::CreateFile(FS::Uid uid, FS::Gid gid, const std::string& path,
FS::FileAttribute attribute, FS::Modes modes, Ticks ticks)
FS::ResultCode FSCore::CreateFile(FS::Uid uid, FS::Gid gid, const std::string& path,
FS::FileAttribute attribute, FS::Modes modes, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);
@ -691,18 +700,18 @@ FS::ResultCode FSDevice::CreateFile(FS::Uid uid, FS::Gid gid, const std::string&
IPCReply FSDevice::CreateFile(const Handle& handle, const IOCtlRequest& request)
{
const auto params = GetParams<ISFSParams>(request);
const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request);
if (!params)
return GetFSReply(ConvertResult(params.Error()));
return MakeIPCReply([&](Ticks ticks) {
return ConvertResult(
CreateFile(handle.uid, handle.gid, params->path, params->attribute, params->modes));
m_core.CreateFile(handle.uid, handle.gid, params->path, params->attribute, params->modes));
});
}
IPCReply FSDevice::SetFileVersionControl(const Handle& handle, const IOCtlRequest& request)
{
const auto params = GetParams<ISFSParams>(request);
const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request);
if (!params)
return GetFSReply(ConvertResult(params.Error()));
@ -718,11 +727,11 @@ IPCReply FSDevice::GetFileStats(const Handle& handle, const IOCtlRequest& reques
return GetFSReply(ConvertResult(ResultCode::Invalid));
return MakeIPCReply([&](Ticks ticks) {
const Result<FileStatus> status = GetFileStatus(request.fd, ticks);
const Result<FileStatus> status = m_core.GetFileStatus(request.fd, ticks);
if (!status)
return ConvertResult(status.Error());
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
ISFSFileStats out;
@ -733,7 +742,7 @@ IPCReply FSDevice::GetFileStats(const Handle& handle, const IOCtlRequest& reques
});
}
FS::Result<FS::FileStatus> FSDevice::GetFileStatus(u64 fd, Ticks ticks)
FS::Result<FS::FileStatus> FSCore::GetFileStatus(u64 fd, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);
const auto& handle = m_fd_map[fd];
@ -753,7 +762,7 @@ IPCReply FSDevice::GetUsage(const Handle& handle, const IOCtlVRequest& request)
return GetFSReply(ConvertResult(ResultCode::Invalid));
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const std::string directory = memory.GetString(request.in_vectors[0].address, 64);

View file

@ -20,13 +20,22 @@ namespace IOS::HLE
{
constexpr FS::Fd INVALID_FD = 0xffffffff;
class FSDevice : public Device
class FSDevice;
class FSCore final
{
public:
explicit FSCore(Kernel& ios);
FSCore(const FSCore& other) = delete;
FSCore(FSCore&& other) = delete;
FSCore& operator=(const FSCore& other) = delete;
FSCore& operator=(FSCore&& other) = delete;
~FSCore();
class ScopedFd
{
public:
ScopedFd(FSDevice* fs, s64 fd, Ticks tick_tracker = {})
ScopedFd(FSCore* fs, s64 fd, Ticks tick_tracker = {})
: m_fs{fs}, m_fd{fd}, m_tick_tracker{tick_tracker}
{
}
@ -46,13 +55,11 @@ public:
s64 Release() { return std::exchange(m_fd, -1); }
private:
FSDevice* m_fs{};
FSCore* m_fs{};
s64 m_fd = -1;
Ticks m_tick_tracker{};
};
FSDevice(Kernel& ios, const std::string& device_name);
// These are the equivalent of the IPC command handlers so IPC overhead is included
// in timing calculations.
ScopedFd Open(FS::Uid uid, FS::Gid gid, const std::string& path, FS::Mode mode,
@ -78,16 +85,6 @@ public:
std::shared_ptr<FS::FileSystem> GetFS() const { return m_ios.GetFS(); }
void DoState(PointerWrap& p) override;
std::optional<IPCReply> Open(const OpenRequest& request) override;
std::optional<IPCReply> Close(u32 fd) override;
std::optional<IPCReply> Read(const ReadWriteRequest& request) override;
std::optional<IPCReply> Write(const ReadWriteRequest& request) override;
std::optional<IPCReply> Seek(const SeekRequest& request) override;
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
private:
struct Handle
{
@ -99,6 +96,40 @@ private:
bool superblock_flush_needed = false;
};
u64 EstimateTicksForReadWrite(const Handle& handle, u64 fd, IPCCommandType command, u32 size);
u64 SimulatePopulateFileCache(u64 fd, u32 offset, u32 file_size);
u64 SimulateFlushFileCache();
bool HasCacheForFile(u64 fd, u32 offset) const;
Kernel& m_ios;
bool m_dirty_cache = false;
u16 m_cache_chain_index = 0;
std::optional<u64> m_cache_fd;
// The first 0x18 IDs are reserved for the PPC.
u64 m_next_fd = 0x18;
std::map<u64, Handle> m_fd_map;
friend class FSDevice;
};
class FSDevice final : public EmulationDevice
{
public:
FSDevice(EmulationKernel& ios, FSCore& core, const std::string& device_name);
~FSDevice();
void DoState(PointerWrap& p) override;
std::optional<IPCReply> Open(const OpenRequest& request) override;
std::optional<IPCReply> Close(u32 fd) override;
std::optional<IPCReply> Read(const ReadWriteRequest& request) override;
std::optional<IPCReply> Write(const ReadWriteRequest& request) override;
std::optional<IPCReply> Seek(const SeekRequest& request) override;
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
private:
enum
{
ISFS_IOCTL_FORMAT = 1,
@ -116,6 +147,8 @@ private:
ISFS_IOCTL_SHUTDOWN = 13,
};
using Handle = FSCore::Handle;
IPCReply Format(const Handle& handle, const IOCtlRequest& request);
IPCReply GetStats(const Handle& handle, const IOCtlRequest& request);
IPCReply CreateDirectory(const Handle& handle, const IOCtlRequest& request);
@ -130,16 +163,6 @@ private:
IPCReply GetUsage(const Handle& handle, const IOCtlVRequest& request);
IPCReply Shutdown(const Handle& handle, const IOCtlRequest& request);
u64 EstimateTicksForReadWrite(const Handle& handle, u64 fd, IPCCommandType command, u32 size);
u64 SimulatePopulateFileCache(u64 fd, u32 offset, u32 file_size);
u64 SimulateFlushFileCache();
bool HasCacheForFile(u64 fd, u32 offset) const;
bool m_dirty_cache = false;
u16 m_cache_chain_index = 0;
std::optional<u64> m_cache_fd;
// The first 0x18 IDs are reserved for the PPC.
u64 m_next_fd = 0x18;
std::map<u64, Handle> m_fd_map;
FSCore& m_core;
};
} // namespace IOS::HLE

View file

@ -474,8 +474,11 @@ ResultCode HostFileSystem::Format(Uid uid)
ResultCode HostFileSystem::CreateFileOrDirectory(Uid uid, Gid gid, const std::string& path,
FileAttribute attr, Modes modes, bool is_file)
{
if (!IsValidNonRootPath(path) || !std::all_of(path.begin(), path.end(), IsPrintableCharacter))
if (!IsValidNonRootPath(path) ||
!std::all_of(path.begin(), path.end(), Common::IsPrintableCharacter))
{
return ResultCode::Invalid;
}
if (!is_file && std::count(path.begin(), path.end(), '/') > int(MaxPathDepth))
return ResultCode::TooManyPathComponents;

View file

@ -8,7 +8,6 @@
#include <deque>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
@ -300,17 +299,15 @@ Kernel::Kernel(IOSC::ConsoleType console_type) : m_iosc(console_type)
if (m_is_responsible_for_nand_root)
Core::InitializeWiiRoot(false);
AddCoreDevices();
m_fs = FS::MakeFileSystem(IOS::HLE::FS::Location::Session, Core::GetActiveNandRedirects());
ASSERT(m_fs);
m_fs_core = std::make_unique<FSCore>(*this);
m_es_core = std::make_unique<ESCore>(*this);
}
Kernel::~Kernel()
{
{
std::lock_guard lock(m_device_map_mutex);
m_device_map.clear();
m_socket_manager.reset();
}
if (m_is_responsible_for_nand_root)
Core::ShutdownWiiRoot();
}
@ -319,7 +316,8 @@ Kernel::Kernel(u64 title_id) : m_title_id(title_id)
{
}
EmulationKernel::EmulationKernel(u64 title_id) : Kernel(title_id)
EmulationKernel::EmulationKernel(Core::System& system, u64 title_id)
: Kernel(title_id), m_system(system)
{
INFO_LOG_FMT(IOS, "Starting IOS {:016x}", title_id);
@ -332,13 +330,23 @@ EmulationKernel::EmulationKernel(u64 title_id) : Kernel(title_id)
return;
}
AddCoreDevices();
m_fs = FS::MakeFileSystem(IOS::HLE::FS::Location::Session, Core::GetActiveNandRedirects());
ASSERT(m_fs);
m_fs_core = std::make_unique<FSCore>(*this);
AddDevice(std::make_unique<FSDevice>(*this, *m_fs_core, "/dev/fs"));
m_es_core = std::make_unique<ESCore>(*this);
AddDevice(std::make_unique<ESDevice>(*this, *m_es_core, "/dev/es"));
AddStaticDevices();
}
EmulationKernel::~EmulationKernel()
{
Core::System::GetInstance().GetCoreTiming().RemoveAllEvents(s_event_enqueue);
m_device_map.clear();
m_socket_manager.reset();
}
// The title ID is a u64 where the first 32 bits are used for the title type.
@ -354,68 +362,78 @@ std::shared_ptr<FS::FileSystem> Kernel::GetFS()
return m_fs;
}
std::shared_ptr<FSDevice> Kernel::GetFSDevice()
FSCore& Kernel::GetFSCore()
{
return *m_fs_core;
}
std::shared_ptr<FSDevice> EmulationKernel::GetFSDevice()
{
return std::static_pointer_cast<FSDevice>(m_device_map.at("/dev/fs"));
}
std::shared_ptr<ESDevice> Kernel::GetES()
ESCore& Kernel::GetESCore()
{
return *m_es_core;
}
std::shared_ptr<ESDevice> EmulationKernel::GetESDevice()
{
return std::static_pointer_cast<ESDevice>(m_device_map.at("/dev/es"));
}
std::shared_ptr<WiiSockMan> Kernel::GetSocketManager()
std::shared_ptr<WiiSockMan> EmulationKernel::GetSocketManager()
{
return m_socket_manager;
}
// Since we don't have actual processes, we keep track of only the PPC's UID/GID.
// These functions roughly correspond to syscalls 0x2b, 0x2c, 0x2d, 0x2e (though only for the PPC).
void Kernel::SetUidForPPC(u32 uid)
void EmulationKernel::SetUidForPPC(u32 uid)
{
m_ppc_uid = uid;
}
u32 Kernel::GetUidForPPC() const
u32 EmulationKernel::GetUidForPPC() const
{
return m_ppc_uid;
}
void Kernel::SetGidForPPC(u16 gid)
void EmulationKernel::SetGidForPPC(u16 gid)
{
m_ppc_gid = gid;
}
u16 Kernel::GetGidForPPC() const
u16 EmulationKernel::GetGidForPPC() const
{
return m_ppc_gid;
}
static std::vector<u8> ReadBootContent(FSDevice* fs, const std::string& path, size_t max_size,
static std::vector<u8> ReadBootContent(FSCore& fs, const std::string& path, size_t max_size,
Ticks ticks = {})
{
const auto fd = fs->Open(0, 0, path, FS::Mode::Read, {}, ticks);
const auto fd = fs.Open(0, 0, path, FS::Mode::Read, {}, ticks);
if (fd.Get() < 0)
return {};
const size_t file_size = fs->GetFileStatus(fd.Get(), ticks)->size;
const size_t file_size = fs.GetFileStatus(fd.Get(), ticks)->size;
if (max_size != 0 && file_size > max_size)
return {};
std::vector<u8> buffer(file_size);
if (!fs->Read(fd.Get(), buffer.data(), buffer.size(), ticks))
if (!fs.Read(fd.Get(), buffer.data(), buffer.size(), ticks))
return {};
return buffer;
}
// This corresponds to syscall 0x41, which loads a binary from the NAND and bootstraps the PPC.
// Unlike 0x42, IOS will set up some constants in memory before booting the PPC.
bool Kernel::BootstrapPPC(Core::System& system, const std::string& boot_content_path)
bool EmulationKernel::BootstrapPPC(Core::System& system, const std::string& boot_content_path)
{
// Seeking and processing overhead is ignored as most time is spent reading from the NAND.
u64 ticks = 0;
const DolReader dol{ReadBootContent(GetFSDevice().get(), boot_content_path, 0, &ticks)};
const DolReader dol{ReadBootContent(GetFSCore(), boot_content_path, 0, &ticks)};
if (!dol.IsValid())
return false;
@ -462,11 +480,11 @@ private:
std::vector<u8> m_bytes;
};
static void FinishIOSBoot(u64 ios_title_id)
static void FinishIOSBoot(Core::System& system, u64 ios_title_id)
{
// Shut down the active IOS first before switching to the new one.
s_ios.reset();
s_ios = std::make_unique<EmulationKernel>(ios_title_id);
s_ios = std::make_unique<EmulationKernel>(system, ios_title_id);
}
static constexpr SystemTimers::TimeBaseTick GetIOSBootTicks(u32 version)
@ -484,8 +502,8 @@ static constexpr SystemTimers::TimeBaseTick GetIOSBootTicks(u32 version)
// Passing a boot content path is optional because we do not require IOSes
// to be installed at the moment. If one is passed, the boot binary must exist
// on the NAND, or the call will fail like on a Wii.
bool Kernel::BootIOS(Core::System& system, const u64 ios_title_id, HangPPC hang_ppc,
const std::string& boot_content_path)
bool EmulationKernel::BootIOS(Core::System& system, const u64 ios_title_id, HangPPC hang_ppc,
const std::string& boot_content_path)
{
// IOS suspends regular PPC<->ARM IPC before loading a new IOS.
// IPC is not resumed if the boot fails for any reason.
@ -496,7 +514,7 @@ bool Kernel::BootIOS(Core::System& system, const u64 ios_title_id, HangPPC hang_
// Load the ARM binary to memory (if possible).
// Because we do not actually emulate the Starlet, only load the sections that are in MEM1.
ARMBinary binary{ReadBootContent(GetFSDevice().get(), boot_content_path, 0xB00000)};
ARMBinary binary{ReadBootContent(GetFSCore(), boot_content_path, 0xB00000)};
if (!binary.IsValid())
return false;
@ -515,13 +533,13 @@ bool Kernel::BootIOS(Core::System& system, const u64 ios_title_id, HangPPC hang_
}
else
{
FinishIOSBoot(ios_title_id);
FinishIOSBoot(system, ios_title_id);
}
return true;
}
void Kernel::InitIPC()
void EmulationKernel::InitIPC()
{
if (!Core::IsRunning())
return;
@ -530,29 +548,19 @@ void Kernel::InitIPC()
GenerateAck(0);
}
void Kernel::AddDevice(std::unique_ptr<Device> device)
void EmulationKernel::AddDevice(std::unique_ptr<Device> device)
{
ASSERT(device->GetDeviceType() == Device::DeviceType::Static);
m_device_map.insert_or_assign(device->GetDeviceName(), std::move(device));
}
void Kernel::AddCoreDevices()
void EmulationKernel::AddStaticDevices()
{
m_fs = FS::MakeFileSystem(IOS::HLE::FS::Location::Session, Core::GetActiveNandRedirects());
ASSERT(m_fs);
std::lock_guard lock(m_device_map_mutex);
AddDevice(std::make_unique<FSDevice>(*this, "/dev/fs"));
AddDevice(std::make_unique<ESDevice>(*this, "/dev/es"));
AddDevice(std::make_unique<DolphinDevice>(*this, "/dev/dolphin"));
}
void Kernel::AddStaticDevices()
{
std::lock_guard lock(m_device_map_mutex);
const Feature features = GetFeatures(GetVersion());
// Dolphin-specific device for letting homebrew access and alter emulator state.
AddDevice(std::make_unique<DolphinDevice>(*this, "/dev/dolphin"));
// OH1 (Bluetooth)
AddDevice(std::make_unique<DeviceStub>(*this, "/dev/usb/oh1"));
if (!Config::Get(Config::MAIN_BLUETOOTH_PASSTHROUGH_ENABLED))
@ -621,7 +629,7 @@ void Kernel::AddStaticDevices()
}
}
s32 Kernel::GetFreeDeviceID()
s32 EmulationKernel::GetFreeDeviceID()
{
for (u32 i = 0; i < IPC_MAX_FDS; i++)
{
@ -634,20 +642,14 @@ s32 Kernel::GetFreeDeviceID()
return -1;
}
std::shared_ptr<Device> Kernel::GetDeviceByName(std::string_view device_name)
std::shared_ptr<Device> EmulationKernel::GetDeviceByName(std::string_view device_name)
{
std::lock_guard lock(m_device_map_mutex);
const auto iterator = m_device_map.find(device_name);
return iterator != m_device_map.end() ? iterator->second : nullptr;
}
std::shared_ptr<Device> EmulationKernel::GetDeviceByName(std::string_view device_name)
{
return Kernel::GetDeviceByName(device_name);
}
// Returns the FD for the newly opened device (on success) or an error code.
std::optional<IPCReply> Kernel::OpenDevice(OpenRequest& request)
std::optional<IPCReply> EmulationKernel::OpenDevice(OpenRequest& request)
{
const s32 new_fd = GetFreeDeviceID();
INFO_LOG_FMT(IOS, "Opening {} (mode {}, fd {})", request.path, static_cast<u32>(request.flags),
@ -689,14 +691,14 @@ std::optional<IPCReply> Kernel::OpenDevice(OpenRequest& request)
return result;
}
std::optional<IPCReply> Kernel::HandleIPCCommand(const Request& request)
std::optional<IPCReply> EmulationKernel::HandleIPCCommand(const Request& request)
{
if (request.command < IPC_CMD_OPEN || request.command > IPC_CMD_IOCTLV)
return IPCReply{IPC_EINVAL, 978_tbticks};
if (request.command == IPC_CMD_OPEN)
{
OpenRequest open_request{request.address};
OpenRequest open_request{GetSystem(), request.address};
return OpenDevice(open_request);
}
@ -714,19 +716,19 @@ std::optional<IPCReply> Kernel::HandleIPCCommand(const Request& request)
ret = device->Close(request.fd);
break;
case IPC_CMD_READ:
ret = device->Read(ReadWriteRequest{request.address});
ret = device->Read(ReadWriteRequest{GetSystem(), request.address});
break;
case IPC_CMD_WRITE:
ret = device->Write(ReadWriteRequest{request.address});
ret = device->Write(ReadWriteRequest{GetSystem(), request.address});
break;
case IPC_CMD_SEEK:
ret = device->Seek(SeekRequest{request.address});
ret = device->Seek(SeekRequest{GetSystem(), request.address});
break;
case IPC_CMD_IOCTL:
ret = device->IOCtl(IOCtlRequest{request.address});
ret = device->IOCtl(IOCtlRequest{GetSystem(), request.address});
break;
case IPC_CMD_IOCTLV:
ret = device->IOCtlV(IOCtlVRequest{request.address});
ret = device->IOCtlV(IOCtlVRequest{GetSystem(), request.address});
break;
default:
ASSERT_MSG(IOS, false, "Unexpected command: {:#x}", static_cast<u32>(request.command));
@ -745,17 +747,16 @@ std::optional<IPCReply> Kernel::HandleIPCCommand(const Request& request)
return ret;
}
void Kernel::ExecuteIPCCommand(const u32 address)
void EmulationKernel::ExecuteIPCCommand(const u32 address)
{
Request request{address};
Request request{GetSystem(), address};
std::optional<IPCReply> result = HandleIPCCommand(request);
if (!result)
return;
// Ensure replies happen in order
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& core_timing = GetSystem().GetCoreTiming();
const s64 ticks_until_last_reply = m_last_reply_time - core_timing.GetTicks();
if (ticks_until_last_reply > 0)
result->reply_delay_ticks += ticks_until_last_reply;
@ -765,20 +766,20 @@ void Kernel::ExecuteIPCCommand(const u32 address)
}
// Happens AS SOON AS IPC gets a new pointer!
void Kernel::EnqueueIPCRequest(u32 address)
void EmulationKernel::EnqueueIPCRequest(u32 address)
{
// 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 2: 658 TB ticks before ACK
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(500_tbticks, s_event_enqueue,
address | ENQUEUE_REQUEST_FLAG);
GetSystem().GetCoreTiming().ScheduleEvent(500_tbticks, s_event_enqueue,
address | ENQUEUE_REQUEST_FLAG);
}
// Called to send a reply to an IOS syscall
void Kernel::EnqueueIPCReply(const Request& request, const s32 return_value, s64 cycles_in_future,
CoreTiming::FromThread from)
void EmulationKernel::EnqueueIPCReply(const Request& request, const s32 return_value,
s64 cycles_in_future, CoreTiming::FromThread from)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(static_cast<u32>(return_value), request.address + 4);
// IOS writes back the command that was responded to in the FD field.
@ -788,7 +789,7 @@ void Kernel::EnqueueIPCReply(const Request& request, const s32 return_value, s64
system.GetCoreTiming().ScheduleEvent(cycles_in_future, s_event_enqueue, request.address, from);
}
void Kernel::HandleIPCEvent(u64 userdata)
void EmulationKernel::HandleIPCEvent(u64 userdata)
{
if (userdata & ENQUEUE_REQUEST_FLAG)
m_request_queue.push_back(static_cast<u32>(userdata));
@ -798,7 +799,7 @@ void Kernel::HandleIPCEvent(u64 userdata)
UpdateIPC();
}
void Kernel::UpdateIPC()
void EmulationKernel::UpdateIPC()
{
if (m_ipc_paused || !IsReady())
return;
@ -822,7 +823,7 @@ void Kernel::UpdateIPC()
}
}
void Kernel::UpdateDevices()
void EmulationKernel::UpdateDevices()
{
// Check if a hardware device must be updated
for (const auto& entry : m_device_map)
@ -834,7 +835,7 @@ void Kernel::UpdateDevices()
}
}
void Kernel::UpdateWantDeterminism(const bool new_want_determinism)
void EmulationKernel::UpdateWantDeterminism(const bool new_want_determinism)
{
if (m_socket_manager)
m_socket_manager->UpdateWantDeterminism(new_want_determinism);
@ -842,7 +843,7 @@ void Kernel::UpdateWantDeterminism(const bool new_want_determinism)
device.second->UpdateWantDeterminism(new_want_determinism);
}
void Kernel::DoState(PointerWrap& p)
void EmulationKernel::DoState(PointerWrap& p)
{
p.Do(m_request_queue);
p.Do(m_reply_queue);
@ -952,15 +953,15 @@ void Init()
s_event_finish_ppc_bootstrap =
core_timing.RegisterEvent("IOSFinishPPCBootstrap", FinishPPCBootstrap);
s_event_finish_ios_boot =
core_timing.RegisterEvent("IOSFinishIOSBoot", [](Core::System& system_, u64 ios_title_id,
s64) { FinishIOSBoot(ios_title_id); });
s_event_finish_ios_boot = core_timing.RegisterEvent(
"IOSFinishIOSBoot",
[](Core::System& system_, u64 ios_title_id, s64) { FinishIOSBoot(system_, ios_title_id); });
DIDevice::s_finish_executing_di_command =
core_timing.RegisterEvent("FinishDICommand", DIDevice::FinishDICommandCallback);
// Start with IOS80 to simulate part of the Wii boot process.
s_ios = std::make_unique<EmulationKernel>(Titles::SYSTEM_MENU_IOS);
s_ios = std::make_unique<EmulationKernel>(system, Titles::SYSTEM_MENU_IOS);
// On a Wii, boot2 launches the system menu IOS, which then launches the system menu
// (which bootstraps the PPC). Bootstrapping the PPC results in memory values being set up.
// This means that the constants in the 0x3100 region are always set up by the time

View file

@ -7,7 +7,6 @@
#include <deque>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
@ -33,7 +32,9 @@ class FileSystem;
}
class Device;
class ESCore;
class ESDevice;
class FSCore;
class FSDevice;
class WiiSockMan;
@ -119,21 +120,53 @@ public:
explicit Kernel(IOSC::ConsoleType console_type = IOSC::ConsoleType::Retail);
virtual ~Kernel();
void DoState(PointerWrap& p);
void HandleIPCEvent(u64 userdata);
void UpdateIPC();
void UpdateDevices();
void UpdateWantDeterminism(bool new_want_determinism);
// These are *always* part of the IOS kernel and always available.
// They are also the only available resource managers even before loading any module.
std::shared_ptr<FS::FileSystem> GetFS();
std::shared_ptr<FSDevice> GetFSDevice();
std::shared_ptr<ESDevice> GetES();
FSCore& GetFSCore();
ESCore& GetESCore();
u32 GetVersion() const;
IOSC& GetIOSC();
protected:
explicit Kernel(u64 title_id);
std::unique_ptr<FSCore> m_fs_core;
std::unique_ptr<ESCore> m_es_core;
bool m_is_responsible_for_nand_root = false;
u64 m_title_id = 0;
IOSC m_iosc;
std::shared_ptr<FS::FileSystem> m_fs;
std::shared_ptr<WiiSockMan> m_socket_manager;
};
// HLE for an IOS tied to emulation: base kernel which may have additional modules loaded.
class EmulationKernel final : public Kernel
{
public:
EmulationKernel(Core::System& system, u64 ios_title_id);
~EmulationKernel();
// Get a resource manager by name.
// This only works for devices which are part of the device map.
std::shared_ptr<Device> GetDeviceByName(std::string_view device_name);
std::shared_ptr<FSDevice> GetFSDevice();
std::shared_ptr<ESDevice> GetESDevice();
void DoState(PointerWrap& p);
void UpdateDevices();
void UpdateWantDeterminism(bool new_want_determinism);
// This is only available on an EmulationKernel if the IOS features require it.
std::shared_ptr<WiiSockMan> GetSocketManager();
void HandleIPCEvent(u64 userdata);
void UpdateIPC();
void EnqueueIPCRequest(u32 address);
void EnqueueIPCReply(const Request& request, s32 return_value, s64 cycles_in_future = 0,
CoreTiming::FromThread from = CoreTiming::FromThread::CPU);
@ -147,28 +180,23 @@ public:
bool BootIOS(Core::System& system, u64 ios_title_id, HangPPC hang_ppc = HangPPC::No,
const std::string& boot_content_path = {});
void InitIPC();
u32 GetVersion() const;
IOSC& GetIOSC();
protected:
explicit Kernel(u64 title_id);
Core::System& GetSystem() const { return m_system; }
private:
void ExecuteIPCCommand(u32 address);
std::optional<IPCReply> HandleIPCCommand(const Request& request);
void AddDevice(std::unique_ptr<Device> device);
void AddCoreDevices();
void AddStaticDevices();
std::shared_ptr<Device> GetDeviceByName(std::string_view device_name);
s32 GetFreeDeviceID();
std::optional<IPCReply> OpenDevice(OpenRequest& request);
bool m_is_responsible_for_nand_root = false;
u64 m_title_id = 0;
Core::System& m_system;
static constexpr u8 IPC_MAX_FDS = 0x18;
std::map<std::string, std::shared_ptr<Device>, std::less<>> m_device_map;
std::mutex m_device_map_mutex;
// TODO: make this fdmap per process.
std::array<std::shared_ptr<Device>, IPC_MAX_FDS> m_fdmap;
@ -180,22 +208,6 @@ protected:
IPCMsgQueue m_reply_queue; // arm -> ppc
u64 m_last_reply_time = 0;
bool m_ipc_paused = false;
IOSC m_iosc;
std::shared_ptr<FS::FileSystem> m_fs;
std::shared_ptr<WiiSockMan> m_socket_manager;
};
// HLE for an IOS tied to emulation: base kernel which may have additional modules loaded.
class EmulationKernel : public Kernel
{
public:
explicit EmulationKernel(u64 ios_title_id);
~EmulationKernel();
// Get a resource manager by name.
// This only works for devices which are part of the device map.
std::shared_ptr<Device> GetDeviceByName(std::string_view device_name);
};
// Used for controlling and accessing an IOS instance that is tied to emulation.

View file

@ -62,8 +62,8 @@ enum SOResultCode : s32
SO_ERROR_HOST_NOT_FOUND = -305,
};
NetIPTopDevice::NetIPTopDevice(Kernel& ios, const std::string& device_name)
: Device(ios, device_name)
NetIPTopDevice::NetIPTopDevice(EmulationKernel& ios, const std::string& device_name)
: EmulationDevice(ios, device_name)
{
m_work_queue.Reset("Network Worker", [this](AsyncTask task) {
const IPCReply reply = task.handler();
@ -330,7 +330,7 @@ std::optional<IPCReply> NetIPTopDevice::IOCtl(const IOCtlRequest& request)
case IOCTL_SO_ICMPCANCEL:
return HandleICMPCancelRequest(request);
default:
request.DumpUnknown(GetDeviceName(), Common::Log::LogType::IOS_NET);
request.DumpUnknown(GetSystem(), GetDeviceName(), Common::Log::LogType::IOS_NET);
break;
}
@ -352,7 +352,7 @@ std::optional<IPCReply> NetIPTopDevice::IOCtlV(const IOCtlVRequest& request)
case IOCTLV_SO_ICMPPING:
return HandleICMPPingRequest(request);
default:
request.DumpUnknown(GetDeviceName(), Common::Log::LogType::IOS_NET);
request.DumpUnknown(GetSystem(), GetDeviceName(), Common::Log::LogType::IOS_NET);
break;
}
@ -366,11 +366,11 @@ void NetIPTopDevice::Update()
while (!m_async_replies.empty())
{
const auto& reply = m_async_replies.front();
GetIOS()->EnqueueIPCReply(reply.request, reply.return_value);
GetEmulationKernel().EnqueueIPCReply(reply.request, reply.return_value);
m_async_replies.pop();
}
}
m_ios.GetSocketManager()->Update();
GetEmulationKernel().GetSocketManager()->Update();
}
IPCReply NetIPTopDevice::HandleInitInterfaceRequest(const IOCtlRequest& request)
@ -381,14 +381,14 @@ IPCReply NetIPTopDevice::HandleInitInterfaceRequest(const IOCtlRequest& request)
IPCReply NetIPTopDevice::HandleSocketRequest(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 af = memory.Read_U32(request.buffer_in);
const u32 type = memory.Read_U32(request.buffer_in + 4);
const u32 prot = memory.Read_U32(request.buffer_in + 8);
const s32 return_value = m_ios.GetSocketManager()->NewSocket(af, type, prot);
const s32 return_value = GetEmulationKernel().GetSocketManager()->NewSocket(af, type, prot);
INFO_LOG_FMT(IOS_NET,
"IOCTL_SO_SOCKET "
"Socket: {:08x} ({},{},{}), BufferIn: ({:08x}, {}), BufferOut: ({:08x}, {})",
@ -400,23 +400,24 @@ IPCReply NetIPTopDevice::HandleSocketRequest(const IOCtlRequest& request)
IPCReply NetIPTopDevice::HandleICMPSocketRequest(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 pf = memory.Read_U32(request.buffer_in);
const s32 return_value = m_ios.GetSocketManager()->NewSocket(pf, SOCK_RAW, IPPROTO_ICMP);
const s32 return_value =
GetEmulationKernel().GetSocketManager()->NewSocket(pf, SOCK_RAW, IPPROTO_ICMP);
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_ICMPSOCKET({:x}) {}", pf, return_value);
return IPCReply(return_value);
}
IPCReply NetIPTopDevice::HandleCloseRequest(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 fd = memory.Read_U32(request.buffer_in);
const s32 return_value = m_ios.GetSocketManager()->DeleteSocket(fd);
const s32 return_value = GetEmulationKernel().GetSocketManager()->DeleteSocket(fd);
const char* const close_fn =
request.request == IOCTL_SO_ICMPCLOSE ? "IOCTL_SO_ICMPCLOSE" : "IOCTL_SO_CLOSE";
@ -427,11 +428,12 @@ IPCReply NetIPTopDevice::HandleCloseRequest(const IOCtlRequest& request)
std::optional<IPCReply> NetIPTopDevice::HandleDoSockRequest(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 fd = memory.Read_U32(request.buffer_in);
m_ios.GetSocketManager()->DoSock(fd, request, static_cast<NET_IOCTL>(request.request));
GetEmulationKernel().GetSocketManager()->DoSock(fd, request,
static_cast<NET_IOCTL>(request.request));
return std::nullopt;
}
@ -444,12 +446,12 @@ IPCReply NetIPTopDevice::HandleShutdownRequest(const IOCtlRequest& request)
return IPCReply(-SO_EINVAL);
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 fd = memory.Read_U32(request.buffer_in);
const u32 how = memory.Read_U32(request.buffer_in + 4);
const s32 return_value = m_ios.GetSocketManager()->ShutdownSocket(fd, how);
const s32 return_value = GetEmulationKernel().GetSocketManager()->ShutdownSocket(fd, how);
INFO_LOG_FMT(IOS_NET, "IOCTL_SO_SHUTDOWN(fd={}, how={}) = {}", fd, how, return_value);
return IPCReply(return_value);
@ -457,12 +459,12 @@ IPCReply NetIPTopDevice::HandleShutdownRequest(const IOCtlRequest& request)
IPCReply NetIPTopDevice::HandleListenRequest(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 fd = memory.Read_U32(request.buffer_in);
u32 BACKLOG = memory.Read_U32(request.buffer_in + 0x04);
auto socket_manager = m_ios.GetSocketManager();
auto socket_manager = GetEmulationKernel().GetSocketManager();
u32 ret = listen(socket_manager->GetHostSocket(fd), BACKLOG);
request.Log(GetDeviceName(), Common::Log::LogType::IOS_WC24);
@ -471,7 +473,7 @@ IPCReply NetIPTopDevice::HandleListenRequest(const IOCtlRequest& request)
IPCReply NetIPTopDevice::HandleGetSockOptRequest(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 fd = memory.Read_U32(request.buffer_out);
@ -487,7 +489,7 @@ IPCReply NetIPTopDevice::HandleGetSockOptRequest(const IOCtlRequest& request)
u8 optval[20];
u32 optlen = 4;
auto socket_manager = m_ios.GetSocketManager();
auto socket_manager = GetEmulationKernel().GetSocketManager();
int ret = getsockopt(socket_manager->GetHostSocket(fd), nat_level, nat_optname, (char*)&optval,
(socklen_t*)&optlen);
const s32 return_value = socket_manager->GetNetErrorCode(ret, "SO_GETSOCKOPT", false);
@ -508,7 +510,7 @@ IPCReply NetIPTopDevice::HandleGetSockOptRequest(const IOCtlRequest& request)
IPCReply NetIPTopDevice::HandleSetSockOptRequest(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 fd = memory.Read_U32(request.buffer_in);
@ -539,7 +541,7 @@ IPCReply NetIPTopDevice::HandleSetSockOptRequest(const IOCtlRequest& request)
const int nat_level = MapWiiSockOptLevelToNative(level);
const int nat_optname = MapWiiSockOptNameToNative(optname);
auto socket_manager = m_ios.GetSocketManager();
auto socket_manager = GetEmulationKernel().GetSocketManager();
const int ret = setsockopt(socket_manager->GetHostSocket(fd), nat_level, nat_optname,
reinterpret_cast<char*>(optval), optlen);
return IPCReply(socket_manager->GetNetErrorCode(ret, "SO_SETSOCKOPT", false));
@ -547,7 +549,7 @@ IPCReply NetIPTopDevice::HandleSetSockOptRequest(const IOCtlRequest& request)
IPCReply NetIPTopDevice::HandleGetSockNameRequest(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 fd = memory.Read_U32(request.buffer_in);
@ -556,7 +558,8 @@ IPCReply NetIPTopDevice::HandleGetSockNameRequest(const IOCtlRequest& request)
sockaddr sa;
socklen_t sa_len = sizeof(sa);
const int ret = getsockname(m_ios.GetSocketManager()->GetHostSocket(fd), &sa, &sa_len);
const int ret =
getsockname(GetEmulationKernel().GetSocketManager()->GetHostSocket(fd), &sa, &sa_len);
if (request.buffer_out_size < 2 + sizeof(sa.sa_data))
WARN_LOG_FMT(IOS_NET, "IOCTL_SO_GETSOCKNAME output buffer is too small. Truncating");
@ -576,14 +579,15 @@ IPCReply NetIPTopDevice::HandleGetSockNameRequest(const IOCtlRequest& request)
IPCReply NetIPTopDevice::HandleGetPeerNameRequest(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 fd = memory.Read_U32(request.buffer_in);
sockaddr sa;
socklen_t sa_len = sizeof(sa);
const int ret = getpeername(m_ios.GetSocketManager()->GetHostSocket(fd), &sa, &sa_len);
const int ret =
getpeername(GetEmulationKernel().GetSocketManager()->GetHostSocket(fd), &sa, &sa_len);
if (request.buffer_out_size < 2 + sizeof(sa.sa_data))
WARN_LOG_FMT(IOS_NET, "IOCTL_SO_GETPEERNAME output buffer is too small. Truncating");
@ -613,7 +617,7 @@ IPCReply NetIPTopDevice::HandleGetHostIDRequest(const IOCtlRequest& request)
IPCReply NetIPTopDevice::HandleInetAToNRequest(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const std::string hostname = memory.GetString(request.buffer_in);
@ -645,7 +649,7 @@ IPCReply NetIPTopDevice::HandleInetAToNRequest(const IOCtlRequest& request)
IPCReply NetIPTopDevice::HandleInetPToNRequest(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const std::string address = memory.GetString(request.buffer_in);
@ -655,7 +659,7 @@ IPCReply NetIPTopDevice::HandleInetPToNRequest(const IOCtlRequest& request)
IPCReply NetIPTopDevice::HandleInetNToPRequest(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
// u32 af = memory.Read_U32(BufferIn);
@ -674,12 +678,12 @@ IPCReply NetIPTopDevice::HandleInetNToPRequest(const IOCtlRequest& request)
std::optional<IPCReply> NetIPTopDevice::HandlePollRequest(const IOCtlRequest& request)
{
auto sm = m_ios.GetSocketManager();
auto sm = GetEmulationKernel().GetSocketManager();
if (!request.buffer_in || !request.buffer_out)
return IPCReply(-SO_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
// Negative timeout indicates wait forever
@ -726,7 +730,7 @@ IPCReply NetIPTopDevice::HandleGetHostByNameRequest(const IOCtlRequest& request)
return IPCReply(-1);
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const std::string hostname = memory.GetString(request.buffer_in);
@ -814,7 +818,7 @@ IPCReply NetIPTopDevice::HandleICMPCancelRequest(const IOCtlRequest& request)
IPCReply NetIPTopDevice::HandleGetInterfaceOptRequest(const IOCtlVRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 param = memory.Read_U32(request.in_vectors[0].address);
@ -1007,27 +1011,27 @@ IPCReply NetIPTopDevice::HandleGetInterfaceOptRequest(const IOCtlVRequest& reque
std::optional<IPCReply> NetIPTopDevice::HandleSendToRequest(const IOCtlVRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 fd = memory.Read_U32(request.in_vectors[1].address);
m_ios.GetSocketManager()->DoSock(fd, request, IOCTLV_SO_SENDTO);
GetEmulationKernel().GetSocketManager()->DoSock(fd, request, IOCTLV_SO_SENDTO);
return std::nullopt;
}
std::optional<IPCReply> NetIPTopDevice::HandleRecvFromRequest(const IOCtlVRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 fd = memory.Read_U32(request.in_vectors[0].address);
m_ios.GetSocketManager()->DoSock(fd, request, IOCTLV_SO_RECVFROM);
GetEmulationKernel().GetSocketManager()->DoSock(fd, request, IOCTLV_SO_RECVFROM);
return std::nullopt;
}
IPCReply NetIPTopDevice::HandleGetAddressInfoRequest(const IOCtlVRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
addrinfo hints;
@ -1113,7 +1117,8 @@ IPCReply NetIPTopDevice::HandleGetAddressInfoRequest(const IOCtlVRequest& reques
ret = SO_ERROR_HOST_NOT_FOUND;
}
request.Dump(GetDeviceName(), Common::Log::LogType::IOS_NET, Common::Log::LogLevel::LINFO);
request.Dump(system, GetDeviceName(), Common::Log::LogType::IOS_NET,
Common::Log::LogLevel::LINFO);
return IPCReply(ret);
}
@ -1127,7 +1132,7 @@ IPCReply NetIPTopDevice::HandleICMPPingRequest(const IOCtlVRequest& request)
u32 ip;
} ip_info;
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 fd = memory.Read_U32(request.in_vectors[0].address);
@ -1176,7 +1181,7 @@ IPCReply NetIPTopDevice::HandleICMPPingRequest(const IOCtlVRequest& request)
icmp_length = 22;
}
auto socket_manager = m_ios.GetSocketManager();
auto socket_manager = GetEmulationKernel().GetSocketManager();
int ret = icmp_echo_req(socket_manager->GetHostSocket(fd), &addr, data, icmp_length);
if (ret == icmp_length)
{

View file

@ -63,10 +63,10 @@ enum NET_IOCTL
IOCTL_SO_ICMPCLOSE
};
class NetIPTopDevice : public Device
class NetIPTopDevice : public EmulationDevice
{
public:
NetIPTopDevice(Kernel& ios, const std::string& device_name);
NetIPTopDevice(EmulationKernel& ios, const std::string& device_name);
void DoState(PointerWrap& p) override;
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;

View file

@ -19,6 +19,8 @@ enum ErrorCode : s32
{
WC24_OK = 0,
WC24_ERR_FATAL = -1,
WC24_ERR_INVALID_VALUE = -3,
WC24_ERR_NULL = -5,
WC24_ERR_NOT_FOUND = -13,
WC24_ERR_BROKEN = -14,
WC24_ERR_FILE_OPEN = -16,

View file

@ -147,9 +147,12 @@ s32 NWC24MakeUserID(u64* nwc24_id, u32 hollywood_id, u16 id_ctr, HardwareModel h
}
} // Anonymous namespace
NetKDRequestDevice::NetKDRequestDevice(Kernel& ios, const std::string& device_name)
: Device(ios, device_name), config{ios.GetFS()}, m_dl_list{ios.GetFS()}
NetKDRequestDevice::NetKDRequestDevice(EmulationKernel& ios, const std::string& device_name)
: EmulationDevice(ios, device_name), config{ios.GetFS()}, m_dl_list{ios.GetFS()}
{
// Enable all NWC24 permissions
m_scheduler_buffer[1] = Common::swap32(-1);
m_work_queue.Reset("WiiConnect24 Worker", [this](AsyncTask task) {
const IPCReply reply = task.handler();
{
@ -161,7 +164,7 @@ NetKDRequestDevice::NetKDRequestDevice(Kernel& ios, const std::string& device_na
NetKDRequestDevice::~NetKDRequestDevice()
{
auto socket_manager = m_ios.GetSocketManager();
auto socket_manager = GetEmulationKernel().GetSocketManager();
if (socket_manager)
socket_manager->Clean();
}
@ -173,12 +176,40 @@ void NetKDRequestDevice::Update()
while (!m_async_replies.empty())
{
const auto& reply = m_async_replies.front();
GetIOS()->EnqueueIPCReply(reply.request, reply.return_value);
GetEmulationKernel().EnqueueIPCReply(reply.request, reply.return_value);
m_async_replies.pop();
}
}
}
void NetKDRequestDevice::LogError(ErrorType error_type, s32 error_code)
{
s32 new_code{};
switch (error_type)
{
case ErrorType::Account:
new_code = -(101200 - error_code);
break;
case ErrorType::Client:
new_code = -(107300 - error_code);
break;
case ErrorType::KD_Download:
new_code = -(107200 - error_code);
break;
case ErrorType::Server:
new_code = -(117000 + error_code);
break;
}
std::lock_guard lg(m_scheduler_buffer_lock);
m_scheduler_buffer[32 + (m_error_count % 32)] = Common::swap32(new_code);
m_error_count++;
m_scheduler_buffer[5] = Common::swap32(m_error_count);
m_scheduler_buffer[2] = Common::swap32(new_code);
}
NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
const std::optional<u8> subtask_id)
{
@ -196,7 +227,14 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
if (!response)
{
ERROR_LOG_FMT(IOS_WC24, "Failed to request data at {}", url);
const s32 last_response_code = m_http.GetLastResponseCode();
ERROR_LOG_FMT(IOS_WC24, "Failed to request data at {}. HTTP Status Code: {}", url,
last_response_code);
// On a real Wii, KD throws 107305 if it cannot connect to the host. While other issues other
// than invalid host may arise, this code is essentially a catch-all for HTTP client failure.
LogError(last_response_code ? ErrorType::Server : ErrorType::Client,
last_response_code ? last_response_code : NWC24::WC24_ERR_NULL);
return NWC24::WC24_ERR_SERVER;
}
@ -204,6 +242,7 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
if (response->size() < sizeof(NWC24::WC24File))
{
ERROR_LOG_FMT(IOS_WC24, "File at {} is too small to be a valid file.", url);
LogError(ErrorType::KD_Download, NWC24::WC24_ERR_BROKEN);
return NWC24::WC24_ERR_BROKEN;
}
@ -230,13 +269,16 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
NWC24::ErrorCode reply = IOS::HLE::NWC24::OpenVFF(m_dl_list.GetVFFPath(entry_index), content_name,
m_ios.GetFS(), file_data);
if (reply != NWC24::WC24_OK)
LogError(ErrorType::KD_Download, reply);
return reply;
}
IPCReply NetKDRequestDevice::HandleNWC24DownloadNowEx(const IOCtlRequest& request)
{
m_dl_list.ReadDlList();
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 flags = memory.Read_U32(request.buffer_in);
// Nintendo converts the entry ID between a u32 and u16
@ -252,15 +294,17 @@ IPCReply NetKDRequestDevice::HandleNWC24DownloadNowEx(const IOCtlRequest& reques
if (entry_index >= NWC24::NWC24Dl::MAX_ENTRIES)
{
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: Entry index out of range.");
WriteReturnValue(NWC24::WC24_ERR_BROKEN, request.buffer_out);
return IPCReply(NWC24::WC24_ERR_BROKEN);
LogError(ErrorType::KD_Download, NWC24::WC24_ERR_INVALID_VALUE);
WriteReturnValue(NWC24::WC24_ERR_INVALID_VALUE, request.buffer_out);
return IPCReply(IPC_SUCCESS);
}
if (!m_dl_list.DoesEntryExist(entry_index))
{
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: Requested entry does not exist in download list!");
LogError(ErrorType::KD_Download, NWC24::WC24_ERR_NOT_FOUND);
WriteReturnValue(NWC24::WC24_ERR_NOT_FOUND, request.buffer_out);
return IPCReply(NWC24::WC24_ERR_NOT_FOUND);
return IPCReply(IPC_SUCCESS);
}
// While in theory reply will always get initialized by KDDownload, things happen.
@ -290,7 +334,7 @@ IPCReply NetKDRequestDevice::HandleNWC24DownloadNowEx(const IOCtlRequest& reques
}
WriteReturnValue(reply, request.buffer_out);
return IPCReply(reply);
return IPCReply(IPC_SUCCESS);
}
std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
@ -321,7 +365,7 @@ std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
IOCTL_NWC24_REQUEST_SHUTDOWN = 0x28,
};
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
s32 return_value = 0;
switch (request.request)
@ -350,7 +394,7 @@ std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
case IOCTL_NWC24_CLEANUP_SOCKET:
INFO_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_CLEANUP_SOCKET");
m_ios.GetSocketManager()->Clean();
GetEmulationKernel().GetSocketManager()->Clean();
break;
case IOCTL_NWC24_LOCK_SOCKET: // WiiMenu
@ -408,6 +452,7 @@ std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
}
else
{
LogError(ErrorType::Account, NWC24::WC24_ERR_INVALID_VALUE);
WriteReturnValue(NWC24::WC24_ERR_FATAL, request.buffer_out);
}
}
@ -424,8 +469,24 @@ std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
break;
case IOCTL_NWC24_GET_SCHEDULER_STAT:
INFO_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_GET_SCHEDULER_STAT - NI");
{
if (request.buffer_out == 0 || request.buffer_out % 4 != 0 || request.buffer_out_size < 16)
{
return_value = IPC_EINVAL;
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_GET_SCHEDULER_STAT = IPC_EINVAL");
break;
}
INFO_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_GET_SCHEDULER_STAT - buffer out size: {}",
request.buffer_out_size);
// On a real Wii, GetSchedulerStat copies memory containing a list of error codes recorded by
// KD among other things. In most instances there will never be more than one error code
// recorded as we do not have a scheduler.
const u32 out_size = std::min(request.buffer_out_size, 256U);
memory.CopyToEmu(request.buffer_out, m_scheduler_buffer.data(), out_size);
break;
}
case IOCTL_NWC24_SAVE_MAIL_NOW:
INFO_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW - NI");
@ -454,7 +515,7 @@ std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
// SOGetInterfaceOpt(0xfffe,0xc001); // DHCP lease time remaining?
// SOGetInterfaceOpt(0xfffe,0x1003); // Error
// Call /dev/net/ip/top 0x1b (SOCleanup), it closes all sockets
m_ios.GetSocketManager()->Clean();
GetEmulationKernel().GetSocketManager()->Clean();
return_value = IPC_SUCCESS;
break;
}

View file

@ -3,6 +3,7 @@
#pragma once
#include <array>
#include <queue>
#include <string>
@ -16,15 +17,13 @@
namespace IOS::HLE
{
constexpr const char DL_CNT_PATH[] = "/" WII_WC24CONF_DIR "/dlcnt.bin";
// KD is the IOS module responsible for implementing WiiConnect24 functionality.
// It can perform HTTPS downloads, send and receive mail via SMTP, and execute a
// JavaScript-like language while the Wii is in standby mode.
class NetKDRequestDevice : public Device
class NetKDRequestDevice : public EmulationDevice
{
public:
NetKDRequestDevice(Kernel& ios, const std::string& device_name);
NetKDRequestDevice(EmulationKernel& ios, const std::string& device_name);
IPCReply HandleNWC24DownloadNowEx(const IOCtlRequest& request);
NWC24::ErrorCode KDDownload(const u16 entry_index, const std::optional<u8> subtask_id);
~NetKDRequestDevice() override;
@ -52,11 +51,24 @@ private:
return std::nullopt;
}
enum class ErrorType
{
Account,
KD_Download,
Client,
Server,
};
void LogError(ErrorType error_type, s32 error_code);
NWC24::NWC24Config config;
NWC24::NWC24Dl m_dl_list;
Common::WorkQueueThread<AsyncTask> m_work_queue;
std::mutex m_async_reply_lock;
std::mutex m_scheduler_buffer_lock;
std::queue<AsyncReply> m_async_replies;
u32 m_error_count = 0;
std::array<u32, 256> m_scheduler_buffer{};
// TODO: Maybe move away from Common::HttpRequest?
Common::HttpRequest m_http{std::chrono::minutes{1}};
};

View file

@ -12,8 +12,8 @@
namespace IOS::HLE
{
NetKDTimeDevice::NetKDTimeDevice(Kernel& ios, const std::string& device_name)
: Device(ios, device_name)
NetKDTimeDevice::NetKDTimeDevice(EmulationKernel& ios, const std::string& device_name)
: EmulationDevice(ios, device_name)
{
}
@ -35,7 +35,7 @@ std::optional<IPCReply> NetKDTimeDevice::IOCtl(const IOCtlRequest& request)
// TODO Writes stuff to /shared2/nwc24/misc.bin
u32 update_misc = 0;
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
switch (request.request)
@ -78,7 +78,7 @@ std::optional<IPCReply> NetKDTimeDevice::IOCtl(const IOCtlRequest& request)
break;
default:
request.DumpUnknown(GetDeviceName(), Common::Log::LogType::IOS_WC24);
request.DumpUnknown(system, GetDeviceName(), Common::Log::LogType::IOS_WC24);
break;
}
@ -91,8 +91,7 @@ u64 NetKDTimeDevice::GetAdjustedUTC() const
{
using namespace ExpansionInterface;
const time_t current_time =
CEXIIPL::GetEmulatedTime(Core::System::GetInstance(), CEXIIPL::UNIX_EPOCH);
const time_t current_time = CEXIIPL::GetEmulatedTime(GetSystem(), CEXIIPL::UNIX_EPOCH);
tm* const gm_time = gmtime(&current_time);
const u32 emulated_time = mktime(gm_time);
return u64(s64(emulated_time) + utcdiff);
@ -102,8 +101,7 @@ void NetKDTimeDevice::SetAdjustedUTC(u64 wii_utc)
{
using namespace ExpansionInterface;
const time_t current_time =
CEXIIPL::GetEmulatedTime(Core::System::GetInstance(), CEXIIPL::UNIX_EPOCH);
const time_t current_time = CEXIIPL::GetEmulatedTime(GetSystem(), CEXIIPL::UNIX_EPOCH);
tm* const gm_time = gmtime(&current_time);
const u32 emulated_time = mktime(gm_time);
utcdiff = s64(emulated_time - wii_utc);

View file

@ -10,10 +10,10 @@
namespace IOS::HLE
{
class NetKDTimeDevice : public Device
class NetKDTimeDevice : public EmulationDevice
{
public:
NetKDTimeDevice(Kernel& ios, const std::string& device_name);
NetKDTimeDevice(EmulationKernel& ios, const std::string& device_name);
~NetKDTimeDevice() override;
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;

View file

@ -267,7 +267,7 @@ ErrorCode OpenVFF(const std::string& path, const std::string& filename,
if (!temp)
{
ERROR_LOG_FMT(IOS_WC24, "Failed to open VFF at: {}", path);
return_value = WC24_ERR_NOT_FOUND;
return_value = WC24_ERR_FILE_OPEN;
return;
}
@ -281,7 +281,7 @@ ErrorCode OpenVFF(const std::string& path, const std::string& filename,
{
// The VFF is most likely broken.
ERROR_LOG_FMT(IOS_WC24, "Failed to mount VFF at: {}", path);
return_value = WC24_ERR_BROKEN;
return_value = WC24_ERR_FILE_READ;
return;
}
@ -290,7 +290,7 @@ ErrorCode OpenVFF(const std::string& path, const std::string& filename,
{
// The VFF is most likely broken.
ERROR_LOG_FMT(IOS_WC24, "Failed to mount VFF at: {}", path);
return_value = WC24_ERR_BROKEN;
return_value = WC24_ERR_FILE_READ;
return;
}

View file

@ -15,8 +15,8 @@
namespace IOS::HLE
{
NetNCDManageDevice::NetNCDManageDevice(Kernel& ios, const std::string& device_name)
: Device(ios, device_name)
NetNCDManageDevice::NetNCDManageDevice(EmulationKernel& ios, const std::string& device_name)
: EmulationDevice(ios, device_name)
{
config.ReadConfig(ios.GetFS().get());
}
@ -33,7 +33,7 @@ std::optional<IPCReply> NetNCDManageDevice::IOCtlV(const IOCtlVRequest& request)
u32 common_result = 0;
u32 common_vector = 0;
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
switch (request.request)

View file

@ -12,10 +12,10 @@
namespace IOS::HLE
{
// Interface for reading and changing network configuration (probably some other stuff as well)
class NetNCDManageDevice : public Device
class NetNCDManageDevice : public EmulationDevice
{
public:
NetNCDManageDevice(Kernel& ios, const std::string& device_name);
NetNCDManageDevice(EmulationKernel& ios, const std::string& device_name);
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;

View file

@ -88,7 +88,8 @@ int SSLRecv(void* ctx, unsigned char* buf, size_t len)
}
} // namespace
NetSSLDevice::NetSSLDevice(Kernel& ios, const std::string& device_name) : Device(ios, device_name)
NetSSLDevice::NetSSLDevice(EmulationKernel& ios, const std::string& device_name)
: EmulationDevice(ios, device_name)
{
for (WII_SSL& ssl : _SSL)
{
@ -496,7 +497,7 @@ std::optional<IPCReply> NetSSLDevice::IOCtlV(const IOCtlVRequest& request)
WII_SSL* ssl = &_SSL[sslID];
mbedtls_ssl_setup(&ssl->ctx, &ssl->config);
ssl->sockfd = memory.Read_U32(BufferOut2);
ssl->hostfd = m_ios.GetSocketManager()->GetHostSocket(ssl->sockfd);
ssl->hostfd = GetEmulationKernel().GetSocketManager()->GetHostSocket(ssl->sockfd);
INFO_LOG_FMT(IOS_SSL, "IOCTLV_NET_SSL_CONNECT socket = {}", ssl->sockfd);
mbedtls_ssl_set_bio(&ssl->ctx, ssl, SSLSendWithoutSNI, SSLRecv, nullptr);
WriteReturnValue(SSL_OK, BufferIn);
@ -519,7 +520,8 @@ std::optional<IPCReply> NetSSLDevice::IOCtlV(const IOCtlVRequest& request)
int sslID = memory.Read_U32(BufferOut) - 1;
if (IsSSLIDValid(sslID))
{
m_ios.GetSocketManager()->DoSock(_SSL[sslID].sockfd, request, IOCTLV_NET_SSL_DOHANDSHAKE);
GetEmulationKernel().GetSocketManager()->DoSock(_SSL[sslID].sockfd, request,
IOCTLV_NET_SSL_DOHANDSHAKE);
return std::nullopt;
}
else
@ -533,7 +535,8 @@ std::optional<IPCReply> NetSSLDevice::IOCtlV(const IOCtlVRequest& request)
const int sslID = memory.Read_U32(BufferOut) - 1;
if (IsSSLIDValid(sslID))
{
m_ios.GetSocketManager()->DoSock(_SSL[sslID].sockfd, request, IOCTLV_NET_SSL_WRITE);
GetEmulationKernel().GetSocketManager()->DoSock(_SSL[sslID].sockfd, request,
IOCTLV_NET_SSL_WRITE);
return std::nullopt;
}
else
@ -556,7 +559,8 @@ std::optional<IPCReply> NetSSLDevice::IOCtlV(const IOCtlVRequest& request)
int sslID = memory.Read_U32(BufferOut) - 1;
if (IsSSLIDValid(sslID))
{
m_ios.GetSocketManager()->DoSock(_SSL[sslID].sockfd, request, IOCTLV_NET_SSL_READ);
GetEmulationKernel().GetSocketManager()->DoSock(_SSL[sslID].sockfd, request,
IOCTLV_NET_SSL_READ);
return std::nullopt;
}
else
@ -615,7 +619,7 @@ std::optional<IPCReply> NetSSLDevice::IOCtlV(const IOCtlVRequest& request)
break;
}
default:
request.DumpUnknown(GetDeviceName(), Common::Log::LogType::IOS_SSL);
request.DumpUnknown(system, GetDeviceName(), Common::Log::LogType::IOS_SSL);
}
// SSL return codes are written to BufferIn

View file

@ -79,10 +79,10 @@ struct WII_SSL
bool active = false;
};
class NetSSLDevice : public Device
class NetSSLDevice : public EmulationDevice
{
public:
NetSSLDevice(Kernel& ios, const std::string& device_name);
NetSSLDevice(EmulationKernel& ios, const std::string& device_name);
virtual ~NetSSLDevice();

View file

@ -260,7 +260,7 @@ void WiiSocket::Update(bool read, bool write, bool except)
IPCCommandType ct = it->request.command;
if (!it->is_ssl && ct == IPC_CMD_IOCTL)
{
IOCtlRequest ioctl{it->request.address};
IOCtlRequest ioctl{system, it->request.address};
switch (it->net_type)
{
case IOCTL_SO_FCNTL:
@ -351,7 +351,7 @@ void WiiSocket::Update(bool read, bool write, bool except)
}
else if (ct == IPC_CMD_IOCTLV)
{
IOCtlVRequest ioctlv{it->request.address};
IOCtlVRequest ioctlv{system, it->request.address};
u32 BufferIn = 0, BufferIn2 = 0;
u32 BufferInSize = 0, BufferInSize2 = 0;
u32 BufferOut = 0, BufferOut2 = 0;
@ -1042,8 +1042,8 @@ void WiiSockMan::UpdatePollCommands()
pending_polls.erase(
std::remove_if(
pending_polls.begin(), pending_polls.end(),
[&memory, this](PollCommand& pcmd) {
const auto request = Request(pcmd.request_addr);
[&system, &memory, this](PollCommand& pcmd) {
const auto request = Request(system, pcmd.request_addr);
auto& pfds = pcmd.wii_fds;
int ret = 0;

View file

@ -15,7 +15,7 @@ typedef pollfd pollfd_t;
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
#elif defined(__linux__) or defined(__APPLE__) or defined(__FreeBSD__) or defined(__NetBSD__) or \
defined(__HAIKU__)
defined(__OpenBSD__) or defined(__HAIKU__)
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>

View file

@ -61,8 +61,8 @@ NetWDCommandDevice::Status NetWDCommandDevice::GetTargetStatusForMode(WD::Mode m
}
}
NetWDCommandDevice::NetWDCommandDevice(Kernel& ios, const std::string& device_name)
: Device(ios, device_name)
NetWDCommandDevice::NetWDCommandDevice(EmulationKernel& ios, const std::string& device_name)
: EmulationDevice(ios, device_name)
{
// TODO: use the MPCH setting in setting.txt to determine this value.
m_nitro_enabled_channels = LegalNitroChannelMask;
@ -87,6 +87,8 @@ void NetWDCommandDevice::Update()
void NetWDCommandDevice::ProcessRecvRequests()
{
auto& system = GetSystem();
// Because we currently do not actually emulate the wireless driver, we have no frames
// and no notification data that could be used to reply to requests.
// Therefore, requests are left pending to simulate the situation where there is nothing to send.
@ -117,7 +119,7 @@ void NetWDCommandDevice::ProcessRecvRequests()
}
INFO_LOG_FMT(IOS_NET, "Processed request {:08x} (result {:08x})", request, result);
m_ios.EnqueueIPCReply(Request{request}, result);
GetEmulationKernel().EnqueueIPCReply(Request{system, request}, result);
queue.pop_front();
}
};
@ -234,7 +236,7 @@ IPCReply NetWDCommandDevice::SetLinkState(const IOCtlVRequest& request)
if (!vector || vector->address == 0)
return IPCReply(u32(ResultCode::IllegalParameter));
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 state = memory.Read_U32(vector->address);
INFO_LOG_FMT(IOS_NET, "WD_SetLinkState called (state={}, mode={})", state, m_mode);
@ -282,7 +284,7 @@ IPCReply NetWDCommandDevice::Disassociate(const IOCtlVRequest& request)
if (!vector || vector->address == 0)
return IPCReply(u32(ResultCode::IllegalParameter));
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
Common::MACAddress mac;
@ -315,7 +317,7 @@ IPCReply NetWDCommandDevice::GetInfo(const IOCtlVRequest& request) const
if (!vector || vector->address == 0)
return IPCReply(u32(ResultCode::IllegalParameter));
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.CopyToEmu(vector->address, &m_info, sizeof(m_info));
return IPCReply(IPC_SUCCESS);
@ -342,7 +344,7 @@ std::optional<IPCReply> NetWDCommandDevice::IOCtlV(const IOCtlVRequest& request)
// XXX - unused
// ScanInfo *scan = (ScanInfo *)memory.GetPointer(request.in_vectors.at(0).m_Address);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u16* results = (u16*)memory.GetPointer(request.io_vectors.at(0).address);
// first u16 indicates number of BSSInfo following
@ -388,7 +390,8 @@ std::optional<IPCReply> NetWDCommandDevice::IOCtlV(const IOCtlVRequest& request)
case IOCTLV_WD_CHANGE_VTSF:
default:
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_WD_UNIMPLEMENTED_IOCTL);
request.Dump(GetDeviceName(), Common::Log::LogType::IOS_NET, Common::Log::LogLevel::LWARNING);
request.Dump(GetSystem(), GetDeviceName(), Common::Log::LogType::IOS_NET,
Common::Log::LogLevel::LWARNING);
}
return IPCReply(IPC_SUCCESS);

View file

@ -39,7 +39,7 @@ constexpr bool IsValidMode(Mode mode)
namespace IOS::HLE
{
class NetWDCommandDevice : public Device
class NetWDCommandDevice : public EmulationDevice
{
public:
enum class ResultCode : u32
@ -50,7 +50,7 @@ public:
DriverError = 0x80008003,
};
NetWDCommandDevice(Kernel& ios, const std::string& device_name);
NetWDCommandDevice(EmulationKernel& ios, const std::string& device_name);
std::optional<IPCReply> Open(const OpenRequest& request) override;
std::optional<IPCReply> Close(u32 fd) override;

View file

@ -25,8 +25,9 @@
namespace IOS::HLE
{
SDIOSlot0Device::SDIOSlot0Device(Kernel& ios, const std::string& device_name)
: Device(ios, device_name), m_sdhc_supported(HasFeature(ios.GetVersion(), Feature::SDv2))
SDIOSlot0Device::SDIOSlot0Device(EmulationKernel& ios, const std::string& device_name)
: EmulationDevice(ios, device_name),
m_sdhc_supported(HasFeature(ios.GetVersion(), Feature::SDv2))
{
if (!Config::Get(Config::MAIN_ALLOW_SD_WRITES))
INFO_LOG_FMT(IOS_SD, "Writes to SD card disabled by user");
@ -83,7 +84,7 @@ void SDIOSlot0Device::EventNotify()
else
INFO_LOG_FMT(IOS_SD, "Notifying PPC of SD card removal");
m_ios.EnqueueIPCReply(m_event->request, m_event->type);
GetEmulationKernel().EnqueueIPCReply(m_event->request, m_event->type);
m_event.reset();
}
}
@ -129,7 +130,7 @@ std::optional<IPCReply> SDIOSlot0Device::Close(u32 fd)
std::optional<IPCReply> SDIOSlot0Device::IOCtl(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Memset(request.buffer_out, 0, request.buffer_out_size);
@ -190,7 +191,7 @@ s32 SDIOSlot0Device::ExecuteCommand(const Request& request, u32 buffer_in, u32 b
u32 pad0;
} req;
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
req.command = memory.Read_U32(buffer_in + 0);
@ -345,7 +346,7 @@ s32 SDIOSlot0Device::ExecuteCommand(const Request& request, u32 buffer_in, u32 b
// release returns 0
// unknown sd int
// technically we do it out of order, oh well
m_ios.EnqueueIPCReply(m_event->request, EVENT_INVALID);
GetEmulationKernel().EnqueueIPCReply(m_event->request, EVENT_INVALID);
m_event.reset();
break;
}
@ -360,7 +361,7 @@ s32 SDIOSlot0Device::ExecuteCommand(const Request& request, u32 buffer_in, u32 b
IPCReply SDIOSlot0Device::WriteHCRegister(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 reg = memory.Read_U32(request.buffer_in);
@ -395,7 +396,7 @@ IPCReply SDIOSlot0Device::WriteHCRegister(const IOCtlRequest& request)
IPCReply SDIOSlot0Device::ReadHCRegister(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 reg = memory.Read_U32(request.buffer_in);
@ -418,7 +419,7 @@ IPCReply SDIOSlot0Device::ResetCard(const IOCtlRequest& request)
{
INFO_LOG_FMT(IOS_SD, "IOCTL_RESETCARD");
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
// Returns 16bit RCA and 16bit 0s (meaning success)
@ -431,7 +432,7 @@ IPCReply SDIOSlot0Device::SetClk(const IOCtlRequest& request)
{
INFO_LOG_FMT(IOS_SD, "IOCTL_SETCLK");
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
// libogc only sets it to 1 and makes sure the return isn't negative...
@ -445,7 +446,7 @@ IPCReply SDIOSlot0Device::SetClk(const IOCtlRequest& request)
std::optional<IPCReply> SDIOSlot0Device::SendCommand(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
INFO_LOG_FMT(IOS_SD, "IOCTL_SENDCMD {:x} IPC:{:08x}", memory.Read_U32(request.buffer_in),
@ -497,7 +498,7 @@ IPCReply SDIOSlot0Device::GetStatus(const IOCtlRequest& request)
(status & CARD_INSERTED) ? "inserted" : "not present",
(status & CARD_INITIALIZED) ? " and initialized" : "");
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(status, request.buffer_out);
return IPCReply(IPC_SUCCESS);
@ -505,7 +506,7 @@ IPCReply SDIOSlot0Device::GetStatus(const IOCtlRequest& request)
IPCReply SDIOSlot0Device::GetOCRegister(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 ocr = GetOCRegister();
@ -517,7 +518,7 @@ IPCReply SDIOSlot0Device::GetOCRegister(const IOCtlRequest& request)
IPCReply SDIOSlot0Device::SendCommand(const IOCtlVRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
DEBUG_LOG_FMT(IOS_SD, "IOCTLV_SENDCMD {:#010x}", memory.Read_U32(request.in_vectors[0].address));

View file

@ -18,10 +18,10 @@ class PointerWrap;
namespace IOS::HLE
{
// The front SD slot
class SDIOSlot0Device : public Device
class SDIOSlot0Device : public EmulationDevice
{
public:
SDIOSlot0Device(Kernel& ios, const std::string& device_name);
SDIOSlot0Device(EmulationKernel& ios, const std::string& device_name);
~SDIOSlot0Device() override;
void DoState(PointerWrap& p) override;

View file

@ -18,7 +18,7 @@ static std::unique_ptr<IOCtlRequest> s_event_hook_request;
std::optional<IPCReply> STMImmediateDevice::IOCtl(const IOCtlRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
s32 return_value = IPC_SUCCESS;
@ -37,7 +37,7 @@ std::optional<IPCReply> STMImmediateDevice::IOCtl(const IOCtlRequest& request)
break;
}
memory.Write_U32(0, s_event_hook_request->buffer_out);
m_ios.EnqueueIPCReply(*s_event_hook_request, IPC_SUCCESS);
GetEmulationKernel().EnqueueIPCReply(*s_event_hook_request, IPC_SUCCESS);
s_event_hook_request.reset();
break;
@ -59,7 +59,7 @@ std::optional<IPCReply> STMImmediateDevice::IOCtl(const IOCtlRequest& request)
break;
default:
request.DumpUnknown(GetDeviceName(), Common::Log::LogType::IOS_STM);
request.DumpUnknown(GetSystem(), GetDeviceName(), Common::Log::LogType::IOS_STM);
}
return IPCReply(return_value);
@ -79,7 +79,7 @@ std::optional<IPCReply> STMEventHookDevice::IOCtl(const IOCtlRequest& request)
return IPCReply(IPC_EEXIST);
// 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>(GetSystem(), request.address);
return std::nullopt;
}
@ -89,9 +89,13 @@ void STMEventHookDevice::DoState(PointerWrap& p)
u32 address = s_event_hook_request ? s_event_hook_request->address : 0;
p.Do(address);
if (address != 0)
s_event_hook_request = std::make_unique<IOCtlRequest>(address);
{
s_event_hook_request = std::make_unique<IOCtlRequest>(GetSystem(), address);
}
else
{
s_event_hook_request.reset();
}
}
bool STMEventHookDevice::HasHookInstalled() const
@ -105,10 +109,10 @@ void STMEventHookDevice::TriggerEvent(const u32 event) const
if (!m_is_active || !s_event_hook_request)
return;
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(event, s_event_hook_request->buffer_out);
m_ios.EnqueueIPCReply(*s_event_hook_request, IPC_SUCCESS);
GetEmulationKernel().EnqueueIPCReply(*s_event_hook_request, IPC_SUCCESS);
s_event_hook_request.reset();
}

View file

@ -38,18 +38,18 @@ enum
};
// The /dev/stm/immediate
class STMImmediateDevice final : public Device
class STMImmediateDevice final : public EmulationDevice
{
public:
using Device::Device;
using EmulationDevice::EmulationDevice;
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
};
// The /dev/stm/eventhook
class STMEventHookDevice final : public Device
class STMEventHookDevice final : public EmulationDevice
{
public:
using Device::Device;
using EmulationDevice::EmulationDevice;
~STMEventHookDevice() override;
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
void DoState(PointerWrap& p) override;

View file

@ -18,10 +18,10 @@ namespace IOS::HLE
void BackUpBTInfoSection(const SysConf* sysconf);
void RestoreBTInfoSection(SysConf* sysconf);
class BluetoothBaseDevice : public Device
class BluetoothBaseDevice : public EmulationDevice
{
public:
using Device::Device;
using EmulationDevice::EmulationDevice;
virtual void UpdateSyncButtonState(bool is_held) {}
virtual void TriggerSyncButtonPressedEvent() {}
virtual void TriggerSyncButtonHeldEvent() {}

View file

@ -36,7 +36,7 @@ SQueuedEvent::SQueuedEvent(u32 size_, u16 handle) : size(size_), connection_hand
PanicAlertFmt("SQueuedEvent: The size is too large.");
}
BluetoothEmuDevice::BluetoothEmuDevice(Kernel& ios, const std::string& device_name)
BluetoothEmuDevice::BluetoothEmuDevice(EmulationKernel& ios, const std::string& device_name)
: BluetoothBaseDevice(ios, device_name)
{
SysConf sysconf{ios.GetFS()};
@ -81,13 +81,13 @@ BluetoothEmuDevice::BluetoothEmuDevice(Kernel& ios, const std::string& device_na
BluetoothEmuDevice::~BluetoothEmuDevice() = default;
template <typename T>
static void DoStateForMessage(Kernel& ios, PointerWrap& p, std::unique_ptr<T>& message)
static void DoStateForMessage(EmulationKernel& ios, PointerWrap& p, std::unique_ptr<T>& message)
{
u32 request_address = (message != nullptr) ? message->ios_request.address : 0;
p.Do(request_address);
if (request_address != 0)
{
IOCtlVRequest request{request_address};
IOCtlVRequest request{ios.GetSystem(), request_address};
message = std::make_unique<T>(ios, request);
}
}
@ -105,8 +105,8 @@ void BluetoothEmuDevice::DoState(PointerWrap& p)
Device::DoState(p);
p.Do(m_controller_bd);
DoStateForMessage(m_ios, p, m_hci_endpoint);
DoStateForMessage(m_ios, p, m_acl_endpoint);
DoStateForMessage(GetEmulationKernel(), p, m_hci_endpoint);
DoStateForMessage(GetEmulationKernel(), p, m_acl_endpoint);
p.Do(m_last_ticks);
p.DoArray(m_packet_count);
p.Do(m_scan_enable);
@ -152,19 +152,19 @@ std::optional<IPCReply> BluetoothEmuDevice::IOCtlV(const IOCtlVRequest& request)
case USB::IOCTLV_USBV0_CTRLMSG: // HCI command is received from the stack
{
// Replies are generated inside
ExecuteHCICommandMessage(USB::V0CtrlMessage(m_ios, request));
ExecuteHCICommandMessage(USB::V0CtrlMessage(GetEmulationKernel(), request));
send_reply = false;
break;
}
case USB::IOCTLV_USBV0_BLKMSG:
{
const USB::V0BulkMessage ctrl{m_ios, request};
const USB::V0BulkMessage ctrl{GetEmulationKernel(), request};
switch (ctrl.endpoint)
{
case ACL_DATA_OUT: // ACL data is received from the stack
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
// This is the ACL datapath from CPU to Wii Remote
@ -181,7 +181,7 @@ std::optional<IPCReply> BluetoothEmuDevice::IOCtlV(const IOCtlVRequest& request)
}
case ACL_DATA_IN: // We are given an ACL buffer to fill
{
m_acl_endpoint = std::make_unique<USB::V0BulkMessage>(m_ios, request);
m_acl_endpoint = std::make_unique<USB::V0BulkMessage>(GetEmulationKernel(), request);
DEBUG_LOG_FMT(IOS_WIIMOTE, "ACL_DATA_IN: {:#010x}", request.address);
send_reply = false;
break;
@ -194,10 +194,10 @@ std::optional<IPCReply> BluetoothEmuDevice::IOCtlV(const IOCtlVRequest& request)
case USB::IOCTLV_USBV0_INTRMSG:
{
const USB::V0IntrMessage ctrl{m_ios, request};
const USB::V0IntrMessage ctrl{GetEmulationKernel(), request};
if (ctrl.endpoint == HCI_EVENT) // We are given a HCI buffer to fill
{
m_hci_endpoint = std::make_unique<USB::V0IntrMessage>(m_ios, request);
m_hci_endpoint = std::make_unique<USB::V0IntrMessage>(GetEmulationKernel(), request);
DEBUG_LOG_FMT(IOS_WIIMOTE, "HCI_EVENT: {:#010x}", request.address);
send_reply = false;
}
@ -209,7 +209,7 @@ std::optional<IPCReply> BluetoothEmuDevice::IOCtlV(const IOCtlVRequest& request)
}
default:
request.DumpUnknown(GetDeviceName(), Common::Log::LogType::IOS_WIIMOTE);
request.DumpUnknown(GetSystem(), GetDeviceName(), Common::Log::LogType::IOS_WIIMOTE);
}
if (!send_reply)
@ -247,7 +247,7 @@ void BluetoothEmuDevice::SendACLPacket(const bdaddr_t& source, const u8* data, u
DEBUG_LOG_FMT(IOS_WIIMOTE, "ACL endpoint valid, sending packet to {:08x}",
m_acl_endpoint->ios_request.address);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
hci_acldata_hdr_t* header =
@ -258,7 +258,8 @@ void BluetoothEmuDevice::SendACLPacket(const bdaddr_t& source, const u8* data, u
// Write the packet to the buffer
memcpy(reinterpret_cast<u8*>(header) + sizeof(hci_acldata_hdr_t), data, header->length);
m_ios.EnqueueIPCReply(m_acl_endpoint->ios_request, sizeof(hci_acldata_hdr_t) + size);
GetEmulationKernel().EnqueueIPCReply(m_acl_endpoint->ios_request,
sizeof(hci_acldata_hdr_t) + size);
m_acl_endpoint.reset();
}
else
@ -287,7 +288,7 @@ void BluetoothEmuDevice::AddEventToQueue(const SQueuedEvent& event)
m_hci_endpoint->FillBuffer(event.buffer, event.size);
// Send a reply to indicate HCI buffer is filled
m_ios.EnqueueIPCReply(m_hci_endpoint->ios_request, event.size);
GetEmulationKernel().EnqueueIPCReply(m_hci_endpoint->ios_request, event.size);
m_hci_endpoint.reset();
}
else // push new one, pop oldest
@ -304,7 +305,7 @@ void BluetoothEmuDevice::AddEventToQueue(const SQueuedEvent& event)
m_hci_endpoint->FillBuffer(queued_event.buffer, queued_event.size);
// Send a reply to indicate HCI buffer is filled
m_ios.EnqueueIPCReply(m_hci_endpoint->ios_request, queued_event.size);
GetEmulationKernel().EnqueueIPCReply(m_hci_endpoint->ios_request, queued_event.size);
m_hci_endpoint.reset();
m_event_queue.pop_front();
}
@ -330,7 +331,7 @@ void BluetoothEmuDevice::Update()
m_hci_endpoint->FillBuffer(event.buffer, event.size);
// Send a reply to indicate HCI buffer is filled
m_ios.EnqueueIPCReply(m_hci_endpoint->ios_request, event.size);
GetEmulationKernel().EnqueueIPCReply(m_hci_endpoint->ios_request, event.size);
m_hci_endpoint.reset();
m_event_queue.pop_front();
}
@ -346,7 +347,7 @@ void BluetoothEmuDevice::Update()
wiimote->Update();
const u64 interval = SystemTimers::GetTicksPerSecond() / Wiimote::UPDATE_FREQ;
const u64 now = Core::System::GetInstance().GetCoreTiming().GetTicks();
const u64 now = GetSystem().GetCoreTiming().GetTicks();
if (now - m_last_ticks > interval)
{
@ -427,7 +428,7 @@ void BluetoothEmuDevice::ACLPool::WriteToEndpoint(const USB::V0BulkMessage& endp
DEBUG_LOG_FMT(IOS_WIIMOTE, "ACL packet being written from queue to {:08x}",
endpoint.ios_request.address);
auto& system = Core::System::GetInstance();
auto& system = m_ios.GetSystem();
auto& memory = system.GetMemory();
hci_acldata_hdr_t* header = (hci_acldata_hdr_t*)memory.GetPointer(endpoint.data_address);
@ -966,7 +967,7 @@ bool BluetoothEmuDevice::SendEventConPacketTypeChange(u16 connection_handle, u16
// This is called from the USB::IOCTLV_USBV0_CTRLMSG Ioctlv
void BluetoothEmuDevice::ExecuteHCICommandMessage(const USB::V0CtrlMessage& ctrl_message)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u8* input = memory.GetPointer(ctrl_message.data_address + 3);
@ -1149,7 +1150,7 @@ void BluetoothEmuDevice::ExecuteHCICommandMessage(const USB::V0CtrlMessage& ctrl
}
// HCI command is finished, send a reply to command
m_ios.EnqueueIPCReply(ctrl_message.ios_request, ctrl_message.length);
GetEmulationKernel().EnqueueIPCReply(ctrl_message.ios_request, ctrl_message.length);
}
//

View file

@ -39,7 +39,7 @@ struct SQueuedEvent
class BluetoothEmuDevice final : public BluetoothBaseDevice
{
public:
BluetoothEmuDevice(Kernel& ios, const std::string& device_name);
BluetoothEmuDevice(EmulationKernel& ios, const std::string& device_name);
virtual ~BluetoothEmuDevice();
@ -74,7 +74,7 @@ private:
class ACLPool
{
public:
explicit ACLPool(Kernel& ios) : m_ios(ios), m_queue() {}
explicit ACLPool(EmulationKernel& ios) : m_ios(ios), m_queue() {}
void Store(const u8* data, const u16 size, const u16 conn_handle);
void WriteToEndpoint(const USB::V0BulkMessage& endpoint);
@ -91,9 +91,9 @@ private:
u16 conn_handle;
};
Kernel& m_ios;
EmulationKernel& m_ios;
std::deque<Packet> m_queue;
} m_acl_pool{m_ios};
} m_acl_pool{GetEmulationKernel()};
u32 m_packet_count[MAX_BBMOTES] = {};
u64 m_last_ticks = 0;

View file

@ -60,7 +60,7 @@ static bool IsBluetoothDevice(const libusb_interface_descriptor& descriptor)
descriptor.bInterfaceProtocol == PROTOCOL_BLUETOOTH;
}
BluetoothRealDevice::BluetoothRealDevice(Kernel& ios, const std::string& device_name)
BluetoothRealDevice::BluetoothRealDevice(EmulationKernel& ios, const std::string& device_name)
: BluetoothBaseDevice(ios, device_name)
{
LoadLinkKeys();
@ -214,11 +214,11 @@ std::optional<IPCReply> BluetoothRealDevice::IOCtlV(const IOCtlVRequest& request
// HCI commands to the Bluetooth adapter
case USB::IOCTLV_USBV0_CTRLMSG:
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
std::lock_guard lk(m_transfers_mutex);
auto cmd = std::make_unique<USB::V0CtrlMessage>(m_ios, request);
auto cmd = std::make_unique<USB::V0CtrlMessage>(GetEmulationKernel(), request);
const u16 opcode = Common::swap16(memory.Read_U16(cmd->data_address));
if (opcode == HCI_CMD_READ_BUFFER_SIZE)
{
@ -263,7 +263,7 @@ std::optional<IPCReply> BluetoothRealDevice::IOCtlV(const IOCtlVRequest& request
case USB::IOCTLV_USBV0_INTRMSG:
{
std::lock_guard lk(m_transfers_mutex);
auto cmd = std::make_unique<USB::V0IntrMessage>(m_ios, request);
auto cmd = std::make_unique<USB::V0IntrMessage>(GetEmulationKernel(), request);
if (request.request == USB::IOCTLV_USBV0_INTRMSG)
{
if (m_sync_button_state == SyncButtonState::Pressed)
@ -347,8 +347,9 @@ void BluetoothRealDevice::DoState(PointerWrap& p)
// On load, discard any pending transfer to make sure the emulated software is not stuck
// waiting for the previous request to complete. This is usually not an issue as long as
// the Bluetooth state is the same (same Wii Remote connections).
auto& system = GetSystem();
for (const auto& address_to_discard : addresses_to_discard)
m_ios.EnqueueIPCReply(Request{address_to_discard}, 0);
GetEmulationKernel().EnqueueIPCReply(Request{system, address_to_discard}, 0);
// Prevent the callbacks from replying to a request that has already been discarded.
m_current_transfers.clear();
@ -494,7 +495,7 @@ bool BluetoothRealDevice::SendHCIStoreLinkKeyCommand()
void BluetoothRealDevice::FakeVendorCommandReply(USB::V0IntrMessage& ctrl)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
SHCIEventCommand hci_event;
@ -504,7 +505,7 @@ void BluetoothRealDevice::FakeVendorCommandReply(USB::V0IntrMessage& ctrl)
hci_event.PacketIndicator = 0x01;
hci_event.Opcode = m_fake_vendor_command_reply_opcode;
memory.CopyToEmu(ctrl.data_address, &hci_event, sizeof(hci_event));
m_ios.EnqueueIPCReply(ctrl.ios_request, static_cast<s32>(sizeof(hci_event)));
GetEmulationKernel().EnqueueIPCReply(ctrl.ios_request, static_cast<s32>(sizeof(hci_event)));
}
// Due to how the widcomm stack which Nintendo uses is coded, we must never
@ -514,7 +515,7 @@ void BluetoothRealDevice::FakeVendorCommandReply(USB::V0IntrMessage& ctrl)
// (including Wiimote disconnects and "event mismatch" warning messages).
void BluetoothRealDevice::FakeReadBufferSizeReply(USB::V0IntrMessage& ctrl)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
SHCIEventCommand hci_event;
@ -532,13 +533,14 @@ void BluetoothRealDevice::FakeReadBufferSizeReply(USB::V0IntrMessage& ctrl)
reply.max_sco_size = SCO_PKT_SIZE;
reply.num_sco_pkts = SCO_PKT_NUM;
memory.CopyToEmu(ctrl.data_address + sizeof(hci_event), &reply, sizeof(reply));
m_ios.EnqueueIPCReply(ctrl.ios_request, static_cast<s32>(sizeof(hci_event) + sizeof(reply)));
GetEmulationKernel().EnqueueIPCReply(ctrl.ios_request,
static_cast<s32>(sizeof(hci_event) + sizeof(reply)));
}
void BluetoothRealDevice::FakeSyncButtonEvent(USB::V0IntrMessage& ctrl, const u8* payload,
const u8 size)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
hci_event_hdr_t hci_event;
@ -547,7 +549,8 @@ void BluetoothRealDevice::FakeSyncButtonEvent(USB::V0IntrMessage& ctrl, const u8
hci_event.length = size;
memory.CopyToEmu(ctrl.data_address, &hci_event, sizeof(hci_event));
memory.CopyToEmu(ctrl.data_address + sizeof(hci_event), payload, size);
m_ios.EnqueueIPCReply(ctrl.ios_request, static_cast<s32>(sizeof(hci_event) + size));
GetEmulationKernel().EnqueueIPCReply(ctrl.ios_request,
static_cast<s32>(sizeof(hci_event) + size));
}
// When the red sync button is pressed, a HCI event is generated:
@ -694,7 +697,8 @@ void BluetoothRealDevice::HandleCtrlTransfer(libusb_transfer* tr)
}
const auto& command = m_current_transfers.at(tr).command;
command->FillBuffer(libusb_control_transfer_get_data(tr), tr->actual_length);
m_ios.EnqueueIPCReply(command->ios_request, tr->actual_length, 0, CoreTiming::FromThread::ANY);
GetEmulationKernel().EnqueueIPCReply(command->ios_request, tr->actual_length, 0,
CoreTiming::FromThread::ANY);
m_current_transfers.erase(tr);
}
@ -743,7 +747,8 @@ void BluetoothRealDevice::HandleBulkOrIntrTransfer(libusb_transfer* tr)
const auto& command = m_current_transfers.at(tr).command;
command->FillBuffer(tr->buffer, tr->actual_length);
m_ios.EnqueueIPCReply(command->ios_request, tr->actual_length, 0, CoreTiming::FromThread::ANY);
GetEmulationKernel().EnqueueIPCReply(command->ios_request, tr->actual_length, 0,
CoreTiming::FromThread::ANY);
m_current_transfers.erase(tr);
}
} // namespace IOS::HLE

View file

@ -42,7 +42,7 @@ using linkkey_t = std::array<u8, 16>;
class BluetoothRealDevice final : public BluetoothBaseDevice
{
public:
BluetoothRealDevice(Kernel& ios, const std::string& device_name);
BluetoothRealDevice(EmulationKernel& ios, const std::string& device_name);
~BluetoothRealDevice() override;
std::optional<IPCReply> Open(const OpenRequest& request) override;

View file

@ -19,7 +19,7 @@ std::unique_ptr<u8[]> TransferCommand::MakeBuffer(const size_t size) const
{
ASSERT_MSG(IOS_USB, data_address != 0, "Invalid data_address");
auto buffer = std::make_unique<u8[]>(size);
auto& system = Core::System::GetInstance();
auto& system = m_ios.GetSystem();
auto& memory = system.GetMemory();
memory.CopyFromEmu(buffer.get(), data_address, size);
return buffer;
@ -28,7 +28,7 @@ std::unique_ptr<u8[]> TransferCommand::MakeBuffer(const size_t size) const
void TransferCommand::FillBuffer(const u8* src, const size_t size) const
{
ASSERT_MSG(IOS_USB, size == 0 || data_address != 0, "Invalid data_address");
auto& system = Core::System::GetInstance();
auto& system = m_ios.GetSystem();
auto& memory = system.GetMemory();
memory.CopyToEmu(data_address, src, size);
}
@ -47,7 +47,7 @@ void TransferCommand::ScheduleTransferCompletion(s32 return_value, u32 expected_
void IsoMessage::SetPacketReturnValue(const size_t packet_num, const u16 return_value) const
{
auto& system = Core::System::GetInstance();
auto& system = m_ios.GetSystem();
auto& memory = system.GetMemory();
memory.Write_U16(return_value, static_cast<u32>(packet_sizes_addr + packet_num * sizeof(u16)));
}

View file

@ -101,7 +101,7 @@ struct TransferCommand
Request ios_request;
u32 data_address = 0;
TransferCommand(Kernel& ios, const Request& ios_request_, u32 data_address_)
TransferCommand(EmulationKernel& ios, const Request& ios_request_, u32 data_address_)
: ios_request(ios_request_), data_address(data_address_), m_ios(ios)
{
}
@ -113,8 +113,8 @@ struct TransferCommand
std::unique_ptr<u8[]> MakeBuffer(size_t size) const;
void FillBuffer(const u8* src, size_t size) const;
private:
Kernel& m_ios;
protected:
EmulationKernel& m_ios;
};
struct CtrlMessage : TransferCommand

View file

@ -0,0 +1,924 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Core/IOS/USB/Emulated/Infinity.h"
#include <array>
#include <bit>
#include <map>
#include <mutex>
#include <span>
#include <vector>
#include "Common/BitUtils.h"
#include "Common/Crypto/SHA1.h"
#include "Common/Logging/Log.h"
#include "Common/Random.h"
#include "Common/StringUtil.h"
#include "Common/Timer.h"
#include "Core/Core.h"
#include "Core/HW/Memmap.h"
#include "Core/System.h"
namespace IOS::HLE::USB
{
// Information taken from https://disneyinfinity.fandom.com/wiki/Model_Numbers
const std::array<std::pair<const char*, const u32>, 104> list_infinity_figures = {
{{"The Incredibles - Mr. Incredible", 0x0F4241},
{"Monsters University - Sulley", 0x0F4242},
{"Pirates of the Caribbean - Jack Sparrow", 0x0F4243},
{"The Lone Ranger - The Lone Ranger", 0x0F4244},
{"The Lone Ranger - Tonto", 0x0F4245},
{"Cars - Lightning McQueen", 0x0F4246},
{"Cars - Holley Shiftwell", 0x0F4247},
{"Toy Story - Buzz Lightyear", 0x0F4248},
{"Toy Story - Jessie", 0x0F4249},
{"Monsters University - Mike Wazowski", 0x0F424A},
{"The Incredibles - Mrs. Incredible", 0x0F424B},
{"Pirates of the Caribbean - Barbossa", 0x0F424C},
{"Pirates of the Caribbean - Davy Jones", 0x0F424D},
{"Monsters University - Randy", 0x0F424E},
{"The Incredibles - Syndrome", 0x0F424F},
{"Toy Story - Woody", 0x0F4250},
{"Cars - Mater", 0x0F4251},
{"The Incredibles - Dash", 0x0F4252},
{"The Incredibles - Violet", 0x0F4253},
{"Cars - Francesco Bernoulli", 0x0F4254},
{"Fantasia - Sorcerer's Apprentice Mickey", 0x0F4255},
{"The Nightmare Before Christmas - Jack Skellington", 0x0F4256},
{"Tangled - Rapunzel", 0x0F4257},
{"Frozen - Anna", 0x0F4258},
{"Frozen - Elsa", 0x0F4259},
{"Phineas and Ferb - Phineas Flynn", 0x0F425A},
{"Phineas and Ferb - Agent P", 0x0F425B},
{"Wreck-It Ralph - Wreck-It Ralph", 0x0F425C},
{"Wreck-It Ralph - Vanellope von Schweetz", 0x0F425D},
{"The Incredibles - Mr. Incredible (Crystal)", 0x0F425E},
{"Pirates of the Caribbean - Jack Sparrow (Crystal)", 0x0F425F},
{"Monsters University - Sulley (Crystal)", 0x0F4260},
{"Cars - Lightning McQueen (Crystal)", 0x0F4261},
{"The Lone Ranger - The Lone Ranger (Crystal)", 0x0F4262},
{"Toy Story - Buzz Lightyear (Crystal)", 0x0F4263},
{"Phineas and Ferb - Agent P (Crystal)", 0x0F4264},
{"Fantasia - Sorcerer's Apprentice Mickey (Crystal)", 0x0F4265},
{"Toy Story - Buzz Lightyear (Glowing)", 0x0F4266},
{"The Incredibles - Pirates of the Caribbean - Monsters University Play Set", 0x1E8481},
{"The Lone Ranger Play Set", 0x1E8482},
{"Cars Play Set", 0x1E8483},
{"Toy Story in Space Play Set", 0x1E8484},
{"Bolt - Bolt's Super Strength - Ability", 0x2DC6C3},
{"Wreck-it Ralph - Ralph's Power of Destruction - Ability", 0x2DC6C4},
{"Fantasia - Chernabog's Power - Ability", 0x2DC6C5},
{"Cars - C.H.R.O.M.E. Damage Increaser - Ability", 0x2DC6C6},
{"Phineas and Ferb - Dr. Doofenshmirtz's Damage-Inator! - Ability", 0x2DC6C7},
{"Frankenweenie - Electro-Charge - Ability", 0x2DC6C8},
{"Wreck-It Ralph - Fix-It Felix's Repair Power - Ability", 0x2DC6C9},
{"Tangled - Rapunzel's Healing - Ability", 0x2DC6CA},
{"Cars - C.H.R.O.M.E. Armor Shield - Ability", 0x2DC6CB},
{"Toy Story - Star Command Shield - Ability", 0x2DC6CC},
{"The Incredibles - Violet's Force Field - Ability", 0x2DC6CD},
{"Pirates of the Caribbean - Pieces of Eight - Ability", 0x2DC6CE},
{"DuckTales - Scrooge McDuck's Lucky Dime - Ability", 0x2DC6CF},
{"TRON - User Control Disc - Ability", 0x2DC6D0},
{"Fantasia - Mickey's Sorcerer Hat - Ability", 0x2DC6D1},
{"Toy Story - Emperor Zurg's Wrath - Ability", 0x2DC6FE},
{"The Sword in the Stone - Merlin's Summon - Ability", 0x2DC6FF},
{"Mickey Mouse Universe - Mickey's Car - Toy (Vehicle)", 0x3D0912},
{"Cinderella - Cinderella's Coach - Toy (Vehicle)", 0x3D0913},
{"The Muppets - Electric Mayhem Bus - Toy (Vehicle)", 0x3D0914},
{"101 Dalmatians - Cruella De Vil's Car - Toy (Vehicle)", 0x3D0915},
{"Toy Story - Pizza Planet Delivery Truck - Toy (Vehicle)", 0x3D0916},
{"Monsters, Inc. - Mike's New Car - Toy (Vehicle)", 0x3D0917},
{"Disney Parks - Disney Parks Parking Lot Tram - Toy (Vehicle)", 0x3D0919},
{"Peter Pan, Disney Parks - Jolly Roger - Toy (Aircraft)", 0x3D091A},
{"Dumbo, Disney Parks - Dumbo the Flying Elephant - Toy (Aircraft)", 0x3D091B},
{"Bolt - Calico Helicopter - Toy (Aircraft)", 0x3D091C},
{"Tangled - Maximus - Toy (Mount)", 0x3D091D},
{"Brave - Angus - Toy (Mount)", 0x3D091E},
{"Aladdin - Abu the Elephant - Toy (Mount)", 0x3D091F},
{"The Adventures of Ichabod and Mr. Toad - Headless Horseman's Horse - Toy (Mount)", 0x3D0920},
{"Beauty and the Beast - Phillipe - Toy (Mount)", 0x3D0921},
{"Mulan - Khan - Toy (Mount)", 0x3D0922},
{"Tarzan - Tantor - Toy (Mount)", 0x3D0923},
{"Mulan - Dragon Firework Cannon - Toy (Weapon)", 0x3D0924},
{"Lilo & Stitch - Stitch's Blaster - Toy (Weapon)", 0x3D0925},
{"Toy Story, Disney Parks - Toy Story Mania Blaster - Toy (Weapon)", 0x3D0926},
{"Alice in Wonderland - Flamingo Croquet Mallet - Toy (Weapon)", 0x3D0927},
{"Up - Carl Fredricksen's Cane - Toy (Weapon)", 0x3D0928},
{"Lilo & Stitch - Hangin' Ten Stitch With Surfboard - Toy (Hoverboard)", 0x3D0929},
{"Condorman - Condorman Glider - Toy (Glider)", 0x3D092A},
{"WALL-E - WALL-E's Fire Extinguisher - Toy (Jetpack)", 0x3D092B},
{"TRON - On the Grid - Customization (Terrain)", 0x3D092C},
{"WALL-E - WALL-E's Collection - Customization (Terrain)", 0x3D092D},
{"Wreck-It Ralph - King Candy's Dessert Toppings - Customization (Terrain)", 0x3D092E},
{"Frankenweenie - Victor's Experiments - Customization (Terrain)", 0x3D0930},
{"The Nightmare Before Christmas - Jack's Scary Decorations - Customization (Terrain)",
0x3D0931},
{"Frozen - Frozen Flourish - Customization (Terrain)", 0x3D0933},
{"Tangled - Rapunzel's Kingdom - Customization (Terrain)", 0x3D0934},
{"TRON - TRON Interface - Customization (Skydome)", 0x3D0935},
{"WALL-E - Buy N Large Atmosphere - Customization (Skydome)", 0x3D0936},
{"Wreck-It Ralph - Sugar Rush Sky - Customization (Skydome)", 0x3D0937},
{"The Nightmare Before Christmas - Halloween Town Sky - Customization (Skydome)", 0x3D093A},
{"Frozen - Chill in the Air - Customization (Skydome)", 0x3D093C},
{"Tangled - Rapunzel's Birthday Sky - Customization (Skydome)", 0x3D093D},
{"Toy Story, Disney Parks - Astro Blasters Space Cruiser - Toy (Vehicle)", 0x3D0940},
{"Finding Nemo - Marlin's Reef - Customization (Terrain)", 0x3D0941},
{"Finding Nemo - Nemo's Seascape - Customization (Skydome)", 0x3D0942},
{"Alice in Wonderland - Alice's Wonderland - Customization (Terrain)", 0x3D0943},
{"Alice in Wonderland - Tulgey Wood - Customization (Skydome)", 0x3D0944},
{"Phineas and Ferb - Tri-State Area Terrain - Customization (Terrain)", 0x3D0945},
{"Phineas and Ferb - Danville Sky - Customization (Skydome)", 0x3D0946}}};
static constexpr std::array<u8, 32> SHA1_CONSTANT = {
0xAF, 0x62, 0xD2, 0xEC, 0x04, 0x91, 0x96, 0x8C, 0xC5, 0x2A, 0x1A, 0x71, 0x65, 0xF8, 0x65, 0xFE,
0x28, 0x63, 0x29, 0x20, 0x44, 0x69, 0x73, 0x6e, 0x65, 0x79, 0x20, 0x32, 0x30, 0x31, 0x33};
static constexpr std::array<u8, 16> BLANK_BLOCK = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
InfinityUSB::InfinityUSB(EmulationKernel& ios, const std::string& device_name) : m_ios(ios)
{
m_vid = 0x0E6F;
m_pid = 0x0129;
m_id = (u64(m_vid) << 32 | u64(m_pid) << 16 | u64(9) << 8 | u64(1));
m_device_descriptor = DeviceDescriptor{0x12, 0x1, 0x200, 0x0, 0x0, 0x0, 0x20,
0x0E6F, 0x0129, 0x200, 0x1, 0x2, 0x3, 0x1};
m_config_descriptor.emplace_back(ConfigDescriptor{0x9, 0x2, 0x29, 0x1, 0x1, 0x0, 0x80, 0xFA});
m_interface_descriptor.emplace_back(
InterfaceDescriptor{0x9, 0x4, 0x0, 0x0, 0x2, 0x3, 0x0, 0x0, 0x0});
m_endpoint_descriptor.emplace_back(EndpointDescriptor{0x7, 0x5, 0x81, 0x3, 0x20, 0x1});
m_endpoint_descriptor.emplace_back(EndpointDescriptor{0x7, 0x5, 0x1, 0x3, 0x20, 0x1});
}
InfinityUSB::~InfinityUSB() = default;
DeviceDescriptor InfinityUSB::GetDeviceDescriptor() const
{
return m_device_descriptor;
}
std::vector<ConfigDescriptor> InfinityUSB::GetConfigurations() const
{
return m_config_descriptor;
}
std::vector<InterfaceDescriptor> InfinityUSB::GetInterfaces(u8 config) const
{
return m_interface_descriptor;
}
std::vector<EndpointDescriptor> InfinityUSB::GetEndpoints(u8 config, u8 interface, u8 alt) const
{
return m_endpoint_descriptor;
}
bool InfinityUSB::Attach()
{
if (m_device_attached)
{
return true;
}
DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x}] Opening device", m_vid, m_pid);
m_device_attached = true;
return true;
}
bool InfinityUSB::AttachAndChangeInterface(const u8 interface)
{
if (!Attach())
return false;
if (interface != m_active_interface)
return ChangeInterface(interface) == 0;
return true;
}
int InfinityUSB::CancelTransfer(const u8 endpoint)
{
INFO_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Cancelling transfers (endpoint {:#x})", m_vid, m_pid,
m_active_interface, endpoint);
return IPC_SUCCESS;
}
int InfinityUSB::ChangeInterface(const u8 interface)
{
DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Changing interface to {}", m_vid, m_pid,
m_active_interface, interface);
m_active_interface = interface;
return 0;
}
int InfinityUSB::GetNumberOfAltSettings(u8 interface)
{
return 0;
}
int InfinityUSB::SetAltSetting(u8 alt_setting)
{
return 0;
}
int InfinityUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
{
DEBUG_LOG_FMT(IOS_USB,
"[{:04x}:{:04x} {}] Control: bRequestType={:02x} bRequest={:02x} wValue={:04x}"
" wIndex={:04x} wLength={:04x}",
m_vid, m_pid, m_active_interface, cmd->request_type, cmd->request, cmd->value,
cmd->index, cmd->length);
return 0;
}
int InfinityUSB::SubmitTransfer(std::unique_ptr<BulkMessage> cmd)
{
DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Bulk: length={:04x} endpoint={:02x}", m_vid, m_pid,
m_active_interface, cmd->length, cmd->endpoint);
return 0;
}
int InfinityUSB::SubmitTransfer(std::unique_ptr<IntrMessage> cmd)
{
DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Interrupt: length={:04x} endpoint={:02x}", m_vid,
m_pid, m_active_interface, cmd->length, cmd->endpoint);
auto& system = m_ios.GetSystem();
auto& memory = system.GetMemory();
auto& infinity_base = system.GetInfinityBase();
u8* buf = memory.GetPointerForRange(cmd->data_address, cmd->length);
if (cmd->length != 32 || buf == nullptr)
{
ERROR_LOG_FMT(IOS_USB, "Infinity Base command invalid");
return IPC_EINVAL;
}
std::array<u8, 32> data = {};
std::array<u8, 32> response_data = {};
// First call - constant device response
if (buf[0] == 0x00)
{
m_response_list.push(std::move(cmd));
}
// Respond with data requested from FF command
else if (buf[0] == 0xAA || buf[0] == 0xAB)
{
// If a new figure has been added or removed, get the updated figure response
if (infinity_base.HasFigureBeenAddedRemoved())
{
ScheduleTransfer(std::move(cmd), infinity_base.PopAddedRemovedResponse(), 1000);
}
else if (m_queries.empty())
{
m_response_list.push(std::move(cmd));
}
else
{
ScheduleTransfer(std::move(cmd), m_queries.front(), 1000);
m_queries.pop();
}
}
else if (buf[0] == 0xFF)
{
// FF <length of packet data> <packet data> <checksum>
// <checksum> is the sum of all the bytes preceding it (including the FF and <packet length>).
//
// <packet data> consists of:
// <command> <sequence> <optional attached data>
//
// <sequence> is an auto-incrementing sequence, so that the game can match up the command
// packet with the response it goes with.
// <length of packet data> includes <command>, <sequence> and <optional attached data>, but
// not FF or <checksum>
u8 command = buf[2];
u8 sequence = buf[3];
switch (command)
{
case 0x80:
{
// Activate Base, constant response (might be specific based on device type)
response_data = {0xaa, 0x15, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x03, 0x02, 0x09, 0x09, 0x43,
0x20, 0x32, 0x62, 0x36, 0x36, 0x4b, 0x34, 0x99, 0x67, 0x31, 0x93, 0x8c};
break;
}
case 0x81:
{
// Initiate random number generation, combine the 8 big endian aligned bytes sent in the
// command in to a u64, and descramble this number, which is then used to generate
// the seed for the random number generator to align with the game. Finally, respond with a
// blank packet as this command doesn't need a response.
infinity_base.DescrambleAndSeed(buf, sequence, response_data);
break;
}
case 0x83:
{
// Respond with random generated numbers based on the seed from the 0x81 command. The next
// random number is 4 bytes, which then needs to be scrambled in to an 8 byte unsigned
// integer, and then passed back as 8 big endian aligned bytes.
infinity_base.GetNextAndScramble(sequence, response_data);
break;
}
case 0x90:
case 0x92:
case 0x93:
case 0x95:
case 0x96:
{
// Set Colors. Needs further input to actually emulate the 'colors', but none of these
// commands expect a response. Potential commands could include turning the lights on
// individual sections of the base, flashing lights, setting colors, initiating a color
// sequence etc.
infinity_base.GetBlankResponse(sequence, response_data);
break;
}
case 0xA1:
{
// A1 - Get Presence Status:
// Returns what figures, if any, are present and the order they were added.
// For each figure on the infinity base, 2 blocks are sent in the response:
// <index> <unknown>
// <index> is 20 for player 1, 30 for player 2, and 10 for the hexagonal position.
// This is also added with the order the figure was added, so 22 would indicate player one,
// which was added 3rd to the base.
// <unknown> is (for me) always 09. If nothing is on the
// infinity base, no data is sent in the response.
infinity_base.GetPresentFigures(sequence, response_data);
break;
}
case 0xA2:
{
// A2 - Read Figure Data:
// This reads a block of 16 bytes from a figure on the infinity base.
// Attached data: II BB UU
// II is the order the figure was added (00 for first, 01 for second and 02 for third etc).
// BB is the block number. 00 is block 1, 01 is block 4, 02 is block 8, and 03 is block 12).
// UU is either 00 or 01 -- not exactly sure what it indicates.
infinity_base.QueryBlock(buf[4], buf[5], response_data, sequence);
break;
}
case 0xA3:
{
// A3 - Write Figure Data:
// This writes a block of 16 bytes to a figure on the infinity base.
// Attached data: II BB UU <16 bytes>
// II is the order the figure was added (00 for first, 01 for second and 02 for third etc).
// BB is the block number. 00 is block 1, 01 is block 4, 02 is block 8, and 03 is block 12).
// UU is either 00 or 01 -- not exactly sure what it indicates.
// <16 bytes> is the raw (encrypted) 16 bytes to be sent to the figure.
infinity_base.WriteBlock(buf[4], buf[5], &buf[7], response_data, sequence);
break;
}
case 0xB4:
{
// B4 - Get Tag ID:
// This gets the tag's unique ID for a figure on the infinity base.
// The first byte is the order the figure was added (00 for first, 01 for second and 02 for
// third etc). The infinity base will respond with 7 bytes (the tag ID).
infinity_base.GetFigureIdentifier(buf[4], sequence, response_data);
break;
}
case 0xB5:
{
// Get status?
infinity_base.GetBlankResponse(sequence, response_data);
break;
}
default:
ERROR_LOG_FMT(IOS_USB, "Unhandled Infinity Base Command: {}", command);
break;
}
memcpy(data.data(), buf, 32);
ScheduleTransfer(std::move(cmd), data, 500);
if (m_response_list.empty())
{
m_queries.push(response_data);
}
else
{
ScheduleTransfer(std::move(m_response_list.front()), response_data, 1000);
m_response_list.pop();
}
}
return 0;
}
int InfinityUSB::SubmitTransfer(std::unique_ptr<IsoMessage> cmd)
{
DEBUG_LOG_FMT(IOS_USB,
"[{:04x}:{:04x} {}] Isochronous: length={:04x} endpoint={:02x} num_packets={:02x}",
m_vid, m_pid, m_active_interface, cmd->length, cmd->endpoint, cmd->num_packets);
return 0;
}
void InfinityUSB::ScheduleTransfer(std::unique_ptr<TransferCommand> command,
const std::array<u8, 32>& data, u64 expected_time_us)
{
command->FillBuffer(data.data(), 32);
command->ScheduleTransferCompletion(32, expected_time_us);
}
bool InfinityBase::HasFigureBeenAddedRemoved() const
{
return !m_figure_added_removed_response.empty();
}
std::array<u8, 32> InfinityBase::PopAddedRemovedResponse()
{
std::array<u8, 32> response = m_figure_added_removed_response.front();
m_figure_added_removed_response.pop();
return response;
}
u8 InfinityBase::GenerateChecksum(const std::array<u8, 32>& data, int num_of_bytes) const
{
int checksum = 0;
for (int i = 0; i < num_of_bytes; i++)
{
checksum += data[i];
}
return (checksum & 0xFF);
}
void InfinityBase::GetBlankResponse(u8 sequence, std::array<u8, 32>& reply_buf)
{
reply_buf[0] = 0xaa;
reply_buf[1] = 0x01;
reply_buf[2] = sequence;
reply_buf[3] = GenerateChecksum(reply_buf, 3);
}
void InfinityBase::GetPresentFigures(u8 sequence, std::array<u8, 32>& reply_buf)
{
int x = 3;
for (u8 i = 0; i < m_figures.size(); i++)
{
u8 slot = i == 0 ? 0x10 : (i > 0 && i < 4) ? 0x20 : 0x30;
if (m_figures[i].present)
{
reply_buf[x] = slot + m_figures[i].order_added;
reply_buf[x + 1] = 0x09;
x = x + 2;
}
}
reply_buf[0] = 0xaa;
reply_buf[1] = x - 2;
reply_buf[2] = sequence;
reply_buf[x] = GenerateChecksum(reply_buf, x);
}
void InfinityBase::GetFigureIdentifier(u8 fig_num, u8 sequence, std::array<u8, 32>& reply_buf)
{
std::lock_guard lock(m_infinity_mutex);
InfinityFigure& figure = GetFigureByOrder(fig_num);
reply_buf[0] = 0xaa;
reply_buf[1] = 0x09;
reply_buf[2] = sequence;
reply_buf[3] = 0x00;
if (figure.present)
{
memcpy(&reply_buf[4], figure.data.data(), 7);
}
reply_buf[11] = GenerateChecksum(reply_buf, 11);
}
void InfinityBase::QueryBlock(u8 fig_num, u8 block, std::array<u8, 32>& reply_buf, u8 sequence)
{
std::lock_guard lock(m_infinity_mutex);
InfinityFigure& figure = GetFigureByOrder(fig_num);
reply_buf[0] = 0xaa;
reply_buf[1] = 0x12;
reply_buf[2] = sequence;
reply_buf[3] = 0x00;
u8 file_block = 0;
if (block == 0)
{
file_block = 1;
}
else
{
file_block = block * 4;
}
if (figure.present && file_block < 20)
{
memcpy(&reply_buf[4], figure.data.data() + (16 * file_block), 16);
}
reply_buf[20] = GenerateChecksum(reply_buf, 20);
}
void InfinityBase::WriteBlock(u8 fig_num, u8 block, const u8* to_write_buf,
std::array<u8, 32>& reply_buf, u8 sequence)
{
std::lock_guard lock(m_infinity_mutex);
InfinityFigure& figure = GetFigureByOrder(fig_num);
reply_buf[0] = 0xaa;
reply_buf[1] = 0x02;
reply_buf[2] = sequence;
reply_buf[3] = 0x00;
u8 file_block = 0;
if (block == 0)
{
file_block = 1;
}
else
{
file_block = block * 4;
}
if (figure.present && file_block < 20)
{
memcpy(figure.data.data() + (file_block * 16), to_write_buf, 16);
figure.Save();
}
reply_buf[4] = GenerateChecksum(reply_buf, 4);
}
static u32 InfinityCRC32(const std::array<u8, 16>& buffer)
{
static constexpr std::array<u32, 256> CRC32_TABLE{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535,
0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd,
0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d,
0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac,
0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb,
0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea,
0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce,
0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409,
0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739,
0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268,
0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0,
0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8,
0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703,
0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae,
0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6,
0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d,
0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5,
0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
// Infinity figures calculate their CRC32 based on 12 bytes in the block of 16
u32 ret = 0;
for (u32 i = 0; i < 12; ++i)
{
u8 index = u8(ret & 0xFF) ^ buffer[i];
ret = ((ret >> 8) ^ CRC32_TABLE[index]);
}
return ret;
}
std::string
InfinityBase::LoadFigure(const std::array<u8, INFINITY_NUM_BLOCKS * INFINITY_BLOCK_SIZE>& buf,
File::IOFile in_file, u8 position)
{
std::lock_guard lock(m_infinity_mutex);
u8 order_added;
std::vector<u8> sha1_calc = {SHA1_CONSTANT.begin(), SHA1_CONSTANT.end() - 1};
for (int i = 0; i < 7; i++)
{
sha1_calc.push_back(buf[i]);
}
std::array<u8, 16> key = GenerateInfinityFigureKey(sha1_calc);
std::unique_ptr<Common::AES::Context> ctx = Common::AES::CreateContextDecrypt(key.data());
std::array<u8, 16> infinity_decrypted_block = {};
ctx->CryptIvZero(&buf[16], infinity_decrypted_block.data(), 16);
u32 number = u32(infinity_decrypted_block[1]) << 16 | u32(infinity_decrypted_block[2]) << 8 |
u32(infinity_decrypted_block[3]);
DEBUG_LOG_FMT(IOS_USB, "Toy Number: {}", number);
InfinityFigure& figure = m_figures[position];
figure.inf_file = std::move(in_file);
memcpy(figure.data.data(), buf.data(), figure.data.size());
figure.present = true;
if (figure.order_added == 255)
{
figure.order_added = m_figure_order;
m_figure_order++;
}
order_added = figure.order_added;
position = DeriveFigurePosition(position);
std::array<u8, 32> figure_change_response = {0xab, 0x04, position, 0x09, order_added, 0x00};
figure_change_response[6] = GenerateChecksum(figure_change_response, 6);
m_figure_added_removed_response.push(figure_change_response);
return FindFigure(number);
}
void InfinityBase::RemoveFigure(u8 position)
{
std::lock_guard lock(m_infinity_mutex);
InfinityFigure& figure = m_figures[position];
if (figure.inf_file.IsOpen())
{
figure.Save();
figure.inf_file.Close();
}
if (figure.present)
{
figure.present = false;
position = DeriveFigurePosition(position);
std::array<u8, 32> figure_change_response = {0xab, 0x04, position, 0x09, figure.order_added,
0x01};
figure_change_response[6] = GenerateChecksum(figure_change_response, 6);
m_figure_added_removed_response.push(figure_change_response);
}
}
bool InfinityBase::CreateFigure(const std::string& file_path, u32 figure_num)
{
File::IOFile inf_file(file_path, "w+b");
if (!inf_file)
{
return false;
}
// Create a 320 byte file with standard NFC read/write permissions
std::array<u8, INFINITY_NUM_BLOCKS * INFINITY_BLOCK_SIZE> file_data{};
u32 first_block = 0x17878E;
u32 other_blocks = 0x778788;
for (s8 i = 2; i >= 0; i--)
{
file_data[0x38 - i] = u8((first_block >> i * 8) & 0xFF);
}
for (u32 index = 1; index < 0x05; index++)
{
for (s8 i = 2; i >= 0; i--)
{
file_data[((index * 0x40) + 0x38) - i] = u8((other_blocks >> i * 8) & 0xFF);
}
}
// Create the vector to calculate the SHA1 hash with
std::vector<u8> sha1_calc = {SHA1_CONSTANT.begin(), SHA1_CONSTANT.end() - 1};
// Generate random UID, used for AES encrypt/decrypt
std::array<u8, 16> uid_data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x44, 0x00, 0xC2};
Common::Random::Generate(&uid_data[0], 7);
for (s8 i = 0; i < 7; i++)
{
sha1_calc.push_back(uid_data[i]);
}
std::array<u8, 16> figure_data = GenerateBlankFigureData(figure_num);
if (figure_data[1] == 0x00)
return false;
std::array<u8, 16> key = GenerateInfinityFigureKey(sha1_calc);
// Create AES Encrypt context based on AES key, use this to encrypt the character data and 4 blank
// blocks
std::unique_ptr<Common::AES::Context> ctx = Common::AES::CreateContextEncrypt(key.data());
std::array<u8, 16> encrypted_block = {};
std::array<u8, 16> encrypted_blank = {};
ctx->CryptIvZero(figure_data.data(), encrypted_block.data(), figure_data.size());
ctx->CryptIvZero(BLANK_BLOCK.data(), encrypted_blank.data(), BLANK_BLOCK.size());
// Copy encrypted data and UID data to the Figure File
memcpy(&file_data[0], uid_data.data(), uid_data.size());
memcpy(&file_data[16], encrypted_block.data(), encrypted_block.size());
memcpy(&file_data[16 * 0x04], encrypted_blank.data(), encrypted_blank.size());
memcpy(&file_data[16 * 0x08], encrypted_blank.data(), encrypted_blank.size());
memcpy(&file_data[16 * 0x0C], encrypted_blank.data(), encrypted_blank.size());
memcpy(&file_data[16 * 0x0D], encrypted_blank.data(), encrypted_blank.size());
DEBUG_LOG_FMT(IOS_USB, "File Data: \n{}", HexDump(file_data.data(), file_data.size()));
inf_file.WriteBytes(file_data.data(), file_data.size());
return true;
}
std::span<const std::pair<const char*, const u32>> InfinityBase::GetFigureList()
{
return list_infinity_figures;
}
std::string InfinityBase::FindFigure(u32 number) const
{
for (auto it = list_infinity_figures.begin(); it != list_infinity_figures.end(); it++)
{
if (it->second == number)
{
return it->first;
}
}
return "";
}
u8 InfinityBase::DeriveFigurePosition(u8 position)
{
// In the added/removed response, position needs to be 1 for the hexagon, 2 for Player 1 and
// Player 1's abilities, and 3 for Player 2 and Player 2's abilities. Abilities are in positions
// > 2 in the UI (3/5 for player 1, 4/6 for player 2) so decrement the position until < 2.
while (position > 2)
position -= 2;
position++;
return position;
}
InfinityFigure& InfinityBase::GetFigureByOrder(u8 order_added)
{
for (u8 i = 0; i < m_figures.size(); i++)
{
if (m_figures[i].order_added == order_added)
{
return m_figures[i];
}
}
// This should never reach this statement, but return 0 reference to supress warnings
ASSERT_MSG(IOS_USB, false, "Unable to find Disney Figure requested by game");
return m_figures[0];
}
std::array<u8, 16> InfinityBase::GenerateInfinityFigureKey(const std::vector<u8>& sha1_data)
{
Common::SHA1::Digest digest = Common::SHA1::CalculateDigest(sha1_data);
// Infinity AES keys are the first 16 bytes of the SHA1 Digest, every set of 4 bytes need to be
// reversed due to endianness
std::array<u8, 16> key = {};
for (int i = 0; i < 4; i++)
{
for (int x = 3; x >= 0; x--)
{
key[(3 - x) + (i * 4)] = digest[x + (i * 4)];
}
}
return key;
}
std::array<u8, 16> InfinityBase::GenerateBlankFigureData(u32 figure_num)
{
std::array<u8, 16> figure_data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xD1, 0x1F};
// Figure Number, input by end user
figure_data[1] = u8((figure_num >> 16) & 0xFF);
figure_data[2] = u8((figure_num >> 8) & 0xFF);
figure_data[3] = u8(figure_num & 0xFF);
// Manufacture date, formatted as YY/MM/DD. Set to Infinity 1.0 release date
figure_data[4] = 0x0D;
figure_data[5] = 0x08;
figure_data[6] = 0x12;
u32 checksum = InfinityCRC32(figure_data);
for (s8 i = 3; i >= 0; i--)
{
figure_data[15 - i] = u8((checksum >> i * 8) & 0xFF);
}
DEBUG_LOG_FMT(IOS_USB, "Block 1: \n{}", HexDump(figure_data.data(), 16));
return figure_data;
}
void InfinityBase::DescrambleAndSeed(u8* buf, u8 sequence, std::array<u8, 32>& reply_buf)
{
u64 value = u64(buf[4]) << 56 | u64(buf[5]) << 48 | u64(buf[6]) << 40 | u64(buf[7]) << 32 |
u64(buf[8]) << 24 | u64(buf[9]) << 16 | u64(buf[10]) << 8 | u64(buf[11]);
u32 seed = Descramble(value);
GenerateSeed(seed);
GetBlankResponse(sequence, reply_buf);
}
void InfinityBase::GetNextAndScramble(u8 sequence, std::array<u8, 32>& reply_buf)
{
u32 next_random = GetNext();
u64 scrambled_next_random = Scramble(next_random, 0);
reply_buf = {0xAA, 0x09, sequence};
reply_buf[3] = u8((scrambled_next_random >> 56) & 0xFF);
reply_buf[4] = u8((scrambled_next_random >> 48) & 0xFF);
reply_buf[5] = u8((scrambled_next_random >> 40) & 0xFF);
reply_buf[6] = u8((scrambled_next_random >> 32) & 0xFF);
reply_buf[7] = u8((scrambled_next_random >> 24) & 0xFF);
reply_buf[8] = u8((scrambled_next_random >> 16) & 0xFF);
reply_buf[9] = u8((scrambled_next_random >> 8) & 0xFF);
reply_buf[10] = u8(scrambled_next_random & 0xFF);
reply_buf[11] = GenerateChecksum(reply_buf, 11);
}
void InfinityBase::GenerateSeed(u32 seed)
{
m_random_a = 0xF1EA5EED;
m_random_b = seed;
m_random_c = seed;
m_random_d = seed;
for (int i = 0; i < 23; i++)
{
GetNext();
}
}
u32 InfinityBase::GetNext()
{
u32 a = m_random_a;
u32 b = m_random_b;
u32 c = m_random_c;
u32 ret = std::rotl(m_random_b, 27);
u32 temp = (a + ((ret ^ 0xFFFFFFFF) + 1));
b ^= std::rotl(c, 17);
a = m_random_d;
c += a;
ret = b + temp;
a += temp;
m_random_c = a;
m_random_a = b;
m_random_b = c;
m_random_d = ret;
return ret;
}
u64 InfinityBase::Scramble(u32 num_to_scramble, u32 garbage)
{
u64 mask = 0x8E55AA1B3999E8AA;
u64 ret = 0;
for (int i = 0; i < 64; i++)
{
ret <<= 1;
if ((mask & 1) != 0)
{
ret |= (num_to_scramble & 1);
num_to_scramble >>= 1;
}
else
{
ret |= (garbage & 1);
garbage >>= 1;
}
mask >>= 1;
}
return ret;
}
u32 InfinityBase::Descramble(u64 num_to_descramble)
{
u64 mask = 0x8E55AA1B3999E8AA;
u32 ret = 0;
for (int i = 0; i < 64; i++)
{
if (Common::ExtractBit(mask, 63))
{
ret = (ret << 1) | (num_to_descramble & 0x01);
}
num_to_descramble >>= 1;
mask <<= 1;
}
return ret;
}
void InfinityFigure::Save()
{
if (!inf_file)
return;
inf_file.Seek(0, File::SeekOrigin::Begin);
inf_file.WriteBytes(data.data(), 0x40 * 0x05);
}
} // namespace IOS::HLE::USB

View file

@ -0,0 +1,115 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <map>
#include <mutex>
#include <queue>
#include <span>
#include <vector>
#include "Common/CommonTypes.h"
#include "Common/IOFile.h"
#include "Core/IOS/USB/Common.h"
namespace IOS::HLE::USB
{
constexpr u8 INFINITY_NUM_BLOCKS = 0x14;
constexpr u8 INFINITY_BLOCK_SIZE = 0x10;
struct InfinityFigure final
{
void Save();
File::IOFile inf_file;
std::array<u8, INFINITY_NUM_BLOCKS * INFINITY_BLOCK_SIZE> data{};
bool present = false;
u8 order_added = 255;
};
class InfinityUSB final : public Device
{
public:
InfinityUSB(EmulationKernel& ios, const std::string& device_name);
~InfinityUSB() override;
DeviceDescriptor GetDeviceDescriptor() const override;
std::vector<ConfigDescriptor> GetConfigurations() const override;
std::vector<InterfaceDescriptor> GetInterfaces(u8 config) const override;
std::vector<EndpointDescriptor> GetEndpoints(u8 config, u8 interface, u8 alt) const override;
bool Attach() override;
bool AttachAndChangeInterface(u8 interface) override;
int CancelTransfer(u8 endpoint) override;
int ChangeInterface(u8 interface) override;
int GetNumberOfAltSettings(u8 interface) override;
int SetAltSetting(u8 alt_setting) override;
int SubmitTransfer(std::unique_ptr<CtrlMessage> message) override;
int SubmitTransfer(std::unique_ptr<BulkMessage> message) override;
int SubmitTransfer(std::unique_ptr<IntrMessage> message) override;
int SubmitTransfer(std::unique_ptr<IsoMessage> message) override;
private:
void ScheduleTransfer(std::unique_ptr<TransferCommand> command, const std::array<u8, 32>& data,
u64 expected_time_us);
EmulationKernel& m_ios;
u16 m_vid = 0;
u16 m_pid = 0;
u8 m_active_interface = 0;
bool m_device_attached = false;
DeviceDescriptor m_device_descriptor;
std::vector<ConfigDescriptor> m_config_descriptor;
std::vector<InterfaceDescriptor> m_interface_descriptor;
std::vector<EndpointDescriptor> m_endpoint_descriptor;
std::queue<std::array<u8, 32>> m_queries;
std::queue<std::unique_ptr<IntrMessage>> m_response_list;
};
class InfinityBase final
{
public:
bool HasFigureBeenAddedRemoved() const;
std::array<u8, 32> PopAddedRemovedResponse();
void GetBlankResponse(u8 sequence, std::array<u8, 32>& reply_buf);
void GetPresentFigures(u8 sequence, std::array<u8, 32>& reply_buf);
void GetFigureIdentifier(u8 fig_num, u8 sequence, std::array<u8, 32>& reply_buf);
void QueryBlock(u8 fig_num, u8 block, std::array<u8, 32>& reply_buf, u8 sequence);
void WriteBlock(u8 fig_num, u8 block, const u8* to_write_buf, std::array<u8, 32>& reply_buf,
u8 sequence);
void DescrambleAndSeed(u8* buf, u8 sequence, std::array<u8, 32>& reply_buf);
void GetNextAndScramble(u8 sequence, std::array<u8, 32>& reply_buf);
void RemoveFigure(u8 position);
// Returns Infinity Figure name based on data from in_file param
std::string LoadFigure(const std::array<u8, INFINITY_NUM_BLOCKS * INFINITY_BLOCK_SIZE>& buf,
File::IOFile in_file, u8 position);
bool CreateFigure(const std::string& file_path, u32 character);
static std::span<const std::pair<const char*, const u32>> GetFigureList();
std::string FindFigure(u32 character) const;
protected:
std::mutex m_infinity_mutex;
std::array<InfinityFigure, 7> m_figures;
private:
InfinityFigure& GetFigureByOrder(u8 order_added);
std::array<u8, 16> GenerateInfinityFigureKey(const std::vector<u8>& sha1_data);
std::array<u8, 16> GenerateBlankFigureData(u32 figure_num);
u8 DeriveFigurePosition(u8 position);
void GenerateSeed(u32 seed);
u32 GetNext();
u64 Scramble(u32 num_to_scramble, u32 garbage);
u32 Descramble(u64 num_to_descramble);
u8 GenerateChecksum(const std::array<u8, 32>& data, int num_of_bytes) const;
// These 4 variables are state variables used during the seeding and use of the random number
// generator.
u32 m_random_a;
u32 m_random_b;
u32 m_random_c;
u32 m_random_d;
u8 m_figure_order = 0;
std::queue<std::array<u8, 32>> m_figure_added_removed_response;
};
} // namespace IOS::HLE::USB

View file

@ -471,7 +471,7 @@ const std::map<const std::pair<const u16, const u16>, const char*> list_skylande
{{3503, 0x0000}, "Kaos Trophy"},
};
SkylanderUSB::SkylanderUSB(Kernel& ios, const std::string& device_name) : m_ios(ios)
SkylanderUSB::SkylanderUSB(EmulationKernel& ios, const std::string& device_name) : m_ios(ios)
{
m_vid = 0x1430;
m_pid = 0x150;
@ -600,7 +600,7 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
else
{
// Skylander Portal Requests
auto& system = Core::System::GetInstance();
auto& system = m_ios.GetSystem();
auto& memory = system.GetMemory();
u8* buf = memory.GetPointerForRange(cmd->data_address, cmd->length);
if (cmd->length == 0 || buf == nullptr)
@ -892,7 +892,7 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<IntrMessage> cmd)
DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Interrupt: length={} endpoint={}", m_vid, m_pid,
m_active_interface, cmd->length, cmd->endpoint);
auto& system = Core::System::GetInstance();
auto& system = m_ios.GetSystem();
auto& memory = system.GetMemory();
u8* buf = memory.GetPointerForRange(cmd->data_address, cmd->length);
if (cmd->length == 0 || buf == nullptr)

View file

@ -23,7 +23,7 @@ extern const std::map<const std::pair<const u16, const u16>, const char*> list_s
class SkylanderUSB final : public Device
{
public:
SkylanderUSB(Kernel& ios, const std::string& device_name);
SkylanderUSB(EmulationKernel& ios, const std::string& device_name);
~SkylanderUSB();
DeviceDescriptor GetDeviceDescriptor() const override;
std::vector<ConfigDescriptor> GetConfigurations() const override;
@ -43,7 +43,7 @@ public:
s32 expected_count, u64 expected_time_us);
private:
Kernel& m_ios;
EmulationKernel& m_ios;
u16 m_vid = 0;
u16 m_pid = 0;
u8 m_active_interface = 0;

View file

@ -22,6 +22,7 @@
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/IOS/USB/Common.h"
#include "Core/IOS/USB/Emulated/Infinity.h"
#include "Core/IOS/USB/Emulated/Skylander.h"
#include "Core/IOS/USB/LibusbDevice.h"
#include "Core/NetPlayProto.h"
@ -29,7 +30,8 @@
namespace IOS::HLE
{
USBHost::USBHost(Kernel& ios, const std::string& device_name) : Device(ios, device_name)
USBHost::USBHost(EmulationKernel& ios, const std::string& device_name)
: EmulationDevice(ios, device_name)
{
}
@ -137,14 +139,9 @@ bool USBHost::AddNewDevices(std::set<u64>& new_devices, DeviceChangeHooks& hooks
if (whitelist.count({descriptor.idVendor, descriptor.idProduct}) == 0)
return true;
auto usb_device = std::make_unique<USB::LibusbDevice>(m_ios, device, descriptor);
if (!ShouldAddDevice(*usb_device))
return true;
const u64 id = usb_device->GetId();
new_devices.insert(id);
if (AddDevice(std::move(usb_device)) || always_add_hooks)
hooks.emplace(GetDeviceById(id), ChangeEvent::Inserted);
auto usb_device =
std::make_unique<USB::LibusbDevice>(GetEmulationKernel(), device, descriptor);
CheckAndAddDevice(std::move(usb_device), new_devices, hooks, always_add_hooks);
return true;
});
if (ret != LIBUSB_SUCCESS)
@ -190,15 +187,27 @@ void USBHost::AddEmulatedDevices(std::set<u64>& new_devices, DeviceChangeHooks&
{
if (Config::Get(Config::MAIN_EMULATE_SKYLANDER_PORTAL) && !NetPlay::IsNetPlayRunning())
{
auto skylanderportal = std::make_unique<USB::SkylanderUSB>(m_ios, "Skylander Portal");
if (ShouldAddDevice(*skylanderportal))
auto skylanderportal =
std::make_unique<USB::SkylanderUSB>(GetEmulationKernel(), "Skylander Portal");
CheckAndAddDevice(std::move(skylanderportal), new_devices, hooks, always_add_hooks);
}
if (Config::Get(Config::MAIN_EMULATE_INFINITY_BASE) && !NetPlay::IsNetPlayRunning())
{
auto infinity_base = std::make_unique<USB::InfinityUSB>(GetEmulationKernel(), "Infinity Base");
CheckAndAddDevice(std::move(infinity_base), new_devices, hooks, always_add_hooks);
}
}
void USBHost::CheckAndAddDevice(std::unique_ptr<USB::Device> device, std::set<u64>& new_devices,
DeviceChangeHooks& hooks, bool always_add_hooks)
{
if (ShouldAddDevice(*device))
{
const u64 deviceid = device->GetId();
new_devices.insert(deviceid);
if (AddDevice(std::move(device)) || always_add_hooks)
{
const u64 skyid = skylanderportal->GetId();
new_devices.insert(skyid);
if (AddDevice(std::move(skylanderportal)) || always_add_hooks)
{
hooks.emplace(GetDeviceById(skyid), ChangeEvent::Inserted);
}
hooks.emplace(GetDeviceById(deviceid), ChangeEvent::Inserted);
}
}
}

View file

@ -26,10 +26,10 @@ class PointerWrap;
namespace IOS::HLE
{
// Common base class for USB host devices (such as /dev/usb/oh0 and /dev/usb/ven).
class USBHost : public Device
class USBHost : public EmulationDevice
{
public:
USBHost(Kernel& ios, const std::string& device_name);
USBHost(EmulationKernel& ios, const std::string& device_name);
virtual ~USBHost();
std::optional<IPCReply> Open(const OpenRequest& request) override;
@ -83,6 +83,8 @@ private:
void DispatchHooks(const DeviceChangeHooks& hooks);
void AddEmulatedDevices(std::set<u64>& new_devices, DeviceChangeHooks& hooks,
bool always_add_hooks);
void CheckAndAddDevice(std::unique_ptr<USB::Device> device, std::set<u64>& new_devices,
DeviceChangeHooks& hooks, bool always_add_hooks);
bool m_has_initialised = false;
LibusbUtils::Context m_context;

View file

@ -25,7 +25,7 @@
namespace IOS::HLE::USB
{
LibusbDevice::LibusbDevice(Kernel& ios, libusb_device* device,
LibusbDevice::LibusbDevice(EmulationKernel& ios, libusb_device* device,
const libusb_device_descriptor& descriptor)
: m_ios(ios), m_device(device)
{
@ -249,7 +249,7 @@ int LibusbDevice::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
libusb_fill_control_setup(buffer.get(), cmd->request_type, cmd->request, cmd->value, cmd->index,
cmd->length);
auto& system = Core::System::GetInstance();
auto& system = m_ios.GetSystem();
auto& memory = system.GetMemory();
memory.CopyFromEmu(buffer.get() + LIBUSB_CONTROL_SETUP_SIZE, cmd->data_address, cmd->length);

View file

@ -26,7 +26,7 @@ namespace IOS::HLE::USB
class LibusbDevice final : public Device
{
public:
LibusbDevice(Kernel& ios, libusb_device* device,
LibusbDevice(EmulationKernel& ios, libusb_device* device,
const libusb_device_descriptor& device_descriptor);
~LibusbDevice();
DeviceDescriptor GetDeviceDescriptor() const override;
@ -46,7 +46,7 @@ public:
int SubmitTransfer(std::unique_ptr<IsoMessage> message) override;
private:
Kernel& m_ios;
EmulationKernel& m_ios;
std::vector<LibusbUtils::ConfigDescriptor> m_config_descriptors;
u16 m_vid = 0;

View file

@ -22,7 +22,7 @@
namespace IOS::HLE
{
OH0::OH0(Kernel& ios, const std::string& device_name) : USBHost(ios, device_name)
OH0::OH0(EmulationKernel& ios, const std::string& device_name) : USBHost(ios, device_name)
{
}
@ -93,7 +93,7 @@ IPCReply OH0::CancelInsertionHook(const IOCtlRequest& request)
if (!request.buffer_in || request.buffer_in_size != 4)
return IPCReply(IPC_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
// IOS assigns random IDs, but ours are simply the VID + PID (see RegisterInsertionHookWithID)
@ -108,7 +108,7 @@ IPCReply OH0::GetDeviceList(const IOCtlVRequest& request) const
if (!request.HasNumberOfValidVectors(2, 2))
return IPCReply(IPC_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u8 max_entries_count = memory.Read_U8(request.in_vectors[0].address);
@ -140,12 +140,13 @@ IPCReply OH0::GetRhDesca(const IOCtlRequest& request) const
if (!request.buffer_out || request.buffer_out_size != 4)
return IPCReply(IPC_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
// Based on a hardware test, this ioctl seems to return a constant value
memory.Write_U32(0x02000302, request.buffer_out);
request.Dump(GetDeviceName(), Common::Log::LogType::IOS_USB, Common::Log::LogLevel::LWARNING);
request.Dump(system, GetDeviceName(), Common::Log::LogType::IOS_USB,
Common::Log::LogLevel::LWARNING);
return IPCReply(IPC_SUCCESS);
}
@ -155,7 +156,8 @@ IPCReply OH0::GetRhPortStatus(const IOCtlVRequest& request) const
return IPCReply(IPC_EINVAL);
ERROR_LOG_FMT(IOS_USB, "Unimplemented IOCtlV: IOCTLV_USBV0_GETRHPORTSTATUS");
request.Dump(GetDeviceName(), Common::Log::LogType::IOS_USB, Common::Log::LogLevel::LERROR);
request.Dump(GetSystem(), GetDeviceName(), Common::Log::LogType::IOS_USB,
Common::Log::LogLevel::LERROR);
return IPCReply(IPC_SUCCESS);
}
@ -165,7 +167,8 @@ IPCReply OH0::SetRhPortStatus(const IOCtlVRequest& request)
return IPCReply(IPC_EINVAL);
ERROR_LOG_FMT(IOS_USB, "Unimplemented IOCtlV: IOCTLV_USBV0_SETRHPORTSTATUS");
request.Dump(GetDeviceName(), Common::Log::LogType::IOS_USB, Common::Log::LogLevel::LERROR);
request.Dump(GetSystem(), GetDeviceName(), Common::Log::LogType::IOS_USB,
Common::Log::LogLevel::LERROR);
return IPCReply(IPC_SUCCESS);
}
@ -184,7 +187,7 @@ std::optional<IPCReply> OH0::RegisterInsertionHook(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(2, 0))
return IPCReply(IPC_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u16 vid = memory.Read_U16(request.in_vectors[0].address);
@ -203,7 +206,7 @@ std::optional<IPCReply> OH0::RegisterInsertionHookWithID(const IOCtlVRequest& re
if (!request.HasNumberOfValidVectors(3, 1))
return IPCReply(IPC_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
std::lock_guard lock{m_hooks_mutex};
@ -224,7 +227,8 @@ std::optional<IPCReply> OH0::RegisterClassChangeHook(const IOCtlVRequest& reques
if (!request.HasNumberOfValidVectors(1, 0))
return IPCReply(IPC_EINVAL);
WARN_LOG_FMT(IOS_USB, "Unimplemented IOCtlV: USB::IOCTLV_USBV0_DEVICECLASSCHANGE (no reply)");
request.Dump(GetDeviceName(), Common::Log::LogType::IOS_USB, Common::Log::LogLevel::LWARNING);
request.Dump(GetSystem(), GetDeviceName(), Common::Log::LogType::IOS_USB,
Common::Log::LogLevel::LWARNING);
return std::nullopt;
}
@ -251,7 +255,8 @@ void OH0::TriggerHook(std::map<T, u32>& hooks, T value, const ReturnCode return_
const auto hook = hooks.find(value);
if (hook == hooks.end())
return;
m_ios.EnqueueIPCReply(Request{hook->second}, return_value, 0, CoreTiming::FromThread::ANY);
GetEmulationKernel().EnqueueIPCReply(Request{GetSystem(), hook->second}, return_value, 0,
CoreTiming::FromThread::ANY);
hooks.erase(hook);
}
@ -323,7 +328,7 @@ std::optional<IPCReply> OH0::DeviceIOCtlV(const u64 device_id, const IOCtlVReque
return HandleTransfer(device, request.request,
[&, this]() { return SubmitTransfer(*device, request); });
case USB::IOCTLV_USBV0_UNKNOWN_32:
request.DumpUnknown(GetDeviceName(), Common::Log::LogType::IOS_USB);
request.DumpUnknown(GetSystem(), GetDeviceName(), Common::Log::LogType::IOS_USB);
return IPCReply(IPC_SUCCESS);
default:
return IPCReply(IPC_EINVAL);
@ -332,7 +337,7 @@ std::optional<IPCReply> OH0::DeviceIOCtlV(const u64 device_id, const IOCtlVReque
s32 OH0::SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
switch (ioctlv.request)
@ -341,7 +346,8 @@ s32 OH0::SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv)
if (!ioctlv.HasNumberOfValidVectors(6, 1) ||
Common::swap16(memory.Read_U16(ioctlv.in_vectors[4].address)) != ioctlv.io_vectors[0].size)
return IPC_EINVAL;
return device.SubmitTransfer(std::make_unique<USB::V0CtrlMessage>(m_ios, ioctlv));
return device.SubmitTransfer(
std::make_unique<USB::V0CtrlMessage>(GetEmulationKernel(), ioctlv));
case USB::IOCTLV_USBV0_BLKMSG:
case USB::IOCTLV_USBV0_LBLKMSG:
@ -349,18 +355,19 @@ s32 OH0::SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv)
memory.Read_U16(ioctlv.in_vectors[1].address) != ioctlv.io_vectors[0].size)
return IPC_EINVAL;
return device.SubmitTransfer(std::make_unique<USB::V0BulkMessage>(
m_ios, ioctlv, ioctlv.request == USB::IOCTLV_USBV0_LBLKMSG));
GetEmulationKernel(), ioctlv, ioctlv.request == USB::IOCTLV_USBV0_LBLKMSG));
case USB::IOCTLV_USBV0_INTRMSG:
if (!ioctlv.HasNumberOfValidVectors(2, 1) ||
memory.Read_U16(ioctlv.in_vectors[1].address) != ioctlv.io_vectors[0].size)
return IPC_EINVAL;
return device.SubmitTransfer(std::make_unique<USB::V0IntrMessage>(m_ios, ioctlv));
return device.SubmitTransfer(
std::make_unique<USB::V0IntrMessage>(GetEmulationKernel(), ioctlv));
case USB::IOCTLV_USBV0_ISOMSG:
if (!ioctlv.HasNumberOfValidVectors(3, 2))
return IPC_EINVAL;
return device.SubmitTransfer(std::make_unique<USB::V0IsoMessage>(m_ios, ioctlv));
return device.SubmitTransfer(std::make_unique<USB::V0IsoMessage>(GetEmulationKernel(), ioctlv));
default:
return IPC_EINVAL;

View file

@ -33,7 +33,7 @@ struct DeviceInfo
class OH0 final : public USBHost
{
public:
OH0(Kernel& ios, const std::string& device_name);
OH0(EmulationKernel& ios, const std::string& device_name);
~OH0() override;
std::optional<IPCReply> Open(const OpenRequest& request) override;

View file

@ -35,7 +35,8 @@ static void GetVidPidFromDevicePath(const std::string& device_path, u16& vid, u1
ss >> pid;
}
OH0Device::OH0Device(Kernel& ios, const std::string& name) : Device(ios, name, DeviceType::OH0)
OH0Device::OH0Device(EmulationKernel& ios, const std::string& name)
: EmulationDevice(ios, name, DeviceType::OH0)
{
if (!name.empty())
GetVidPidFromDevicePath(name, m_vid, m_pid);
@ -43,7 +44,7 @@ OH0Device::OH0Device(Kernel& ios, const std::string& name) : Device(ios, name, D
void OH0Device::DoState(PointerWrap& p)
{
m_oh0 = std::static_pointer_cast<OH0>(GetIOS()->GetDeviceByName("/dev/usb/oh0"));
m_oh0 = std::static_pointer_cast<OH0>(GetEmulationKernel().GetDeviceByName("/dev/usb/oh0"));
Device::DoState(p);
p.Do(m_vid);
p.Do(m_pid);
@ -55,7 +56,7 @@ std::optional<IPCReply> OH0Device::Open(const OpenRequest& request)
if (m_vid == 0 && m_pid == 0)
return IPCReply(IPC_ENOENT);
m_oh0 = std::static_pointer_cast<OH0>(GetIOS()->GetDeviceByName("/dev/usb/oh0"));
m_oh0 = std::static_pointer_cast<OH0>(GetEmulationKernel().GetDeviceByName("/dev/usb/oh0"));
ReturnCode return_code;
std::tie(return_code, m_device_id) = m_oh0->DeviceOpen(m_vid, m_pid);

View file

@ -14,10 +14,10 @@ class PointerWrap;
namespace IOS::HLE
{
class OH0;
class OH0Device final : public Device
class OH0Device final : public EmulationDevice
{
public:
OH0Device(Kernel& ios, const std::string& device_name);
OH0Device(EmulationKernel& ios, const std::string& device_name);
std::optional<IPCReply> Open(const OpenRequest& request) override;
std::optional<IPCReply> Close(u32 fd) override;

View file

@ -13,10 +13,10 @@
namespace IOS::HLE::USB
{
V0CtrlMessage::V0CtrlMessage(Kernel& ios, const IOCtlVRequest& ioctlv)
V0CtrlMessage::V0CtrlMessage(EmulationKernel& ios, const IOCtlVRequest& ioctlv)
: CtrlMessage(ios, ioctlv, ioctlv.io_vectors[0].address)
{
auto& system = Core::System::GetInstance();
auto& system = ios.GetSystem();
auto& memory = system.GetMemory();
request_type = memory.Read_U8(ioctlv.in_vectors[0].address);
request = memory.Read_U8(ioctlv.in_vectors[1].address);
@ -25,10 +25,10 @@ V0CtrlMessage::V0CtrlMessage(Kernel& ios, const IOCtlVRequest& ioctlv)
length = Common::swap16(memory.Read_U16(ioctlv.in_vectors[4].address));
}
V0BulkMessage::V0BulkMessage(Kernel& ios, const IOCtlVRequest& ioctlv, bool long_length)
V0BulkMessage::V0BulkMessage(EmulationKernel& ios, const IOCtlVRequest& ioctlv, bool long_length)
: BulkMessage(ios, ioctlv, ioctlv.io_vectors[0].address)
{
auto& system = Core::System::GetInstance();
auto& system = ios.GetSystem();
auto& memory = system.GetMemory();
endpoint = memory.Read_U8(ioctlv.in_vectors[0].address);
if (long_length)
@ -37,19 +37,19 @@ V0BulkMessage::V0BulkMessage(Kernel& ios, const IOCtlVRequest& ioctlv, bool long
length = memory.Read_U16(ioctlv.in_vectors[1].address);
}
V0IntrMessage::V0IntrMessage(Kernel& ios, const IOCtlVRequest& ioctlv)
V0IntrMessage::V0IntrMessage(EmulationKernel& ios, const IOCtlVRequest& ioctlv)
: IntrMessage(ios, ioctlv, ioctlv.io_vectors[0].address)
{
auto& system = Core::System::GetInstance();
auto& system = ios.GetSystem();
auto& memory = system.GetMemory();
endpoint = memory.Read_U8(ioctlv.in_vectors[0].address);
length = memory.Read_U16(ioctlv.in_vectors[1].address);
}
V0IsoMessage::V0IsoMessage(Kernel& ios, const IOCtlVRequest& ioctlv)
V0IsoMessage::V0IsoMessage(EmulationKernel& ios, const IOCtlVRequest& ioctlv)
: IsoMessage(ios, ioctlv, ioctlv.io_vectors[1].address)
{
auto& system = Core::System::GetInstance();
auto& system = ios.GetSystem();
auto& memory = system.GetMemory();
endpoint = memory.Read_U8(ioctlv.in_vectors[0].address);
length = memory.Read_U16(ioctlv.in_vectors[1].address);

View file

@ -38,22 +38,22 @@ enum V0Requests
struct V0CtrlMessage final : CtrlMessage
{
V0CtrlMessage(Kernel& ios, const IOCtlVRequest& ioctlv);
V0CtrlMessage(EmulationKernel& ios, const IOCtlVRequest& ioctlv);
};
struct V0BulkMessage final : BulkMessage
{
V0BulkMessage(Kernel& ios, const IOCtlVRequest& ioctlv, bool long_length = false);
V0BulkMessage(EmulationKernel& ios, const IOCtlVRequest& ioctlv, bool long_length = false);
};
struct V0IntrMessage final : IntrMessage
{
V0IntrMessage(Kernel& ios, const IOCtlVRequest& ioctlv);
V0IntrMessage(EmulationKernel& ios, const IOCtlVRequest& ioctlv);
};
struct V0IsoMessage final : IsoMessage
{
V0IsoMessage(Kernel& ios, const IOCtlVRequest& ioctlv);
V0IsoMessage(EmulationKernel& ios, const IOCtlVRequest& ioctlv);
};
} // namespace USB
} // namespace IOS::HLE

View file

@ -46,9 +46,10 @@ struct HIDRequest
};
#pragma pack(pop)
V4CtrlMessage::V4CtrlMessage(Kernel& ios, const IOCtlRequest& ioctl) : CtrlMessage(ios, ioctl, 0)
V4CtrlMessage::V4CtrlMessage(EmulationKernel& ios, const IOCtlRequest& ioctl)
: CtrlMessage(ios, ioctl, 0)
{
auto& system = Core::System::GetInstance();
auto& system = ios.GetSystem();
auto& memory = system.GetMemory();
HIDRequest hid_request;
@ -64,10 +65,10 @@ V4CtrlMessage::V4CtrlMessage(Kernel& ios, const IOCtlRequest& ioctl) : CtrlMessa
// Since this is just a standard control request, but with additional requirements
// (US for the language and replacing non-ASCII characters with '?'),
// we can simply submit it as a usual control request.
V4GetUSStringMessage::V4GetUSStringMessage(Kernel& ios, const IOCtlRequest& ioctl)
V4GetUSStringMessage::V4GetUSStringMessage(EmulationKernel& ios, const IOCtlRequest& ioctl)
: CtrlMessage(ios, ioctl, 0)
{
auto& system = Core::System::GetInstance();
auto& system = ios.GetSystem();
auto& memory = system.GetMemory();
HIDRequest hid_request;
@ -82,18 +83,19 @@ V4GetUSStringMessage::V4GetUSStringMessage(Kernel& ios, const IOCtlRequest& ioct
void V4GetUSStringMessage::OnTransferComplete(s32 return_value) const
{
auto& system = Core::System::GetInstance();
auto& system = m_ios.GetSystem();
auto& memory = system.GetMemory();
std::string message = memory.GetString(data_address);
std::replace_if(message.begin(), message.end(), std::not_fn(IsPrintableCharacter), '?');
std::replace_if(message.begin(), message.end(), std::not_fn(Common::IsPrintableCharacter), '?');
memory.CopyToEmu(data_address, message.c_str(), message.size());
TransferCommand::OnTransferComplete(return_value);
}
V4IntrMessage::V4IntrMessage(Kernel& ios, const IOCtlRequest& ioctl) : IntrMessage(ios, ioctl, 0)
V4IntrMessage::V4IntrMessage(EmulationKernel& ios, const IOCtlRequest& ioctl)
: IntrMessage(ios, ioctl, 0)
{
auto& system = Core::System::GetInstance();
auto& system = ios.GetSystem();
auto& memory = system.GetMemory();
HIDRequest hid_request;

Some files were not shown because too many files have changed in this diff Show more