Compare commits

..

32 Commits

Author SHA1 Message Date
CamilleLaVey 71cf0e0daa fix build 2026-02-14 03:41:57 -04:00
CamilleLaVey 59444d5c48 [vulkan] bump to vk 1.4 and some features to 1.4 tree 2026-02-14 03:28:00 -04:00
CamilleLaVey 3aa4fb867c [vulkan, tu] Returning timeline semaphores to turnip 2026-02-14 01:07:52 -04:00
lizzie ab1ad1dc4a [maxwell] fix divide by 0 (#3540)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3540
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-02-14 05:12:01 +01:00
CamilleLaVey 0dc64e2a48 fix build. 2026-02-14 03:46:23 +01:00
CamilleLaVey 420b002448 Revert "[texture_cache, buffer_cache] Rebuild modified pages in texture cache" 2026-02-14 03:46:23 +01:00
CamilleLaVey 413cebca20 Revert "smol change" 2026-02-14 03:46:23 +01:00
CamilleLaVey a2d830e51b [vulkan] BindVertexBuffers2EXT reset per pipeline configuration 2026-02-14 03:46:23 +01:00
CamilleLaVey 47d6360038 smol change 2026-02-14 03:46:23 +01:00
CamilleLaVey e0daa0d83d [texture_cache, buffer_cache] Rebuild modified pages in texture cache 2026-02-14 03:46:23 +01:00
lizzie c487a5cbc4 properly do tls + array pod (#3529)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3529
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-02-14 03:46:23 +01:00
CamilleLaVey 6b7e54e115 Revert "[engine, dma] Adjustment of the execution mask handling" 2026-02-14 03:46:23 +01:00
CamilleLaVey 8bbbd28f48 Revert "fix license headers" 2026-02-14 03:46:23 +01:00
CamilleLaVey ca7c1c7230 Revert "small change" 2026-02-14 03:46:23 +01:00
CamilleLaVey db10193a16 Revert "fix build" 2026-02-14 03:46:23 +01:00
CamilleLaVey 8c045a47d2 fix build 2026-02-14 03:46:23 +01:00
CamilleLaVey 616e0a93c7 small change 2026-02-14 03:46:23 +01:00
CamilleLaVey 78e7037ccc fix license headers 2026-02-14 03:46:23 +01:00
CamilleLaVey 635335fc85 [engine, dma] Adjustment of the execution mask handling 2026-02-14 03:46:23 +01:00
CamilleLaVey e35efd3db1 fix build 2026-02-14 03:46:23 +01:00
CamilleLaVey 901f556af5 [buffer_cache, memory, pipeline] Added translation entry structure and update buffer cache handling 2026-02-14 03:46:23 +01:00
CamilleLaVey ef730ed490 fix build 2026-02-14 03:46:23 +01:00
CamilleLaVey c188b6a819 [vulkan, texture_cache] Add RT's management and feedback loop tracking in texture cache 2026-02-14 03:46:23 +01:00
wildcard 476f035672 [vulkan] disable robustbufferaccess when gpu debugging is off 2026-02-14 03:46:23 +01:00
CamilleLaVey b4a1207dab Revert "[vulkan] Added dirty tracking in PushDescriptor" 2026-02-14 03:46:23 +01:00
CamilleLaVey 59c41f0746 Revert "fix building" 2026-02-14 03:46:23 +01:00
CamilleLaVey c2f0a1c786 fix building 2026-02-14 03:46:23 +01:00
CamilleLaVey a711a4e6ab [vulkan] Added dirty tracking in PushDescriptor 2026-02-14 03:46:23 +01:00
CamilleLaVey 5aa9ed4dc0 fix license headers 2026-02-14 03:46:23 +01:00
CamilleLaVey 1b8f4c2062 [common, gpu] Added a page bitset range to convert Subtract within linear operations 2026-02-14 03:46:23 +01:00
CamilleLaVey 1eaf8bb28f [buffer_cache] Adjusted PopAsyncBuffers for range management 2026-02-14 03:46:23 +01:00
CamilleLaVey 28bf78db3a [common, gpu_thread] Exchanging command queue + adjusting Subtract in the OverlapRangeSetImpl 2026-02-14 03:46:23 +01:00
194 changed files with 4814 additions and 2601 deletions
+35
View File
@@ -0,0 +1,35 @@
diff --git a/library/aesni.h b/library/aesni.h
index 754c984c79..59e27afd3e 100644
--- a/library/aesni.h
+++ b/library/aesni.h
@@ -35,7 +35,7 @@
/* GCC-like compilers: currently, we only support intrinsics if the requisite
* target flag is enabled when building the library (e.g. `gcc -mpclmul -msse2`
* or `clang -maes -mpclmul`). */
-#if (defined(__GNUC__) || defined(__clang__)) && defined(__AES__) && defined(__PCLMUL__)
+#if defined(__GNUC__) || defined(__clang__)
#define MBEDTLS_AESNI_HAVE_INTRINSICS
#endif
/* For 32-bit, we only support intrinsics */
diff --git a/library/aesni.c b/library/aesni.c
index 2857068..3e104ab 100644
--- a/library/aesni.c
+++ b/library/aesni.c
@@ -31,16 +31,14 @@
#include <immintrin.h>
#endif
-#if defined(MBEDTLS_ARCH_IS_X86)
#if defined(MBEDTLS_COMPILER_IS_GCC)
#pragma GCC push_options
#pragma GCC target ("pclmul,sse2,aes")
#define MBEDTLS_POP_TARGET_PRAGMA
-#elif defined(__clang__) && (__clang_major__ >= 5)
+#elif defined(__clang__)
#pragma clang attribute push (__attribute__((target("pclmul,sse2,aes"))), apply_to=function)
#define MBEDTLS_POP_TARGET_PRAGMA
#endif
-#endif
#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
/*
+20
View File
@@ -0,0 +1,20 @@
diff --git a/library/common.h b/library/common.h
index 50f2a29..c60d9dc 100644
--- a/library/common.h
+++ b/library/common.h
@@ -19,11 +19,11 @@
#include <stdint.h>
#include <stddef.h>
-#if defined(__ARM_NEON)
-#include <arm_neon.h>
+#if defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
+#include <arm64_neon.h>
#define MBEDTLS_HAVE_NEON_INTRINSICS
-#elif defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
-#include <arm64_neon.h>
+#elif (defined(__ANDROID__) && defined(__ARM_FP)) || defined(__ARM_NEON)
+#include <arm_neon.h>
#define MBEDTLS_HAVE_NEON_INTRINSICS
#endif
+149 -88
View File
@@ -55,23 +55,29 @@ if (YUZU_STATIC_ROOM)
set(ENABLE_UPDATE_CHECKER OFF)
set(USE_DISCORD_PRESENCE OFF)
set(BUILD_TESTING OFF)
set(ENABLE_OPENSSL OFF)
set(ENABLE_WEB_SERVICE OFF)
set(ENABLE_LIBUSB OFF)
# allow static libs for boost though
# allow static libs for boost and mbedtls though
set(Boost_USE_STATIC_LIBS ON)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
set(OPENSSL_USE_STATIC_LIBS ON)
set(MBEDTLS_LIB_SUFFIX "_static")
set(YUZU_USE_CPM ON)
set(zstd_FORCE_BUNDLED ON)
set(fmt_FORCE_BUNDLED ON)
endif()
# common network mbedtls
# common: xbyak? booost fmt lz4 zstd
# network: enet boost
# qt stuff
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
option(ENABLE_UPDATE_CHECKER "Enable update checker (for Qt and Android)" OFF)
# option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
cmake_dependent_option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF "NOT YUZU_USE_BUNDLED_QT" OFF)
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
cmake_dependent_option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
@@ -124,7 +130,12 @@ if (YUZU_STATIC_BUILD)
set(YUZU_USE_BUNDLED_OPENSSL ON)
set(HTTPLIB_USE_BROTLI_IF_AVAILABLE OFF)
## some libraries define a Library::Name_static alternative ##
set(MBEDTLS_LIB_SUFFIX _static)
elseif(APPLE)
set(YUZU_USE_CPM ON)
set(YUZU_USE_BUNDLED_FFMPEG ON)
set(YUZU_USE_BUNDLED_SDL2 ON)
set(YUZU_USE_BUNDLED_OPENSSL ON)
@@ -134,6 +145,7 @@ if (YUZU_STATIC_BUILD)
set(SPIRV-Tools_FORCE_BUNDLED ON)
set(SPIRV-Headers_FORCE_BUNDLED ON)
set(zstd_FORCE_BUNDLED ON)
set(MbedTLS_FORCE_BUNDLED ON)
endif()
endif()
@@ -186,6 +198,8 @@ if (MSVC OR ANDROID)
set(EXT_DEFAULT ON)
endif()
option(YUZU_USE_CPM "Use CPM to fetch system dependencies (fmt, boost, etc) if needed. Externals will still be fetched." ${EXT_DEFAULT})
# ffmpeg
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${PLATFORM_SUN}" "NOT WIN32 AND NOT ANDROID" OFF)
@@ -231,12 +245,30 @@ cmake_dependent_option(YUZU_USE_BUNDLED_MOLTENVK "Download bundled MoltenVK lib"
option(YUZU_DISABLE_LLVM "Disable LLVM (useful for CI)" OFF)
set(DEFAULT_ENABLE_OPENSSL ON)
if (ANDROID OR WIN32 OR APPLE OR PLATFORM_SUN OR PLATFORM_OPENBSD)
# - Windows defaults to the Schannel backend.
# - macOS defaults to the SecureTransport backend.
# - Android currently has no SSL backend as the NDK doesn't include any SSL
# library; a proper 'native' backend would have to go through Java.
# - Solaris and OpenBSD have too old backends
# But you can force builds for those platforms to use OpenSSL if you have
# your own copy of it.
set(DEFAULT_ENABLE_OPENSSL OFF)
endif()
if (ENABLE_WEB_SERVICE OR USE_DISCORD_PRESENCE)
set(DEFAULT_ENABLE_OPENSSL ON)
endif()
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL OFF)
if (EXT_DEFAULT OR PLATFORM_SUN OR PLATFORM_OPENBSD)
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL ON)
endif()
option(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" ${DEFAULT_YUZU_USE_BUNDLED_OPENSSL})
cmake_dependent_option(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" ${DEFAULT_YUZU_USE_BUNDLED_OPENSSL} "ENABLE_OPENSSL" OFF)
if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL)
AddJsonPackage(vulkan-validation-layers)
@@ -364,94 +396,123 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(RenderDoc MODULE)
# openssl funniness
if (YUZU_USE_BUNDLED_OPENSSL)
if (ENABLE_OPENSSL)
if (YUZU_USE_BUNDLED_OPENSSL)
set(BUILD_SHARED_LIBS OFF)
AddJsonPackage(openssl)
if (OpenSSL_ADDED)
add_compile_definitions(YUZU_BUNDLED_OPENSSL)
endif()
endif()
find_package(OpenSSL 1.1.1 REQUIRED)
endif()
if (YUZU_USE_CPM)
message(STATUS "Fetching needed dependencies with CPM")
set(BUILD_SHARED_LIBS OFF)
AddJsonPackage(openssl)
if (OpenSSL_ADDED)
add_compile_definitions(YUZU_BUNDLED_OPENSSL)
endif()
endif()
set(BUILD_TESTING OFF)
set(ENABLE_TESTING OFF)
find_package(OpenSSL 3 REQUIRED)
# TODO(crueter): renderdoc?
message(STATUS "Fetching needed dependencies with CPM")
# boost
set(BOOST_INCLUDE_LIBRARIES algorithm icl pool container heap asio headers process filesystem crc variant)
set(BUILD_SHARED_LIBS OFF)
set(BUILD_TESTING OFF)
set(ENABLE_TESTING OFF)
AddJsonPackage(boost)
# boost
set(BOOST_INCLUDE_LIBRARIES algorithm icl pool container heap asio headers process filesystem crc variant)
# really annoying thing where boost::headers doesn't work with cpm
# TODO(crueter) investigate
set(BOOST_NO_HEADERS ${Boost_ADDED})
AddJsonPackage(boost)
# really annoying thing where boost::headers doesn't work with cpm
# TODO(crueter) investigate
set(BOOST_NO_HEADERS ${Boost_ADDED})
if (Boost_ADDED)
if (MSVC OR ANDROID)
add_compile_definitions(YUZU_BOOST_v1)
endif()
if (NOT MSVC OR CXX_CLANG)
# boost sucks
if (PLATFORM_SUN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthreads")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthreads")
if (Boost_ADDED)
if (MSVC OR ANDROID)
add_compile_definitions(YUZU_BOOST_v1)
endif()
target_compile_options(boost_heap INTERFACE -Wno-shadow)
target_compile_options(boost_icl INTERFACE -Wno-shadow)
target_compile_options(boost_asio INTERFACE -Wno-conversion -Wno-implicit-fallthrough)
endif()
endif()
if (NOT MSVC OR CXX_CLANG)
# boost sucks
if (PLATFORM_SUN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthreads")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthreads")
endif()
# fmt
AddJsonPackage(fmt)
# lz4
AddJsonPackage(lz4)
if (lz4_ADDED)
add_library(lz4::lz4 ALIAS lz4_static)
endif()
# zstd
AddJsonPackage(zstd)
if (zstd_ADDED)
add_library(zstd::zstd ALIAS libzstd_static)
add_library(zstd::libzstd ALIAS libzstd_static)
endif()
if (NOT YUZU_STATIC_ROOM)
# nlohmann
AddJsonPackage(nlohmann)
# zlib
AddJsonPackage(zlib)
if (ZLIB_ADDED)
add_library(ZLIB::ZLIB ALIAS zlibstatic)
endif()
# Opus
AddJsonPackage(opus)
if (Opus_ADDED)
if (MSVC AND CXX_CLANG)
target_compile_options(opus PRIVATE
-Wno-implicit-function-declaration
)
target_compile_options(boost_heap INTERFACE -Wno-shadow)
target_compile_options(boost_icl INTERFACE -Wno-shadow)
target_compile_options(boost_asio INTERFACE -Wno-conversion -Wno-implicit-fallthrough)
endif()
endif()
if (NOT TARGET Opus::opus)
add_library(Opus::opus ALIAS opus)
# fmt
AddJsonPackage(fmt)
# lz4
AddJsonPackage(lz4)
if (lz4_ADDED)
add_library(lz4::lz4 ALIAS lz4_static)
endif()
# zstd
AddJsonPackage(zstd)
if (zstd_ADDED)
add_library(zstd::zstd ALIAS libzstd_static)
add_library(zstd::libzstd ALIAS libzstd_static)
endif()
if (NOT YUZU_STATIC_ROOM)
# nlohmann
AddJsonPackage(nlohmann)
# zlib
AddJsonPackage(zlib)
if (ZLIB_ADDED)
add_library(ZLIB::ZLIB ALIAS zlibstatic)
endif()
# Opus
AddJsonPackage(opus)
if (Opus_ADDED)
if (MSVC AND CXX_CLANG)
target_compile_options(opus PRIVATE
-Wno-implicit-function-declaration
)
endif()
endif()
if (NOT TARGET Opus::opus)
add_library(Opus::opus ALIAS opus)
endif()
endif()
else()
# TODO: we can probably just use CPM for this... right?
# Enforce the search mode of non-required packages for better and shorter failure messages
find_package(fmt 8 REQUIRED)
if (NOT YUZU_DISABLE_LLVM)
find_package(LLVM MODULE COMPONENTS Demangle)
endif()
find_package(nlohmann_json 3.8 REQUIRED)
find_package(lz4 REQUIRED)
find_package(RenderDoc MODULE)
find_package(stb MODULE)
find_package(Opus 1.3 MODULE REQUIRED)
find_package(ZLIB 1.2 REQUIRED)
find_package(zstd 1.5 REQUIRED MODULE)
# wow
find_package(Boost 1.57.0 CONFIG REQUIRED OPTIONAL_COMPONENTS headers context system fiber filesystem)
if (ENABLE_OPENSSL)
find_package(OpenSSL 1.1.1 REQUIRED)
endif()
endif()
@@ -513,8 +574,8 @@ message(STATUS "Platform Libraries: ${PLATFORM_LIBRARIES}")
add_subdirectory(externals)
# pass targets from externals
# TODO(crueter): CPMUtil Propagate func?
find_package(enet)
find_package(MbedTLS)
find_package(unordered_dense REQUIRED)
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
@@ -580,11 +641,11 @@ if (ENABLE_QT)
list(APPEND CMAKE_PREFIX_PATH "${Qt6_DIR}")
endif()
find_package(Qt6 CONFIG REQUIRED COMPONENTS Widgets Charts Concurrent)
find_package(Qt6 CONFIG REQUIRED COMPONENTS Widgets Concurrent)
# if (YUZU_USE_QT_MULTIMEDIA)
# find_package(Qt6 REQUIRED COMPONENTS Multimedia)
# endif()
if (YUZU_USE_QT_MULTIMEDIA)
find_package(Qt6 REQUIRED COMPONENTS Multimedia)
endif()
if (PLATFORM_LINUX OR PLATFORM_FREEBSD)
# yes Qt, we get it
@@ -619,13 +680,13 @@ if (ENABLE_QT)
## Components ##
# Best practice is to ask for all components at once, so they are from the same version
set(YUZU_QT_COMPONENTS Core Widgets Charts Concurrent)
set(YUZU_QT_COMPONENTS Core Widgets Concurrent)
if (PLATFORM_LINUX)
list(APPEND YUZU_QT_COMPONENTS DBus)
endif()
# if (YUZU_USE_QT_MULTIMEDIA)
# list(APPEND YUZU_QT_COMPONENTS Multimedia)
# endif()
if (YUZU_USE_QT_MULTIMEDIA)
list(APPEND YUZU_QT_COMPONENTS Multimedia)
endif()
if (YUZU_USE_QT_WEB_ENGINE)
list(APPEND YUZU_QT_COMPONENTS WebEngineCore WebEngineWidgets)
endif()
+4 -7
View File
@@ -36,17 +36,14 @@ set(GIT_DESC ${BUILD_VERSION})
# Also if this is a CI build, add the build name (ie: Nightly, Canary) to the scm_rev file as well
# Auto-updater metadata! Must somewhat mirror GitHub API endpoint
set(BUILD_AUTO_UPDATE_WEBSITE "https://github.com")
set(BUILD_AUTO_UPDATE_API "http://api.github.com")
if (NIGHTLY_BUILD)
set(BUILD_AUTO_UPDATE_WEBSITE "https://github.com")
set(BUILD_AUTO_UPDATE_API "api.github.com")
set(BUILD_AUTO_UPDATE_API_PATH "/repos/")
set(BUILD_AUTO_UPDATE_REPO "Eden-CI/Nightly")
set(REPO_NAME "Eden Nightly")
else()
set(BUILD_AUTO_UPDATE_WEBSITE "https://git.eden-emu.dev")
set(BUILD_AUTO_UPDATE_API "git.eden-emu.dev")
set(BUILD_AUTO_UPDATE_API_PATH "/api/v1/repos/")
set(BUILD_AUTO_UPDATE_REPO "eden-emu/eden")
set(BUILD_AUTO_UPDATE_REPO "eden-emulator/Releases")
set(REPO_NAME "Eden")
endif()
+1 -1
View File
@@ -5,7 +5,7 @@
"name": "openssl",
"repo": "crueter-ci/OpenSSL",
"version": "3.6.0-1cb0d36b39",
"min_version": "3"
"min_version": "1.1.1"
},
"boost": {
"package": "Boost",
+196 -215
View File
@@ -6,225 +6,206 @@
viewBox="0 0 512 512"
version="1.1"
id="svg7"
sodipodi:docname="base.svg.2026_01_12_14_43_47.0.svg"
inkscape:version="1.4.2 (ebf0e94, 2025-05-08)"
inkscape:export-filename="base.svg.2026_01_12_14_43_47.0.svg"
sodipodi:docname="EdenLogoLoveWhiteV3.svg"
inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
xml:space="preserve"
inkscape:export-filename="dev.eden_emu.eden.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata1">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:creator>
<cc:Agent>
<dc:title>Madeline_Dev</dc:title>
<dc:identifier>mailto:madelvidel@gmail.com</dc:identifier>
</cc:Agent>
</dc:creator>
<dc:date>2025</dc:date>
<dc:license
rdf:resource="https://www.gnu.org/licenses/gpl-3.0.html" />
<dc:rights>2025 Eden Emulator Project</dc:rights>
<dc:source>https://git.eden-emu.dev</dc:source>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs7">
<linearGradient
id="linearGradient1"
inkscape:collect="always">
<stop
style="stop-color:#ff2e88;stop-opacity:0.5;"
offset="0"
id="stop3" />
<stop
style="stop-color:#bf42f6;stop-opacity:0.5;"
offset="0.44631511"
id="stop4" />
<stop
style="stop-color:#5da5ed;stop-opacity:0.5;"
offset="0.90088946"
id="stop2" />
</linearGradient>
<linearGradient
id="linearGradient138"
inkscape:collect="always">
<stop
style="stop-color:#ff2e88;stop-opacity:1;"
offset="0"
id="stop152" />
<stop
style="stop-color:#bf42f6;stop-opacity:1;"
offset="0.44971901"
id="stop137" />
<stop
style="stop-color:#5da5ed;stop-opacity:1;"
offset="0.89793283"
id="stop138" />
</linearGradient>
<linearGradient
id="swatch37"
inkscape:swatch="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop37" />
</linearGradient>
<linearGradient
id="swatch28"
inkscape:swatch="solid">
<stop
style="stop-color:#252525;stop-opacity:1;"
offset="0"
id="stop28" />
</linearGradient>
<linearGradient
id="swatch27"
inkscape:swatch="solid">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop27" />
</linearGradient>
<linearGradient
id="swatch15"
inkscape:swatch="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop16" />
</linearGradient>
<linearGradient
id="linearGradient14"
inkscape:swatch="gradient">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop14" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop15" />
</linearGradient>
<linearGradient
id="swatch9"
inkscape:swatch="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop10" />
</linearGradient>
<linearGradient
id="swatch8"
inkscape:swatch="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop9" />
</linearGradient>
<rect
x="22.627417"
y="402.76802"
width="521.34025"
height="248.94868"
id="rect24" />
<linearGradient
id="linearGradient11"
inkscape:collect="always">
<stop
style="stop-color:#ff2e88;stop-opacity:1;"
offset="0"
id="stop11" />
<stop
style="stop-color:#bf42f6;stop-opacity:1;"
offset="0.44971901"
id="stop154" />
<stop
style="stop-color:#5da5ed;stop-opacity:1;"
offset="0.89793283"
id="stop12" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient138"
id="linearGradient6"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.118028,0,0,1.116699,-46.314723,-42.388667)"
x1="270.39996"
y1="40.000019"
x2="270.39996"
y2="494.39996"
spreadMethod="pad" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath18">
<circle
style="opacity:1;mix-blend-mode:normal;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.8382;stroke-opacity:0.566238;paint-order:stroke fill markers"
id="circle18"
cx="-246.8315"
cy="246.8338"
inkscape:label="Circle"
r="191.89999" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath22">
<circle
style="opacity:1;mix-blend-mode:normal;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.8382;stroke-opacity:0.566238;paint-order:stroke fill markers"
id="circle22"
cx="256"
cy="256"
inkscape:label="Circle"
r="191.89999" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient11"
id="linearGradient27"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-6.9401139e-5,-2.8678628)"
x1="256.00012"
y1="102.94693"
x2="256.00012"
y2="409.05307" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath128">
<circle
style="fill:none;fill-opacity:1;stroke:#03ffff;stroke-width:0;stroke-dasharray:none;stroke-opacity:1"
id="circle128"
cx="256"
cy="256"
r="192" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1"
id="linearGradient2"
x1="256"
y1="64"
x2="256"
y2="448"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.3229974,0,0,1.3214002,-82.687336,-82.290326)" />
</defs>
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.4142136"
inkscape:cx="261.62951"
inkscape:cy="230.87036"
inkscape:window-width="1920"
inkscape:window-height="1008"
inkscape:window-x="1080"
inkscape:window-y="351"
inkscape:window-maximized="1"
inkscape:current-layer="svg7" />
<path
id="path8-7"
style="display:inline;mix-blend-mode:multiply;fill:url(#linearGradient6);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2);stroke-width:3.9666;stroke-dasharray:none;stroke-opacity:0.566238;paint-order:stroke fill markers"
inkscape:label="Circle"
d="M 256,2.2792898 A 254.0155,253.71401 0 0 0 150.68475,25.115202 c 19.54414,1.070775 38.74692,5.250294 51.56848,11.647658 14.14361,7.056691 28.63804,19.185961 39.4212,29.347551 h 40.60981 c 1.03847,-0.68139 2.10297,-1.36938 3.1938,-2.05957 5.45602,-15.78533 14.79164,-43.183497 19.49612,-57.0097682 A 254.0155,253.71401 0 0 0 256,2.2792898 Z m 61.57106,7.567234 -18.26098,46.1544672 c 7.79702,-4.13918 16.35655,-7.87447 25.20671,-10.87081 23.1229,-7.828433 43.96931,-10.170904 54.94058,-10.868226 A 254.0155,253.71401 0 0 0 317.57106,9.8465238 Z m 65.39277,26.4001532 c -9.68256,4.806644 -33.05532,16.642034 -55.68217,29.863734 H 424.4677 A 254.0155,253.71401 0 0 0 382.96383,36.246677 Z M 113.90698,45.690231 A 254.0155,253.71401 0 0 0 87.532302,66.110411 H 194.2739 c -1.47402,-0.80231 -2.35141,-1.25949 -2.35141,-1.25949 l 10.4496,-11.83348 -38.40568,7.01234 c 0,1e-5 -12.21537,-4.60266 -40.17313,-12.27223 -3.45336,-0.94731 -6.75329,-1.61824 -9.8863,-2.06732 z m -36.803618,30.18635 a 254.0155,253.71401 0 0 0 -34.88372,43.090929 h 59.976738 c 18.11461,-12.04145 40.14252,-22.882149 62.31266,-24.534159 52.93006,-3.9444 70.16538,1.86342 70.16538,1.86342 0,0 -4.612,-4.8206 -14.51938,-13.36656 -2.72366,-2.34942 -6.0844,-4.77373 -9.52455,-7.05363 z m 174.472868,0 c 4.57322,4.7186 7.29716,7.83565 7.29716,7.83565 0,0 3.53501,-3.18484 9.62532,-7.83565 z m 60.27649,0 c -21.56573,15.45339 -25.4703,27.979669 -25.4703,27.979669 0,0 54.83326,-19.215729 100.70543,-0.31228 11.63986,4.79661 21.58481,10.13159 29.94832,15.42354 h 52.74419 A 254.0155,253.71401 0 0 0 434.89664,75.876581 Z M 36.250648,128.73367 A 254.0155,253.71401 0 0 0 16.372095,171.82459 H 147.45478 c 1.45695,-2.5815 3.06539,-5.08648 4.83979,-7.48982 14.23694,-19.28301 27.92088,-30.0088 36.86047,-35.6011 h -30.25323 c -5.87346,0.93472 -12.04945,1.99094 -18.28166,3.16937 -30.12936,5.69727 -81.157618,22.78945 -81.157618,22.78945 0,0 11.47125,-12.39249 29.11369,-25.95882 z m 265.630492,0 c 33.48676,11.2434 52.42799,26.78443 62.7752,43.09092 h 130.97157 a 254.0155,253.71401 0 0 0 -19.87856,-43.09092 h -44.81136 c 14.85233,11.5863 21.59948,20.9854 21.59948,20.9854 0,0 -33.5226,-12.37087 -66.0646,-20.9854 z m -45.96641,16.27007 c -1.00419,0.0106 -10.12705,0.72026 -44.98966,20.64729 -3.12132,1.78406 -6.25434,3.86182 -9.37468,6.17356 h 41.81911 c 7.17181,-17.34774 12.64083,-26.82085 12.64083,-26.82085 0,0 -0.0287,-7.1e-4 -0.0957,0 z m 14.18088,0.0465 c 0,0 -3.31228,9.32762 -7.30492,26.77438 h 51.78554 C 287.6577,146.14158 270.09561,145.0502 270.09561,145.0502 Z M 13.152456,181.59075 A 254.0155,253.71401 0 0 0 3.927651,224.68167 H 134.1447 c 0.56161,-12.72411 2.67825,-28.50188 8.61499,-43.09092 z m 176.661504,0 c -14.27121,13.10564 -27.60733,29.58761 -37.56073,43.09092 h 73.3721 c 4.47018,-16.79061 9.35068,-31.26371 13.86562,-43.09092 z m 70.85787,0 c -2.41384,11.76417 -4.9032,26.20707 -6.94831,43.09092 H 360.4832 c -8.32133,-10.88917 -20.66988,-26.17008 -36.35141,-43.09092 z m 109.17313,0 c 6.63611,15.24089 6.92441,30.5373 5.57882,43.09092 h 132.64857 a 254.0155,253.71401 0 0 0 -9.22481,-43.09092 z M 2.90181,234.44783 A 254.0155,253.71401 0 0 0 1.984498,255.9933 254.0155,253.71401 0 0 0 2.90181,277.53876 h 211.89923 c 2.25762,-15.52555 5.14325,-29.93448 8.3385,-43.09093 h -77.8863 c -6.46396,9.27617 -10.33076,15.56549 -10.33076,15.56549 0,0 -0.82623,-6.14945 -0.9354,-15.56549 z m 249.72093,0 c -1.3692,13.09684 -2.4456,27.49209 -3.02068,43.09093 h 259.49613 a 254.0155,253.71401 0 0 0 0.91731,-21.54546 254.0155,253.71401 0 0 0 -0.91731,-21.54547 H 374.02584 c -0.445,2.5469 -0.90878,4.89768 -1.32817,7.01751 0,0 -1.69726,-2.53821 -4.94056,-7.01751 z M 3.927651,287.30493 a 254.0155,253.71401 0 0 0 9.224805,43.09091 H 214.04393 c -1.29238,-15.40742 -1.57503,-30.04388 -0.41861,-43.09091 z m 245.385009,0 c -0.30355,13.54349 -0.22032,27.92598 0.36951,43.09091 h 249.16537 a 254.0155,253.71401 0 0 0 9.22481,-43.09091 z M 16.369511,340.16201 a 254.0155,253.71401 0 0 0 19.878554,43.09091 H 221.4677 c -2.69781,-14.4523 -4.96108,-29.01285 -6.4832,-43.09091 z m 233.842379,0 c 1.15864,15.47765 3.81286,29.83979 7.51679,43.09091 h 218.02325 a 254.0155,253.71401 0 0 0 19.87856,-43.09091 z M 42.217052,393.01909 a 254.0155,253.71401 0 0 0 34.88372,43.09093 H 233.09561 c -3.40902,-13.67281 -6.76794,-28.2531 -9.73902,-43.09093 z m 218.490958,0 c 5.34985,16.15926 12.22007,30.51982 19.68733,43.09093 h 154.50389 a 254.0155,253.71401 0 0 0 34.88371,-43.09093 z M 87.529722,445.87618 a 254.0155,253.71401 0 0 0 166.229968,63.8208 c -3.67805,-12.0825 -10.85464,-35.49828 -18.18088,-63.8208 z m 199.010328,0 c 17.5887,26.43772 36.99259,43.60598 47.33592,51.61309 a 254.0155,253.71401 0 0 0 90.59431,-51.61309 z" />
<path
id="path27"
style="display:inline;mix-blend-mode:multiply;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient27);stroke-width:3;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
d="m 318.98012,441.7375 c -9.87518,-6.73978 -64.39137,-49.0272 -67.68975,-127.81978 -3.69298,-88.21893 15.36468,-141.91029 15.36468,-141.91029 0,0 16.00378,0.99513 39.80316,26.53195 23.79939,25.53753 37.74965,46.43102 37.74965,46.43102 3.91262,-19.79992 12.84563,-66.32402 -60.72865,-87.55523 0,0 12.82326,-5.38883 39.3925,-3.81382 26.56907,1.57572 81.6822,21.93799 81.6822,21.93799 0,0 -14.79766,-20.63773 -49.47063,-34.94295 -34.67291,-14.30533 -76.1182,0.23644 -76.1182,0.23644 0,0 3.86959,-12.43127 27.22669,-26.38478 23.35718,-13.9537 49.27409,-26.501533 49.27409,-26.501533 0,0 -21.97854,-0.26548 -47.67725,8.44535 -6.68948,2.267506 -13.15863,5.094213 -19.05208,8.226563 l 16.05803,-40.634103 -4.4617,-1.89059 -5.1305,-0.95965 c 0,0 -11.24072,33.12428 -16.92051,49.576513 -12.13137,7.68489 -20.11005,14.87735 -20.11005,14.87735 0,0 -21.90573,-25.09227 -42.79668,-35.527803 -26.03412,-13.00525 -86.88249,-13.90359 -94.0044,10.401173 0,0 13.56804,-7.884703 34.70032,-2.080917 21.13214,5.803997 30.3644,9.287307 30.3644,9.287307 l 29.02989,-5.30681 -7.89811,8.95527 c 0,0 13.8496,7.21324 21.33822,13.68063 7.48859,6.46722 10.9757,10.11472 10.9757,10.11472 0,0 -13.02739,-4.39388 -53.03507,-1.40893 -40.00771,2.98473 -79.40016,45.60209 -79.40016,45.60209 0,0 38.57037,-12.93531 61.34393,-17.24677 22.77354,-4.31126 44.52166,-6.46757 44.52166,-6.46757 0,0 -17.23298,5.97003 -35.69792,31.00932 -18.46522,25.03987 -13.13146,64.83866 -13.13146,64.83866 0,0 29.33874,-47.7577 57.44675,-63.84249 28.10798,-16.08527 34.0799,-15.6238 34.0799,-15.6238 0,0 -22.56785,39.13486 -31.39017,101.98268 -8.03005,57.2039 26.77689,163.75449 31.1572,178.89699"
sodipodi:nodetypes="cscsccscscscsccccccscscccscscscscscsc"
inkscape:label="MainOutline"
clip-path="url(#clipPath128)"
transform="matrix(1.3229974,0,0,1.3214002,-82.687282,-82.278451)" />
</svg>
id="defs7"><linearGradient
id="swatch14"
inkscape:swatch="solid"><stop
style="stop-color:#66003b;stop-opacity:1;"
offset="0"
id="stop14" /></linearGradient><linearGradient
id="linearGradient1"
inkscape:collect="always"><stop
style="stop-color:#ffffff;stop-opacity:0.50980395;"
offset="0"
id="stop1" /><stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop2" /></linearGradient><linearGradient
id="linearGradient11"
inkscape:collect="always"><stop
style="stop-color:#9523a7;stop-opacity:0.50980395;"
offset="0"
id="stop11" /><stop
style="stop-color:#ffabad;stop-opacity:1;"
offset="0.99898213"
id="stop20" /><stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="0.99898213"
id="stop12" /></linearGradient><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient11"
id="linearGradient12"
x1="109.74531"
y1="106.54533"
x2="431.05463"
y2="427.85461"
gradientUnits="userSpaceOnUse"
spreadMethod="reflect"
gradientTransform="matrix(1.0945321,0,0,1.0945321,-39.661525,-35.159057)" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1"
id="linearGradient2"
x1="125.40197"
y1="271.834"
x2="431.02424"
y2="271.834"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0964243,0,0,1.0253208,-40.187969,-20.060025)" /><filter
inkscape:label="Light Contour"
inkscape:menu="Image Paint and Draw"
inkscape:menu-tooltip="Uses vertical specular light to draw lines"
style="color-interpolation-filters:sRGB"
id="filter11"
x="-0.01907517"
y="-0.054959154"
width="1.0379885"
height="1.1092314"><feGaussianBlur
in="SourceGraphic"
stdDeviation="0.38250006"
result="result3"
id="feGaussianBlur9" /><feComponentTransfer
result="result1"
in="result3"
id="feComponentTransfer9"><feFuncR
type="discrete"
tableValues="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1"
id="feFuncR9" /><feFuncG
type="discrete"
tableValues="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1"
id="feFuncG9" /><feFuncB
type="discrete"
tableValues="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1"
id="feFuncB9" /></feComponentTransfer><feGaussianBlur
result="result5"
stdDeviation="0.01"
id="feGaussianBlur10" /><feBlend
in2="result5"
result="result6"
mode="lighten"
in="result5"
id="feBlend10" /><feColorMatrix
in="result6"
type="luminanceToAlpha"
result="result2"
id="feColorMatrix10" /><feSpecularLighting
surfaceScale="5"
result="result9"
specularExponent="20"
in="result2"
specularConstant="1"
id="feSpecularLighting10"><feDistantLight
azimuth="180"
elevation="90"
id="feDistantLight10" /></feSpecularLighting><feComposite
in2="result6"
operator="arithmetic"
in="result9"
k1="0.4"
k3="0.7"
result="result3"
id="feComposite10"
k2="0"
k4="0" /><feBlend
in2="result1"
in="result3"
mode="normal"
result="result8"
id="feBlend11" /><feComposite
in2="SourceGraphic"
in="result8"
operator="in"
result="result7"
id="feComposite11" /></filter></defs><sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.35"
inkscape:cx="254.81481"
inkscape:cy="260.37037"
inkscape:window-width="1920"
inkscape:window-height="1001"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg7"
showguides="false" /><circle
style="fill:url(#linearGradient12);fill-opacity:1;stroke:#e4e4e4;stroke-width:14.0448;stroke-opacity:1;paint-order:stroke fill markers"
id="path8"
cx="256.2999"
cy="257.2999"
r="248.67769" /><path
id="path15"
style="fill:url(#linearGradient2);fill-opacity:1;stroke:#ffffff;stroke-width:16.9642;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.52156866;paint-order:stroke fill markers"
d="m 306.72111,24.233031 c 0,0 -11.98397,40.08696 -18.0546,60.431848 -12.96613,9.503601 -21.49377,18.397701 -21.49377,18.397701 0,0 -23.41313,-31.029398 -45.74145,-43.934598 -22.32833,-12.905201 -52.42065,-11.242483 -52.42065,-11.242483 0,0 -12.50052,4e-4 -27.63117,5.537132 -15.13066,5.536732 -21.27107,9.227888 -21.27107,9.227888 0,0 15.35165,-0.410529 37.93799,6.766716 22.58635,7.177243 32.45374,11.484796 32.45374,11.484796 l 31.02752,-6.562453 -8.44161,11.074275 c 0,0 14.80259,8.920284 22.80648,16.917787 8.0039,7.9975 11.73088,12.50812 11.73088,12.50812 0,0 -13.92373,-5.43341 -56.68427,-1.74226 -42.76055,3.69116 -84.86368,56.39265 -84.86368,56.39265 0,0 41.22428,-15.9958 65.5649,-21.32747 24.34062,-5.33166 47.58524,-7.9983 47.58524,-7.9983 0,0 -18.41865,7.3827 -38.15428,38.3474 -19.73564,30.96468 -14.0351,80.18128 -14.0351,80.18128 0,0 31.35774,-59.05848 61.39977,-78.94969 30.04203,-19.89124 36.182,-20.50642 36.182,-20.50642 0,0 -24.1209,48.39514 -33.55015,126.11445 -9.42924,77.71931 30.26089,207.72959 30.26089,207.72959 l 47.80367,-6.97298 c 0,0 -45.61041,-42.24281 -49.55753,-151.33695 -3.94713,-109.09413 16.66479,-174.30453 16.66479,-174.30453 0,0 17.10508,1.23039 42.54213,32.81027 25.43704,31.57987 40.34713,57.41795 40.34713,57.41795 0,0 9.65024,-51.26683 -11.4011,-74.64415 -21.05135,-23.3773 -53.50637,-33.62931 -53.50637,-33.62931 0,0 13.70573,-6.66419 42.10313,-4.71609 28.39738,1.94813 87.30278,27.12897 87.30278,27.12896 0,0 -15.8158,-25.5214 -52.87463,-43.21167 -37.05881,-17.69028 -81.35597,0.29238 -81.35597,0.29238 0,0 4.13589,-15.37277 29.10021,-32.628037 24.96432,-17.25527 56.907,-34.36427 56.907,-34.36427 0,0 -26.3595,1.160335 -55.20025,12.035504 -7.176,2.7059 -14.064,6.299542 -20.36309,10.173104 l 17.40574,-51.051762 z" /><path
id="path4-2-6"
style="fill:#ffffff;fill-opacity:0.509804;stroke:#ffffff;stroke-width:8.49614;stroke-dasharray:none;stroke-opacity:0.521569"
d="m 105.64857,363.95957 a 27.851731,25.309928 0 0 0 -7.115581,35.20471 27.851731,25.309928 0 0 0 5.656921,5.48617 c 7.16052,5.83605 21.58543,14.65841 45.88391,17.847 37.57172,4.93039 41.7105,10.38005 41.71122,10.381 -4.5e-4,-6e-4 -4.13529,-5.45309 4.14459,-39.11953 5.35491,-21.77281 1.40624,-37.16078 -2.05217,-45.31698 a 27.851731,25.309928 0 0 0 -3.63281,-6.75471 27.851731,25.309928 0 0 0 -38.74027,-6.4662 27.851731,25.309928 0 0 0 -7.11556,35.20472 27.851731,25.309928 0 0 0 -38.74025,-6.46618 z" /><path
id="path4-2-6-1"
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:6.89965;stroke-dasharray:none;stroke-opacity:0.519962"
d="m 351.29524,378.32915 a 20.862787,22.283365 87.929759 0 0 -28.94663,11.7882 20.862787,22.283365 87.929759 0 0 -1.50914,6.04125 c -1.09835,7.13663 -1.16134,20.16231 7.28339,36.72931 13.0577,25.61689 10.90177,30.69793 10.90138,30.69882 2.4e-4,-5.6e-4 2.16,-5.08045 30.49632,-15.43688 18.32576,-6.69765 27.84648,-16.23659 32.287,-22.14109 a 20.862787,22.283365 87.929759 0 0 3.33646,-5.36755 20.862787,22.283365 87.929759 0 0 -12.45108,-27.05014 20.862787,22.283365 87.929759 0 0 -28.94664,11.78822 20.862787,22.283365 87.929759 0 0 -12.45106,-27.05014 z" /><path
id="path4-2-6-1-5"
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:6.89965;stroke-dasharray:none;stroke-opacity:0.52156866"
d="m 83.024352,249.4105 a 22.283365,20.862787 0 0 0 -29.353581,10.73482 22.283365,20.862787 0 0 0 -1.72639,5.98278 c -1.35544,7.0923 -1.88894,20.10721 5.951801,36.96846 12.12378,26.07187 9.7857,31.07171 9.78528,31.07259 2.6e-4,-5.5e-4 2.34212,-4.99911 31.03406,-14.32513 18.555748,-6.03127 28.414858,-15.22005 33.065768,-20.96029 a 22.283365,20.862787 0 0 0 3.52818,-5.24352 22.283365,20.862787 0 0 0 -11.46577,-27.48227 22.283365,20.862787 0 0 0 -29.353588,10.73483 22.283365,20.862787 0 0 0 -11.46576,-27.48227 z" /><path
id="path4-2-6-1-9"
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:5.01078;stroke-dasharray:none;stroke-opacity:0.519962"
d="m 320.97602,291.36362 a 16.625347,14.748181 0 0 0 -21.90036,7.58859 16.625347,14.748181 0 0 0 -1.28804,4.2293 c -1.01128,5.01364 -1.40932,14.21406 4.44057,26.1335 9.0454,18.43055 7.30098,21.965 7.30067,21.96562 2e-4,-3.9e-4 1.74743,-3.53394 23.15415,-10.12663 13.84423,-4.26358 21.19999,-10.75925 24.66998,-14.8171 a 16.625347,14.748181 0 0 0 2.63233,-3.70671 16.625347,14.748181 0 0 0 -8.55447,-19.42758 16.625347,14.748181 0 0 0 -21.90037,7.58859 16.625347,14.748181 0 0 0 -8.55446,-19.42758 z" /><path
id="path4-2-6-1-9-8"
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:4.22313;stroke-dasharray:none;stroke-opacity:0.519962"
d="m 416.90426,193.13811 a 12.322476,14.134158 82.30909 0 0 -17.56469,8.83612 12.322476,14.134158 82.30909 0 0 -0.59553,3.65007 c -0.27175,4.26676 0.45709,11.92642 6.76182,21.10665 9.74867,14.19503 8.68847,17.32338 8.68827,17.3239 1.2e-4,-3.3e-4 1.06282,-3.12827 18.32699,-11.08266 11.16516,-5.14424 16.60821,-11.37802 19.06101,-15.14093 a 12.322476,14.134158 82.30909 0 0 1.788,-3.37453 12.322476,14.134158 82.30909 0 0 -9.45059,-15.07737 12.322476,14.134158 82.30909 0 0 -17.5647,8.83612 12.322476,14.134158 82.30909 0 0 -9.45058,-15.07737 z" /><path
id="path4-2-6-1-9-8-4"
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:3.48342;stroke-dasharray:none;stroke-opacity:0.519962"
d="m 96.169666,99.754795 a 10.296362,11.508677 62.365085 0 0 -7.330189,13.841365 10.296362,11.508677 62.365085 0 0 1.473186,2.6805 c 2.008889,2.93989 6.437543,7.66269 15.415927,10.84633 13.88288,4.92276 14.77391,7.47086 14.77407,7.4713 -1e-4,-2.8e-4 -0.88925,-2.54921 6.69094,-15.67164 4.90232,-8.48655 5.37758,-15.08279 5.10162,-18.6847 a 10.296362,11.508677 62.365085 0 0 -0.5257,-3.042454 10.296362,11.508677 62.365085 0 0 -14.1348,-5.641051 10.296362,11.508677 62.365085 0 0 -7.33021,13.841385 10.296362,11.508677 62.365085 0 0 -14.134844,-5.641035 z" /><path
id="path4-2-6-1-9-8-4-9-2"
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:3.05139;stroke-dasharray:none;stroke-opacity:0.519962"
d="m 296.64657,233.26347 a 8.8114666,10.319195 80.445391 0 0 -11.58972,8.06989 8.8114666,10.319195 80.445391 0 0 0.0366,2.62543 c 0.35019,3.02392 1.86017,8.32306 7.60386,14.09672 8.8812,8.92759 8.51432,11.23624 8.51426,11.23663 5e-5,-2.5e-4 0.36876,-2.30885 11.85385,-9.72788 7.4277,-4.79799 10.57103,-9.75243 11.86523,-12.65455 a 8.8114666,10.319195 80.445391 0 0 0.86244,-2.55882 8.8114666,10.319195 80.445391 0 0 -8.77837,-9.57865 8.8114666,10.319195 80.445391 0 0 -11.58975,8.06989 8.8114666,10.319195 80.445391 0 0 -8.77842,-9.57866 z" /><path
id="path4-2-6-1-9-8-4-9-2-6"
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:2.49738;stroke-dasharray:none;stroke-opacity:0.519962"
d="m 403.95446,91.44744 a 7.0950375,8.5844443 82.142743 0 0 -9.64888,6.492875 7.0950375,8.5844443 82.142743 0 0 0.0305,2.112375 c 0.29155,2.43298 1.54866,6.69657 6.33049,11.34195 7.39392,7.18298 7.08848,9.04046 7.08843,9.04078 4e-5,-2.1e-4 0.307,-1.85765 9.86876,-7.82686 6.18383,-3.86038 8.80077,-7.84663 9.87824,-10.18161 a 7.0950375,8.5844443 82.142743 0 0 0.718,-2.05879 7.0950375,8.5844443 82.142743 0 0 -7.30831,-7.706798 7.0950375,8.5844443 82.142743 0 0 -9.64889,6.492875 7.0950375,8.5844443 82.142743 0 0 -7.30834,-7.706797 z" /><path
id="path4-2-6-1-9-8-4-9-5"
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:7.54176;stroke-dasharray:none;stroke-opacity:0.521569"
d="m 410.46352,265.86621 a 24.802737,22.39469 2.0523303 0 0 -30.17074,15.95063 24.802737,22.39469 2.0523303 0 0 -0.74427,6.61415 c -0.12337,7.7333 1.79614,21.62064 13.65297,38.28529 18.33368,25.76802 16.72835,31.4347 16.72811,31.43572 1.4e-4,-6.3e-4 1.60998,-5.66652 31.32518,-20.02007 19.21759,-9.28266 28.27643,-20.56192 32.27921,-27.37361 a 24.802737,22.39469 2.0523303 0 0 2.8654,-6.11021 24.802737,22.39469 2.0523303 0 0 -17.88248,-27.36631 24.802737,22.39469 2.0523303 0 0 -30.17081,15.95066 24.802737,22.39469 2.0523303 0 0 -17.88257,-27.36625 z" /><path
id="path4-2-6-1-9-8-5"
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:3.6405;stroke-dasharray:none;stroke-opacity:0.519962"
d="m 114.43099,189.33754 a 10.333135,12.525309 79.004057 0 0 -14.00848,9.75499 10.333135,12.525309 79.004057 0 0 0.0547,3.08382 c 0.43602,3.54457 2.28588,9.73496 9.26636,16.38295 10.79359,10.27954 10.35819,13.00063 10.3581,13.00111 6e-5,-3e-4 0.4377,-2.72141 14.32197,-11.70923 8.9793,-5.8126 12.76786,-11.70785 14.32433,-15.14812 a 10.333135,12.525309 79.004057 0 0 1.03481,-3.02677 10.333135,12.525309 79.004057 0 0 -10.67161,-11.04688 10.333135,12.525309 79.004057 0 0 -14.00848,9.75501 10.333135,12.525309 79.004057 0 0 -10.6716,-11.04688 z" /><path
id="path4-2-6-1-9-8-4-9-2-2"
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:3.62674;stroke-dasharray:none;stroke-opacity:0.519962"
d="m 178.56055,273.32338 a 10.656883,12.053184 66.089768 0 0 -7.97821,14.16205 10.656883,12.053184 66.089768 0 0 1.49012,2.79504 c 2.04675,3.07265 6.5954,8.03049 15.94965,11.48124 14.46412,5.33577 15.34612,7.98353 15.34628,7.98398 -8e-5,-2.8e-4 -0.88012,-2.64887 7.3455,-16.0639 5.31973,-8.67576 5.95524,-15.47956 5.74045,-19.20452 a 10.656883,12.053184 66.089768 0 0 -0.48843,-3.15169 10.656883,12.053184 66.089768 0 0 -14.7135,-6.08217 10.656883,12.053184 66.089768 0 0 -7.97826,14.1621 10.656883,12.053184 66.089768 0 0 -14.71355,-6.08215 z" /></svg>

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 15 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 256 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 KiB

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 79 KiB

+3 -11
View File
@@ -22,25 +22,17 @@ Debug logs can be found in General -> Debug -> Open Log Location on desktop, and
Ignoring SIGSEGV when debugging in host:
- **gdb**: `handle SIGSEGV nostop pass`.
- **gdb**: `handle all nostop pass`.
- **lldb**: `pro hand -p true -s false -n false SIGSEGV`.
## Debugging (guest code)
### gdb
You must have GDB installed for aarch64 to debug the target. Install it through your package manager, e.g.:
* On Arch:
* `sudo pacman -Syu aarch64-linux-gnu-gdb`
* On Gentoo:
* `sudo emerge --ask crossdev`
* `sudo crossdev -t aarch64-unknown-linux-gnu --ex-gdb`
Run `./build/bin/eden-cli -c <path to your config file (see logs where you run eden normally to see where it is)> -d -g <path to game>`
Or `Enable GDB Stub` at General > Debug, then hook up an aarch64-gdb:
* `target remote localhost:6543`
Type `c` (for continue) and then if it crashes just do a `bt` (backtrace) and `layout asm`
Then hook up an aarch64-gdb (use `yay aarch64-gdb` or `sudo pkg in arch64-gdb` to install)
Then type `target remote localhost:1234` and type `c` (for continue) - and then if it crashes just do a `bt` (backtrace) and `layout asm`.
### gdb cheatsheet
+16 -14
View File
@@ -51,11 +51,12 @@ All other dependencies will be downloaded and built by [CPM](https://github.com/
* [fmt](https://fmt.dev/) 8.0.1+
* [lz4](http://www.lz4.org)
* [nlohmann\_json](https://github.com/nlohmann/json) 3.8+
* [OpenSSL](https://www.openssl.org/source/) 3+
* [OpenSSL](https://www.openssl.org/source/) 1.1.1+
* [ZLIB](https://www.zlib.net/) 1.2+
* [zstd](https://facebook.github.io/zstd/) 1.5+
* [enet](http://enet.bespin.org/) 1.3+
* [Opus](https://opus-codec.org/) 1.3+
* [MbedTLS](https://github.com/Mbed-TLS/mbedtls) 3+
Vulkan 1.3.274+ is also needed:
@@ -120,7 +121,7 @@ sudo emerge -a \
dev-util/vulkan-utility-libraries dev-util/glslang \
media-gfx/renderdoc media-libs/libva media-libs/opus media-video/ffmpeg \
media-libs/VulkanMemoryAllocator media-libs/libsdl2 media-libs/cubeb \
net-libs/enet \
net-libs/enet net-libs/mbedtls \
sys-libs/zlib \
dev-cpp/nlohmann_json dev-cpp/simpleini dev-cpp/cpp-httplib dev-cpp/cpp-jwt \
games-util/gamemode \
@@ -138,6 +139,7 @@ Required USE flags:
* `dev-qt/qtbase network concurrent dbus gui widgets`
* `dev-libs/quazip qt6`
* `net-libs/mbedtls cmac`
* `media-libs/libsdl2 haptic joystick sound video`
* `dev-cpp/cpp-httplib ssl`
@@ -149,7 +151,7 @@ Required USE flags:
<summary>Arch Linux</summary>
```sh
sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 ninja nlohmann-json openssl opus qt6-base qt6-multimedia qt6-charts sdl2 zlib zstd zip unzip vulkan-headers vulkan-utility-libraries libusb spirv-tools spirv-headers
sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 mbedtls ninja nlohmann-json openssl opus qt6-base qt6-multimedia sdl2 zlib zstd zip unzip vulkan-headers vulkan-utility-libraries libusb spirv-tools spirv-headers
```
* Building with QT Web Engine requires `qt6-webengine` as well.
@@ -162,7 +164,7 @@ sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glsl
<summary>Ubuntu, Debian, Mint Linux</summary>
```sh
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev qt6-charts-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev libboost-dev libboost-fiber-dev libboost-context-dev libsdl2-dev libopus-dev libasound2t64 vulkan-utility-libraries-dev
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev libboost-dev libboost-fiber-dev libboost-context-dev libsdl2-dev libopus-dev libasound2t64 vulkan-utility-libraries-dev
```
* Ubuntu 22.04, Linux Mint 20, or Debian 12 or later is required.
@@ -176,7 +178,7 @@ sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev l
Fedora:
```sh
sudo dnf install autoconf cmake fmt-devel gcc{,-c++} glslang hidapi-devel json-devel libtool libusb1-devel libzstd-devel lz4-devel nasm ninja-build openssl-devel pulseaudio-libs-devel qt6-linguist qt6-qtbase{-private,}-devel qt6-qtwebengine-devel qt6-qtmultimedia-devel qt6-charts-devel speexdsp-devel wayland-devel zlib-devel ffmpeg-devel libXext-devel boost jq
sudo dnf install autoconf cmake fmt-devel gcc{,-c++} glslang hidapi-devel json-devel libtool libusb1-devel libzstd-devel lz4-devel nasm ninja-build openssl-devel pulseaudio-libs-devel qt6-linguist qt6-qtbase{-private,}-devel qt6-qtwebengine-devel qt6-qtmultimedia-devel speexdsp-devel wayland-devel zlib-devel ffmpeg-devel libXext-devel boost jq
```
AlmaLinux (use `YUZU_USE_CPM=ON`):
@@ -209,15 +211,17 @@ First, enable the community repository; [see here](https://wiki.alpinelinux.org/
# Enable the community repository
setup-apkrepos -c
# Install
apk add g++ git cmake make mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libquazip1-qt6 ffmpeg-dev qt6-charts-dev libusb-dev libtool boost-dev sdl2-dev zstd-dev vulkan-utility-libraries spirv-tools-dev openssl-dev nlohmann-json lz4-dev opus-dev jq patch
apk add g++ git cmake make mbedtls-dev mbedtls-static mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libquazip1-qt6 ffmpeg-dev libusb-dev libtool boost-dev sdl2-dev zstd-dev vulkan-utility-libraries spirv-tools-dev openssl-dev nlohmann-json lz4-dev opus-dev jq patch
```
`mbedtls-static` has to be specified otherwise `libeverest.a` and `libp256m.a` will fail to be found.
</details>
<details>
<summary>Void Linux</summary>
```sh
xbps-install -Su git make cmake clang pkg-config patch SPIRV-Tools-devel SPIRV-Headers lz4 liblz4-devel boost-devel ffmpeg6-devel catch2 Vulkan-Utility-Libraries Vulkan-Headers glslang openssl-devel SDL2-devel quazip-qt6-devel qt6-base-devel qt6-qt5compat-devel qt6-charts-devel fmt-devel json-c++ libenet-devel libusb-devel
xbps-install -Su git make cmake clang pkg-config patch mbedtls-devel SPIRV-Tools-devel SPIRV-Headers lz4 liblz4-devel boost-devel ffmpeg6-devel catch2 Vulkan-Utility-Libraries Vulkan-Headers glslang openssl-devel SDL2-devel quazip-qt6-devel qt6-base-devel qt6-qt5compat-devel fmt-devel json-c++ libenet-devel libusb-devel
```
Yes, `nlohmann-json` is just named `json-c++`. Why?
@@ -229,8 +233,6 @@ Yes, `nlohmann-json` is just named `json-c++`. Why?
A convenience script is provided on the root of this project [shell.nix](../shell.nix). Run the usual `nix-shell`.
If you're going for a pure build (i.e no downloaded deps), use `-DYUZU_USE_CPM=ON -DCPMUTIL_FORCE_SYSTEM=ON`.
</details>
<details>
<summary>macOS</summary>
@@ -255,7 +257,7 @@ brew install molten-vk
<details>
<summary>FreeBSD</summary>
As root run: `pkg install devel/cmake devel/sdl20 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base devel/qt6-charts devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib devel/unordered-dense vulkan-headers quazip-qt6`
As root run: `pkg install devel/cmake devel/sdl20 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib devel/unordered-dense mbedtls3 vulkan-headers quazip-qt6`
If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
@@ -265,7 +267,7 @@ If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
<details>
<summary>NetBSD</summary>
For NetBSD +10.1: `pkgin install git cmake boost fmtlib SDL2 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq libopus qt6 cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx`.
For NetBSD +10.1: `pkgin install git cmake boost fmtlib SDL2 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq libopus qt6 mbedtls3 cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx`.
[Caveats](./Caveats.md#netbsd).
@@ -285,7 +287,7 @@ pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gm
<summary>DragonFlyBSD</summary>
```sh
pkg install gcc14 git cmake unzip nasm autoconf bash pkgconf ffmpeg glslang gmake jq nlohmann-json enet spirv-tools sdl2 vulkan-utility-libraries vulkan-headers catch2 libfmt openssl liblz4 boost-libs cpp-httplib qt6-base qt6-charts quazip-qt6 unordered-dense libva-vdpau-driver libva-utils libva-intel-driver
pkg install gcc14 git cmake unzip nasm autoconf bash pkgconf ffmpeg glslang gmake jq nlohmann-json enet spirv-tools sdl2 vulkan-utility-libraries vulkan-headers catch2 libfmt openssl liblz4 boost-libs cpp-httplib qt6-base quazip-qt6 unordered-dense libva-vdpau-driver libva-utils libva-intel-driver
```
[Caveats](./Caveats.md#dragonflybsd).
@@ -309,7 +311,7 @@ sudo pkg install qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json ope
```sh
BASE="git make autoconf libtool automake-wrapper jq patch"
MINGW="qt6-base qt6-charts qt6-tools qt6-translations qt6-svg cmake toolchain clang python-pip openssl vulkan-memory-allocator vulkan-devel glslang boost fmt lz4 nlohmann-json zlib zstd enet opus libusb unordered_dense openssl SDL2"
MINGW="qt6-base qt6-tools qt6-translations qt6-svg cmake toolchain clang python-pip openssl vulkan-memory-allocator vulkan-devel glslang boost fmt lz4 nlohmann-json zlib zstd enet opus mbedtls libusb unordered_dense openssl SDL2"
# Either x86_64 or clang-aarch64 (Windows on ARM)
packages="$BASE"
for pkg in $MINGW; do
@@ -335,7 +337,7 @@ pacman -Syuu --needed --noconfirm $packages
<summary>HaikuOS</summary>
```sh
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.89_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl2_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.89_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl2_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel mbedtls3_devel glslang qt6_devel
```
[Caveats](./Caveats.md#haikuos).
+9
View File
@@ -286,6 +286,15 @@ Exclusive OR (i.e.: XOR)
Memory access.
### Terminal: Interpret
```c++
SetTerm(IR::Term::Interpret{next})
```
This terminal instruction calls the interpreter, starting at `next`.
The interpreter must interpret exactly one instruction.
### Terminal: ReturnToDispatch
```c++
+5
View File
@@ -117,6 +117,11 @@ public:
MemoryWrite32(vaddr + 4, u32(value >> 32));
}
void InterpreterFallback(u32 pc, size_t num_instructions) override {
// This is never called in practice.
std::terminate();
}
void CallSVC(u32 swi) override {
// Do something.
}
+2 -41
View File
@@ -12,13 +12,12 @@ The setting ranges from 0 to 65535 (0x0000 to 0xFFFF), where each bit represents
* [Accessing Debug Knobs (dev side)](#accessing-debug-knobs-dev-side)
* [Setting Debug Knobs (user side)](#setting-debug-knobs-user-side)
* [Bit Manipulation Examples](#bit-manipulation-examples)
3. [Terminology and user communication](#terminology-and-user-communication)
4. [Examples](#examples)
3. [Examples](#examples)
* [Example 1: Conditional Debug Logging](#example-1-conditional-debug-logging)
* [Example 2: Performance Tuning](#example-2-performance-tuning)
* [Example 3: Feature Gating](#example-3-feature-gating)
5. [Best Practices](#best-practices)
4. [Best Practices](#best-practices)
---
@@ -78,44 +77,6 @@ To enable specific features, calculate the decimal value by setting the appropri
* **Enable bits 0 and 1**: Value = 3 (2^0 + 2^1)
* **Enable bit 15**: Value = 32768 (2^15)
## Terminology and user communication
There are two main confusions when talking about knobs:
### Whether it's zero-based or one-based
Sometimes when an user reports: knobs 1 and 2 gets better performance, dev may get confuse whether he means the knobs 1 and 2 literally, or the 1st and 2nd knobs (knobs 0 and 1).
Debug knobs are **zero-based**, which means:
* The first knob is the knob(0) (or knob0 henceforth), and the last one is the 15 (knob15, likewise)
* You can talk: "knob0 is enabled/disabled", "In this video i was using only knobs 0 and 2", etc.
### Whether one is talking about the knob itself or about the entire parameter value (which represents all knobs)
Sometimes when an user reports: knob 3 results, it's unclear whether he's referring to knob setting with value 3 (which means both knob 0 and 1 are enabled), or to knob(3) specifically.
Whenever you're instructing tests or reporting results, be precise about whether one you're talking to avoid confusion:
### Setting based terminology
ALWAYS use the word in PLURAL (knobs), without mentioning which one, to refer to the setting, aka multiple knobs at once:
Examples:
- **knobs=0**: no knobs enabled
- **knobs=1**: knob0 enabled, others disabled
- **knobs=2**: knob1 enabled, others disabled
- **knobs=3**: knobs 0 and 1 enabled, others disabled
...
### Knob based terminology
Use the word in SINGULAR (knob), or in plural but referring which ones, when meaning multiple knobs at once:
Examples:
- **knob0**: knob 0 enabled, others disabled
- **knob1**: knob 1 enabled, others disabled
- **knobs 0 and 1**: knobs 0 and 1 enabled, others disabled
...
## Examples
### Example 1: Conditional Debug Logging
+4 -1
View File
@@ -6,4 +6,7 @@ Debugging on physical hardware can get tedious and time consuming. Users are emp
**Standard key prefix**: Allows to redirect the key manager to a file other than `prod.keys` (for example `other` would redirect to `other.keys`). This is useful for testing multiple keysets. Default is `prod`.
**Changing serial**: Very basic way to set debug values for the serial (and battery number). Developers do not need to write the full serial as only the first digits (excluding the last) will be accoutned for. Region settings will affect the generated serial. The serial corresponds to a non-OLED/Lite console.
**Changing serial**: Very basic way to set debug values for the serial (and battery number). Developers do not need to write the full serial as it will be writen in-place (that is, it will be filled with the default serial and then overwrite the serial from the beginning).
- Battery serial: `YUZU0EMULATOR14022024`
- Board serial: `YUZ10000000001`
If the user were to set their board serial as `ABC`, then it will be written in-place and the resulting serial would be `ABC10000000001`. There are no underlying checks to ensure correctness of serials other than a hard limit of 16-characters for both.
+9 -2
View File
@@ -41,6 +41,9 @@ if (NOT TARGET enet::enet)
add_library(enet::enet ALIAS enet)
endif()
# mbedtls
AddJsonPackage(mbedtls)
# stb
add_library(stb stb/stb_dxt.cpp)
target_include_directories(stb PUBLIC ./stb)
@@ -231,7 +234,9 @@ if (VulkanMemoryAllocator_ADDED)
endif()
# httplib
AddJsonPackage(httplib)
if (ENABLE_WEB_SERVICE OR ENABLE_UPDATE_CHECKER OR USE_DISCORD_PRESENCE OR ENABLE_OPENSSL)
AddJsonPackage(httplib)
endif()
# cpp-jwt
if (ENABLE_WEB_SERVICE OR ENABLE_UPDATE_CHECKER)
@@ -402,10 +407,12 @@ if (APPLE)
# moltenvk
if (NOT YUZU_USE_BUNDLED_MOLTENVK)
find_library(MOLTENVK_LIBRARY MoltenVK)
else()
unset(MOLTENVK_LIBRARY)
endif()
# TODO: kosmickrisp?
if (NOT MOLTENVK_LIBRARY OR YUZU_USE_BUNDLED_MOLTENVK)
if (NOT MOLTENVK_LIBRARY)
AddJsonPackage(moltenvk)
set(MOLTENVK_LIBRARY "${moltenvk_SOURCE_DIR}/MoltenVK/dylib/macOS/libMoltenVK.dylib" CACHE STRING "" FORCE)
+17 -6
View File
@@ -33,9 +33,6 @@
"find_args": "MODULE GLOBAL",
"patches": [
"0001-mingw.patch"
],
"options": [
"HTTPLIB_REQUIRE_OPENSSL ON"
]
},
"cpp-jwt": {
@@ -91,6 +88,20 @@
"0001-avoid-memset-when-clearing-an-empty-table.patch"
]
},
"mbedtls": {
"package": "MbedTLS",
"repo": "Mbed-TLS/mbedtls",
"tag": "mbedtls-%VERSION%",
"hash": "6671fb8fcaa832e5b115dfdce8f78baa6a4aea71f5c89a640583634cdee27aefe3bf4be075744da91f7c3ae5ea4e0c765c8fc3937b5cfd9ea73d87ef496524da",
"version": "3",
"git_version": "3.6.4",
"artifact": "%TAG%.tar.bz2",
"skip_updates": true,
"patches": [
"0001-aesni-fix.patch",
"0002-arm64-aes-fix.patch"
]
},
"enet": {
"repo": "lsalzman/enet",
"tag": "v%VERSION%",
@@ -231,8 +242,8 @@
},
"ffmpeg": {
"repo": "FFmpeg/FFmpeg",
"sha": "c7b5f1537d",
"hash": "ed177621176b3961bdcaa339187d3a7688c1c8b060b79c4bb0257cbc67ad7021ae5d5adca5303b45625abbbe3d9aafdd87ce777b8690ac295290d744c875489a",
"sha": "5e56937b74",
"hash": "9ab0457dcd6ce6359b5053c1662f57910d332f68ca0cca9d4134d858464840917027374de3d97e0863c3a7daaea2fe4f4cd17d1c6d8e7f740f4ad91e71c2932b",
"bundled": true
},
"ffmpeg-ci": {
@@ -240,7 +251,7 @@
"package": "FFmpeg",
"name": "ffmpeg",
"repo": "crueter-ci/FFmpeg",
"version": "8.0.1-c7b5f1537d",
"version": "8.0.1-5e56937b74",
"min_version": "4.1"
},
"tzdb": {
+3 -6
View File
@@ -94,10 +94,6 @@ if (MSVC AND NOT CXX_CLANG)
/wd4324 # 'struct_name': structure was padded due to __declspec(align())
/wd4201 # nonstandard extension used : nameless struct/union
/wd4702 # unreachable code (when used with LTO)
$<$<CONFIG:Release>:/GS-> # No stack buffer overflow checks
/Gy # Enable function level linking
/GR- # Disable run time type information
)
if (NOT CXX_CLANG)
@@ -112,14 +108,15 @@ if (MSVC AND NOT CXX_CLANG)
add_compile_options(/QIntel-jcc-erratum)
endif()
# /GS- - No stack buffer overflow checks
add_compile_options("$<$<CONFIG:Release>:/GS->")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG /MANIFEST:NO" CACHE STRING "" FORCE)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /MANIFEST:NO /INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE)
else()
if (NOT MSVC)
add_compile_options(
-fwrapv
-fno-rtti # Disable RTTI
-pipe
)
endif()
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -24,7 +24,6 @@ import org.yuzu.yuzu_emu.utils.DocumentsTree
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.PowerStateUpdater
import org.yuzu.yuzu_emu.utils.ControllerNavigationGlobalHook
import java.util.Locale
fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
@@ -73,7 +72,6 @@ class YuzuApplication : Application() {
NativeLibrary.logDeviceInfo()
PowerStateUpdater.start()
Log.logDeviceInfo()
ControllerNavigationGlobalHook.install(this)
createNotificationChannels()
}
@@ -37,7 +37,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
PICTURE_IN_PICTURE("picture_in_picture"),
USE_CUSTOM_RTC("custom_rtc_enabled"),
BLACK_BACKGROUNDS("black_backgrounds"),
INVERT_CONFIRM_BACK_CONTROLLER_BUTTONS("invert_confirm_back_controller_buttons"),
ENABLE_FOLDER_BUTTON("enable_folder_button"),
ENABLE_QLAUNCH_BUTTON("enable_qlaunch_button"),
@@ -68,6 +68,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
MY_PAGE_APPLET("my_page_applet_mode"),
INPUT_OVERLAY_AUTO_HIDE("input_overlay_auto_hide"),
OVERLAY_GRID_SIZE("overlay_grid_size"),
DEBUG_KNOBS("debug_knobs"),
GPU_LOG_RING_BUFFER_SIZE("gpu_log_ring_buffer_size")
;
@@ -12,7 +12,6 @@ enum class ShortSetting(override val key: String) : AbstractShortSetting {
RENDERER_SPEED_LIMIT("speed_limit"),
RENDERER_TURBO_SPEED_LIMIT("turbo_speed_limit"),
RENDERER_SLOW_SPEED_LIMIT("slow_speed_limit"),
DEBUG_KNOBS("debug_knobs")
;
override fun getShort(needsGlobal: Boolean): Short = NativeConfig.getShort(key, needsGlobal)
@@ -29,4 +28,4 @@ enum class ShortSetting(override val key: String) : AbstractShortSetting {
override fun getValueAsString(needsGlobal: Boolean): String = getShort(needsGlobal).toString()
override fun reset() = NativeConfig.setShort(key, defaultValue)
}
}
@@ -378,13 +378,6 @@ abstract class SettingsItem(
warningMessage = R.string.warning_resolution
)
)
put(
SwitchSetting(
BooleanSetting.INVERT_CONFIRM_BACK_CONTROLLER_BUTTONS,
titleId = R.string.invert_confirm_back_controller_buttons,
descriptionId = R.string.invert_confirm_back_controller_buttons_description
)
)
put(
SwitchSetting(
BooleanSetting.SHOW_INPUT_OVERLAY,
@@ -903,7 +896,7 @@ abstract class SettingsItem(
)
put(
SpinBoxSetting(
ShortSetting.DEBUG_KNOBS,
IntSetting.DEBUG_KNOBS,
titleId = R.string.debug_knobs,
descriptionId = R.string.debug_knobs_description,
valueHint = R.string.debug_knobs_hint,
@@ -1076,7 +1076,6 @@ class SettingsFragmentPresenter(
}
add(BooleanSetting.ENABLE_QUICK_SETTINGS.key)
add(BooleanSetting.INVERT_CONFIRM_BACK_CONTROLLER_BUTTONS.key)
add(HeaderSetting(R.string.theme_and_color))
@@ -1230,7 +1229,7 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.general))
add(ShortSetting.DEBUG_KNOBS.key)
add(IntSetting.DEBUG_KNOBS.key)
add(HeaderSetting(R.string.gpu_logging_header))
add(BooleanSetting.GPU_LOGGING_ENABLED.key)
@@ -1,168 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.utils
import android.app.Activity
import android.app.Application
import android.os.Bundle
import android.view.InputDevice
import android.view.KeyEvent
import android.view.View
import android.view.Window
import androidx.activity.ComponentActivity
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import java.util.concurrent.atomic.AtomicBoolean
object ControllerNavigationGlobalHook {
private val installed = AtomicBoolean(false)
fun install(application: Application) {
if (!installed.compareAndSet(false, true)) {
return
}
application.registerActivityLifecycleCallbacks(HookInstaller)
}
private object HookInstaller : Application.ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
installHookIfNeeded(activity)
}
override fun onActivityResumed(activity: Activity) {
installHookIfNeeded(activity)
}
override fun onActivityStarted(activity: Activity) = Unit
override fun onActivityPaused(activity: Activity) = Unit
override fun onActivityStopped(activity: Activity) = Unit
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit
override fun onActivityDestroyed(activity: Activity) = Unit
}
private fun installHookIfNeeded(activity: Activity) {
val window = activity.window ?: return
val currentCallback = window.callback ?: return
if (currentCallback is ControllerNavigationWindowCallback) {
return
}
window.callback = ControllerNavigationWindowCallback(activity, currentCallback)
}
private class ControllerNavigationWindowCallback(
private val activity: Activity,
private val delegate: Window.Callback
) : Window.Callback by delegate {
private val componentActivity = activity as? ComponentActivity
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if (activity.isFinishing || activity.isDestroyed) {
return delegate.dispatchKeyEvent(event)
}
if (!BooleanSetting.INVERT_CONFIRM_BACK_CONTROLLER_BUTTONS.getBoolean()) {
return delegate.dispatchKeyEvent(event)
}
if (!isControllerInput(event) || componentActivity == null) {
return delegate.dispatchKeyEvent(event)
}
if (shouldBypassInGameplay()) {
return delegate.dispatchKeyEvent(event)
}
if (isConfirmAction(event.keyCode)) {
return when (event.action) {
KeyEvent.ACTION_DOWN -> {
if (event.repeatCount == 0) {
componentActivity.onBackPressedDispatcher.onBackPressed()
}
true
}
KeyEvent.ACTION_UP -> true
else -> false
}
}
if (isBackAction(event.keyCode)) {
val remappedEvent = KeyEvent(
event.downTime,
event.eventTime,
event.action,
KeyEvent.KEYCODE_DPAD_CENTER,
event.repeatCount,
event.metaState,
event.deviceId,
event.scanCode,
event.flags,
event.source
)
return delegate.dispatchKeyEvent(remappedEvent)
}
return delegate.dispatchKeyEvent(event)
}
private fun shouldBypassInGameplay(): Boolean {
if (activity.javaClass.name != "org.yuzu.yuzu_emu.activities.EmulationActivity") {
return false
}
if (!NativeLibrary.isRunning()) {
return false
}
val surface = activity.findViewById<View?>(R.id.surface_emulation) ?: return false
if (!surface.isShown || surface.visibility != View.VISIBLE) {
return false
}
val focused = activity.currentFocus
if (focused != null) {
val inputOverlay = activity.findViewById<View?>(R.id.surface_input_overlay)
if (!isDescendantOf(focused, inputOverlay)) {
return false
}
}
return true
}
private fun isDescendantOf(view: View, parent: View?): Boolean {
if (parent == null) {
return false
}
var current: View? = view
while (current != null) {
if (current === parent) {
return true
}
current = current.parent as? View
}
return false
}
private fun isControllerInput(event: KeyEvent): Boolean {
val source = event.source
val deviceSources = event.device?.sources ?: InputDevice.getDevice(event.deviceId)?.sources ?: 0
return hasControllerSource(source) || hasControllerSource(deviceSources)
}
private fun isConfirmAction(keyCode: Int): Boolean {
return keyCode == KeyEvent.KEYCODE_BUTTON_A
}
private fun isBackAction(keyCode: Int): Boolean {
return keyCode == KeyEvent.KEYCODE_BUTTON_B
}
private fun hasControllerSource(source: Int): Boolean {
return source and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD ||
source and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK ||
source and InputDevice.SOURCE_DPAD == InputDevice.SOURCE_DPAD
}
}
}
@@ -65,8 +65,6 @@ namespace AndroidSettings {
Settings::Category::Android};
Settings::Setting<bool> enable_qlaunch_button{linkage, false, "enable_qlaunch_button",
Settings::Category::Android};
Settings::Setting<bool> invert_confirm_back_controller_buttons{
linkage, false, "invert_confirm_back_controller_buttons", Settings::Category::Android};
// Input/performance overlay settings
std::vector<OverlayControlData> overlay_control_data;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 KiB

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 203 KiB

@@ -534,8 +534,8 @@
<item>@string/frame_pacing_mode_target_Auto</item>
<item>@string/frame_pacing_mode_target_30</item>
<item>@string/frame_pacing_mode_target_60</item>
<item>@string/frame_pacing_mode_target_90</item>
<item>@string/frame_pacing_mode_target_120</item>
<item>@string/frame_pacing_mode_target_240</item>
</string-array>
<integer-array name="framePacingModeValues">
<item>0</item>
@@ -1 +1 @@
<?xml version='1.0' encoding='utf-8'?><resources><color name='ic_launcher_background'>#1F143C</color></resources>
<?xml version='1.0' encoding='utf-8'?><resources><color name='ic_launcher_background'>#e48cc9ff</color></resources>
@@ -36,8 +36,6 @@
<string name="enable_input_overlay_auto_hide">Enable Overlay Auto Hide</string>
<string name="hide_overlay_on_controller_input">Hide Overlay on Controller Input</string>
<string name="hide_overlay_on_controller_input_description">Automatically hide the touch controls overlay when a physical controller is used. Overlay reappears when controller is disconnected.</string>
<string name="invert_confirm_back_controller_buttons">Invert Confirm/Back Controller Buttons</string>
<string name="invert_confirm_back_controller_buttons_description">Swap Android Confirm and Back button handling to match both Switch and Xbox styles while using the app UI.</string>
<string name="input_overlay_options">Input Overlay</string>
<string name="input_overlay_options_description">Configure on-screen controls</string>
@@ -1040,8 +1038,8 @@
<string name="frame_pacing_mode_target_Auto">Auto</string>
<string name="frame_pacing_mode_target_30">30 FPS</string>
<string name="frame_pacing_mode_target_60">60 FPS</string>
<string name="frame_pacing_mode_target_90">90 FPS</string>
<string name="frame_pacing_mode_target_120">120 FPS</string>
<string name="frame_pacing_mode_target_240">240 FPS</string>
<!-- ASTC Decoding Method Choices -->
<string name="accelerate_astc_cpu" translatable="false">CPU</string>
-2
View File
@@ -186,8 +186,6 @@ if(ARCHITECTURE_x86_64)
common
PRIVATE x64/cpu_detect.cpp
x64/cpu_detect.h
x64/cpu_wait.cpp
x64/cpu_wait.h
x64/native_clock.cpp
x64/native_clock.h
x64/rdtsc.cpp
+1 -2
View File
@@ -25,8 +25,7 @@ void AssertFailSoftImpl();
#define ASSERT_MSG(_a_, ...) \
([&]() YUZU_NO_INLINE { \
auto&& assert_condition = (_a_); \
if (!(assert_condition)) [[unlikely]] { \
if (!(_a_)) [[unlikely]] { \
LOG_CRITICAL(Debug, __FILE__ ": assert " __VA_ARGS__); \
AssertFailSoftImpl(); \
} \
+26 -1
View File
@@ -219,6 +219,11 @@ public:
}
}
bool ClearBackingRegion(size_t physical_offset, size_t length) {
// TODO: This does not seem to be possible on Windows.
return false;
}
void EnableDirectMappedAddress() {
// TODO
UNREACHABLE();
@@ -612,6 +617,24 @@ public:
ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
}
bool ClearBackingRegion(size_t physical_offset, size_t length) {
#ifdef __linux__
// Only incur syscall cost IF memset would be slower (theshold = 16MiB)
// TODO(lizzie): Smarter way to dynamically get this threshold (broadwell != raptor lake) for example
if (length >= 2097152UL * 8) {
// Set MADV_REMOVE on backing map to destroy it instantly.
// This also deletes the area from the backing file.
int ret = madvise(backing_base + physical_offset, length, MADV_REMOVE);
ASSERT_MSG(ret == 0, "madvise failed: {}", strerror(errno));
return true;
} else {
return false;
}
#else
return false;
#endif
}
void EnableDirectMappedAddress() {
virtual_base = nullptr;
}
@@ -725,7 +748,9 @@ void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission
}
void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value) {
std::memset(backing_base + physical_offset, fill_value, length);
if (!impl || fill_value != 0 || !impl->ClearBackingRegion(physical_offset, length)) {
std::memset(backing_base + physical_offset, fill_value, length);
}
}
void HostMemory::EnableDirectMappedAddress() {
+143
View File
@@ -0,0 +1,143 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <vector>
#include "common/common_types.h"
#include "common/div_ceil.h"
namespace Common {
template <typename AddressType, u32 PageBits, u64 MaxAddress>
class PageBitsetRangeSet {
public:
PageBitsetRangeSet() : m_words(kWordCount) {
static_assert((MaxAddress % kPageSize) == 0, "MaxAddress must be page-aligned.");
}
void Add(AddressType base_address, size_t size) {
Modify(base_address, size, true);
}
void Subtract(AddressType base_address, size_t size) {
Modify(base_address, size, false);
}
void Clear() {
std::fill(m_words.begin(), m_words.end(), 0);
}
bool Empty() const {
return std::none_of(m_words.begin(), m_words.end(), [](u64 word) { return word != 0; });
}
template <typename Func>
void ForEachInRange(AddressType base_address, size_t size, Func&& func) const {
if (size == 0 || m_words.empty()) {
return;
}
const AddressType end_address = base_address + static_cast<AddressType>(size);
const u64 start_page = static_cast<u64>(base_address) >> PageBits;
const u64 end_page = Common::DivCeil(static_cast<u64>(end_address), kPageSize);
const u64 clamped_start = (std::min)(start_page, kPageCount);
const u64 clamped_end = (std::min)(end_page, kPageCount);
if (clamped_start >= clamped_end) {
return;
}
bool in_run = false;
u64 run_start_page = 0;
for (u64 page = clamped_start; page < clamped_end; ++page) {
if (Test(page)) {
if (!in_run) {
in_run = true;
run_start_page = page;
}
continue;
}
if (in_run) {
EmitRun(run_start_page, page, base_address, end_address, func);
in_run = false;
}
}
if (in_run) {
EmitRun(run_start_page, clamped_end, base_address, end_address, func);
}
}
private:
static constexpr u64 kPageSize = u64{1} << PageBits;
static constexpr u64 kPageCount = MaxAddress / kPageSize;
static constexpr u64 kWordCount = (kPageCount + 63) / 64;
void Modify(AddressType base_address, size_t size, bool set_bits) {
if (size == 0 || m_words.empty()) {
return;
}
const AddressType end_address = base_address + static_cast<AddressType>(size);
const u64 start_page = static_cast<u64>(base_address) >> PageBits;
const u64 end_page = Common::DivCeil(static_cast<u64>(end_address), kPageSize);
const u64 clamped_start = (std::min)(start_page, kPageCount);
const u64 clamped_end = (std::min)(end_page, kPageCount);
if (clamped_start >= clamped_end) {
return;
}
const u64 start_word = clamped_start / 64;
const u64 end_word = (clamped_end - 1) / 64;
const u64 start_mask = ~0ULL << (clamped_start % 64);
const u64 end_mask = (clamped_end % 64) == 0 ? ~0ULL : ((1ULL << (clamped_end % 64)) - 1);
if (start_word == end_word) {
const u64 mask = start_mask & end_mask;
if (set_bits) {
m_words[start_word] |= mask;
} else {
m_words[start_word] &= ~mask;
}
return;
}
if (set_bits) {
m_words[start_word] |= start_mask;
m_words[end_word] |= end_mask;
std::fill(m_words.begin() + static_cast<std::ptrdiff_t>(start_word + 1),
m_words.begin() + static_cast<std::ptrdiff_t>(end_word), ~0ULL);
} else {
m_words[start_word] &= ~start_mask;
m_words[end_word] &= ~end_mask;
std::fill(m_words.begin() + static_cast<std::ptrdiff_t>(start_word + 1),
m_words.begin() + static_cast<std::ptrdiff_t>(end_word), 0ULL);
}
}
bool Test(u64 page) const {
const u64 word = page / 64;
const u64 bit = page % 64;
return (m_words[word] & (1ULL << bit)) != 0;
}
template <typename Func>
static void EmitRun(u64 run_start_page, u64 run_end_page, AddressType base_address,
AddressType end_address, Func&& func) {
AddressType run_start = static_cast<AddressType>(run_start_page * kPageSize);
AddressType run_end = static_cast<AddressType>(run_end_page * kPageSize);
if (run_start < base_address) {
run_start = base_address;
}
if (run_end > end_address) {
run_end = end_address;
}
if (run_start < run_end) {
func(run_start, run_end);
}
}
std::vector<u64> m_words;
};
} // namespace Common
+18 -18
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -116,28 +119,25 @@ struct OverlapRangeSet<AddressType>::OverlapRangeSetImpl {
}
AddressType end_address = base_address + static_cast<AddressType>(size);
IntervalType interval{base_address, end_address};
bool any_removals = false;
m_split_ranges_set += std::make_pair(interval, -amount);
do {
any_removals = false;
auto it = m_split_ranges_set.lower_bound(interval);
if (it == m_split_ranges_set.end()) {
return;
}
auto end_it = m_split_ranges_set.upper_bound(interval);
for (; it != end_it; it++) {
if (it->second <= 0) {
if constexpr (has_on_delete) {
if (it->second == 0) {
on_delete(it->first.lower(), it->first.upper());
}
auto it = m_split_ranges_set.lower_bound(interval);
if (it == m_split_ranges_set.end()) {
return;
}
auto end_it = m_split_ranges_set.upper_bound(interval);
while (it != end_it) {
if (it->second <= 0) {
if constexpr (has_on_delete) {
if (it->second == 0) {
on_delete(it->first.lower(), it->first.upper());
}
any_removals = true;
m_split_ranges_set.erase(it);
break;
}
auto to_erase = it++;
m_split_ranges_set.erase(to_erase);
continue;
}
} while (any_removals);
++it;
}
}
template <typename Func>
-2
View File
@@ -20,7 +20,6 @@
#define COMPILER_ID "@CXX_COMPILER@"
#define BUILD_AUTO_UPDATE_WEBSITE "@BUILD_AUTO_UPDATE_WEBSITE@"
#define BUILD_AUTO_UPDATE_API "@BUILD_AUTO_UPDATE_API@"
#define BUILD_AUTO_UPDATE_API_PATH "@BUILD_AUTO_UPDATE_API_PATH@"
#define BUILD_AUTO_UPDATE_REPO "@BUILD_AUTO_UPDATE_REPO@"
#define IS_NIGHTLY_BUILD @IS_NIGHTLY_BUILD@
@@ -43,7 +42,6 @@ constexpr const bool g_is_nightly_build = IS_NIGHTLY_BUILD;
constexpr const char g_build_auto_update_website[] = BUILD_AUTO_UPDATE_WEBSITE;
constexpr const char g_build_auto_update_api[] = BUILD_AUTO_UPDATE_API;
constexpr const char g_build_auto_update_api_path[] = BUILD_AUTO_UPDATE_API_PATH;
constexpr const char g_build_auto_update_repo[] = BUILD_AUTO_UPDATE_REPO;
} // namespace Common
-1
View File
@@ -26,7 +26,6 @@ extern const bool g_is_nightly_build;
extern const char g_build_auto_update_website[];
extern const char g_build_auto_update_api[];
extern const char g_build_auto_update_api_path[];
extern const char g_build_auto_update_repo[];
} // namespace Common
+9 -10
View File
@@ -462,12 +462,9 @@ struct Values {
SwitchableSetting<FramePacingMode, true> frame_pacing_mode{linkage,
FramePacingMode::Target_Auto,
FramePacingMode::Target_Auto,
FramePacingMode::Target_120,
FramePacingMode::Target_240,
"frame_pacing_mode",
Category::RendererAdvanced,
Specialization::Default,
true,
true};
Category::RendererAdvanced};
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
AstcRecompression::Uncompressed,
@@ -623,11 +620,11 @@ struct Values {
"language_index",
Category::System};
SwitchableSetting<Region, true> region_index{linkage, Region::Usa, "region_index", Category::System};
SwitchableSetting<TimeZone, true> time_zone_index{linkage, TimeZone::Auto, "time_zone_index", Category::System};
Setting<u32> serial_battery{linkage, 0, "serial_battery", Category::System};
Setting<u32> serial_unit{linkage, 0, "serial_unit", Category::System};
SwitchableSetting<TimeZone, true> time_zone_index{linkage, TimeZone::Auto,
"time_zone_index", Category::System};
// Measured in seconds since epoch
SwitchableSetting<bool> custom_rtc_enabled{linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
SwitchableSetting<bool> custom_rtc_enabled{
linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
SwitchableSetting<s64> custom_rtc{
linkage, 0, "custom_rtc", Category::System, Specialization::Time,
false, true, &custom_rtc_enabled};
@@ -791,12 +788,14 @@ struct Values {
0,
65535,
"debug_knobs",
Category::Core,
Category::Debugging,
Specialization::Countable,
true,
true};
// Miscellaneous
Setting<std::string> serial_battery{linkage, std::string(), "serial_battery", Category::Miscellaneous};
Setting<std::string> serial_unit{linkage, std::string(), "serial_unit", Category::Miscellaneous};
Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous};
Setting<bool> log_flush_line{linkage, false, "flush_line", Category::Miscellaneous, Specialization::Default, true, true};
Setting<bool> censor_username{linkage, true, "censor_username", Category::Miscellaneous};
+2 -2
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -162,7 +162,7 @@ public:
/**
* @returns A unique identifier for the Setting's internal data type.
*/
[[nodiscard]] virtual std::string_view TypeId() const = 0;
[[nodiscard]] virtual std::type_index TypeId() const = 0;
/**
* Returns true if the Setting's internal data type is an enum.
+1 -1
View File
@@ -129,7 +129,7 @@ ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16, X32, X64, None);
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_90, Target_120);
ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_120, Target_240);
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
ENUM(VramUsageMode, Conservative, Aggressive);
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
+3 -9
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -220,14 +220,8 @@ public:
*
* @returns the type_index of the setting's type
*/
[[nodiscard]] std::string_view TypeId() const override final {
if constexpr (std::is_same_v<Type, std::string>) {
return "string";
} else if constexpr (std::is_same_v<Type, bool>) {
return "bool";
} else {
return "other";
}
[[nodiscard]] std::type_index TypeId() const override final {
return std::type_index(typeid(Type));
}
[[nodiscard]] constexpr u32 EnumIndex() const override final {
-75
View File
@@ -1,75 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <thread>
#ifdef _MSC_VER
#include <intrin.h>
#endif
#include "common/x64/cpu_detect.h"
#include "common/x64/cpu_wait.h"
#include "common/x64/rdtsc.h"
namespace Common::X64 {
namespace {
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
// For reference:
// At 1 GHz, 100K cycles is 100us
// At 2 GHz, 100K cycles is 50us
// At 4 GHz, 100K cycles is 25us
constexpr auto PauseCycles = 100'000U;
} // Anonymous namespace
#if defined(_MSC_VER) && !defined(__clang__)
__forceinline static void TPAUSE() {
static constexpr auto RequestC02State = 0U;
_tpause(RequestC02State, FencedRDTSC() + PauseCycles);
}
__forceinline static void MWAITX() {
static constexpr auto EnableWaitTimeFlag = 1U << 1;
static constexpr auto RequestC1State = 0U;
// monitor_var should be aligned to a cache line.
alignas(64) u64 monitor_var{};
_mm_monitorx(&monitor_var, 0, 0);
_mm_mwaitx(EnableWaitTimeFlag, RequestC1State, PauseCycles);
}
#else
static void TPAUSE() {
static constexpr auto RequestC02State = 0U;
const auto tsc = FencedRDTSC() + PauseCycles;
const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF);
const auto edx = static_cast<u32>(tsc >> 32);
asm volatile("tpause %0" : : "r"(RequestC02State), "d"(edx), "a"(eax));
}
static void MWAITX() {
static constexpr auto EnableWaitTimeFlag = 1U << 1;
static constexpr auto RequestC1State = 0U;
// monitor_var should be aligned to a cache line.
alignas(64) u64 monitor_var{};
asm volatile("monitorx" : : "a"(&monitor_var), "c"(0), "d"(0));
asm volatile("mwaitx" : : "a"(RequestC1State), "b"(PauseCycles), "c"(EnableWaitTimeFlag));
}
#endif
void MicroSleep() {
static const bool has_waitpkg = GetCPUCaps().waitpkg;
static const bool has_monitorx = GetCPUCaps().monitorx;
if (has_waitpkg) {
TPAUSE();
} else if (has_monitorx) {
MWAITX();
} else {
std::this_thread::yield();
}
}
} // namespace Common::X64
-10
View File
@@ -1,10 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
namespace Common::X64 {
void MicroSleep();
} // namespace Common::X64
+23 -19
View File
@@ -1219,9 +1219,12 @@ target_link_libraries(core PRIVATE
fmt::fmt
nlohmann_json::nlohmann_json
RenderDoc::API
ZLIB::ZLIB)
MbedTLS::mbedcrypto${MBEDTLS_LIB_SUFFIX}
MbedTLS::mbedtls${MBEDTLS_LIB_SUFFIX})
target_link_libraries(core PRIVATE httplib::httplib)
if (ENABLE_WEB_SERVICE OR ENABLE_OPENSSL)
target_link_libraries(core PRIVATE httplib::httplib)
endif()
if (ENABLE_WEB_SERVICE)
target_compile_definitions(core PUBLIC ENABLE_WEB_SERVICE)
@@ -1267,24 +1270,25 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
target_link_libraries(core PRIVATE dynarmic::dynarmic)
endif()
target_sources(core PRIVATE hle/service/ssl/ssl_backend_openssl.cpp)
if(ENABLE_OPENSSL)
target_sources(core PRIVATE
hle/service/ssl/ssl_backend_openssl.cpp)
target_link_libraries(core PRIVATE OpenSSL::SSL OpenSSL::Crypto)
target_compile_definitions(core PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT)
find_package(OpenSSL REQUIRED)
# TODO
# elseif (APPLE)
# target_sources(core PRIVATE
# hle/service/ssl/ssl_backend_securetransport.cpp)
# target_link_libraries(core PRIVATE "-framework Security")
# elseif (WIN32)
# target_sources(core PRIVATE
# hle/service/ssl/ssl_backend_schannel.cpp)
# target_link_libraries(core PRIVATE crypt32 secur32)
# else()
# target_sources(core PRIVATE
# hle/service/ssl/ssl_backend_none.cpp)
# endif()
target_link_libraries(core PRIVATE OpenSSL::SSL OpenSSL::Crypto)
target_compile_definitions(core PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT)
elseif (APPLE)
target_sources(core PRIVATE
hle/service/ssl/ssl_backend_securetransport.cpp)
target_link_libraries(core PRIVATE "-framework Security")
elseif (WIN32)
target_sources(core PRIVATE
hle/service/ssl/ssl_backend_schannel.cpp)
target_link_libraries(core PRIVATE crypt32 secur32)
else()
target_sources(core PRIVATE
hle/service/ssl/ssl_backend_none.cpp)
endif()
create_target_directory_groups(core)
@@ -88,6 +88,13 @@ bool DynarmicCallbacks32::MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expec
m_memory.WriteExclusive64(vaddr, value, expected);
}
void DynarmicCallbacks32::InterpreterFallback(u32 pc, std::size_t num_instructions) {
m_parent.LogBacktrace(m_process);
LOG_ERROR(Core_ARM,
"Unimplemented instruction @ {:#X} for {} instructions (instr = {:08X})", pc,
num_instructions, m_memory.Read32(pc));
}
void DynarmicCallbacks32::ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) {
switch (exception) {
case Dynarmic::A32::Exception::NoExecuteFault:
+1 -3
View File
@@ -35,9 +35,6 @@ public:
u32 MemoryRead32(u32 vaddr) override;
u64 MemoryRead64(u32 vaddr) override;
std::optional<u32> MemoryReadCode(u32 vaddr) override;
void InstructionSynchronizationBarrierRaised() override {
last_code_addr = 0; //reset back, force refetch
}
void MemoryWrite8(u32 vaddr, u8 value) override;
void MemoryWrite16(u32 vaddr, u16 value) override;
void MemoryWrite32(u32 vaddr, u32 value) override;
@@ -46,6 +43,7 @@ public:
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override;
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override;
bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override;
void InterpreterFallback(u32 pc, std::size_t num_instructions) override;
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override;
void CallSVC(u32 swi) override;
void AddTicks(u64 ticks) override;
@@ -102,6 +102,13 @@ bool DynarmicCallbacks64::MemoryWriteExclusive128(u64 vaddr, Dynarmic::A64::Vect
m_memory.WriteExclusive128(vaddr, value, expected);
}
void DynarmicCallbacks64::InterpreterFallback(u64 pc, std::size_t num_instructions) {
m_parent.LogBacktrace(m_process);
LOG_ERROR(Core_ARM, "Unimplemented instruction @ {:#X} for {} instructions (instr = {:08X})", pc,
num_instructions, m_memory.Read32(pc));
ReturnException(pc, PrefetchAbort);
}
void DynarmicCallbacks64::InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, u64 value) {
switch (op) {
case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: {
+1 -3
View File
@@ -42,9 +42,6 @@ public:
u64 MemoryRead64(u64 vaddr) override;
Dynarmic::A64::Vector MemoryRead128(u64 vaddr) override;
std::optional<u32> MemoryReadCode(u64 vaddr) override;
void InstructionSynchronizationBarrierRaised() override {
last_code_addr = 0; //reset back, force refetch
}
void MemoryWrite8(u64 vaddr, u8 value) override;
void MemoryWrite16(u64 vaddr, u16 value) override;
void MemoryWrite32(u64 vaddr, u32 value) override;
@@ -55,6 +52,7 @@ public:
bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override;
bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override;
bool MemoryWriteExclusive128(u64 vaddr, Dynarmic::A64::Vector value, Dynarmic::A64::Vector expected) override;
void InterpreterFallback(u64 pc, std::size_t num_instructions) override;
void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, u64 value) override;
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override;
void CallSVC(u32 svc) override;
+7 -3
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -772,8 +772,12 @@ std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, m
u32 instruction = memory.Read32(pc);
bool was_executed = false;
auto decoder = Dynarmic::A64::Decode<VisitorBase>(instruction);
was_executed = decoder.get().call(visitor, instruction);
if (auto decoder = Dynarmic::A64::Decode<VisitorBase>(instruction)) {
was_executed = decoder->get().call(visitor, instruction);
} else {
LOG_ERROR(Core_ARM, "Unallocated encoding: {:#x}", instruction);
}
return was_executed ? std::optional<u64>(pc + 4) : std::nullopt;
}
+4
View File
@@ -806,6 +806,10 @@ void System::RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
impl->content_provider->SetSlot(slot, provider);
}
void System::ClearContentProvider(FileSys::ContentProviderUnionSlot slot) {
impl->content_provider->ClearSlot(slot);
}
const Reporter& System::GetReporter() const {
return impl->reporter;
}
+5 -2
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
@@ -358,7 +358,10 @@ public:
[[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController();
[[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const;
void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot, FileSys::ContentProvider* provider);
void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
FileSys::ContentProvider* provider);
void ClearContentProvider(FileSys::ContentProviderUnionSlot slot);
[[nodiscard]] const Reporter& GetReporter() const;
+1 -26
View File
@@ -13,10 +13,6 @@
#include "common/windows/timer_resolution.h"
#endif
#ifdef ARCHITECTURE_x86_64
#include "common/x64/cpu_wait.h"
#endif
#include "common/settings.h"
#include "core/core_timing.h"
#include "core/hardware_properties.h"
@@ -287,28 +283,7 @@ void CoreTiming::ThreadLoop() {
if (next_time) {
// There are more events left in the queue, wait until the next event.
auto wait_time = *next_time - GetGlobalTimeNs().count();
if (wait_time > 0) {
#ifdef _WIN32
while (!paused && !event.IsSet() && wait_time > 0) {
wait_time = *next_time - GetGlobalTimeNs().count();
if (wait_time >= timer_resolution_ns) {
Common::Windows::SleepForOneTick();
} else {
#ifdef ARCHITECTURE_x86_64
Common::X64::MicroSleep();
#else
std::this_thread::yield();
#endif
}
}
if (event.IsSet()) {
event.Reset();
}
#else
event.WaitFor(std::chrono::nanoseconds(wait_time));
#endif
}
event.WaitFor(std::chrono::nanoseconds(wait_time));
} else {
// Queue is empty, wait until another event is scheduled and signals us to
// continue.
+60 -99
View File
@@ -1,13 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <array>
#include <cstring>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <mbedtls/cipher.h>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/crypto/aes_util.h"
@@ -28,121 +28,83 @@ NintendoTweak CalculateNintendoTweak(std::size_t sector_id) {
}
} // Anonymous namespace
// Structure to hide OpenSSL types from header file
static_assert(static_cast<std::size_t>(Mode::CTR) ==
static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_CTR),
"CTR has incorrect value.");
static_assert(static_cast<std::size_t>(Mode::ECB) ==
static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_ECB),
"ECB has incorrect value.");
static_assert(static_cast<std::size_t>(Mode::XTS) ==
static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_XTS),
"XTS has incorrect value.");
// Structure to hide mbedtls types from header file
struct CipherContext {
EVP_CIPHER_CTX* encryption_context = nullptr;
EVP_CIPHER_CTX* decryption_context = nullptr;
EVP_CIPHER* cipher = nullptr;
mbedtls_cipher_context_t encryption_context;
mbedtls_cipher_context_t decryption_context;
};
static inline const std::string GetCipherName(Mode mode, u32 key_size) {
std::string cipher;
std::size_t effective_bits = key_size * 8;
switch (mode) {
case Mode::CTR:
cipher = "CTR";
break;
case Mode::ECB:
cipher = "ECB";
break;
case Mode::XTS:
cipher = "XTS";
effective_bits /= 2;
break;
default:
UNREACHABLE();
}
return fmt::format("AES-{}-{}", effective_bits, cipher);
};
static EVP_CIPHER *GetCipher(Mode mode, u32 key_size) {
static auto fetch_cipher = [](Mode m, u32 k) {
return EVP_CIPHER_fetch(nullptr, GetCipherName(m, k).c_str(), nullptr);
};
static const struct {
EVP_CIPHER* ctr_16 = fetch_cipher(Mode::CTR, 16);
EVP_CIPHER* ecb_16 = fetch_cipher(Mode::ECB, 16);
EVP_CIPHER* xts_16 = fetch_cipher(Mode::XTS, 16);
EVP_CIPHER* ctr_32 = fetch_cipher(Mode::CTR, 32);
EVP_CIPHER* ecb_32 = fetch_cipher(Mode::ECB, 32);
EVP_CIPHER* xts_32 = fetch_cipher(Mode::XTS, 32);
} ciphers = {};
switch (mode) {
case Mode::CTR:
return key_size == 16 ? ciphers.ctr_16 : ciphers.ctr_32;
case Mode::ECB:
return key_size == 16 ? ciphers.ecb_16 : ciphers.ecb_32;
case Mode::XTS:
return key_size == 16 ? ciphers.xts_16 : ciphers.xts_32;
default:
UNIMPLEMENTED();
}
return nullptr;
}
// TODO: WHY TEMPLATE???????
template <typename Key, std::size_t KeySize>
Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode)
: ctx(std::make_unique<CipherContext>()) {
mbedtls_cipher_init(&ctx->encryption_context);
mbedtls_cipher_init(&ctx->decryption_context);
ctx->encryption_context = EVP_CIPHER_CTX_new();
ctx->decryption_context = EVP_CIPHER_CTX_new();
ctx->cipher = GetCipher(mode, KeySize);
if (ctx->cipher) {
EVP_CIPHER_up_ref(ctx->cipher);
} else {
UNIMPLEMENTED();
}
ASSERT_MSG((mbedtls_cipher_setup(
&ctx->encryption_context,
mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode))) ||
mbedtls_cipher_setup(
&ctx->decryption_context,
mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode)))) == 0,
"Failed to initialize mbedtls ciphers.");
ASSERT_MSG(ctx->encryption_context && ctx->decryption_context && ctx->cipher,
"OpenSSL cipher context failed init!");
// now init ciphers
ASSERT(EVP_CipherInit_ex2(ctx->encryption_context, ctx->cipher, key.data(), NULL, 1, NULL));
ASSERT(EVP_CipherInit_ex2(ctx->decryption_context, ctx->cipher, key.data(), NULL, 0, NULL));
EVP_CIPHER_CTX_set_padding(ctx->encryption_context, 0);
EVP_CIPHER_CTX_set_padding(ctx->decryption_context, 0);
ASSERT(
!mbedtls_cipher_setkey(&ctx->encryption_context, key.data(), KeySize * 8, MBEDTLS_ENCRYPT));
ASSERT(
!mbedtls_cipher_setkey(&ctx->decryption_context, key.data(), KeySize * 8, MBEDTLS_DECRYPT));
//"Failed to set key on mbedtls ciphers.");
}
template <typename Key, std::size_t KeySize>
AESCipher<Key, KeySize>::~AESCipher() {
EVP_CIPHER_CTX_free(ctx->encryption_context);
EVP_CIPHER_CTX_free(ctx->decryption_context);
EVP_CIPHER_free(ctx->cipher);
mbedtls_cipher_free(&ctx->encryption_context);
mbedtls_cipher_free(&ctx->decryption_context);
}
template <typename Key, std::size_t KeySize>
void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const {
auto* const context = op == Op::Encrypt ? ctx->encryption_context : ctx->decryption_context;
auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
mbedtls_cipher_reset(context);
if (size == 0)
return;
// reset
ASSERT(EVP_CipherInit_ex(context, nullptr, nullptr, nullptr, nullptr, -1));
const auto mode = mbedtls_cipher_get_cipher_mode(context);
std::size_t written = 0;
const int block_size = EVP_CIPHER_CTX_get_block_size(context);
ASSERT(block_size > 0 && block_size <= int(AesBlockBytes));
if (mode != MBEDTLS_MODE_ECB) {
const int ret = mbedtls_cipher_update(context, src, size, dest, &written);
ASSERT(ret == 0);
if (written != size) {
LOG_WARNING(Crypto, "Not all data was processed requested={:016X}, actual={:016X}.", size, written);
}
return;
}
const auto block_size = mbedtls_cipher_get_block_size(context);
ASSERT(block_size <= AesBlockBytes);
const std::size_t whole_block_bytes = size - (size % block_size);
int written = 0;
if (whole_block_bytes != 0) {
ASSERT(EVP_CipherUpdate(context, dest, &written, src, static_cast<int>(whole_block_bytes)));
if (std::size_t(written) != whole_block_bytes) {
const int ret = mbedtls_cipher_update(context, src, whole_block_bytes, dest, &written);
ASSERT(ret == 0);
if (written != whole_block_bytes) {
LOG_WARNING(Crypto, "Not all data was processed requested={:016X}, actual={:016X}.",
whole_block_bytes, written);
}
}
// tail
const std::size_t tail = size - whole_block_bytes;
if (tail == 0)
return;
@@ -150,13 +112,13 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* des
std::array<u8, AesBlockBytes> tail_buffer{};
std::memcpy(tail_buffer.data(), src + whole_block_bytes, tail);
int tail_written = 0;
ASSERT(EVP_CipherUpdate(context, tail_buffer.data(), &tail_written, tail_buffer.data(), block_size));
std::size_t tail_written = 0;
const int ret = mbedtls_cipher_update(context, tail_buffer.data(), block_size, tail_buffer.data(),
&tail_written);
ASSERT(ret == 0);
if (tail_written != block_size) {
LOG_WARNING(Crypto, "Tail block not fully processed requested={:016X}, actual={:016X}.",
block_size, tail_written);
LOG_WARNING(Crypto, "Not all data was processed requested={:016X}, actual={:016X}.", block_size,
tail_written);
}
std::memcpy(dest + whole_block_bytes, tail_buffer.data(), tail);
@@ -175,10 +137,9 @@ void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8*
template <typename Key, std::size_t KeySize>
void AESCipher<Key, KeySize>::SetIV(std::span<const u8> data) {
const int ret_enc = EVP_CipherInit_ex(ctx->encryption_context, nullptr, nullptr, nullptr, data.data(), -1);
const int ret_dec = EVP_CipherInit_ex(ctx->decryption_context, nullptr, nullptr, nullptr, data.data(), -1);
ASSERT_MSG(ret_enc == 1 && ret_dec == 1, "Failed to set IV on OpenSSL contexts");
ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, data.data(), data.size()) ||
mbedtls_cipher_set_iv(&ctx->decryption_context, data.data(), data.size())) == 0,
"Failed to set IV on mbedtls ciphers.");
}
template class AESCipher<Key128>;
+2 -2
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -10,6 +10,7 @@
#include <span>
#include <type_traits>
#include "common/common_types.h"
#include "core/file_sys/vfs/vfs.h"
namespace Core::Crypto {
@@ -61,5 +62,4 @@ public:
private:
std::unique_ptr<CipherContext> ctx;
};
} // namespace Core::Crypto
+39 -48
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -9,26 +9,35 @@
#include <bitset>
#include <cctype>
#include <fstream>
#include <locale>
#include <map>
#include <sstream>
#include <tuple>
#include <vector>
#include <openssl/evp.h>
#include <mbedtls/bignum.h>
#include <mbedtls/cipher.h>
#include <mbedtls/cmac.h>
#include <mbedtls/sha256.h>
#include "common/fs/file.h"
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/key_manager.h"
#include "core/crypto/partition_data_manager.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#ifndef MBEDTLS_CMAC_C
#error mbedtls was compiled without CMAC support. Check your USE flags (Gentoo) or contact your package maintainer.
#endif
namespace Core::Crypto {
namespace {
@@ -518,27 +527,15 @@ static std::array<u8, target_size> MGF1(const std::array<u8, in_size>& seed) {
std::array<u8, in_size + 4> seed_exp{};
std::memcpy(seed_exp.data(), seed.data(), in_size);
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
const EVP_MD* sha256 = EVP_sha256();
std::vector<u8> out;
size_t i = 0;
while (out.size() < target_size) {
size_t offset = out.size();
out.resize(offset + 0x20);
seed_exp[in_size + 3] = u8(i);
u32 hash_len = 0;
EVP_DigestInit_ex(ctx, sha256, nullptr);
EVP_DigestUpdate(ctx, seed_exp.data(), seed_exp.size());
EVP_DigestFinal_ex(ctx, out.data() + offset, &hash_len);
out.resize(out.size() + 0x20);
seed_exp[in_size + 3] = static_cast<u8>(i);
mbedtls_sha256(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0);
++i;
}
EVP_MD_CTX_free(ctx);
std::array<u8, target_size> target;
std::memcpy(target.data(), out.data(), target_size);
return target;
@@ -591,28 +588,32 @@ std::optional<Key128> KeyManager::ParseTicketTitleKey(const Ticket& ticket) {
return std::nullopt;
}
mbedtls_mpi D; // RSA Private Exponent
mbedtls_mpi N; // RSA Modulus
mbedtls_mpi S; // Input
mbedtls_mpi M; // Output
mbedtls_mpi_init(&D);
mbedtls_mpi_init(&N);
mbedtls_mpi_init(&S);
mbedtls_mpi_init(&M);
const auto& title_key_block = ticket.GetData().title_key_block;
mbedtls_mpi_read_binary(&D, eticket_rsa_keypair.decryption_key.data(),
eticket_rsa_keypair.decryption_key.size());
mbedtls_mpi_read_binary(&N, eticket_rsa_keypair.modulus.data(),
eticket_rsa_keypair.modulus.size());
mbedtls_mpi_read_binary(&S, title_key_block.data(), title_key_block.size());
mbedtls_mpi_exp_mod(&M, &S, &D, &N, nullptr);
std::array<u8, 0x100> rsa_step;
{
// Private context for OpenSSL bignumbers
// Inside block because I dont wanna pollute the space...
const auto& title_key_block = ticket.GetData().title_key_block;
BIGNUM* D = BN_bin2bn(eticket_rsa_keypair.decryption_key.data(), int(eticket_rsa_keypair.decryption_key.size()), NULL);
BIGNUM* N = BN_bin2bn(eticket_rsa_keypair.modulus.data(), int(eticket_rsa_keypair.modulus.size()), NULL);
BIGNUM* S = BN_bin2bn(title_key_block.data(), int(title_key_block.size()), NULL);
BIGNUM* M = BN_new();
// M = S ^ D mod N
BN_mod_exp(M, S, D, N, NULL);
BN_bn2bin(M, rsa_step.data());
BN_free(D);
BN_free(N);
BN_free(S);
BN_free(M);
}
mbedtls_mpi_write_binary(&M, rsa_step.data(), rsa_step.size());
u8 m_0 = rsa_step[0];
std::array<u8, 0x20> m_1;
std::array<u8, 0xDF> m_2;
std::memcpy(m_1.data(), rsa_step.data() + 0x01, m_1.size());
std::array<u8, 0xDF> m_2;
std::memcpy(m_2.data(), rsa_step.data() + 0x21, m_2.size());
if (m_0 != 0) {
@@ -953,18 +954,8 @@ void KeyManager::DeriveSDSeedLazy() {
static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) {
Key128 out{};
static EVP_MAC* mac = EVP_MAC_fetch(nullptr, "cmac", nullptr);
if (!mac) return out;
static EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(mac);
if (!ctx) return out;
EVP_MAC_init(ctx, key.data(), key.size() * CHAR_BIT, NULL);
EVP_MAC_update(ctx, source, size);
size_t len;
EVP_MAC_final(ctx, out.data(), &len, out.size());
mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), key.data(),
key.size() * 8, source, size, out.data());
return out;
}
+7 -2
View File
@@ -1,20 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <array>
#include <cctype>
#include <cstring>
#include <mbedtls/sha256.h>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/string_util.h"
#include "common/swap.h"
#include "core/crypto/key_manager.h"
#include "core/crypto/partition_data_manager.h"
#include "core/crypto/xts_encryption_layer.h"
#include "core/file_sys/kernel_executable.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/file_sys/vfs/vfs_offset.h"
#include "core/file_sys/vfs/vfs_vector.h"
#include "core/loader/loader.h"
@@ -250,4 +255,4 @@ std::array<u8, 576> PartitionDataManager::GetETicketExtendedKek() const {
prodinfo_decrypted->Read(out.data(), out.size(), 0x3890);
return out;
}
} // namespace Core::Crypto
} // namespace Core::Crypto
-75
View File
@@ -4,13 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include <cstddef>
#include <cstring>
#include <limits>
#include <span>
#include <zlib.h>
#include "common/settings.h"
#include "common/string_util.h"
#include "common/swap.h"
@@ -38,73 +31,6 @@ const std::array<const char*, 16> LANGUAGE_NAMES{{
"BrazilianPortuguese",
}};
namespace {
constexpr std::size_t LEGACY_LANGUAGE_REGION_SIZE = sizeof(std::array<LanguageEntry, 16>);
constexpr std::size_t PACKED_LANGUAGE_REGION_MAX_SIZE = sizeof(LanguageEntry) * 32;
bool InflateRawDeflate(std::span<const u8> compressed, std::vector<u8>& out) {
if (compressed.empty() || compressed.size() > std::numeric_limits<uInt>::max()) {
return false;
}
z_stream stream{};
stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(compressed.data()));
stream.avail_in = static_cast<uInt>(compressed.size());
if (inflateInit2(&stream, -MAX_WBITS) != Z_OK) {
return false;
}
std::array<u8, 0x1000> chunk{};
int ret = Z_OK;
while (ret == Z_OK) {
stream.next_out = reinterpret_cast<Bytef*>(chunk.data());
stream.avail_out = static_cast<uInt>(chunk.size());
ret = inflate(&stream, Z_NO_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END) {
inflateEnd(&stream);
return false;
}
const auto produced = chunk.size() - static_cast<std::size_t>(stream.avail_out);
if (produced != 0) {
if (out.size() + produced > PACKED_LANGUAGE_REGION_MAX_SIZE) {
inflateEnd(&stream);
return false;
}
out.insert(out.end(), chunk.begin(),
chunk.begin() + static_cast<std::ptrdiff_t>(produced));
}
}
inflateEnd(&stream);
return ret == Z_STREAM_END;
}
void DecodePackedLanguageEntries(RawNACP& raw) {
auto* packed_region = reinterpret_cast<u8*>(raw.language_entries.data());
u16_le compressed_size_le{};
std::memcpy(&compressed_size_le, packed_region, sizeof(compressed_size_le));
const auto compressed_size = static_cast<std::size_t>(compressed_size_le);
if (compressed_size == 0 || compressed_size > LEGACY_LANGUAGE_REGION_SIZE - sizeof(u16_le)) {
return;
}
std::vector<u8> decompressed;
if (!InflateRawDeflate(
std::span<const u8>(packed_region + sizeof(u16_le), compressed_size), decompressed)) {
return;
}
if (decompressed.size() < LEGACY_LANGUAGE_REGION_SIZE ||
decompressed.size() % sizeof(LanguageEntry) != 0) {
return;
}
std::memcpy(raw.language_entries.data(), decompressed.data(), LEGACY_LANGUAGE_REGION_SIZE);
}
} // namespace
std::string LanguageEntry::GetApplicationName() const {
return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(),
application_name.size());
@@ -140,7 +66,6 @@ NACP::NACP() = default;
NACP::NACP(VirtualFile file) {
file->ReadObject(&raw);
DecodePackedLanguageEntries(raw);
}
NACP::~NACP() = default;
-4
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -40,7 +37,6 @@ enum class ContentRecordType : u8 {
HtmlDocument = 4,
LegalInformation = 5,
DeltaFragment = 6,
Count,
};
struct ContentRecord {
+7 -7
View File
@@ -143,7 +143,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
bool checked_external = false;
bool checked_manual = false;
const auto* content_union = static_cast<const ContentProviderUnion*>(&content_provider);
const auto* content_union = dynamic_cast<const ContentProviderUnion*>(&content_provider);
const auto update_tid = GetUpdateTitleID(title_id);
if (content_union) {
@@ -167,7 +167,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
// Also check ManualContentProvider (for Android)
if (!checked_external) {
const auto* manual_provider = static_cast<const ManualContentProvider*>(
const auto* manual_provider = dynamic_cast<const ManualContentProvider*>(
content_union->GetSlotProvider(ContentProviderUnionSlot::FrontendManual));
if (manual_provider) {
const auto manual_update_versions = manual_provider->ListUpdateVersions(update_tid);
@@ -243,7 +243,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
// Also try ManualContentProvider
if (update == nullptr) {
const auto* manual_provider = static_cast<const ManualContentProvider*>(
const auto* manual_provider = dynamic_cast<const ManualContentProvider*>(
content_union->GetSlotProvider(ContentProviderUnionSlot::FrontendManual));
if (manual_provider) {
auto file = manual_provider->GetEntryForVersion(update_tid, ContentRecordType::Program, *enabled_version);
@@ -570,7 +570,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
bool checked_external = false;
bool checked_manual = false;
const auto* content_union = static_cast<const ContentProviderUnion*>(&content_provider);
const auto* content_union = dynamic_cast<const ContentProviderUnion*>(&content_provider);
if (content_union) {
// First, check ExternalContentProvider
const auto* external_provider = content_union->GetExternalProvider();
@@ -592,7 +592,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
}
if (!checked_external) {
const auto* manual_provider = static_cast<const ManualContentProvider*>(
const auto* manual_provider = dynamic_cast<const ManualContentProvider*>(
content_union->GetSlotProvider(ContentProviderUnionSlot::FrontendManual));
if (manual_provider) {
const auto manual_update_versions = manual_provider->ListUpdateVersions(update_tid);
@@ -690,7 +690,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
std::vector<Patch> external_update_patches;
const auto* content_union = static_cast<const ContentProviderUnion*>(&content_provider);
const auto* content_union = dynamic_cast<const ContentProviderUnion*>(&content_provider);
if (content_union) {
// First, check ExternalContentProvider for updates
@@ -721,7 +721,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
}
}
const auto* manual_provider = static_cast<const ManualContentProvider*>(
const auto* manual_provider = dynamic_cast<const ManualContentProvider*>(
content_union->GetSlotProvider(ContentProviderUnionSlot::FrontendManual));
if (manual_provider && external_update_patches.empty()) {
const auto manual_update_versions = manual_provider->ListUpdateVersions(update_tid);
+178 -124
View File
@@ -7,11 +7,12 @@
#include <algorithm>
#include <random>
#include <regex>
#include <openssl/evp.h>
#include <mbedtls/sha256.h>
#include "common/assert.h"
#include "common/fs/path_util.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "common/string_util.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/card_image.h"
@@ -63,23 +64,17 @@ static bool FollowsNcaIdFormat(std::string_view name) {
static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bool second_hex_upper,
bool within_two_digit, bool cnmt_suffix) {
const auto nca_str = Common::HexToString(nca_id, second_hex_upper);
if (!within_two_digit) {
const auto format_str = fmt::runtime(cnmt_suffix ? "{}.cnmt.nca" : "/{}.nca");
return fmt::format(format_str, nca_str);
return fmt::format(format_str, Common::HexToString(nca_id, second_hex_upper));
}
Core::Crypto::SHA256Hash hash{};
u32 hash_len = 0;
EVP_Digest(nca_id.data(), nca_id.size(), hash.data(), &hash_len, EVP_sha256(), nullptr);
mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0);
const auto format_str =
fmt::runtime(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca");
LOG_DEBUG(Loader, "Decoded {} bytes, nca id {}", hash_len, nca_str);
return fmt::format(format_str, hash[0], nca_str);
return fmt::format(format_str, hash[0], Common::HexToString(nca_id, second_hex_upper));
}
static std::string GetCNMTName(TitleType type, u64 title_id) {
@@ -157,11 +152,7 @@ bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
}
Core::Crypto::SHA256Hash hash{};
u32 hash_len = 0;
EVP_Digest(id.data(), id.size(), hash.data(), &hash_len, EVP_sha256(), nullptr);
LOG_DEBUG(Loader, "Decoded {} bytes, nca id {}", hash_len, id);
mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
const auto dirname = fmt::format("000000{:02X}", hash[0]);
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
@@ -185,11 +176,7 @@ bool PlaceholderCache::Delete(const NcaID& id) const {
}
Core::Crypto::SHA256Hash hash{};
u32 hash_len = 0;
EVP_Digest(id.data(), id.size(), hash.data(), &hash_len, EVP_sha256(), nullptr);
LOG_DEBUG(Loader, "Decoded {} bytes, nca id {}", hash_len, id);
mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
const auto dirname = fmt::format("000000{:02X}", hash[0]);
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
@@ -366,7 +353,8 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
return file;
}
static std::optional<NcaID> CheckMapForContentRecord(const ankerl::unordered_dense::map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
static std::optional<NcaID> CheckMapForContentRecord(const std::map<u64, CNMT>& map, u64 title_id,
ContentRecordType type) {
const auto cmnt_iter = map.find(title_id);
if (cmnt_iter == map.cend()) {
return std::nullopt;
@@ -683,12 +671,7 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
const OptionalHeader opt_header{0, 0};
ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}};
const auto& data = nca.GetBaseFile()->ReadBytes(0x100000);
u32 hash_len = 0;
EVP_Digest(data.data(), data.size(), c_rec.hash.data(), &hash_len, EVP_sha256(), nullptr);
LOG_DEBUG(Loader, "Decoded {} bytes, nca {}", hash_len, nca.GetName());
mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0);
std::memcpy(&c_rec.nca_id, &c_rec.hash, 16);
const CNMT new_cnmt(header, opt_header, {c_rec}, {});
if (!RawInstallYuzuMeta(new_cnmt)) {
@@ -799,12 +782,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
id = *override_id;
} else {
const auto& data = in->ReadBytes(0x100000);
u32 hash_len = 0;
EVP_Digest(data.data(), data.size(), hash.data(), &hash_len, EVP_sha256(), nullptr);
LOG_DEBUG(Loader, "Decoded {} bytes, nca {}", hash_len, nca.GetName());
mbedtls_sha256(data.data(), data.size(), hash.data(), 0);
memcpy(id.data(), hash.data(), 16);
}
@@ -851,119 +829,174 @@ bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) {
}
}
Refresh();
return std::find_if(yuzu_meta.begin(), yuzu_meta.end(), [&cnmt](const std::pair<u64, CNMT>& kv) {
return kv.second.GetType() == cnmt.GetType() && kv.second.GetTitleID() == cnmt.GetTitleID();
}) != yuzu_meta.end();
return std::find_if(yuzu_meta.begin(), yuzu_meta.end(),
[&cnmt](const std::pair<u64, CNMT>& kv) {
return kv.second.GetType() == cnmt.GetType() &&
kv.second.GetTitleID() == cnmt.GetTitleID();
}) != yuzu_meta.end();
}
ContentProviderUnion::~ContentProviderUnion() = default;
void ContentProviderUnion::SetSlot(ContentProviderUnionSlot slot, ContentProvider* provider) {
providers[size_t(slot)] = provider;
providers[slot] = provider;
}
void ContentProviderUnion::ClearSlot(ContentProviderUnionSlot slot) {
providers[slot] = nullptr;
}
void ContentProviderUnion::Refresh() {
for (auto e : providers)
if (e != nullptr)
e->Refresh();
for (auto& provider : providers) {
if (provider.second == nullptr)
continue;
provider.second->Refresh();
}
}
bool ContentProviderUnion::HasEntry(u64 title_id, ContentRecordType type) const {
for (auto const e : providers)
if (e && e->HasEntry(title_id, type))
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
if (provider.second->HasEntry(title_id, type))
return true;
}
return false;
}
std::optional<u32> ContentProviderUnion::GetEntryVersion(u64 title_id) const {
for (auto const e : providers) {
if (e == nullptr)
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
if (auto const res = e->GetEntryVersion(title_id); res != std::nullopt)
const auto res = provider.second->GetEntryVersion(title_id);
if (res != std::nullopt)
return res;
}
return std::nullopt;
}
VirtualFile ContentProviderUnion::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
for (auto const e : providers) {
if (e == nullptr)
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
if (auto const res = e->GetEntryUnparsed(title_id, type); res != nullptr)
const auto res = provider.second->GetEntryUnparsed(title_id, type);
if (res != nullptr)
return res;
}
return nullptr;
}
VirtualFile ContentProviderUnion::GetEntryRaw(u64 title_id, ContentRecordType type) const {
for (auto const e : providers) {
if (e == nullptr)
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
if (auto const res = e->GetEntryRaw(title_id, type); res != nullptr)
const auto res = provider.second->GetEntryRaw(title_id, type);
if (res != nullptr)
return res;
}
return nullptr;
}
std::unique_ptr<NCA> ContentProviderUnion::GetEntry(u64 title_id, ContentRecordType type) const {
for (auto const e : providers) {
if (e == nullptr)
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
if (auto res = e->GetEntry(title_id, type); res != nullptr)
auto res = provider.second->GetEntry(title_id, type);
if (res != nullptr)
return res;
}
return nullptr;
}
std::vector<ContentProviderEntry> ContentProviderUnion::ListEntriesFilter(
std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
std::optional<u64> title_id) const {
std::vector<ContentProviderEntry> out;
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
const auto vec = provider.second->ListEntriesFilter(title_type, record_type, title_id);
std::copy(vec.begin(), vec.end(), std::back_inserter(out));
}
std::sort(out.begin(), out.end());
out.erase(std::unique(out.begin(), out.end()), out.end());
return out;
}
std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>>
ContentProviderUnion::ListEntriesFilterOrigin(std::optional<ContentProviderUnionSlot> origin,
std::optional<TitleType> title_type,
std::optional<ContentRecordType> record_type,
std::optional<u64> title_id) const {
std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> out;
for (const auto& provider : providers) {
if (provider.second == nullptr)
continue;
if (origin.has_value() && *origin != provider.first)
continue;
const auto vec = provider.second->ListEntriesFilter(title_type, record_type, title_id);
std::transform(vec.begin(), vec.end(), std::back_inserter(out),
[&provider](const ContentProviderEntry& entry) {
return std::make_pair(provider.first, entry);
});
}
std::sort(out.begin(), out.end());
out.erase(std::unique(out.begin(), out.end()), out.end());
return out;
}
std::optional<ContentProviderUnionSlot> ContentProviderUnion::GetSlotForEntry(
u64 title_id, ContentRecordType type) const {
const auto iter =
std::find_if(providers.begin(), providers.end(), [title_id, type](const auto& provider) {
return provider.second != nullptr && provider.second->HasEntry(title_id, type);
});
if (iter == providers.end()) {
return std::nullopt;
}
return iter->first;
}
const ExternalContentProvider* ContentProviderUnion::GetExternalProvider() const {
auto it = providers.find(ContentProviderUnionSlot::External);
if (it != providers.end() && it->second != nullptr) {
return dynamic_cast<const ExternalContentProvider*>(it->second);
}
return nullptr;
}
std::vector<ContentProviderEntry> ContentProviderUnion::ListEntriesFilter(std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type, std::optional<u64> title_id) const {
std::vector<ContentProviderEntry> out;
for (auto const& e : providers) {
if (e != nullptr) {
auto const vec = e->ListEntriesFilter(title_type, record_type, title_id);
std::copy(vec.begin(), vec.end(), std::back_inserter(out));
}
const ContentProvider* ContentProviderUnion::GetSlotProvider(ContentProviderUnionSlot slot) const {
auto it = providers.find(slot);
if (it != providers.end()) {
return it->second;
}
std::sort(out.begin(), out.end());
out.erase(std::unique(out.begin(), out.end()), out.end());
return out;
}
std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> ContentProviderUnion::ListEntriesFilterOrigin(std::optional<ContentProviderUnionSlot> origin, std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type, std::optional<u64> title_id) const {
std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> out;
for (size_t i = 0; i < providers.size(); ++i) {
auto const& e = providers[i];
if (e == nullptr)
continue;
if (origin.has_value() && *origin != ContentProviderUnionSlot(i))
continue;
auto const vec = e->ListEntriesFilter(title_type, record_type, title_id);
std::transform(vec.begin(), vec.end(), std::back_inserter(out), [i](const ContentProviderEntry& entry) {
return std::make_pair(ContentProviderUnionSlot(i), entry);
});
}
std::sort(out.begin(), out.end());
out.erase(std::unique(out.begin(), out.end()), out.end());
return out;
}
std::optional<ContentProviderUnionSlot> ContentProviderUnion::GetSlotForEntry(u64 title_id, ContentRecordType type) const {
for (size_t i = 0; i < providers.size(); ++i) {
auto const& e = providers[i];
if (e != nullptr && e->HasEntry(title_id, type))
return {ContentProviderUnionSlot(i)};
}
return std::nullopt;
}
const ExternalContentProvider* ContentProviderUnion::GetExternalProvider() const {
return static_cast<const ExternalContentProvider*>(providers[size_t(ContentProviderUnionSlot::External)]);
return nullptr;
}
ManualContentProvider::~ManualContentProvider() = default;
void ManualContentProvider::AddEntry(TitleType title_type, ContentRecordType content_type, u64 title_id, VirtualFile file) {
void ManualContentProvider::AddEntry(TitleType title_type, ContentRecordType content_type,
u64 title_id, VirtualFile file) {
entries.insert_or_assign({title_type, content_type, title_id}, file);
}
@@ -971,13 +1004,14 @@ void ManualContentProvider::AddEntryWithVersion(TitleType title_type, ContentRec
u64 title_id, u32 version,
const std::string& version_string, VirtualFile file) {
if (title_type == TitleType::Update) {
auto it = std::find_if(multi_version_entries.begin(), multi_version_entries.end(), [title_id, version](const ExternalUpdateEntry& entry) {
return entry.title_id == title_id && entry.version == version;
});
auto it = std::find_if(multi_version_entries.begin(), multi_version_entries.end(),
[title_id, version](const ExternalUpdateEntry& entry) {
return entry.title_id == title_id && entry.version == version;
});
if (it != multi_version_entries.end()) {
// Update existing entry
it->files[size_t(content_type)] = file;
it->files[content_type] = file;
if (!version_string.empty()) {
it->version_string = version_string;
}
@@ -987,7 +1021,7 @@ void ManualContentProvider::AddEntryWithVersion(TitleType title_type, ContentRec
new_entry.title_id = title_id;
new_entry.version = version;
new_entry.version_string = version_string;
new_entry.files[size_t(content_type)] = file;
new_entry.files[content_type] = file;
multi_version_entries.push_back(new_entry);
}
@@ -1084,19 +1118,26 @@ std::vector<ExternalUpdateEntry> ManualContentProvider::ListUpdateVersions(u64 t
VirtualFile ManualContentProvider::GetEntryForVersion(u64 title_id, ContentRecordType type, u32 version) const {
for (const auto& entry : multi_version_entries) {
if (entry.title_id == title_id && entry.version == version) {
if (auto const p = entry.files[size_t(type)])
return p;
auto it = entry.files.find(type);
if (it != entry.files.end()) {
return it->second;
}
}
}
return nullptr;
}
bool ManualContentProvider::HasMultipleVersions(u64 title_id, ContentRecordType type) const {
size_t count = 0;
for (const auto& entry : multi_version_entries)
if (entry.title_id == title_id && entry.files[size_t(type)])
++count;
return count > 0;
int count = 0;
for (const auto& entry : multi_version_entries) {
if (entry.title_id == title_id && entry.files.count(type) > 0) {
count++;
if (count > 1) {
return true;
}
}
}
return false;
}
ExternalContentProvider::ExternalContentProvider(std::vector<VirtualDir> load_directories)
@@ -1215,7 +1256,7 @@ void ExternalContentProvider::ProcessNSP(const VirtualFile& file) {
}
}
std::map<std::pair<u64, u32>, std::array<VirtualFile, size_t(ContentRecordType::Count)>> version_files;
std::map<std::pair<u64, u32>, std::map<ContentRecordType, VirtualFile>> version_files;
for (const auto& [title_id, nca_map] : ncas) {
for (const auto& [type_pair, nca] : nca_map) {
@@ -1236,7 +1277,7 @@ void ExternalContentProvider::ProcessNSP(const VirtualFile& file) {
version = ver_it->second;
}
version_files[{title_id, version}][size_t(content_type)] = nca_file;
version_files[{title_id, version}][content_type] = nca_file;
}
LOG_DEBUG(Service_FS, "Added entry - Title ID: {:016X}, Type: {}, Content: {}",
@@ -1257,7 +1298,9 @@ void ExternalContentProvider::ProcessNSP(const VirtualFile& file) {
bool version_exists = false;
for (auto& existing : multi_version_entries) {
if (existing.title_id == title_id && existing.version == version) {
existing.files = files_map;
for (const auto& [content_type, _file] : files_map) {
existing.files[content_type] = _file;
}
if (existing.version_string.empty() && !ver_str.empty()) {
existing.version_string = ver_str;
}
@@ -1340,7 +1383,7 @@ void ExternalContentProvider::ProcessXCI(const VirtualFile& file) {
}
}
std::map<std::pair<u64, u32>, std::array<VirtualFile, size_t(ContentRecordType::Count)>> version_files;
std::map<std::pair<u64, u32>, std::map<ContentRecordType, VirtualFile>> version_files;
for (const auto& [title_id, nca_map] : ncas) {
for (const auto& [type_pair, nca] : nca_map) {
@@ -1361,7 +1404,7 @@ void ExternalContentProvider::ProcessXCI(const VirtualFile& file) {
version = ver_it->second;
}
version_files[{title_id, version}][size_t(content_type)] = nca_file;
version_files[{title_id, version}][content_type] = nca_file;
}
}
}
@@ -1379,7 +1422,9 @@ void ExternalContentProvider::ProcessXCI(const VirtualFile& file) {
bool version_exists = false;
for (auto& existing : multi_version_entries) {
if (existing.title_id == title_id && existing.version == version) {
existing.files = files_map;
for (const auto& [content_type, _file] : files_map) {
existing.files[content_type] = _file;
}
if (existing.version_string.empty() && !ver_str.empty()) {
existing.version_string = ver_str;
}
@@ -1484,19 +1529,28 @@ std::vector<ExternalUpdateEntry> ExternalContentProvider::ListUpdateVersions(u64
}
VirtualFile ExternalContentProvider::GetEntryForVersion(u64 title_id, ContentRecordType type, u32 version) const {
for (const auto& entry : multi_version_entries)
if (entry.title_id == title_id && entry.version == version)
if (auto const p = entry.files[size_t(type)])
return p;
for (const auto& entry : multi_version_entries) {
if (entry.title_id == title_id && entry.version == version) {
auto it = entry.files.find(type);
if (it != entry.files.end()) {
return it->second;
}
}
}
return nullptr;
}
bool ExternalContentProvider::HasMultipleVersions(u64 title_id, ContentRecordType type) const {
size_t count = 0;
for (const auto& entry : multi_version_entries)
if (entry.title_id == title_id && entry.files[size_t(type)])
++count;
return count > 1;
for (const auto& entry : multi_version_entries) {
if (entry.title_id == title_id && entry.files.count(type) > 0) {
count++;
if (count > 1) {
return true;
}
}
}
return false;
}
} // namespace FileSys
+17 -16
View File
@@ -11,19 +11,19 @@
#include <memory>
#include <string>
#include <vector>
#include <ankerl/unordered_dense.h>
#include <boost/container/flat_map.hpp>
#include "common/common_types.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/file_sys/nca_metadata.h"
namespace FileSys {
class ExternalContentProvider;
class CNMT;
class ExternalContentProvider;
class CNMT;
class NCA;
class NSP;
class XCI;
enum class ContentRecordType : u8;
enum class NCAContentType : u8;
enum class TitleType : u8;
@@ -56,7 +56,7 @@ struct ExternalUpdateEntry {
u64 title_id;
u32 version;
std::string version_string;
std::array<VirtualFile, size_t(ContentRecordType::Count)> files;
std::map<ContentRecordType, VirtualFile> files;
};
constexpr u64 GetUpdateTitleID(u64 base_title_id) {
@@ -207,11 +207,11 @@ private:
ContentProviderParsingFunction parser;
// maps tid -> NcaID of meta
ankerl::unordered_dense::map<u64, NcaID> meta_id;
std::map<u64, NcaID> meta_id;
// maps tid -> meta
ankerl::unordered_dense::map<u64, CNMT> meta;
std::map<u64, CNMT> meta;
// maps tid -> meta for CNMT in yuzu_meta
ankerl::unordered_dense::map<u64, CNMT> yuzu_meta;
std::map<u64, CNMT> yuzu_meta;
};
enum class ContentProviderUnionSlot {
@@ -220,7 +220,6 @@ enum class ContentProviderUnionSlot {
SDMC, ///< SD Card
FrontendManual, ///< Frontend-defined game list or similar
External, ///< External content from NSP/XCI files in configured directories
Count,
};
// Combines multiple ContentProvider(s) (i.e. SysNAND, UserNAND, SDMC) into one interface.
@@ -229,6 +228,8 @@ public:
~ContentProviderUnion() override;
void SetSlot(ContentProviderUnionSlot slot, ContentProvider* provider);
void ClearSlot(ContentProviderUnionSlot slot);
void Refresh() override;
bool HasEntry(u64 title_id, ContentRecordType type) const override;
std::optional<u32> GetEntryVersion(u64 title_id) const override;
@@ -240,18 +241,18 @@ public:
std::optional<u64> title_id) const override;
const ExternalContentProvider* GetExternalProvider() const;
[[nodiscard]] inline const ContentProvider* GetSlotProvider(ContentProviderUnionSlot slot) const {
return providers[size_t(slot)];
}
const ContentProvider* GetSlotProvider(ContentProviderUnionSlot slot) const;
std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> ListEntriesFilterOrigin(
std::optional<ContentProviderUnionSlot> origin = {},
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
std::optional<u64> title_id = {}) const;
std::optional<ContentProviderUnionSlot> GetSlotForEntry(u64 title_id, ContentRecordType type) const;
std::optional<ContentProviderUnionSlot> GetSlotForEntry(u64 title_id,
ContentRecordType type) const;
private:
std::array<ContentProvider*, size_t(ContentProviderUnionSlot::Count)> providers;
std::map<ContentProviderUnionSlot, ContentProvider*> providers;
};
class ManualContentProvider : public ContentProvider {
@@ -311,8 +312,8 @@ private:
void ProcessXCI(const VirtualFile& file);
std::vector<VirtualDir> load_dirs;
ankerl::unordered_dense::map<std::tuple<u64, ContentRecordType, TitleType>, VirtualFile> entries;
ankerl::unordered_dense::map<u64, u32> versions;
std::map<std::tuple<u64, ContentRecordType, TitleType>, VirtualFile> entries;
std::map<u64, u32> versions;
std::vector<ExternalUpdateEntry> multi_version_entries;
};
+2 -7
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -52,9 +52,7 @@ constexpr FS::FileAccessMode ModeFlagsToFileAccessMode(OpenMode mode) {
} // Anonymous namespace
RealVfsFilesystem::RealVfsFilesystem() : VfsFilesystem(nullptr) {}
RealVfsFilesystem::~RealVfsFilesystem() {
in_dtor = true;
}
RealVfsFilesystem::~RealVfsFilesystem() = default;
std::string RealVfsFilesystem::GetName() const {
return "Real";
@@ -226,9 +224,6 @@ std::unique_lock<std::mutex> RealVfsFilesystem::RefreshReference(const std::stri
}
void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference) {
if (in_dtor)
return;
std::scoped_lock lk{list_lock};
// Remove from list.
-5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -55,8 +52,6 @@ private:
ReferenceListType closed_references;
std::mutex list_lock;
size_t num_open_files{};
// TODO: Workaround for improper dtor() ordering on clang + FreeBSD
bool in_dtor = false;
private:
friend class RealVfsFile;
+15 -24
View File
@@ -1,16 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <array>
#include <cstring>
#include <regex>
#include <string>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <mbedtls/md.h>
#include <mbedtls/sha256.h>
#include "common/fs/path_util.h"
#include "common/hex_util.h"
@@ -30,24 +31,19 @@ constexpr u64 NAX_HEADER_PADDING_SIZE = 0x4000;
template <typename SourceData, typename SourceKey, typename Destination>
static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t key_length,
const SourceData* data, std::size_t data_length) {
size_t out_len = 0;
mbedtls_md_context_t context;
mbedtls_md_init(&context);
static EVP_MAC* mac = EVP_MAC_fetch(nullptr, "HMAC", nullptr);
if (!mac) return false;
static EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(mac);
if (!ctx) return false;
static OSSL_PARAM params[] = {
OSSL_PARAM_construct_utf8_string("digest", (char*)"SHA256", 0),
OSSL_PARAM_construct_end()
};
if (!EVP_MAC_init(ctx, reinterpret_cast<const unsigned char*>(key), key_length, params))
if (mbedtls_md_setup(&context, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) ||
mbedtls_md_hmac_starts(&context, reinterpret_cast<const u8*>(key), key_length) ||
mbedtls_md_hmac_update(&context, reinterpret_cast<const u8*>(data), data_length) ||
mbedtls_md_hmac_finish(&context, reinterpret_cast<u8*>(out))) {
mbedtls_md_free(&context);
return false;
}
return EVP_MAC_update(ctx, reinterpret_cast<const unsigned char*>(data), data_length) &&
EVP_MAC_final(ctx, reinterpret_cast<unsigned char*>(out), &out_len, 32);
mbedtls_md_free(&context);
return true;
}
NAX::NAX(VirtualFile file_)
@@ -72,12 +68,7 @@ NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
: header(std::make_unique<NAXHeader>()),
file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
Core::Crypto::SHA256Hash hash{};
u32 hash_len = 0;
EVP_Digest(nca_id.data(), nca_id.size(), hash.data(), &hash_len, EVP_sha256(), nullptr);
LOG_DEBUG(Loader, "Decoded {} bytes, nca id {}", hash_len, nca_id);
mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0);
status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0],
Common::HexToString(nca_id, false)));
}
+1 -3
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -8,6 +5,7 @@
#include <array>
#include <cctype>
#include <mbedtls/md5.h>
#include "core/hle/service/bcat/bcat_result.h"
#include "core/hle/service/bcat/bcat_types.h"
@@ -1,11 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <openssl/err.h>
#include <openssl/evp.h>
#include "common/string_util.h"
#include "core/file_sys/vfs/vfs_types.h"
#include "core/hle/service/bcat/bcat_result.h"
@@ -20,10 +18,7 @@ namespace Service::BCAT {
static BcatDigest DigestFile(const FileSys::VirtualFile& file) {
BcatDigest out{};
const auto bytes = file->ReadAllBytes();
u32 hash_len = 0;
EVP_Digest(bytes.data(), bytes.size(), out.data(), &hash_len, EVP_md5(), nullptr);
mbedtls_md5(bytes.data(), bytes.size(), out.data());
return out;
}
+3 -3
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -444,9 +444,9 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
const bool _is_domain = _mgr ? _mgr->IsDomain() : false;
ASSERT_MSG(!_is_domain,
"Non-domain reply used on domain session\n"
"Service={} (TIPC={} CmdType={} Cmd=0x{:08X}\n"
"Service={} (type={})\nTIPC={} CmdType={} Cmd=0x{:08X}\n"
"HasDomainHeader={} DomainHandlers={}\nDesc={}",
t.GetServiceName(), ctx.IsTipc(),
t.GetServiceName(), typeid(T).name(), ctx.IsTipc(),
static_cast<u32>(ctx.GetCommandType()), static_cast<u32>(ctx.GetCommand()),
ctx.HasDomainMessageHeader(), _mgr ? static_cast<u32>(_mgr->DomainHandlerCount()) : 0u,
ctx.Description());
+6 -3
View File
@@ -56,9 +56,6 @@ public:
}
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
}
void InstructionSynchronizationBarrierRaised() override {
last_code_addr = 0; //reset back, force refetch
}
u8 MemoryRead8(u64 vaddr) override {
return ReadMemory<u8>(vaddr);
}
@@ -119,6 +116,7 @@ public:
void CallSVC(u32 swi) override;
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override;
void InterpreterFallback(u64 pc, size_t num_instructions) override;
void AddTicks(u64 ticks) override {}
u64 GetTicksRemaining() override {
@@ -434,6 +432,11 @@ void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception excep
parent.jit->HaltExecution();
}
void DynarmicCallbacks64::InterpreterFallback(u64 pc, size_t num_instructions) {
LOG_CRITICAL(Service_JIT, "Unimplemented instruction PC @ {:08x}", pc);
parent.jit->HaltExecution();
}
JITContext::JITContext(Core::Memory::Memory& memory)
: impl{std::make_unique<JITContextImpl>(memory)} {}
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -8,9 +5,8 @@
// SPDX-License-Identifier: MIT
#include <array>
#include <openssl/evp.h>
#include <openssl/core_names.h>
#include <mbedtls/aes.h>
#include <mbedtls/hmac_drbg.h>
#include "common/fs/file.h"
#include "common/fs/fs.h"
@@ -183,7 +179,7 @@ std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed
return output;
}
void CryptoInit(CryptoCtx& ctx, EVP_MAC_CTX* hmac_ctx, const HmacKey& hmac_key,
void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key,
std::span<const u8> seed) {
// Initialize context
ctx.used = false;
@@ -192,17 +188,15 @@ void CryptoInit(CryptoCtx& ctx, EVP_MAC_CTX* hmac_ctx, const HmacKey& hmac_key,
memcpy(ctx.buffer.data() + sizeof(u16), seed.data(), seed.size());
// Initialize HMAC context
OSSL_PARAM params[2];
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, (char*)"SHA256", 0);
params[1] = OSSL_PARAM_construct_end();
EVP_MAC_init(hmac_ctx, hmac_key.data(), hmac_key.size(), params);
mbedtls_md_init(&hmac_ctx);
mbedtls_md_setup(&hmac_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1);
mbedtls_md_hmac_starts(&hmac_ctx, hmac_key.data(), hmac_key.size());
}
void CryptoStep(CryptoCtx& ctx, EVP_MAC_CTX* hmac_ctx, DrgbOutput& output) {
void CryptoStep(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, DrgbOutput& output) {
// If used at least once, reinitialize the HMAC
if (ctx.used) {
EVP_MAC_init(hmac_ctx, nullptr, 0, nullptr);
mbedtls_md_hmac_reset(&hmac_ctx);
}
ctx.used = true;
@@ -213,10 +207,9 @@ void CryptoStep(CryptoCtx& ctx, EVP_MAC_CTX* hmac_ctx, DrgbOutput& output) {
ctx.counter++;
// Do HMAC magic
size_t out_len = 0;
EVP_MAC_update(hmac_ctx, reinterpret_cast<const unsigned char*>(ctx.buffer.data()),
ctx.buffer_size);
EVP_MAC_final(hmac_ctx, output.data(), &out_len, output.size());
mbedtls_md_hmac_update(&hmac_ctx, reinterpret_cast<const unsigned char*>(ctx.buffer.data()),
ctx.buffer_size);
mbedtls_md_hmac_finish(&hmac_ctx, output.data());
}
DerivedKeys GenerateKey(const InternalKey& key, const NTAG215File& data) {
@@ -227,9 +220,7 @@ DerivedKeys GenerateKey(const InternalKey& key, const NTAG215File& data) {
// Initialize context
CryptoCtx ctx{};
EVP_MAC* mac = EVP_MAC_fetch(nullptr, "HMAC", nullptr);
EVP_MAC_CTX* hmac_ctx = EVP_MAC_CTX_new(mac);
mbedtls_md_context_t hmac_ctx;
CryptoInit(ctx, hmac_ctx, key.hmac_key, internal_key);
// Generate derived keys
@@ -240,25 +231,26 @@ DerivedKeys GenerateKey(const InternalKey& key, const NTAG215File& data) {
memcpy(&derived_keys, temp.data(), sizeof(DerivedKeys));
// Cleanup context
EVP_MAC_CTX_free(hmac_ctx);
EVP_MAC_free(mac);
mbedtls_md_free(&hmac_ctx);
return derived_keys;
}
void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& out_data) {
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), nullptr, keys.aes_key.data(), keys.aes_iv.data());
mbedtls_aes_context aes;
std::size_t nc_off = 0;
std::array<u8, sizeof(keys.aes_iv)> nonce_counter{};
std::array<u8, sizeof(keys.aes_iv)> stream_block{};
const auto aes_key_size = static_cast<u32>(keys.aes_key.size() * 8);
mbedtls_aes_setkey_enc(&aes, keys.aes_key.data(), aes_key_size);
memcpy(nonce_counter.data(), keys.aes_iv.data(), sizeof(keys.aes_iv));
constexpr std::size_t encrypted_data_size = HMAC_TAG_START - SETTINGS_START;
int out_len1 = 0;
int out_len2 = 0;
EVP_EncryptUpdate(ctx, reinterpret_cast<unsigned char*>(&out_data.settings), &out_len1,
reinterpret_cast<const unsigned char*>(&in_data.settings), encrypted_data_size);
EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char*>(&out_data.settings) + out_len1, &out_len2);
EVP_CIPHER_CTX_free(ctx);
mbedtls_aes_crypt_ctr(&aes, encrypted_data_size, &nc_off, nonce_counter.data(),
stream_block.data(),
reinterpret_cast<const unsigned char*>(&in_data.settings),
reinterpret_cast<unsigned char*>(&out_data.settings));
// Copy the rest of the data directly
out_data.uid = in_data.uid;
@@ -325,18 +317,16 @@ bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& t
// Regenerate tag HMAC. Note: order matters, data HMAC depends on tag HMAC!
constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START;
size_t out_len = 0;
EVP_Q_mac(nullptr, "HMAC", nullptr, "SHA256", nullptr,
tag_keys.hmac_key.data(), sizeof(HmacKey),
reinterpret_cast<const unsigned char*>(&tag_data.uid), input_length,
reinterpret_cast<unsigned char*>(&tag_data.hmac_tag), sizeof(tag_data.hmac_tag), &out_len);
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(),
sizeof(HmacKey), reinterpret_cast<const unsigned char*>(&tag_data.uid),
input_length, reinterpret_cast<unsigned char*>(&tag_data.hmac_tag));
// Regenerate data HMAC
constexpr std::size_t input_length2 = DYNAMIC_LOCK_START - WRITE_COUNTER_START;
EVP_Q_mac(nullptr, "HMAC", nullptr, "SHA256", nullptr,
data_keys.hmac_key.data(), sizeof(HmacKey),
reinterpret_cast<const unsigned char*>(&tag_data.write_counter), input_length2,
reinterpret_cast<unsigned char*>(&tag_data.hmac_data), sizeof(tag_data.hmac_data), &out_len);
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), data_keys.hmac_key.data(),
sizeof(HmacKey),
reinterpret_cast<const unsigned char*>(&tag_data.write_counter), input_length2,
reinterpret_cast<unsigned char*>(&tag_data.hmac_data));
if (tag_data.hmac_data != encrypted_tag_data.user_memory.hmac_data) {
LOG_ERROR(Service_NFP, "hmac_data doesn't match");
@@ -364,33 +354,31 @@ bool EncodeAmiibo(const NTAG215File& tag_data, EncryptedNTAG215File& encrypted_t
const auto tag_keys = GenerateKey(locked_secret, tag_data);
NTAG215File encoded_tag_data{};
size_t out_len = 0;
// Generate tag HMAC
constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START;
constexpr std::size_t input_length2 = HMAC_TAG_START - WRITE_COUNTER_START;
EVP_Q_mac(nullptr, "HMAC", nullptr, "SHA256", nullptr,
tag_keys.hmac_key.data(), sizeof(HmacKey),
reinterpret_cast<const unsigned char*>(&tag_data.uid), input_length,
reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag), sizeof(encoded_tag_data.hmac_tag), &out_len);
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(),
sizeof(HmacKey), reinterpret_cast<const unsigned char*>(&tag_data.uid),
input_length, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag));
// Init OpenSSL HMAC context
EVP_MAC* mac = EVP_MAC_fetch(nullptr, "HMAC", nullptr);
EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(mac);
OSSL_PARAM params[2];
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, (char*)"SHA256", 0);
params[1] = OSSL_PARAM_construct_end();
// Init mbedtls HMAC context
mbedtls_md_context_t ctx;
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1);
// Generate data HMAC
EVP_MAC_init(ctx, data_keys.hmac_key.data(), sizeof(HmacKey), params);
EVP_MAC_update(ctx, reinterpret_cast<const unsigned char*>(&tag_data.write_counter), input_length2); // data
EVP_MAC_update(ctx, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag), sizeof(HashData)); // tag hmax
EVP_MAC_update(ctx, reinterpret_cast<const unsigned char*>(&tag_data.uid), input_length);
EVP_MAC_final(ctx, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_data), &out_len, sizeof(encoded_tag_data.hmac_data));
mbedtls_md_hmac_starts(&ctx, data_keys.hmac_key.data(), sizeof(HmacKey));
mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char*>(&tag_data.write_counter),
input_length2); // Data
mbedtls_md_hmac_update(&ctx, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag),
sizeof(HashData)); // Tag HMAC
mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char*>(&tag_data.uid),
input_length);
mbedtls_md_hmac_finish(&ctx, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_data));
// HMAC cleanup
EVP_MAC_CTX_free(ctx);
EVP_MAC_free(mac);
mbedtls_md_free(&ctx);
// Encrypt
Cipher(data_keys, tag_data, encoded_tag_data);
@@ -1,18 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include <span>
#include <openssl/err.h>
#include "core/hle/service/nfp/nfp_types.h"
typedef struct evp_mac_ctx_st EVP_MAC_CTX;
struct mbedtls_md_context_t;
namespace Service::NFP::AmiiboCrypto {
// Byte locations in Service::NFP::NTAG215File
@@ -78,12 +73,12 @@ HashSeed GetSeed(const NTAG215File& data);
// Middle step on the generation of derived keys
std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed);
// Initializes OpenSSL HMAC context
void CryptoInit(CryptoCtx& ctx, EVP_MAC_CTX* hmac_ctx, const HmacKey& hmac_key,
// Initializes mbedtls context
void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key,
std::span<const u8> seed);
// Feeds data to OpenSSL context to generate the derived key
void CryptoStep(CryptoCtx& ctx, EVP_MAC_CTX* hmac_ctx, DrgbOutput& output);
// Feeds data to mbedtls context to generate the derived key
void CryptoStep(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, DrgbOutput& output);
// Generates the derived key from amiibo data
DerivedKeys GenerateKey(const InternalKey& key, const NTAG215File& data);
+5 -6
View File
@@ -1,21 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <openssl/err.h>
#include <openssl/evp.h>
#include <mbedtls/sha256.h>
#include "common/scope_exit.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ro/ro.h"
#include "core/hle/service/ro/ro_nro_utils.h"
#include "core/hle/service/ro/ro_results.h"
#include "core/hle/service/ro/ro_types.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::RO {
@@ -181,8 +181,7 @@ struct ProcessContext {
std::vector<u8> nro_data(size);
m_process->GetMemory().ReadBlock(base_address, nro_data.data(), size);
u32 hash_len = 0;
EVP_Digest(nro_data.data(), nro_data.size(), hash.data(), &hash_len, EVP_sha256(), nullptr);
mbedtls_sha256(nro_data.data(), size, hash.data(), 0);
}
for (size_t i = 0; i < MaxNrrInfos; i++) {
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -980,82 +980,25 @@ Result ISystemSettingsServer::SetPrimaryAlbumStorage(PrimaryAlbumStorage primary
R_SUCCEED();
}
static void Fill3DS_CRC(u32 d, char* data) {
std::array<u8, 10> digits = {
u8((d / 1000000000) % 100),
u8((d / 100000000) % 10),
u8((d / 10000000) % 10),
u8((d / 1000000) % 10),
u8((d / 100000) % 10),
u8((d / 10000) % 10),
u8((d / 1000) % 10),
u8((d / 100) % 10),
u8((d / 10) % 10),
u8(d % 10),
};
// Normalize to retail values
std::array<u8, 4> retail_digits = { 1, 4, 5, 7 };
digits[0] = retail_digits[(d % 10) % 4];
digits[1] = 0;
//
for (size_t i = 0; i < sizeof(digits); ++i)
data[i] = char(digits[i] + '0');
u8 sum_odd = 0, sum_even = 0;
for (size_t i = 0; i < sizeof(digits); i += 2) {
sum_odd += digits[i + 0];
sum_even += digits[i + 1];
}
u8 sum_digit = u8(((sum_even * 3) + sum_odd) % 10);
if (sum_digit != 0)
sum_digit = 10 - sum_digit;
data[sizeof(digits)] = char(sum_digit + '0');
}
Result ISystemSettingsServer::GetBatteryLot(Out<BatteryLot> out_battery_lot) {
LOG_INFO(Service_SET, "called");
*out_battery_lot = []{
u32 d = ::Settings::values.serial_battery.GetValue();
BatteryLot c{};
c.lot_number[0] = 'B';
c.lot_number[1] = 'H';
c.lot_number[2] = 'A';
c.lot_number[3] = 'C';
// TODO: I have no fucking idea what the letters mean
c.lot_number[4] = 'H';
c.lot_number[5] = 'Z';
c.lot_number[6] = 'Z';
c.lot_number[7] = 'A';
c.lot_number[8] = 'D';
c.lot_number[9] = char(((d / 100000) % 26) + 'A');
Fill3DS_CRC(d, c.lot_number.data() + 10);
return c;
}();
*out_battery_lot = {"YUZU0EMULATOR14022024"};
if (auto const s = ::Settings::values.serial_battery.GetValue(); !s.empty()) {
auto const max_size = out_battery_lot->lot_number.size();
auto const end = s.size() > max_size ? s.begin() + max_size : s.end();
std::copy(s.begin(), end, out_battery_lot->lot_number.begin());
}
R_SUCCEED();
}
Result ISystemSettingsServer::GetSerialNumber(Out<SerialNumber> out_console_serial) {
LOG_INFO(Service_SET, "called");
*out_console_serial = []{
u32 d = ::Settings::values.serial_unit.GetValue();
SerialNumber c{};
c.serial_number[0] = 'X';
c.serial_number[1] = 'A';
c.serial_number[2] = [] {
// Adding another setting would be tedious so... let's just reuse region_index :)
switch (::Settings::values.region_index.GetValue()) {
case ::Settings::Region::Japan: return 'J';
case ::Settings::Region::Usa: return 'W';
case ::Settings::Region::Europe: return 'E';
case ::Settings::Region::Australia: return 'M'; //pretend its Malaysia
case ::Settings::Region::China:
case ::Settings::Region::Taiwan: return 'C';
case ::Settings::Region::Korea: return 'K';
default: return 'W';
}
}();
Fill3DS_CRC(d, c.serial_number.data() + 3);
return c;
}();
*out_console_serial = {"YUZ10000000001"};
if (auto const s = ::Settings::values.serial_unit.GetValue(); !s.empty()) {
auto const max_size = out_console_serial->serial_number.size();
auto const end = s.size() > max_size ? s.begin() + max_size : s.end();
std::copy(s.begin(), end, out_console_serial->serial_number.begin());
}
R_SUCCEED();
}
+2 -2
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -178,7 +178,7 @@ void LoopProcess(Core::System& system) {
auto module = std::make_shared<Module>();
server_manager->RegisterNamedService("csrng", std::make_shared<CSRNG>(system, module));
server_manager->RegisterNamedService("spl:", std::make_shared<SPL>(system, module));
server_manager->RegisterNamedService("spl", std::make_shared<SPL>(system, module));
server_manager->RegisterNamedService("spl:mig", std::make_shared<SPL_MIG>(system, module));
server_manager->RegisterNamedService("spl:fs", std::make_shared<SPL_FS>(system, module));
server_manager->RegisterNamedService("spl:ssl", std::make_shared<SPL_SSL>(system, module));
+10 -18
View File
@@ -1,12 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <utility>
#include <openssl/err.h>
#include <openssl/evp.h>
#include "common/hex_util.h"
#include "common/scope_exit.h"
@@ -19,6 +17,7 @@
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/deconstructed_rom_directory.h"
#include "core/loader/nca.h"
#include "mbedtls/sha256.h"
#include "common/literals.h"
namespace Loader {
@@ -134,8 +133,9 @@ ResultStatus AppLoader_NCA::VerifyIntegrity(std::function<bool(size_t, size_t)>
const auto name = file->GetName();
// We won't try to verify meta NCAs.
if (name.ends_with(".cnmt.nca"))
if (name.ends_with(".cnmt.nca")) {
return ResultStatus::Success;
}
// Check if we can verify this file. NCAs should be named after their hashes.
if (!name.ends_with(".nca") || name.size() != NcaFileNameWithHashLength) {
@@ -151,18 +151,15 @@ ResultStatus AppLoader_NCA::VerifyIntegrity(std::function<bool(size_t, size_t)>
std::vector<u8> buffer(4_MiB);
// Initialize sha256 verification context.
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
if (!ctx)
return ResultStatus::ErrorNotInitialized;
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
mbedtls_sha256_starts(&ctx, 0);
// Ensure we maintain a clean state on exit.
SCOPE_EXIT {
EVP_MD_CTX_free(ctx);
mbedtls_sha256_free(&ctx);
};
if (!EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr))
return ResultStatus::ErrorIntegrityVerificationFailed;
// Declare counters.
const size_t total_size = file->GetSize();
size_t processed_size = 0;
@@ -174,9 +171,7 @@ ResultStatus AppLoader_NCA::VerifyIntegrity(std::function<bool(size_t, size_t)>
const size_t read_size = file->Read(buffer.data(), intended_read_size, processed_size);
// Update the hash function with the buffer contents.
if (!EVP_DigestUpdate(ctx, buffer.data(), read_size)) {
return ResultStatus::ErrorIntegrityVerificationFailed;
}
mbedtls_sha256_update(&ctx, buffer.data(), read_size);
// Update counters.
processed_size += read_size;
@@ -189,10 +184,7 @@ ResultStatus AppLoader_NCA::VerifyIntegrity(std::function<bool(size_t, size_t)>
// Finalize context and compute the output hash.
std::array<u8, NcaSha256HashLength> output_hash;
unsigned int output_len = 0;
if (!EVP_DigestFinal_ex(ctx, output_hash.data(), &output_len)) {
return ResultStatus::ErrorIntegrityVerificationFailed;
}
mbedtls_sha256_finish(&ctx, output_hash.data());
// Compare to expected.
if (std::memcmp(input_hash.data(), output_hash.data(), NcaSha256HalfHashLength) != 0) {
+101 -83
View File
@@ -6,7 +6,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <bit>
#include <cstring>
#include <mutex>
#include <span>
@@ -128,14 +127,83 @@ struct Memory::Impl {
}
}
[[nodiscard]] inline u8* GetPointerFromRasterizerCachedMemory(u64 vaddr) const {
auto const paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr;
return paddr ? system.DeviceMemory().GetPointer<u8>(paddr + vaddr) : nullptr;
[[nodiscard]] u8* GetPointerFromRasterizerCachedMemory(u64 vaddr) const {
Common::PhysicalAddress const paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr;
if (paddr)
return system.DeviceMemory().GetPointer<u8>(paddr + vaddr);
return {};
}
[[nodiscard]] inline u8* GetPointerFromDebugMemory(u64 vaddr) const {
auto const paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr;
return paddr ? system.DeviceMemory().GetPointer<u8>(paddr + vaddr) : nullptr;
[[nodiscard]] u8* GetPointerFromDebugMemory(u64 vaddr) const {
const Common::PhysicalAddress paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr;
if (paddr != 0)
return system.DeviceMemory().GetPointer<u8>(paddr + vaddr);
return {};
}
u8 Read8(const Common::ProcessAddress addr) {
return Read<u8>(addr);
}
u16 Read16(const Common::ProcessAddress addr) {
if ((addr & 1) == 0) {
return Read<u16_le>(addr);
} else {
const u32 a{Read<u8>(addr)};
const u32 b{Read<u8>(addr + sizeof(u8))};
return static_cast<u16>((b << 8) | a);
}
}
u32 Read32(const Common::ProcessAddress addr) {
if ((addr & 3) == 0) {
return Read<u32_le>(addr);
} else {
const u32 a{Read16(addr)};
const u32 b{Read16(addr + sizeof(u16))};
return (b << 16) | a;
}
}
u64 Read64(const Common::ProcessAddress addr) {
if ((addr & 7) == 0) {
return Read<u64_le>(addr);
} else {
const u32 a{Read32(addr)};
const u32 b{Read32(addr + sizeof(u32))};
return (static_cast<u64>(b) << 32) | a;
}
}
void Write8(const Common::ProcessAddress addr, const u8 data) {
Write<u8>(addr, data);
}
void Write16(const Common::ProcessAddress addr, const u16 data) {
if ((addr & 1) == 0) {
Write<u16_le>(addr, data);
} else {
Write<u8>(addr, static_cast<u8>(data));
Write<u8>(addr + sizeof(u8), static_cast<u8>(data >> 8));
}
}
void Write32(const Common::ProcessAddress addr, const u32 data) {
if ((addr & 3) == 0) {
Write<u32_le>(addr, data);
} else {
Write16(addr, static_cast<u16>(data));
Write16(addr + sizeof(u16), static_cast<u16>(data >> 16));
}
}
void Write64(const Common::ProcessAddress addr, const u64 data) {
if ((addr & 7) == 0) {
Write<u64_le>(addr, data);
} else {
Write32(addr, static_cast<u32>(data));
Write32(addr + sizeof(u32), static_cast<u32>(data >> 32));
}
}
bool WriteExclusive8(const Common::ProcessAddress addr, const u8 data, const u8 expected) {
@@ -590,7 +658,7 @@ struct Memory::Impl {
}
template<typename F, typename G>
[[nodiscard]] inline u8* GetPointerImpl(u64 vaddr, F&& on_unmapped, G&& on_rasterizer) const {
[[nodiscard]] u8* GetPointerImpl(u64 vaddr, F&& on_unmapped, G&& on_rasterizer) const {
// AARCH64 masks the upper 16 bit of all memory accesses
vaddr &= 0xffffffffffffULL;
if (AddressSpaceContains(*current_page_table, vaddr, 1)) [[likely]] {
@@ -645,42 +713,18 @@ struct Memory::Impl {
/// @returns The instance of T read from the specified virtual address.
template <typename T>
inline T Read(Common::ProcessAddress vaddr) noexcept requires(std::is_trivially_copyable_v<T>) {
auto const addr_c1 = GetInteger(vaddr);
if (!(sizeof(T) > 1 && (addr_c1 & 4095) + sizeof(T) > 4096)) {
if (auto const ptr_c1 = GetPointerImpl(addr_c1, [addr_c1] {
LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr_c1);
}, [&] {
HandleRasterizerDownload(addr_c1, sizeof(T));
}); ptr_c1) {
// It may be tempting to rewrite this particular section to use "reinterpret_cast";
// afterall, it's trivially copyable so surely it can be copied ov- Alignment.
// Remember, alignment. memcpy() will deal with all the alignment extremely fast.
T result{};
std::memcpy(&result, ptr_c1, sizeof(T));
return result;
}
} else {
auto const addr_c2 = (addr_c1 & (~0xfff)) + 0x1000;
// page crossing: say if sizeof(T) = 2, vaddr = 4095
// 4095 + 2 mod 4096 = 1 => 2 - 1 = 1, thus c1=1, c2=1
auto const count_c2 = (addr_c1 + sizeof(T)) & 4095;
auto const count_c1 = sizeof(T) - count_c2;
if (auto const ptr_c1 = GetPointerImpl(addr_c1, [addr_c1] {
LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr_c1);
}, [&] {
HandleRasterizerDownload(addr_c1, count_c1);
}); ptr_c1) {
if (auto const ptr_c2 = GetPointerImpl(addr_c2, [addr_c2] {
LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr_c2);
}, [&] {
HandleRasterizerDownload(addr_c2, count_c2);
}); ptr_c2) {
std::array<char, sizeof(T)> result{};
std::memcpy(result.data() + 0, ptr_c1, count_c1);
std::memcpy(result.data() + count_c1, ptr_c2, count_c2);
return std::bit_cast<T>(result);
}
}
const u64 addr = GetInteger(vaddr);
if (auto const ptr = GetPointerImpl(addr, [addr]() {
LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr);
}, [&]() {
HandleRasterizerDownload(addr, sizeof(T));
}); ptr) [[likely]] {
// It may be tempting to rewrite this particular section to use "reinterpret_cast";
// afterall, it's trivially copyable so surely it can be copied ov- Alignment.
// Remember, alignment. memcpy() will deal with all the alignment extremely fast.
T result{};
std::memcpy(&result, ptr, sizeof(T));
return result;
}
return T{};
}
@@ -690,37 +734,11 @@ struct Memory::Impl {
/// @tparam T The data type to write to memory.
template <typename T>
inline void Write(Common::ProcessAddress vaddr, const T data) noexcept requires(std::is_trivially_copyable_v<T>) {
auto const addr_c1 = GetInteger(vaddr);
if (!(sizeof(T) > 1 && (addr_c1 & 4095) + sizeof(T) > 4096)) {
if (auto const ptr_c1 = GetPointerImpl(addr_c1, [addr_c1] {
LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr_c1);
}, [&] {
HandleRasterizerWrite(addr_c1, sizeof(T));
}); ptr_c1) {
std::memcpy(ptr_c1, &data, sizeof(T));
}
} else {
auto const addr_c2 = (addr_c1 & (~0xfff)) + 0x1000;
// page crossing: say if sizeof(T) = 2, vaddr = 4095
// 4095 + 2 mod 4096 = 1 => 2 - 1 = 1, thus c1=1, c2=1
auto const count_c2 = (addr_c1 + sizeof(T)) & 4095;
auto const count_c1 = sizeof(T) - count_c2;
if (auto const ptr_c1 = GetPointerImpl(addr_c1, [addr_c1] {
LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X}", sizeof(T) * 8, addr_c1);
}, [&] {
HandleRasterizerWrite(addr_c1, count_c1);
}); ptr_c1) {
if (auto const ptr_c2 = GetPointerImpl(addr_c2, [addr_c2] {
LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X}", sizeof(T) * 8, addr_c2);
}, [&] {
HandleRasterizerWrite(addr_c2, count_c2);
}); ptr_c2) {
std::array<char, sizeof(T)> tmp = std::bit_cast<std::array<char, sizeof(T)>>(data);
std::memcpy(ptr_c1, tmp.data() + 0, count_c1);
std::memcpy(ptr_c2, tmp.data() + count_c1, count_c2);
}
}
}
const u64 addr = GetInteger(vaddr);
if (auto const ptr = GetPointerImpl(addr, [addr, data]() {
LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, addr, u64(data));
}, [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); ptr) [[likely]]
std::memcpy(ptr, &data, sizeof(T));
}
template <typename T>
@@ -924,35 +942,35 @@ const u8* Memory::GetPointer(Common::ProcessAddress vaddr) const {
}
u8 Memory::Read8(const Common::ProcessAddress addr) {
return impl->Read<u8>(addr);
return impl->Read8(addr);
}
u16 Memory::Read16(const Common::ProcessAddress addr) {
return impl->Read<u16_le>(addr);
return impl->Read16(addr);
}
u32 Memory::Read32(const Common::ProcessAddress addr) {
return impl->Read<u32_le>(addr);
return impl->Read32(addr);
}
u64 Memory::Read64(const Common::ProcessAddress addr) {
return impl->Read<u64_le>(addr);
return impl->Read64(addr);
}
void Memory::Write8(Common::ProcessAddress addr, u8 data) {
impl->Write<u8>(addr, data);
impl->Write8(addr, data);
}
void Memory::Write16(Common::ProcessAddress addr, u16 data) {
impl->Write<u16_le>(addr, data);
impl->Write16(addr, data);
}
void Memory::Write32(Common::ProcessAddress addr, u32 data) {
impl->Write<u32_le>(addr, data);
impl->Write32(addr, data);
}
void Memory::Write64(Common::ProcessAddress addr, u64 data) {
impl->Write<u64_le>(addr, data);
impl->Write64(addr, data);
}
bool Memory::WriteExclusive8(Common::ProcessAddress addr, u8 data, u8 expected) {
+2 -5
View File
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2017 Citra Emulator Project
@@ -16,10 +16,7 @@ if (ENABLE_WEB_SERVICE)
target_link_libraries(yuzu-room PRIVATE web_service)
endif()
target_link_libraries(yuzu-room PRIVATE
OpenSSL::SSL
OpenSSL::Crypto)
target_link_libraries(yuzu-room PRIVATE MbedTLS::mbedcrypto${MBEDTLS_LIB_SUFFIX} MbedTLS::mbedtls${MBEDTLS_LIB_SUFFIX})
if (MSVC)
target_link_libraries(yuzu-room PRIVATE getopt)
endif()
+18 -8
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
@@ -22,7 +22,7 @@
#include <shellapi.h>
#endif
#include <openssl/evp.h>
#include <mbedtls/base64.h>
#include "common/common_types.h"
#include "common/detached_tasks.h"
#include "common/fs/file.h"
@@ -84,11 +84,15 @@ static constexpr char BanListMagic[] = "YuzuRoom-BanList-1";
static constexpr char token_delimiter{':'};
static void PadToken(std::string& token) {
std::size_t outlen = 0;
std::array<unsigned char, 512> output{};
std::array<unsigned char, 2048> roundtrip{};
for (size_t i = 0; i < 3; i++) {
EVP_DecodeBlock(output.data(), reinterpret_cast<const unsigned char*>(token.c_str()), token.size());
EVP_EncodeBlock(output.data(), roundtrip.data(), roundtrip.size());
mbedtls_base64_decode(output.data(), output.size(), &outlen,
reinterpret_cast<const unsigned char*>(token.c_str()),
token.length());
mbedtls_base64_encode(roundtrip.data(), roundtrip.size(), &outlen, output.data(), outlen);
if (memcmp(roundtrip.data(), token.data(), token.size()) == 0) {
break;
}
@@ -97,17 +101,23 @@ static void PadToken(std::string& token) {
}
static std::string UsernameFromDisplayToken(const std::string& display_token) {
std::size_t outlen = 4 * ((display_token.length() + 2) / 3);
std::size_t outlen;
std::array<unsigned char, 512> output{};
EVP_DecodeBlock(output.data(), reinterpret_cast<const unsigned char*>(display_token.c_str()), display_token.length());
mbedtls_base64_decode(output.data(), output.size(), &outlen,
reinterpret_cast<const unsigned char*>(display_token.c_str()),
display_token.length());
std::string decoded_display_token(reinterpret_cast<char*>(&output), outlen);
return decoded_display_token.substr(0, decoded_display_token.find(token_delimiter));
}
static std::string TokenFromDisplayToken(const std::string& display_token) {
std::size_t outlen = 4 * ((display_token.length() + 2) / 3);
std::size_t outlen;
std::array<unsigned char, 512> output{};
EVP_DecodeBlock(output.data(), reinterpret_cast<const unsigned char*>(display_token.c_str()), display_token.length());
mbedtls_base64_decode(output.data(), output.size(), &outlen,
reinterpret_cast<const unsigned char*>(display_token.c_str()),
display_token.length());
std::string decoded_display_token(reinterpret_cast<char*>(&output), outlen);
return decoded_display_token.substr(decoded_display_token.find(token_delimiter) + 1);
}
+4
View File
@@ -105,6 +105,9 @@ add_library(dynarmic STATIC
frontend/A32/decoder/thumb32.inc
frontend/A32/decoder/vfp.h
frontend/A32/decoder/vfp.inc
frontend/A32/disassembler/disassembler.h
frontend/A32/disassembler/disassembler_arm.cpp
frontend/A32/disassembler/disassembler_thumb.cpp
frontend/A32/FPSCR.h
frontend/A32/ITState.h
frontend/A32/PSR.h
@@ -119,6 +122,7 @@ add_library(dynarmic STATIC
interface/A32/config.h
interface/A32/coprocessor.h
interface/A32/coprocessor_util.h
interface/A32/disassembler.h
# A64
frontend/A64/a64_ir_emitter.cpp
frontend/A64/a64_ir_emitter.h
@@ -212,7 +212,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E
oaknut::Label pass;
pass = conf.emit_cond(code, ctx, ctx.block.GetCondition());
EmitAddCycles(code, ctx, ctx.block.cond_failed_cycle_count);
EmitAddCycles(code, ctx, ctx.block.ConditionFailedCycleCount());
conf.emit_condition_failed_terminal(code, ctx);
code.l(pass);
@@ -254,7 +254,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E
reg_alloc.AssertNoMoreUses();
EmitAddCycles(code, ctx, block.cycle_count);
EmitAddCycles(code, ctx, block.CycleCount());
conf.emit_terminal(code, ctx);
code.BRK(0);
@@ -36,6 +36,10 @@ oaknut::Label EmitA32Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond co
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA32Terminal(oaknut::CodeGenerator&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
UNREACHABLE();
}
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
EmitRelocation(code, ctx, LinkTarget::ReturnToDispatcher);
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
@@ -35,6 +35,10 @@ oaknut::Label EmitA64Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond co
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA64Terminal(oaknut::CodeGenerator&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
UNREACHABLE();
}
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
EmitRelocation(code, ctx, LinkTarget::ReturnToDispatcher);
}
@@ -151,7 +151,7 @@ EmittedBlockInfo EmitRV64(biscuit::Assembler& as, IR::Block block, const EmitCon
reg_alloc.AssertNoMoreUses();
if (emit_conf.enable_cycle_counting) {
const size_t cycles_to_add = block.cycle_count;
const size_t cycles_to_add = block.CycleCount();
as.LD(Xscratch0, offsetof(StackLayout, cycles_remaining), sp);
if (mcl::bit::sign_extend<12>(-cycles_to_add) == -cycles_to_add) {
as.ADDI(Xscratch0, Xscratch0, -cycles_to_add);
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
@@ -114,6 +114,10 @@ void EmitA32Cond(biscuit::Assembler& as, EmitContext&, IR::Cond cond, biscuit::L
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA32Terminal(biscuit::Assembler&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
UNREACHABLE();
}
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
EmitRelocation(as, ctx, LinkTarget::ReturnFromRunCode);
}
@@ -153,7 +153,7 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
reg_alloc.AssertNoMoreUses();
if (conf.enable_cycle_counting) {
EmitAddCycles(block.cycle_count);
EmitAddCycles(block.CycleCount());
}
EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
code.int3();
@@ -197,7 +197,7 @@ void A32EmitX64::EmitCondPrelude(const A32EmitContext& ctx) {
Xbyak::Label pass = EmitCond(ctx.block.GetCondition());
if (conf.enable_cycle_counting) {
EmitAddCycles(ctx.block.cond_failed_cycle_count);
EmitAddCycles(ctx.block.ConditionFailedCycleCount());
}
EmitTerminal(IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
code.L(pass);
@@ -1135,6 +1135,19 @@ void A32EmitX64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_locat
}
namespace {
void EmitTerminalImpl(A32EmitX64& e, IR::Term::Interpret terminal, IR::LocationDescriptor initial_location, bool) {
ASSERT(A32::LocationDescriptor{terminal.next}.TFlag() == A32::LocationDescriptor{initial_location}.TFlag() && "Unimplemented");
ASSERT(A32::LocationDescriptor{terminal.next}.EFlag() == A32::LocationDescriptor{initial_location}.EFlag() && "Unimplemented");
ASSERT(terminal.num_instructions == 1 && "Unimplemented");
e.code.mov(e.code.ABI_PARAM2.cvt32(), A32::LocationDescriptor{terminal.next}.PC());
e.code.mov(e.code.ABI_PARAM3.cvt32(), 1);
e.code.mov(MJitStateReg(A32::Reg::PC), e.code.ABI_PARAM2.cvt32());
e.code.SwitchMxcsrOnExit();
Devirtualize<&A32::UserCallbacks::InterpreterFallback>(e.conf.callbacks).EmitCall(e.code);
e.code.ReturnFromRunCode(true); // TODO: Check cycles
}
void EmitTerminalImpl(A32EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
e.code.ReturnFromRunCode();
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
@@ -14,7 +14,7 @@
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <mcl/type_traits/integer_of_size.hpp>
#include "dynarmic/backend/x64/xbyak.h"
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/a32_emit_x64.h"
#include "dynarmic/backend/x64/abi.h"
@@ -146,7 +146,7 @@ finish_this_inst:
reg_alloc.AssertNoMoreUses();
if (conf.enable_cycle_counting) {
EmitAddCycles(block.cycle_count);
EmitAddCycles(block.CycleCount());
}
EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
code.int3();
@@ -619,6 +619,16 @@ std::string A64EmitX64::LocationDescriptorToFriendlyName(const IR::LocationDescr
}
namespace {
void EmitTerminalImpl(A64EmitX64& e, IR::Term::Interpret terminal, IR::LocationDescriptor, bool) {
e.code.SwitchMxcsrOnExit();
Devirtualize<&A64::UserCallbacks::InterpreterFallback>(e.conf.callbacks).EmitCall(e.code, [&](RegList param) {
e.code.mov(param[0], A64::LocationDescriptor{terminal.next}.PC());
e.code.mov(qword[e.code.ABI_JIT_PTR + offsetof(A64JitState, pc)], param[0]);
e.code.mov(param[1].cvt32(), terminal.num_instructions);
});
e.code.ReturnFromRunCode(true); // TODO: Check cycles
}
void EmitTerminalImpl(A64EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
e.code.ReturnFromRunCode();
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
@@ -14,7 +14,7 @@
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <mcl/type_traits/integer_of_size.hpp>
#include "dynarmic/backend/x64/xbyak.h"
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/a64_emit_x64.h"
#include "dynarmic/backend/x64/abi.h"
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
@@ -11,7 +11,7 @@
#include <algorithm>
#include "dynarmic/common/common_types.h"
#include "dynarmic/backend/x64/xbyak.h"
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/block_of_code.h"
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
@@ -26,7 +26,7 @@
#include "dynarmic/common/assert.h"
#include <mcl/bit/bit_field.hpp>
#include "dynarmic/backend/x64/xbyak.h"
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/a32_jitstate.h"
#include "dynarmic/backend/x64/abi.h"
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
@@ -15,7 +15,9 @@
#include <mcl/bit/bit_field.hpp>
#include "dynarmic/common/common_types.h"
#include "dynarmic/backend/x64/xbyak.h"
#include <xbyak/xbyak.h>
#include <xbyak/xbyak_util.h>
#include "dynarmic/backend/x64/abi.h"
#include "dynarmic/backend/x64/callback.h"
#include "dynarmic/backend/x64/constant_pool.h"
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
@@ -12,7 +12,7 @@
#include <vector>
#include "dynarmic/common/common_types.h"
#include "dynarmic/backend/x64/xbyak.h"
#include <xbyak/xbyak.h>
namespace Dynarmic::Backend::X64 {

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