mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-29 12:19:12 +00:00
Merge #15
This commit is contained in:
parent
7d8fe0f105
commit
871da4e307
275 changed files with 33002 additions and 27474 deletions
|
@ -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}
|
||||
)
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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); });
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
|
@ -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.");
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, {},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(¶ms, 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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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}};
|
||||
};
|
||||
|
|
|
@ -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(¤t_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(¤t_time);
|
||||
const u32 emulated_time = mktime(gm_time);
|
||||
utcdiff = s64(emulated_time - wii_utc);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
924
Source/Core/Core/IOS/USB/Emulated/Infinity.cpp
Normal file
924
Source/Core/Core/IOS/USB/Emulated/Infinity.cpp
Normal 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
|
115
Source/Core/Core/IOS/USB/Emulated/Infinity.h
Normal file
115
Source/Core/Core/IOS/USB/Emulated/Infinity.h
Normal 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
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue