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

101
CMake/FindIconv.cmake Normal file
View file

@ -0,0 +1,101 @@
# Based on CMake's FindIconv.cmake
# Modified to prefer non-built-in iconv over the built-in one
# See https://gitlab.kitware.com/cmake/cmake/-/issues/24695 for details
# This file can be deleted once that issue has been closed and the fix has
# made it into a satisfactory number of cmake versions. FreeBSD is the only
# system known to hit this so far, so "satisfactory" can probably be defined
# as "enough that most FreeBSD users have a fixed cmake".
find_path(Iconv_INCLUDE_DIR
NAMES "iconv.h"
DOC "iconv include directory")
mark_as_advanced(Iconv_INCLUDE_DIR)
find_library(Iconv_LIBRARY
NAMES iconv libiconv
NAMES_PER_DIR
DOC "iconv library (if not in the C library)")
mark_as_advanced(Iconv_LIBRARY)
# iconv can only be provided in libc on a POSIX system.
if(UNIX AND (NOT Iconv_INCLUDE_DIR OR NOT Iconv_LIBRARY))
include(CMakePushCheckState)
include(CheckCXXSourceCompiles)
cmake_push_check_state(RESET)
# We always suppress the message here: Otherwise on supported systems
# not having iconv in their C library (e.g. those using libiconv)
# would always display a confusing "Looking for iconv - not found" message
set(CMAKE_FIND_QUIETLY TRUE)
# The following code will not work, but it's sufficient to see if it compiles.
# Note: libiconv will define the iconv functions as macros, so CheckSymbolExists
# will not yield correct results.
set(Iconv_IMPLICIT_TEST_CODE
"
#include <stddef.h>
#include <iconv.h>
int main() {
char *a, *b;
size_t i, j;
iconv_t ic;
ic = iconv_open(\"to\", \"from\");
iconv(ic, &a, &i, &b, &j);
iconv_close(ic);
}
"
)
check_cxx_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN)
cmake_pop_check_state()
if(Iconv_IS_BUILT_IN)
unset(Iconv_INCLUDE_DIR)
unset(Iconv_LIBRARY)
endif()
else()
set(Iconv_IS_BUILT_IN FALSE)
endif()
set(_Iconv_REQUIRED_VARS)
if(Iconv_IS_BUILT_IN)
set(_Iconv_REQUIRED_VARS _Iconv_IS_BUILT_IN_MSG)
set(_Iconv_IS_BUILT_IN_MSG "built in to C library")
else()
set(_Iconv_REQUIRED_VARS Iconv_LIBRARY Iconv_INCLUDE_DIR)
endif()
# NOTE: glibc's iconv.h does not define _LIBICONV_VERSION
if(Iconv_INCLUDE_DIR AND EXISTS "${Iconv_INCLUDE_DIR}/iconv.h")
file(STRINGS ${Iconv_INCLUDE_DIR}/iconv.h Iconv_VERSION_DEFINE REGEX "_LIBICONV_VERSION (.*)")
if(Iconv_VERSION_DEFINE MATCHES "(0x[A-Fa-f0-9]+)")
set(Iconv_VERSION_NUMBER "${CMAKE_MATCH_1}")
# encoding -> version number: (major<<8) + minor
math(EXPR Iconv_VERSION_MAJOR "${Iconv_VERSION_NUMBER} >> 8" OUTPUT_FORMAT HEXADECIMAL)
math(EXPR Iconv_VERSION_MINOR "${Iconv_VERSION_NUMBER} - (${Iconv_VERSION_MAJOR} << 8)" OUTPUT_FORMAT HEXADECIMAL)
math(EXPR Iconv_VERSION_MAJOR "${Iconv_VERSION_MAJOR}" OUTPUT_FORMAT DECIMAL)
math(EXPR Iconv_VERSION_MINOR "${Iconv_VERSION_MINOR}" OUTPUT_FORMAT DECIMAL)
set(Iconv_VERSION "${Iconv_VERSION_MAJOR}.${Iconv_VERSION_MINOR}")
endif()
unset(Iconv_VERSION_DEFINE)
unset(Iconv_VERSION_NUMBER)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Iconv
REQUIRED_VARS ${_Iconv_REQUIRED_VARS}
VERSION_VAR Iconv_VERSION)
if(Iconv_FOUND)
if(Iconv_IS_BUILT_IN)
set(Iconv_INCLUDE_DIRS "")
set(Iconv_LIBRARIES "")
else()
set(Iconv_INCLUDE_DIRS "${Iconv_INCLUDE_DIR}")
set(Iconv_LIBRARIES "${Iconv_LIBRARY}")
endif()
if(NOT TARGET Iconv::Iconv)
add_library(Iconv::Iconv INTERFACE IMPORTED)
set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${Iconv_INCLUDE_DIRS}")
set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_LINK_LIBRARIES "${Iconv_LIBRARIES}")
endif()
endif()

View file

@ -42,6 +42,31 @@ if (MSVC)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
set(COMPILER ${CMAKE_CXX_COMPILER_ID})
if (COMPILER STREQUAL "GNU")
set(COMPILER "GCC") # perfer printing GCC instead of GNU
endif()
# Enforce minimium compiler versions that support the c++20 features we use
set (GCC_min_version 10)
set (Clang_min_version 12)
set (AppleClang_min_version 13.0.0)
set (min_xcode_version "13.0") # corrosponding xcode version for AppleClang_min_version
set (MSVC_min_version 14.32)
set (min_vs_version "2022 17.2.3") # corrosponding Visual Studio version for MSVC_min_version
message(STATUS "Using ${COMPILER} ${CMAKE_CXX_COMPILER_VERSION}")
if ("-" STREQUAL "${${COMPILER}_min_version}-")
message(WARNING "Unknown compiler ${COMPILER}, assuming it is new enough")
else()
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${${COMPILER}_min_version})
message(FATAL_ERROR "Requires GCC ${GCC_min_version}, Clang ${Clang_min_version},"
" AppleClang ${AppleClang_min_version} (Xcode ${min_xcode_version}),"
" or MSVC ${MSVC_min_version} (Visual Studio ${min_vs_version}) or higher")
endif()
endif()
# Name of the Dolphin distributor. If you redistribute Dolphin builds (forks,
# unofficial builds) please consider identifying your distribution with a
# unique name here.
@ -260,12 +285,6 @@ else()
" Enable generic build if you really want a JIT-less binary.")
endif()
# Enforce minimum GCC version
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
message(FATAL_ERROR "Dolphin requires at least GCC 7.0 (found ${CMAKE_CXX_COMPILER_VERSION})")
endif()
if(CMAKE_GENERATOR MATCHES "Ninja")
check_and_add_flag(DIAGNOSTICS_COLOR -fdiagnostics-color)
elseif(CMAKE_GENERATOR MATCHES "Visual Studio")
@ -918,19 +937,16 @@ else()
include_directories(BEFORE Externals/curl/include)
endif()
if (NOT ANDROID)
find_library(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c)
find_path(ICONV_INCLUDE_DIR NAMES iconv.h)
if(NOT ANDROID)
find_package(Iconv)
endif()
if (NOT ANDROID AND ICONV_LIBRARIES AND ICONV_INCLUDE_DIR)
mark_as_advanced(ICONV_INCLUDE_DIR ICONV_LIBRARIES)
if(TARGET Iconv::Iconv)
message(STATUS "Using shared iconv")
else()
check_vendoring_approved(iconv)
message(STATUS "Using static iconv from Externals")
include_directories(Externals/libiconv-1.14/include)
add_subdirectory(Externals/libiconv-1.14)
set(ICONV_LIBRARIES iconv)
endif()
if(NOT ANDROID)

View file

@ -173,7 +173,8 @@ Summary:
- [Classes and Structs](#cpp-code-classes-and-structs)
## <a name="cpp-code-general"></a>General
- The codebase currently uses C++17.
- The codebase currently uses C++20, though not all compilers support all C++20 features.
- See CMakeLists.txt "Enforce minimium compiler versions" for the currently supported compilers.
- Use the [nullptr](https://en.cppreference.com/w/cpp/language/nullptr) type over the macro `NULL`.
- If a [range-based for loop](https://en.cppreference.com/w/cpp/language/range-for) can be used instead of container iterators, use it.
- Obviously, try not to use `goto` unless you have a *really* good reason for it.

View file

@ -14,3 +14,7 @@
[Video_Settings]
SafeTextureCacheColorSamples = 0
# Many areas of the game have unused vertexes, especially with cutscenes
# involving Shadow Pokémon, such as the purification cutscene.
# CPU Cull ends up greatly boosting performance for these cases.
CPUCull = True

View file

@ -19,3 +19,7 @@ MMU = True
[Video_Settings]
# Fixes garbled text.
SafeTextureCacheColorSamples = 0
# Many areas of the game have unused vertexes, especially with cutscenes
# involving Shadow Pokémon, such as the purification cutscene.
# CPU Cull ends up greatly boosting performance for these cases.
CPUCull = True

View file

@ -0,0 +1,17 @@
# RSOE4Z, RSOP4Z - Solitaire & Mahjong
[Core]
# Values set here will override the main Dolphin settings.
[OnLoad]
# Add memory patches to be loaded once on boot here.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Hacks]
BBoxEnable = True
ImmediateXFBEnable = False

Binary file not shown.

Before

Width:  |  Height:  |  Size: 926 B

@ -1 +1 @@
Subproject commit c351692490513cdb0e5a2c925aaf7ea4a9b672f4
Subproject commit 498e20dfd1343d99b9115201034bb0219801cdec

View file

@ -1,10 +1,13 @@
include_directories(include)
include_directories(libcharset/include)
set(SRCS lib/iconv.c
add_library(iconv STATIC
lib/iconv.c
lib/relocatable.c
libcharset/lib/localcharset.c
)
add_library(iconv STATIC ${SRCS})
target_include_directories(iconv
PUBLIC
include
PRIVATE
libcharset/include
)
dolphin_disable_warnings_msvc(iconv)
add_library(Iconv::Iconv ALIAS iconv)

View file

@ -48,7 +48,8 @@ option(ENABLE_ZLIB_SUPPORT "Build mbed TLS with zlib library." OFF)
option(ENABLE_PROGRAMS "Build mbed TLS programs." OFF)
option(UNSAFE_BUILD "Allow unsafe builds. These builds ARE NOT SECURE." OFF)
option(MBEDTLS_FATAL_WARNINGS "Compiler warnings treated as errors" ON)
# Dolphin: werror makes updating compilers painful
option(MBEDTLS_FATAL_WARNINGS "Compiler warnings treated as errors" OFF)
string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${CMAKE_C_COMPILER_ID}")
string(REGEX MATCH "GNU" CMAKE_COMPILER_IS_GNU "${CMAKE_C_COMPILER_ID}")
@ -233,8 +234,7 @@ endif(CMAKE_COMPILER_IS_MSVC)
if(MBEDTLS_FATAL_WARNINGS)
if(CMAKE_COMPILER_IS_MSVC)
# Dolphin/MSVC: we want to disable all warnings for externals
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
endif(CMAKE_COMPILER_IS_MSVC)
if(CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_GNU)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -39,9 +39,10 @@ Dolphin can only be installed on devices that satisfy the above requirements. At
## Building for Windows
Use the solution file `Source/dolphin-emu.sln` to build Dolphin on Windows.
Visual Studio 2022 17.2.3 or later is a hard requirement. Other compilers might be
able to build Dolphin on Windows but have not been tested and are not
recommended to be used. Git and Windows 11 SDK must be installed when building.
Dolphin targets the latest MSVC shipped with Visual Studio or Build Tools.
Other compilers might be able to build Dolphin on Windows but have not been
tested and are not recommended to be used. Git and latest Windows SDK must be
installed when building.
Make sure to pull submodules before building:
```sh
@ -53,10 +54,12 @@ The "Debug" solution configuration is significantly slower, more verbose and les
## Building for Linux and macOS
Dolphin requires [CMake](https://cmake.org/) for systems other than Windows. Many libraries are
bundled with Dolphin and used if they're not installed on your system. CMake
will inform you if a bundled library is used or if you need to install any
missing packages yourself. You may refer to the [wiki](https://github.com/dolphin-emu/dolphin/wiki/Building-for-Linux) for more information.
Dolphin requires [CMake](https://cmake.org/) for systems other than Windows.
You need a recent version of GCC or Clang with decent c++20 support. CMake will
inform you if your compiler is too old.
Many libraries are bundled with Dolphin and used if they're not installed on
your system. CMake will inform you if a bundled library is used or if you need
to install any missing packages yourself. You may refer to the [wiki](https://github.com/dolphin-emu/dolphin/wiki/Building-for-Linux) for more information.
Make sure to pull submodules before building:
```sh

View file

@ -160,7 +160,7 @@ JNIEXPORT jboolean JNICALL
Java_org_dolphinemu_dolphinemu_utils_WiiUtils_isSystemMenuInstalled(JNIEnv* env, jclass)
{
IOS::HLE::Kernel ios;
const auto tmd = ios.GetES()->FindInstalledTMD(Titles::SYSTEM_MENU);
const auto tmd = ios.GetESCore().FindInstalledTMD(Titles::SYSTEM_MENU);
return tmd.IsValid();
}
@ -169,7 +169,7 @@ JNIEXPORT jboolean JNICALL
Java_org_dolphinemu_dolphinemu_utils_WiiUtils_isSystemMenuvWii(JNIEnv* env, jclass)
{
IOS::HLE::Kernel ios;
const auto tmd = ios.GetES()->FindInstalledTMD(Titles::SYSTEM_MENU);
const auto tmd = ios.GetESCore().FindInstalledTMD(Titles::SYSTEM_MENU);
return tmd.IsvWii();
}
@ -178,7 +178,7 @@ JNIEXPORT jstring JNICALL
Java_org_dolphinemu_dolphinemu_utils_WiiUtils_getSystemMenuVersion(JNIEnv* env, jclass)
{
IOS::HLE::Kernel ios;
const auto tmd = ios.GetES()->FindInstalledTMD(Titles::SYSTEM_MENU);
const auto tmd = ios.GetESCore().FindInstalledTMD(Titles::SYSTEM_MENU);
if (!tmd.IsValid())
{

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -25,7 +25,7 @@
namespace IOS::HLE
{
static ES::TMDReader FindTMD(FSDevice& fs, const std::string& tmd_path, Ticks ticks)
static ES::TMDReader FindTMD(FSCore& fs, const std::string& tmd_path, Ticks ticks)
{
const auto fd = fs.Open(PID_KERNEL, PID_KERNEL, tmd_path, FS::Mode::Read, {}, ticks);
if (fd.Get() < 0)
@ -38,18 +38,18 @@ static ES::TMDReader FindTMD(FSDevice& fs, const std::string& tmd_path, Ticks ti
return ES::TMDReader{std::move(tmd_bytes)};
}
ES::TMDReader ESDevice::FindImportTMD(u64 title_id, Ticks ticks) const
ES::TMDReader ESCore::FindImportTMD(u64 title_id, Ticks ticks) const
{
return FindTMD(*m_ios.GetFSDevice(), Common::GetImportTitlePath(title_id) + "/content/title.tmd",
return FindTMD(m_ios.GetFSCore(), Common::GetImportTitlePath(title_id) + "/content/title.tmd",
ticks);
}
ES::TMDReader ESDevice::FindInstalledTMD(u64 title_id, Ticks ticks) const
ES::TMDReader ESCore::FindInstalledTMD(u64 title_id, Ticks ticks) const
{
return FindTMD(*m_ios.GetFSDevice(), Common::GetTMDFileName(title_id), ticks);
return FindTMD(m_ios.GetFSCore(), Common::GetTMDFileName(title_id), ticks);
}
ES::TicketReader ESDevice::FindSignedTicket(u64 title_id, std::optional<u8> desired_version) const
ES::TicketReader ESCore::FindSignedTicket(u64 title_id, std::optional<u8> desired_version) const
{
std::string path = desired_version == 1 ? Common::GetV1TicketFileName(title_id) :
Common::GetTicketFileName(title_id);
@ -125,17 +125,17 @@ static std::vector<u64> GetTitlesInTitleOrImport(FS::FileSystem* fs, const std::
return title_ids;
}
std::vector<u64> ESDevice::GetInstalledTitles() const
std::vector<u64> ESCore::GetInstalledTitles() const
{
return GetTitlesInTitleOrImport(m_ios.GetFS().get(), "/title");
}
std::vector<u64> ESDevice::GetTitleImports() const
std::vector<u64> ESCore::GetTitleImports() const
{
return GetTitlesInTitleOrImport(m_ios.GetFS().get(), "/import");
}
std::vector<u64> ESDevice::GetTitlesWithTickets() const
std::vector<u64> ESCore::GetTitlesWithTickets() const
{
const auto fs = m_ios.GetFS();
const auto entries = fs->ReadDirectory(PID_KERNEL, PID_KERNEL, "/ticket");
@ -179,7 +179,7 @@ std::vector<u64> ESDevice::GetTitlesWithTickets() const
}
std::vector<ES::Content>
ESDevice::GetStoredContentsFromTMD(const ES::TMDReader& tmd,
ESCore::GetStoredContentsFromTMD(const ES::TMDReader& tmd,
CheckContentHashes check_content_hashes) const
{
if (!tmd.IsValid())
@ -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,
std::string ESCore::GetContentPath(const u64 title_id, const ES::Content& content,
Ticks ticks) const
{
if (content.IsShared())
{
ES::SharedContentMap content_map{m_ios.GetFSDevice()};
ES::SharedContentMap content_map{m_ios.GetFSCore()};
ticks.Add(content_map.GetTicks());
return content_map.GetFilenameFromSHA1(content.sha1).value_or("");
}
@ -406,7 +406,7 @@ std::string ESDevice::GetContentPath(const u64 title_id, const ES::Content& cont
s32 ESDevice::WriteSystemFile(const std::string& path, const std::vector<u8>& data, Ticks ticks)
{
auto& fs = *m_ios.GetFSDevice();
auto& fs = GetEmulationKernel().GetFSCore();
const std::string tmp_path = "/tmp/" + PathToFileName(path);
auto result = fs.CreateFile(PID_KERNEL, PID_KERNEL, tmp_path, {},

View file

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

View file

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

View file

@ -39,7 +39,7 @@ static ReturnCode WriteTicket(FS::FileSystem* fs, const ES::TicketReader& ticket
return file->Write(raw_ticket.data(), raw_ticket.size()) ? IPC_SUCCESS : ES_EIO;
}
void ESDevice::TitleImportExportContext::DoState(PointerWrap& p)
void ESCore::TitleImportExportContext::DoState(PointerWrap& p)
{
p.Do(valid);
p.Do(key_handle);
@ -50,7 +50,7 @@ void ESDevice::TitleImportExportContext::DoState(PointerWrap& p)
p.Do(content.buffer);
}
ReturnCode ESDevice::ImportTicket(const std::vector<u8>& ticket_bytes,
ReturnCode ESCore::ImportTicket(const std::vector<u8>& ticket_bytes,
const std::vector<u8>& cert_chain, TicketImportType type,
VerifySignature verify_signature)
{
@ -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,14 +132,14 @@ 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,
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,7 +217,7 @@ 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,
ReturnCode ESCore::ImportTitleInit(Context& context, const std::vector<u8>& tmd_bytes,
const std::vector<u8>& cert_chain,
VerifySignature verify_signature)
{
@ -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,15 +338,15 @@ 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,
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);
@ -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,13 +683,13 @@ 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),
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,
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.
@ -722,19 +723,19 @@ IPCReply ESDevice::ExportTitleInit(Context& context, const IOCtlVRequest& reques
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != 8)
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
u8* tmd_bytes = memory.GetPointer(request.io_vectors[0].address);
const u32 tmd_size = request.io_vectors[0].size;
return IPCReply(ExportTitleInit(context, title_id, tmd_bytes, tmd_size,
m_title_context.tmd.GetTitleId(),
m_title_context.tmd.GetTitleFlags()));
return IPCReply(m_core.ExportTitleInit(context, title_id, tmd_bytes, tmd_size,
m_core.m_title_context.tmd.GetTitleId(),
m_core.m_title_context.tmd.GetTitleFlags()));
}
ReturnCode ESDevice::ExportContentBegin(Context& context, u64 title_id, u32 content_id)
ReturnCode ESCore::ExportContentBegin(Context& context, u64 title_id, u32 content_id)
{
context.title_import_export.content = {};
if (!context.title_import_export.valid ||
@ -771,16 +772,16 @@ IPCReply ESDevice::ExportContentBegin(Context& context, const IOCtlVRequest& req
request.in_vectors[1].size != 4)
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const u32 content_id = memory.Read_U32(request.in_vectors[1].address);
return IPCReply(ExportContentBegin(context, title_id, content_id));
return IPCReply(m_core.ExportContentBegin(context, title_id, content_id));
}
ReturnCode ESDevice::ExportContentData(Context& context, u32 content_fd, u8* data, u32 data_size)
ReturnCode ESCore::ExportContentData(Context& context, u32 content_fd, u8* data, u32 data_size)
{
if (!context.title_import_export.valid || !context.title_import_export.content.valid || !data ||
data_size == 0)
@ -822,17 +823,17 @@ IPCReply ESDevice::ExportContentData(Context& context, const IOCtlVRequest& requ
return IPCReply(ES_EINVAL);
}
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 content_fd = memory.Read_U32(request.in_vectors[0].address);
u8* data = memory.GetPointer(request.io_vectors[0].address);
const u32 bytes_to_read = request.io_vectors[0].size;
return IPCReply(ExportContentData(context, content_fd, data, bytes_to_read));
return IPCReply(m_core.ExportContentData(context, content_fd, data, bytes_to_read));
}
ReturnCode ESDevice::ExportContentEnd(Context& context, u32 content_fd)
ReturnCode ESCore::ExportContentEnd(Context& context, u32 content_fd)
{
if (!context.title_import_export.valid || !context.title_import_export.content.valid)
return ES_EINVAL;
@ -844,14 +845,14 @@ IPCReply ESDevice::ExportContentEnd(Context& context, const IOCtlVRequest& reque
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 4)
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 content_fd = memory.Read_U32(request.in_vectors[0].address);
return IPCReply(ExportContentEnd(context, content_fd));
return IPCReply(m_core.ExportContentEnd(context, content_fd));
}
ReturnCode ESDevice::ExportTitleDone(Context& context)
ReturnCode ESCore::ExportTitleDone(Context& context)
{
ResetTitleImportContext(&context, m_ios.GetIOSC());
return IPC_SUCCESS;
@ -859,12 +860,12 @@ ReturnCode ESDevice::ExportTitleDone(Context& context)
IPCReply ESDevice::ExportTitleDone(Context& context, const IOCtlVRequest& request)
{
return IPCReply(ExportTitleDone(context));
return IPCReply(m_core.ExportTitleDone(context));
}
ReturnCode ESDevice::DeleteSharedContent(const std::array<u8, 20>& sha1) const
ReturnCode ESCore::DeleteSharedContent(const std::array<u8, 20>& sha1) const
{
ES::SharedContentMap map{m_ios.GetFSDevice()};
ES::SharedContentMap map{m_ios.GetFSCore()};
const auto content_path = map.GetFilenameFromSHA1(sha1);
if (!content_path)
return ES_EINVAL;
@ -905,10 +906,10 @@ IPCReply ESDevice::DeleteSharedContent(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sha1.size())
return IPCReply(ES_EINVAL);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.CopyFromEmu(sha1.data(), request.in_vectors[0].address, request.in_vectors[0].size);
return IPCReply(DeleteSharedContent(sha1));
return IPCReply(m_core.DeleteSharedContent(sha1));
}
} // namespace IOS::HLE

View file

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

View file

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

View file

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

View file

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

View file

@ -8,7 +8,6 @@
#include <deque>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
@ -300,17 +299,15 @@ Kernel::Kernel(IOSC::ConsoleType console_type) : m_iosc(console_type)
if (m_is_responsible_for_nand_root)
Core::InitializeWiiRoot(false);
AddCoreDevices();
m_fs = FS::MakeFileSystem(IOS::HLE::FS::Location::Session, Core::GetActiveNandRedirects());
ASSERT(m_fs);
m_fs_core = std::make_unique<FSCore>(*this);
m_es_core = std::make_unique<ESCore>(*this);
}
Kernel::~Kernel()
{
{
std::lock_guard lock(m_device_map_mutex);
m_device_map.clear();
m_socket_manager.reset();
}
if (m_is_responsible_for_nand_root)
Core::ShutdownWiiRoot();
}
@ -319,7 +316,8 @@ Kernel::Kernel(u64 title_id) : m_title_id(title_id)
{
}
EmulationKernel::EmulationKernel(u64 title_id) : Kernel(title_id)
EmulationKernel::EmulationKernel(Core::System& system, u64 title_id)
: Kernel(title_id), m_system(system)
{
INFO_LOG_FMT(IOS, "Starting IOS {:016x}", title_id);
@ -332,13 +330,23 @@ EmulationKernel::EmulationKernel(u64 title_id) : Kernel(title_id)
return;
}
AddCoreDevices();
m_fs = FS::MakeFileSystem(IOS::HLE::FS::Location::Session, Core::GetActiveNandRedirects());
ASSERT(m_fs);
m_fs_core = std::make_unique<FSCore>(*this);
AddDevice(std::make_unique<FSDevice>(*this, *m_fs_core, "/dev/fs"));
m_es_core = std::make_unique<ESCore>(*this);
AddDevice(std::make_unique<ESDevice>(*this, *m_es_core, "/dev/es"));
AddStaticDevices();
}
EmulationKernel::~EmulationKernel()
{
Core::System::GetInstance().GetCoreTiming().RemoveAllEvents(s_event_enqueue);
m_device_map.clear();
m_socket_manager.reset();
}
// The title ID is a u64 where the first 32 bits are used for the title type.
@ -354,68 +362,78 @@ std::shared_ptr<FS::FileSystem> Kernel::GetFS()
return m_fs;
}
std::shared_ptr<FSDevice> Kernel::GetFSDevice()
FSCore& Kernel::GetFSCore()
{
return *m_fs_core;
}
std::shared_ptr<FSDevice> EmulationKernel::GetFSDevice()
{
return std::static_pointer_cast<FSDevice>(m_device_map.at("/dev/fs"));
}
std::shared_ptr<ESDevice> Kernel::GetES()
ESCore& Kernel::GetESCore()
{
return *m_es_core;
}
std::shared_ptr<ESDevice> EmulationKernel::GetESDevice()
{
return std::static_pointer_cast<ESDevice>(m_device_map.at("/dev/es"));
}
std::shared_ptr<WiiSockMan> Kernel::GetSocketManager()
std::shared_ptr<WiiSockMan> EmulationKernel::GetSocketManager()
{
return m_socket_manager;
}
// Since we don't have actual processes, we keep track of only the PPC's UID/GID.
// These functions roughly correspond to syscalls 0x2b, 0x2c, 0x2d, 0x2e (though only for the PPC).
void Kernel::SetUidForPPC(u32 uid)
void EmulationKernel::SetUidForPPC(u32 uid)
{
m_ppc_uid = uid;
}
u32 Kernel::GetUidForPPC() const
u32 EmulationKernel::GetUidForPPC() const
{
return m_ppc_uid;
}
void Kernel::SetGidForPPC(u16 gid)
void EmulationKernel::SetGidForPPC(u16 gid)
{
m_ppc_gid = gid;
}
u16 Kernel::GetGidForPPC() const
u16 EmulationKernel::GetGidForPPC() const
{
return m_ppc_gid;
}
static std::vector<u8> ReadBootContent(FSDevice* fs, const std::string& path, size_t max_size,
static std::vector<u8> ReadBootContent(FSCore& fs, const std::string& path, size_t max_size,
Ticks ticks = {})
{
const auto fd = fs->Open(0, 0, path, FS::Mode::Read, {}, ticks);
const auto fd = fs.Open(0, 0, path, FS::Mode::Read, {}, ticks);
if (fd.Get() < 0)
return {};
const size_t file_size = fs->GetFileStatus(fd.Get(), ticks)->size;
const size_t file_size = fs.GetFileStatus(fd.Get(), ticks)->size;
if (max_size != 0 && file_size > max_size)
return {};
std::vector<u8> buffer(file_size);
if (!fs->Read(fd.Get(), buffer.data(), buffer.size(), ticks))
if (!fs.Read(fd.Get(), buffer.data(), buffer.size(), ticks))
return {};
return buffer;
}
// This corresponds to syscall 0x41, which loads a binary from the NAND and bootstraps the PPC.
// Unlike 0x42, IOS will set up some constants in memory before booting the PPC.
bool Kernel::BootstrapPPC(Core::System& system, const std::string& boot_content_path)
bool EmulationKernel::BootstrapPPC(Core::System& system, const std::string& boot_content_path)
{
// Seeking and processing overhead is ignored as most time is spent reading from the NAND.
u64 ticks = 0;
const DolReader dol{ReadBootContent(GetFSDevice().get(), boot_content_path, 0, &ticks)};
const DolReader dol{ReadBootContent(GetFSCore(), boot_content_path, 0, &ticks)};
if (!dol.IsValid())
return false;
@ -462,11 +480,11 @@ private:
std::vector<u8> m_bytes;
};
static void FinishIOSBoot(u64 ios_title_id)
static void FinishIOSBoot(Core::System& system, u64 ios_title_id)
{
// Shut down the active IOS first before switching to the new one.
s_ios.reset();
s_ios = std::make_unique<EmulationKernel>(ios_title_id);
s_ios = std::make_unique<EmulationKernel>(system, ios_title_id);
}
static constexpr SystemTimers::TimeBaseTick GetIOSBootTicks(u32 version)
@ -484,7 +502,7 @@ 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,
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.
@ -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,
GetSystem().GetCoreTiming().ScheduleEvent(500_tbticks, s_event_enqueue,
address | ENQUEUE_REQUEST_FLAG);
}
// Called to send a reply to an IOS syscall
void Kernel::EnqueueIPCReply(const Request& request, const s32 return_value, s64 cycles_in_future,
CoreTiming::FromThread from)
void EmulationKernel::EnqueueIPCReply(const Request& request, const s32 return_value,
s64 cycles_in_future, CoreTiming::FromThread from)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(static_cast<u32>(return_value), request.address + 4);
// IOS writes back the command that was responded to in the FD field.
@ -788,7 +789,7 @@ void Kernel::EnqueueIPCReply(const Request& request, const s32 return_value, s64
system.GetCoreTiming().ScheduleEvent(cycles_in_future, s_event_enqueue, request.address, from);
}
void Kernel::HandleIPCEvent(u64 userdata)
void EmulationKernel::HandleIPCEvent(u64 userdata)
{
if (userdata & ENQUEUE_REQUEST_FLAG)
m_request_queue.push_back(static_cast<u32>(userdata));
@ -798,7 +799,7 @@ void Kernel::HandleIPCEvent(u64 userdata)
UpdateIPC();
}
void Kernel::UpdateIPC()
void EmulationKernel::UpdateIPC()
{
if (m_ipc_paused || !IsReady())
return;
@ -822,7 +823,7 @@ void Kernel::UpdateIPC()
}
}
void Kernel::UpdateDevices()
void EmulationKernel::UpdateDevices()
{
// Check if a hardware device must be updated
for (const auto& entry : m_device_map)
@ -834,7 +835,7 @@ void Kernel::UpdateDevices()
}
}
void Kernel::UpdateWantDeterminism(const bool new_want_determinism)
void EmulationKernel::UpdateWantDeterminism(const bool new_want_determinism)
{
if (m_socket_manager)
m_socket_manager->UpdateWantDeterminism(new_want_determinism);
@ -842,7 +843,7 @@ void Kernel::UpdateWantDeterminism(const bool new_want_determinism)
device.second->UpdateWantDeterminism(new_want_determinism);
}
void Kernel::DoState(PointerWrap& p)
void EmulationKernel::DoState(PointerWrap& p)
{
p.Do(m_request_queue);
p.Do(m_reply_queue);
@ -952,15 +953,15 @@ void Init()
s_event_finish_ppc_bootstrap =
core_timing.RegisterEvent("IOSFinishPPCBootstrap", FinishPPCBootstrap);
s_event_finish_ios_boot =
core_timing.RegisterEvent("IOSFinishIOSBoot", [](Core::System& system_, u64 ios_title_id,
s64) { FinishIOSBoot(ios_title_id); });
s_event_finish_ios_boot = core_timing.RegisterEvent(
"IOSFinishIOSBoot",
[](Core::System& system_, u64 ios_title_id, s64) { FinishIOSBoot(system_, ios_title_id); });
DIDevice::s_finish_executing_di_command =
core_timing.RegisterEvent("FinishDICommand", DIDevice::FinishDICommandCallback);
// Start with IOS80 to simulate part of the Wii boot process.
s_ios = std::make_unique<EmulationKernel>(Titles::SYSTEM_MENU_IOS);
s_ios = std::make_unique<EmulationKernel>(system, Titles::SYSTEM_MENU_IOS);
// On a Wii, boot2 launches the system menu IOS, which then launches the system menu
// (which bootstraps the PPC). Bootstrapping the PPC results in memory values being set up.
// This means that the constants in the 0x3100 region are always set up by the time

View file

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

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