mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-15 19:28:29 +12:00
Merge branch 'refs/heads/main' into loadaudio
# Conflicts: # src/config/CemuConfig.h
This commit is contained in:
commit
da3144a801
148 changed files with 5509 additions and 2279 deletions
38
.github/workflows/build.yml
vendored
38
.github/workflows/build.yml
vendored
|
@ -19,7 +19,7 @@ jobs:
|
|||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: "Checkout repo"
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: "recursive"
|
||||
fetch-depth: 0
|
||||
|
@ -28,7 +28,6 @@ jobs:
|
|||
run: |
|
||||
cd dependencies/vcpkg
|
||||
git fetch --unshallow
|
||||
git checkout 431eb6bda0950874c8d4ed929cc66e15d8aae46f
|
||||
|
||||
- name: Setup release mode parameters (for deploy)
|
||||
if: ${{ inputs.deploymode == 'release' }}
|
||||
|
@ -55,6 +54,11 @@ jobs:
|
|||
sudo apt update -qq
|
||||
sudo apt install -y clang-15 cmake freeglut3-dev libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev libudev-dev nasm ninja-build
|
||||
|
||||
- name: "Setup cmake"
|
||||
uses: jwlawson/actions-setup-cmake@v2
|
||||
with:
|
||||
cmake-version: '3.29.0'
|
||||
|
||||
- name: "Bootstrap vcpkg"
|
||||
run: |
|
||||
bash ./dependencies/vcpkg/bootstrap-vcpkg.sh
|
||||
|
@ -86,7 +90,7 @@ jobs:
|
|||
run: mv bin/Cemu_release bin/Cemu
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.deploymode == 'release' }}
|
||||
with:
|
||||
name: cemu-bin-linux-x64
|
||||
|
@ -97,9 +101,9 @@ jobs:
|
|||
needs: build-ubuntu
|
||||
steps:
|
||||
- name: Checkout Upstream Repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-bin-linux-x64
|
||||
path: bin
|
||||
|
@ -116,7 +120,7 @@ jobs:
|
|||
dist/linux/appimage.sh
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cemu-appimage-x64
|
||||
path: artifacts
|
||||
|
@ -125,7 +129,7 @@ jobs:
|
|||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: "Checkout repo"
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: "recursive"
|
||||
|
||||
|
@ -133,7 +137,6 @@ jobs:
|
|||
run: |
|
||||
cd dependencies/vcpkg
|
||||
git fetch --unshallow
|
||||
git checkout 431eb6bda0950874c8d4ed929cc66e15d8aae46f
|
||||
|
||||
- name: Setup release mode parameters (for deploy)
|
||||
if: ${{ inputs.deploymode == 'release' }}
|
||||
|
@ -154,6 +157,11 @@ jobs:
|
|||
echo "[INFO] Experimental version ${{ inputs.experimentalversion }}"
|
||||
echo "BUILD_FLAGS=${{ env.BUILD_FLAGS }} -DEXPERIMENTAL_VERSION=${{ inputs.experimentalversion }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
|
||||
|
||||
- name: "Setup cmake"
|
||||
uses: jwlawson/actions-setup-cmake@v2
|
||||
with:
|
||||
cmake-version: '3.29.0'
|
||||
|
||||
- name: "Bootstrap vcpkg"
|
||||
run: |
|
||||
./dependencies/vcpkg/bootstrap-vcpkg.bat
|
||||
|
@ -190,7 +198,7 @@ jobs:
|
|||
run: Rename-Item bin/Cemu_release.exe Cemu.exe
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.deploymode == 'release' }}
|
||||
with:
|
||||
name: cemu-bin-windows-x64
|
||||
|
@ -200,7 +208,7 @@ jobs:
|
|||
runs-on: macos-12
|
||||
steps:
|
||||
- name: "Checkout repo"
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: "recursive"
|
||||
|
||||
|
@ -208,7 +216,6 @@ jobs:
|
|||
run: |
|
||||
cd dependencies/vcpkg
|
||||
git fetch --unshallow
|
||||
git pull --all
|
||||
|
||||
- name: Setup release mode parameters (for deploy)
|
||||
if: ${{ inputs.deploymode == 'release' }}
|
||||
|
@ -234,6 +241,11 @@ jobs:
|
|||
brew update
|
||||
brew install llvm@15 ninja nasm molten-vk automake libtool
|
||||
|
||||
- name: "Setup cmake"
|
||||
uses: jwlawson/actions-setup-cmake@v2
|
||||
with:
|
||||
cmake-version: '3.29.0'
|
||||
|
||||
- name: "Bootstrap vcpkg"
|
||||
run: |
|
||||
bash ./dependencies/vcpkg/bootstrap-vcpkg.sh
|
||||
|
@ -274,14 +286,14 @@ jobs:
|
|||
mv bin/Cemu_release.app bin/Cemu_app/Cemu.app
|
||||
mv bin/Cemu_app/Cemu.app/Contents/MacOS/Cemu_release bin/Cemu_app/Cemu.app/Contents/MacOS/Cemu
|
||||
sed -i '' 's/Cemu_release/Cemu/g' bin/Cemu_app/Cemu.app/Contents/Info.plist
|
||||
chmod a+x bin/Cemu_app/Cemu.app/Contents/MacOS/Cemu
|
||||
chmod a+x bin/Cemu_app/Cemu.app/Contents/MacOS/{Cemu,update.sh}
|
||||
ln -s /Applications bin/Cemu_app/Applications
|
||||
hdiutil create ./bin/tmp.dmg -ov -volname "Cemu" -fs HFS+ -srcfolder "./bin/Cemu_app"
|
||||
hdiutil convert ./bin/tmp.dmg -format UDZO -o bin/Cemu.dmg
|
||||
rm bin/tmp.dmg
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.deploymode == 'release' }}
|
||||
with:
|
||||
name: cemu-bin-macos-x64
|
||||
|
|
|
@ -15,22 +15,22 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-bin-linux-x64
|
||||
path: cemu-bin-linux-x64
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-appimage-x64
|
||||
path: cemu-appimage-x64
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-bin-windows-x64
|
||||
path: cemu-bin-windows-x64
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-bin-macos-x64
|
||||
path: cemu-bin-macos-x64
|
||||
|
|
8
.github/workflows/deploy_stable_release.yml
vendored
8
.github/workflows/deploy_stable_release.yml
vendored
|
@ -17,22 +17,22 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-bin-linux-x64
|
||||
path: cemu-bin-linux-x64
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-appimage-x64
|
||||
path: cemu-appimage-x64
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-bin-windows-x64
|
||||
path: cemu-bin-windows-x64
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-bin-macos-x64
|
||||
path: cemu-bin-macos-x64
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -39,6 +39,7 @@ bin/sdcard/*
|
|||
bin/screenshots/*
|
||||
bin/dump/*
|
||||
bin/cafeLibs/*
|
||||
bin/portable/*
|
||||
bin/keys.txt
|
||||
|
||||
!bin/shaderCache/info.txt
|
||||
|
|
2
dependencies/vcpkg
vendored
2
dependencies/vcpkg
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 53bef8994c541b6561884a8395ea35715ece75db
|
||||
Subproject commit cbf4a6641528cee6f172328984576f51698de726
|
13
dependencies/vcpkg_overlay_ports/tiff/FindCMath.patch
vendored
Normal file
13
dependencies/vcpkg_overlay_ports/tiff/FindCMath.patch
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
diff --git a/cmake/FindCMath.cmake b/cmake/FindCMath.cmake
|
||||
index ad92218..dd42aba 100644
|
||||
--- a/cmake/FindCMath.cmake
|
||||
+++ b/cmake/FindCMath.cmake
|
||||
@@ -31,7 +31,7 @@ include(CheckSymbolExists)
|
||||
include(CheckLibraryExists)
|
||||
|
||||
check_symbol_exists(pow "math.h" CMath_HAVE_LIBC_POW)
|
||||
-find_library(CMath_LIBRARY NAMES m)
|
||||
+find_library(CMath_LIBRARY NAMES m PATHS ${CMAKE_C_IMPLICIT_LINK_DIRECTORIES})
|
||||
|
||||
if(NOT CMath_HAVE_LIBC_POW)
|
||||
set(CMAKE_REQUIRED_LIBRARIES_SAVE ${CMAKE_REQUIRED_LIBRARIES})
|
86
dependencies/vcpkg_overlay_ports/tiff/portfile.cmake
vendored
Normal file
86
dependencies/vcpkg_overlay_ports/tiff/portfile.cmake
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
vcpkg_from_gitlab(
|
||||
GITLAB_URL https://gitlab.com
|
||||
OUT_SOURCE_PATH SOURCE_PATH
|
||||
REPO libtiff/libtiff
|
||||
REF "v${VERSION}"
|
||||
SHA512 ef2f1d424219d9e245069b7d23e78f5e817cf6ee516d46694915ab6c8909522166f84997513d20a702f4e52c3f18467813935b328fafa34bea5156dee00f66fa
|
||||
HEAD_REF master
|
||||
PATCHES
|
||||
FindCMath.patch
|
||||
)
|
||||
|
||||
vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
|
||||
FEATURES
|
||||
cxx cxx
|
||||
jpeg jpeg
|
||||
jpeg CMAKE_REQUIRE_FIND_PACKAGE_JPEG
|
||||
libdeflate libdeflate
|
||||
libdeflate CMAKE_REQUIRE_FIND_PACKAGE_Deflate
|
||||
lzma lzma
|
||||
lzma CMAKE_REQUIRE_FIND_PACKAGE_liblzma
|
||||
tools tiff-tools
|
||||
webp webp
|
||||
webp CMAKE_REQUIRE_FIND_PACKAGE_WebP
|
||||
zip zlib
|
||||
zip CMAKE_REQUIRE_FIND_PACKAGE_ZLIB
|
||||
zstd zstd
|
||||
zstd CMAKE_REQUIRE_FIND_PACKAGE_ZSTD
|
||||
)
|
||||
|
||||
vcpkg_cmake_configure(
|
||||
SOURCE_PATH "${SOURCE_PATH}"
|
||||
OPTIONS
|
||||
${FEATURE_OPTIONS}
|
||||
-DCMAKE_FIND_PACKAGE_PREFER_CONFIG=ON
|
||||
-Dtiff-docs=OFF
|
||||
-Dtiff-contrib=OFF
|
||||
-Dtiff-tests=OFF
|
||||
-Djbig=OFF # This is disabled by default due to GPL/Proprietary licensing.
|
||||
-Djpeg12=OFF
|
||||
-Dlerc=OFF
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_OpenGL=ON
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_GLUT=ON
|
||||
-DZSTD_HAVE_DECOMPRESS_STREAM=ON
|
||||
-DHAVE_JPEGTURBO_DUAL_MODE_8_12=OFF
|
||||
OPTIONS_DEBUG
|
||||
-DCMAKE_DEBUG_POSTFIX=d # tiff sets "d" for MSVC only.
|
||||
MAYBE_UNUSED_VARIABLES
|
||||
CMAKE_DISABLE_FIND_PACKAGE_GLUT
|
||||
CMAKE_DISABLE_FIND_PACKAGE_OpenGL
|
||||
ZSTD_HAVE_DECOMPRESS_STREAM
|
||||
)
|
||||
|
||||
vcpkg_cmake_install()
|
||||
|
||||
# CMake config wasn't packaged in the past and is not yet usable now,
|
||||
# cf. https://gitlab.com/libtiff/libtiff/-/merge_requests/496
|
||||
# vcpkg_cmake_config_fixup(CONFIG_PATH "lib/cmake/tiff")
|
||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/lib/cmake" "${CURRENT_PACKAGES_DIR}/debug/lib/cmake")
|
||||
|
||||
set(_file "${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/libtiff-4.pc")
|
||||
if(EXISTS "${_file}")
|
||||
vcpkg_replace_string("${_file}" "-ltiff" "-ltiffd")
|
||||
endif()
|
||||
vcpkg_fixup_pkgconfig()
|
||||
|
||||
file(REMOVE_RECURSE
|
||||
"${CURRENT_PACKAGES_DIR}/debug/include"
|
||||
"${CURRENT_PACKAGES_DIR}/debug/share"
|
||||
)
|
||||
|
||||
configure_file("${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake.in" "${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-cmake-wrapper.cmake" @ONLY)
|
||||
|
||||
if ("tools" IN_LIST FEATURES)
|
||||
vcpkg_copy_tools(TOOL_NAMES
|
||||
tiffcp
|
||||
tiffdump
|
||||
tiffinfo
|
||||
tiffset
|
||||
tiffsplit
|
||||
AUTO_CLEAN
|
||||
)
|
||||
endif()
|
||||
|
||||
vcpkg_copy_pdbs()
|
||||
file(COPY "${CURRENT_PORT_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
|
||||
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE.md")
|
9
dependencies/vcpkg_overlay_ports/tiff/usage
vendored
Normal file
9
dependencies/vcpkg_overlay_ports/tiff/usage
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
tiff is compatible with built-in CMake targets:
|
||||
|
||||
find_package(TIFF REQUIRED)
|
||||
target_link_libraries(main PRIVATE TIFF::TIFF)
|
||||
|
||||
tiff provides pkg-config modules:
|
||||
|
||||
# Tag Image File Format (TIFF) library.
|
||||
libtiff-4
|
104
dependencies/vcpkg_overlay_ports/tiff/vcpkg-cmake-wrapper.cmake.in
vendored
Normal file
104
dependencies/vcpkg_overlay_ports/tiff/vcpkg-cmake-wrapper.cmake.in
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
cmake_policy(PUSH)
|
||||
cmake_policy(SET CMP0012 NEW)
|
||||
cmake_policy(SET CMP0057 NEW)
|
||||
set(z_vcpkg_tiff_find_options "")
|
||||
if("REQUIRED" IN_LIST ARGS)
|
||||
list(APPEND z_vcpkg_tiff_find_options "REQUIRED")
|
||||
endif()
|
||||
if("QUIET" IN_LIST ARGS)
|
||||
list(APPEND z_vcpkg_tiff_find_options "QUIET")
|
||||
endif()
|
||||
|
||||
_find_package(${ARGS})
|
||||
|
||||
if(TIFF_FOUND AND "@VCPKG_LIBRARY_LINKAGE@" STREQUAL "static")
|
||||
include(SelectLibraryConfigurations)
|
||||
set(z_vcpkg_tiff_link_libraries "")
|
||||
set(z_vcpkg_tiff_libraries "")
|
||||
if("@webp@")
|
||||
find_package(WebP CONFIG ${z_vcpkg_tiff_find_options})
|
||||
list(APPEND z_vcpkg_tiff_link_libraries "\$<LINK_ONLY:WebP::WebP>")
|
||||
list(APPEND z_vcpkg_tiff_libraries ${WebP_LIBRARIES})
|
||||
endif()
|
||||
if("@lzma@")
|
||||
find_package(LibLZMA ${z_vcpkg_tiff_find_options})
|
||||
list(APPEND z_vcpkg_tiff_link_libraries "\$<LINK_ONLY:LibLZMA::LibLZMA>")
|
||||
list(APPEND z_vcpkg_tiff_libraries ${LIBLZMA_LIBRARIES})
|
||||
endif()
|
||||
if("@jpeg@")
|
||||
find_package(JPEG ${z_vcpkg_tiff_find_options})
|
||||
list(APPEND z_vcpkg_tiff_link_libraries "\$<LINK_ONLY:JPEG::JPEG>")
|
||||
list(APPEND z_vcpkg_tiff_libraries ${JPEG_LIBRARIES})
|
||||
endif()
|
||||
if("@zstd@")
|
||||
find_package(zstd CONFIG ${z_vcpkg_tiff_find_options})
|
||||
set(z_vcpkg_tiff_zstd_target_property "IMPORTED_LOCATION_")
|
||||
if(TARGET zstd::libzstd_shared)
|
||||
set(z_vcpkg_tiff_zstd "\$<LINK_ONLY:zstd::libzstd_shared>")
|
||||
set(z_vcpkg_tiff_zstd_target zstd::libzstd_shared)
|
||||
if(WIN32)
|
||||
set(z_vcpkg_tiff_zstd_target_property "IMPORTED_IMPLIB_")
|
||||
endif()
|
||||
else()
|
||||
set(z_vcpkg_tiff_zstd "\$<LINK_ONLY:zstd::libzstd_static>")
|
||||
set(z_vcpkg_tiff_zstd_target zstd::libzstd_static)
|
||||
endif()
|
||||
get_target_property(z_vcpkg_tiff_zstd_configs "${z_vcpkg_tiff_zstd_target}" IMPORTED_CONFIGURATIONS)
|
||||
foreach(z_vcpkg_config IN LISTS z_vcpkg_tiff_zstd_configs)
|
||||
get_target_property(ZSTD_LIBRARY_${z_vcpkg_config} "${z_vcpkg_tiff_zstd_target}" "${z_vcpkg_tiff_zstd_target_property}${z_vcpkg_config}")
|
||||
endforeach()
|
||||
select_library_configurations(ZSTD)
|
||||
if(NOT TARGET ZSTD::ZSTD)
|
||||
add_library(ZSTD::ZSTD INTERFACE IMPORTED)
|
||||
set_property(TARGET ZSTD::ZSTD APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${z_vcpkg_tiff_zstd})
|
||||
endif()
|
||||
list(APPEND z_vcpkg_tiff_link_libraries ${z_vcpkg_tiff_zstd})
|
||||
list(APPEND z_vcpkg_tiff_libraries ${ZSTD_LIBRARIES})
|
||||
unset(z_vcpkg_tiff_zstd)
|
||||
unset(z_vcpkg_tiff_zstd_configs)
|
||||
unset(z_vcpkg_config)
|
||||
unset(z_vcpkg_tiff_zstd_target)
|
||||
endif()
|
||||
if("@libdeflate@")
|
||||
find_package(libdeflate ${z_vcpkg_tiff_find_options})
|
||||
set(z_vcpkg_property "IMPORTED_LOCATION_")
|
||||
if(TARGET libdeflate::libdeflate_shared)
|
||||
set(z_vcpkg_libdeflate_target libdeflate::libdeflate_shared)
|
||||
if(WIN32)
|
||||
set(z_vcpkg_property "IMPORTED_IMPLIB_")
|
||||
endif()
|
||||
else()
|
||||
set(z_vcpkg_libdeflate_target libdeflate::libdeflate_static)
|
||||
endif()
|
||||
get_target_property(z_vcpkg_libdeflate_configs "${z_vcpkg_libdeflate_target}" IMPORTED_CONFIGURATIONS)
|
||||
foreach(z_vcpkg_config IN LISTS z_vcpkg_libdeflate_configs)
|
||||
get_target_property(Z_VCPKG_DEFLATE_LIBRARY_${z_vcpkg_config} "${z_vcpkg_libdeflate_target}" "${z_vcpkg_property}${z_vcpkg_config}")
|
||||
endforeach()
|
||||
select_library_configurations(Z_VCPKG_DEFLATE)
|
||||
list(APPEND z_vcpkg_tiff_link_libraries "\$<LINK_ONLY:${z_vcpkg_libdeflate_target}>")
|
||||
list(APPEND z_vcpkg_tiff_libraries ${Z_VCPKG_DEFLATE_LIBRARIES})
|
||||
unset(z_vcpkg_config)
|
||||
unset(z_vcpkg_libdeflate_configs)
|
||||
unset(z_vcpkg_libdeflate_target)
|
||||
unset(z_vcpkg_property)
|
||||
unset(Z_VCPKG_DEFLATE_FOUND)
|
||||
endif()
|
||||
if("@zlib@")
|
||||
find_package(ZLIB ${z_vcpkg_tiff_find_options})
|
||||
list(APPEND z_vcpkg_tiff_link_libraries "\$<LINK_ONLY:ZLIB::ZLIB>")
|
||||
list(APPEND z_vcpkg_tiff_libraries ${ZLIB_LIBRARIES})
|
||||
endif()
|
||||
if(UNIX)
|
||||
list(APPEND z_vcpkg_tiff_link_libraries m)
|
||||
list(APPEND z_vcpkg_tiff_libraries m)
|
||||
endif()
|
||||
|
||||
if(TARGET TIFF::TIFF)
|
||||
set_property(TARGET TIFF::TIFF APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${z_vcpkg_tiff_link_libraries})
|
||||
endif()
|
||||
list(APPEND TIFF_LIBRARIES ${z_vcpkg_tiff_libraries})
|
||||
unset(z_vcpkg_tiff_link_libraries)
|
||||
unset(z_vcpkg_tiff_libraries)
|
||||
endif()
|
||||
unset(z_vcpkg_tiff_find_options)
|
||||
cmake_policy(POP)
|
67
dependencies/vcpkg_overlay_ports/tiff/vcpkg.json
vendored
Normal file
67
dependencies/vcpkg_overlay_ports/tiff/vcpkg.json
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"name": "tiff",
|
||||
"version": "4.6.0",
|
||||
"port-version": 2,
|
||||
"description": "A library that supports the manipulation of TIFF image files",
|
||||
"homepage": "https://libtiff.gitlab.io/libtiff/",
|
||||
"license": "libtiff",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "vcpkg-cmake",
|
||||
"host": true
|
||||
},
|
||||
{
|
||||
"name": "vcpkg-cmake-config",
|
||||
"host": true
|
||||
}
|
||||
],
|
||||
"default-features": [
|
||||
"jpeg",
|
||||
"zip"
|
||||
],
|
||||
"features": {
|
||||
"cxx": {
|
||||
"description": "Build C++ libtiffxx library"
|
||||
},
|
||||
"jpeg": {
|
||||
"description": "Support JPEG compression in TIFF image files",
|
||||
"dependencies": [
|
||||
"libjpeg-turbo"
|
||||
]
|
||||
},
|
||||
"libdeflate": {
|
||||
"description": "Use libdeflate for faster ZIP support",
|
||||
"dependencies": [
|
||||
"libdeflate",
|
||||
{
|
||||
"name": "tiff",
|
||||
"default-features": false,
|
||||
"features": [
|
||||
"zip"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"tools": {
|
||||
"description": "Build tools"
|
||||
},
|
||||
"webp": {
|
||||
"description": "Support WEBP compression in TIFF image files",
|
||||
"dependencies": [
|
||||
"libwebp"
|
||||
]
|
||||
},
|
||||
"zip": {
|
||||
"description": "Support ZIP/deflate compression in TIFF image files",
|
||||
"dependencies": [
|
||||
"zlib"
|
||||
]
|
||||
},
|
||||
"zstd": {
|
||||
"description": "Support ZSTD compression in TIFF image files",
|
||||
"dependencies": [
|
||||
"zstd"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
13
dependencies/vcpkg_overlay_ports_mac/tiff/FindCMath.patch
vendored
Normal file
13
dependencies/vcpkg_overlay_ports_mac/tiff/FindCMath.patch
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
diff --git a/cmake/FindCMath.cmake b/cmake/FindCMath.cmake
|
||||
index ad92218..dd42aba 100644
|
||||
--- a/cmake/FindCMath.cmake
|
||||
+++ b/cmake/FindCMath.cmake
|
||||
@@ -31,7 +31,7 @@ include(CheckSymbolExists)
|
||||
include(CheckLibraryExists)
|
||||
|
||||
check_symbol_exists(pow "math.h" CMath_HAVE_LIBC_POW)
|
||||
-find_library(CMath_LIBRARY NAMES m)
|
||||
+find_library(CMath_LIBRARY NAMES m PATHS ${CMAKE_C_IMPLICIT_LINK_DIRECTORIES})
|
||||
|
||||
if(NOT CMath_HAVE_LIBC_POW)
|
||||
set(CMAKE_REQUIRED_LIBRARIES_SAVE ${CMAKE_REQUIRED_LIBRARIES})
|
86
dependencies/vcpkg_overlay_ports_mac/tiff/portfile.cmake
vendored
Normal file
86
dependencies/vcpkg_overlay_ports_mac/tiff/portfile.cmake
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
vcpkg_from_gitlab(
|
||||
GITLAB_URL https://gitlab.com
|
||||
OUT_SOURCE_PATH SOURCE_PATH
|
||||
REPO libtiff/libtiff
|
||||
REF "v${VERSION}"
|
||||
SHA512 ef2f1d424219d9e245069b7d23e78f5e817cf6ee516d46694915ab6c8909522166f84997513d20a702f4e52c3f18467813935b328fafa34bea5156dee00f66fa
|
||||
HEAD_REF master
|
||||
PATCHES
|
||||
FindCMath.patch
|
||||
)
|
||||
|
||||
vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
|
||||
FEATURES
|
||||
cxx cxx
|
||||
jpeg jpeg
|
||||
jpeg CMAKE_REQUIRE_FIND_PACKAGE_JPEG
|
||||
libdeflate libdeflate
|
||||
libdeflate CMAKE_REQUIRE_FIND_PACKAGE_Deflate
|
||||
lzma lzma
|
||||
lzma CMAKE_REQUIRE_FIND_PACKAGE_liblzma
|
||||
tools tiff-tools
|
||||
webp webp
|
||||
webp CMAKE_REQUIRE_FIND_PACKAGE_WebP
|
||||
zip zlib
|
||||
zip CMAKE_REQUIRE_FIND_PACKAGE_ZLIB
|
||||
zstd zstd
|
||||
zstd CMAKE_REQUIRE_FIND_PACKAGE_ZSTD
|
||||
)
|
||||
|
||||
vcpkg_cmake_configure(
|
||||
SOURCE_PATH "${SOURCE_PATH}"
|
||||
OPTIONS
|
||||
${FEATURE_OPTIONS}
|
||||
-DCMAKE_FIND_PACKAGE_PREFER_CONFIG=ON
|
||||
-Dtiff-docs=OFF
|
||||
-Dtiff-contrib=OFF
|
||||
-Dtiff-tests=OFF
|
||||
-Djbig=OFF # This is disabled by default due to GPL/Proprietary licensing.
|
||||
-Djpeg12=OFF
|
||||
-Dlerc=OFF
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_OpenGL=ON
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_GLUT=ON
|
||||
-DZSTD_HAVE_DECOMPRESS_STREAM=ON
|
||||
-DHAVE_JPEGTURBO_DUAL_MODE_8_12=OFF
|
||||
OPTIONS_DEBUG
|
||||
-DCMAKE_DEBUG_POSTFIX=d # tiff sets "d" for MSVC only.
|
||||
MAYBE_UNUSED_VARIABLES
|
||||
CMAKE_DISABLE_FIND_PACKAGE_GLUT
|
||||
CMAKE_DISABLE_FIND_PACKAGE_OpenGL
|
||||
ZSTD_HAVE_DECOMPRESS_STREAM
|
||||
)
|
||||
|
||||
vcpkg_cmake_install()
|
||||
|
||||
# CMake config wasn't packaged in the past and is not yet usable now,
|
||||
# cf. https://gitlab.com/libtiff/libtiff/-/merge_requests/496
|
||||
# vcpkg_cmake_config_fixup(CONFIG_PATH "lib/cmake/tiff")
|
||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/lib/cmake" "${CURRENT_PACKAGES_DIR}/debug/lib/cmake")
|
||||
|
||||
set(_file "${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/libtiff-4.pc")
|
||||
if(EXISTS "${_file}")
|
||||
vcpkg_replace_string("${_file}" "-ltiff" "-ltiffd")
|
||||
endif()
|
||||
vcpkg_fixup_pkgconfig()
|
||||
|
||||
file(REMOVE_RECURSE
|
||||
"${CURRENT_PACKAGES_DIR}/debug/include"
|
||||
"${CURRENT_PACKAGES_DIR}/debug/share"
|
||||
)
|
||||
|
||||
configure_file("${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake.in" "${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-cmake-wrapper.cmake" @ONLY)
|
||||
|
||||
if ("tools" IN_LIST FEATURES)
|
||||
vcpkg_copy_tools(TOOL_NAMES
|
||||
tiffcp
|
||||
tiffdump
|
||||
tiffinfo
|
||||
tiffset
|
||||
tiffsplit
|
||||
AUTO_CLEAN
|
||||
)
|
||||
endif()
|
||||
|
||||
vcpkg_copy_pdbs()
|
||||
file(COPY "${CURRENT_PORT_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
|
||||
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE.md")
|
9
dependencies/vcpkg_overlay_ports_mac/tiff/usage
vendored
Normal file
9
dependencies/vcpkg_overlay_ports_mac/tiff/usage
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
tiff is compatible with built-in CMake targets:
|
||||
|
||||
find_package(TIFF REQUIRED)
|
||||
target_link_libraries(main PRIVATE TIFF::TIFF)
|
||||
|
||||
tiff provides pkg-config modules:
|
||||
|
||||
# Tag Image File Format (TIFF) library.
|
||||
libtiff-4
|
104
dependencies/vcpkg_overlay_ports_mac/tiff/vcpkg-cmake-wrapper.cmake.in
vendored
Normal file
104
dependencies/vcpkg_overlay_ports_mac/tiff/vcpkg-cmake-wrapper.cmake.in
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
cmake_policy(PUSH)
|
||||
cmake_policy(SET CMP0012 NEW)
|
||||
cmake_policy(SET CMP0057 NEW)
|
||||
set(z_vcpkg_tiff_find_options "")
|
||||
if("REQUIRED" IN_LIST ARGS)
|
||||
list(APPEND z_vcpkg_tiff_find_options "REQUIRED")
|
||||
endif()
|
||||
if("QUIET" IN_LIST ARGS)
|
||||
list(APPEND z_vcpkg_tiff_find_options "QUIET")
|
||||
endif()
|
||||
|
||||
_find_package(${ARGS})
|
||||
|
||||
if(TIFF_FOUND AND "@VCPKG_LIBRARY_LINKAGE@" STREQUAL "static")
|
||||
include(SelectLibraryConfigurations)
|
||||
set(z_vcpkg_tiff_link_libraries "")
|
||||
set(z_vcpkg_tiff_libraries "")
|
||||
if("@webp@")
|
||||
find_package(WebP CONFIG ${z_vcpkg_tiff_find_options})
|
||||
list(APPEND z_vcpkg_tiff_link_libraries "\$<LINK_ONLY:WebP::WebP>")
|
||||
list(APPEND z_vcpkg_tiff_libraries ${WebP_LIBRARIES})
|
||||
endif()
|
||||
if("@lzma@")
|
||||
find_package(LibLZMA ${z_vcpkg_tiff_find_options})
|
||||
list(APPEND z_vcpkg_tiff_link_libraries "\$<LINK_ONLY:LibLZMA::LibLZMA>")
|
||||
list(APPEND z_vcpkg_tiff_libraries ${LIBLZMA_LIBRARIES})
|
||||
endif()
|
||||
if("@jpeg@")
|
||||
find_package(JPEG ${z_vcpkg_tiff_find_options})
|
||||
list(APPEND z_vcpkg_tiff_link_libraries "\$<LINK_ONLY:JPEG::JPEG>")
|
||||
list(APPEND z_vcpkg_tiff_libraries ${JPEG_LIBRARIES})
|
||||
endif()
|
||||
if("@zstd@")
|
||||
find_package(zstd CONFIG ${z_vcpkg_tiff_find_options})
|
||||
set(z_vcpkg_tiff_zstd_target_property "IMPORTED_LOCATION_")
|
||||
if(TARGET zstd::libzstd_shared)
|
||||
set(z_vcpkg_tiff_zstd "\$<LINK_ONLY:zstd::libzstd_shared>")
|
||||
set(z_vcpkg_tiff_zstd_target zstd::libzstd_shared)
|
||||
if(WIN32)
|
||||
set(z_vcpkg_tiff_zstd_target_property "IMPORTED_IMPLIB_")
|
||||
endif()
|
||||
else()
|
||||
set(z_vcpkg_tiff_zstd "\$<LINK_ONLY:zstd::libzstd_static>")
|
||||
set(z_vcpkg_tiff_zstd_target zstd::libzstd_static)
|
||||
endif()
|
||||
get_target_property(z_vcpkg_tiff_zstd_configs "${z_vcpkg_tiff_zstd_target}" IMPORTED_CONFIGURATIONS)
|
||||
foreach(z_vcpkg_config IN LISTS z_vcpkg_tiff_zstd_configs)
|
||||
get_target_property(ZSTD_LIBRARY_${z_vcpkg_config} "${z_vcpkg_tiff_zstd_target}" "${z_vcpkg_tiff_zstd_target_property}${z_vcpkg_config}")
|
||||
endforeach()
|
||||
select_library_configurations(ZSTD)
|
||||
if(NOT TARGET ZSTD::ZSTD)
|
||||
add_library(ZSTD::ZSTD INTERFACE IMPORTED)
|
||||
set_property(TARGET ZSTD::ZSTD APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${z_vcpkg_tiff_zstd})
|
||||
endif()
|
||||
list(APPEND z_vcpkg_tiff_link_libraries ${z_vcpkg_tiff_zstd})
|
||||
list(APPEND z_vcpkg_tiff_libraries ${ZSTD_LIBRARIES})
|
||||
unset(z_vcpkg_tiff_zstd)
|
||||
unset(z_vcpkg_tiff_zstd_configs)
|
||||
unset(z_vcpkg_config)
|
||||
unset(z_vcpkg_tiff_zstd_target)
|
||||
endif()
|
||||
if("@libdeflate@")
|
||||
find_package(libdeflate ${z_vcpkg_tiff_find_options})
|
||||
set(z_vcpkg_property "IMPORTED_LOCATION_")
|
||||
if(TARGET libdeflate::libdeflate_shared)
|
||||
set(z_vcpkg_libdeflate_target libdeflate::libdeflate_shared)
|
||||
if(WIN32)
|
||||
set(z_vcpkg_property "IMPORTED_IMPLIB_")
|
||||
endif()
|
||||
else()
|
||||
set(z_vcpkg_libdeflate_target libdeflate::libdeflate_static)
|
||||
endif()
|
||||
get_target_property(z_vcpkg_libdeflate_configs "${z_vcpkg_libdeflate_target}" IMPORTED_CONFIGURATIONS)
|
||||
foreach(z_vcpkg_config IN LISTS z_vcpkg_libdeflate_configs)
|
||||
get_target_property(Z_VCPKG_DEFLATE_LIBRARY_${z_vcpkg_config} "${z_vcpkg_libdeflate_target}" "${z_vcpkg_property}${z_vcpkg_config}")
|
||||
endforeach()
|
||||
select_library_configurations(Z_VCPKG_DEFLATE)
|
||||
list(APPEND z_vcpkg_tiff_link_libraries "\$<LINK_ONLY:${z_vcpkg_libdeflate_target}>")
|
||||
list(APPEND z_vcpkg_tiff_libraries ${Z_VCPKG_DEFLATE_LIBRARIES})
|
||||
unset(z_vcpkg_config)
|
||||
unset(z_vcpkg_libdeflate_configs)
|
||||
unset(z_vcpkg_libdeflate_target)
|
||||
unset(z_vcpkg_property)
|
||||
unset(Z_VCPKG_DEFLATE_FOUND)
|
||||
endif()
|
||||
if("@zlib@")
|
||||
find_package(ZLIB ${z_vcpkg_tiff_find_options})
|
||||
list(APPEND z_vcpkg_tiff_link_libraries "\$<LINK_ONLY:ZLIB::ZLIB>")
|
||||
list(APPEND z_vcpkg_tiff_libraries ${ZLIB_LIBRARIES})
|
||||
endif()
|
||||
if(UNIX)
|
||||
list(APPEND z_vcpkg_tiff_link_libraries m)
|
||||
list(APPEND z_vcpkg_tiff_libraries m)
|
||||
endif()
|
||||
|
||||
if(TARGET TIFF::TIFF)
|
||||
set_property(TARGET TIFF::TIFF APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${z_vcpkg_tiff_link_libraries})
|
||||
endif()
|
||||
list(APPEND TIFF_LIBRARIES ${z_vcpkg_tiff_libraries})
|
||||
unset(z_vcpkg_tiff_link_libraries)
|
||||
unset(z_vcpkg_tiff_libraries)
|
||||
endif()
|
||||
unset(z_vcpkg_tiff_find_options)
|
||||
cmake_policy(POP)
|
67
dependencies/vcpkg_overlay_ports_mac/tiff/vcpkg.json
vendored
Normal file
67
dependencies/vcpkg_overlay_ports_mac/tiff/vcpkg.json
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"name": "tiff",
|
||||
"version": "4.6.0",
|
||||
"port-version": 2,
|
||||
"description": "A library that supports the manipulation of TIFF image files",
|
||||
"homepage": "https://libtiff.gitlab.io/libtiff/",
|
||||
"license": "libtiff",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "vcpkg-cmake",
|
||||
"host": true
|
||||
},
|
||||
{
|
||||
"name": "vcpkg-cmake-config",
|
||||
"host": true
|
||||
}
|
||||
],
|
||||
"default-features": [
|
||||
"jpeg",
|
||||
"zip"
|
||||
],
|
||||
"features": {
|
||||
"cxx": {
|
||||
"description": "Build C++ libtiffxx library"
|
||||
},
|
||||
"jpeg": {
|
||||
"description": "Support JPEG compression in TIFF image files",
|
||||
"dependencies": [
|
||||
"libjpeg-turbo"
|
||||
]
|
||||
},
|
||||
"libdeflate": {
|
||||
"description": "Use libdeflate for faster ZIP support",
|
||||
"dependencies": [
|
||||
"libdeflate",
|
||||
{
|
||||
"name": "tiff",
|
||||
"default-features": false,
|
||||
"features": [
|
||||
"zip"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"tools": {
|
||||
"description": "Build tools"
|
||||
},
|
||||
"webp": {
|
||||
"description": "Support WEBP compression in TIFF image files",
|
||||
"dependencies": [
|
||||
"libwebp"
|
||||
]
|
||||
},
|
||||
"zip": {
|
||||
"description": "Support ZIP/deflate compression in TIFF image files",
|
||||
"dependencies": [
|
||||
"zlib"
|
||||
]
|
||||
},
|
||||
"zstd": {
|
||||
"description": "Support ZSTD compression in TIFF image files",
|
||||
"dependencies": [
|
||||
"zstd"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
1
dist/linux/appimage.sh
vendored
1
dist/linux/appimage.sh
vendored
|
@ -33,6 +33,7 @@ chmod +x AppDir/usr/bin/Cemu
|
|||
cp /usr/lib/x86_64-linux-gnu/{libsepol.so.1,libffi.so.7,libpcre.so.3,libGLU.so.1,libthai.so.0} AppDir/usr/lib
|
||||
|
||||
export UPD_INFO="gh-releases-zsync|cemu-project|Cemu|ci|Cemu.AppImage.zsync"
|
||||
export NO_STRIP=1
|
||||
./linuxdeploy-x86_64.AppImage --appimage-extract-and-run \
|
||||
--appdir="${GITHUB_WORKSPACE}"/AppDir/ \
|
||||
-d "${GITHUB_WORKSPACE}"/AppDir/info.cemu.Cemu.desktop \
|
||||
|
|
17
dist/network_services.xml
vendored
Normal file
17
dist/network_services.xml
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<content>
|
||||
<networkname>CustomExample</networkname>
|
||||
<disablesslverification>0</disablesslverification>
|
||||
<urls>
|
||||
<act>https://account.nintendo.net</act>
|
||||
<ecs>https://ecs.wup.shop.nintendo.net/ecs/services/ECommerceSOAP</ecs>
|
||||
<nus>https://nus.wup.shop.nintendo.net/nus/services/NetUpdateSOAP</nus>
|
||||
<ias>https://ias.wup.shop.nintendo.net/ias/services/IdentityAuthenticationSOAP</ias>
|
||||
<ccsu>https://ccs.wup.shop.nintendo.net/ccs/download</ccsu>
|
||||
<ccs>http://ccs.cdn.wup.shop.nintendo.net/ccs/download</ccs>
|
||||
<idbe>https://idbe-wup.cdn.nintendo.net/icondata</idbe>
|
||||
<boss>https://npts.app.nintendo.net/p01/tasksheet</boss>
|
||||
<tagaya>https://tagaya.wup.shop.nintendo.net/tagaya/versionlist</tagaya>
|
||||
<olv>https://discovery.olv.nintendo.net/v1/endpoint</olv>
|
||||
</urls>
|
||||
</content>
|
|
@ -98,6 +98,7 @@ if (MACOS_BUNDLE)
|
|||
add_custom_command (TARGET CemuBin POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E copy "/usr/local/lib/libMoltenVK.dylib" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libMoltenVK.dylib"
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E copy "${CMAKE_BINARY_DIR}/vcpkg_installed/x64-osx/lib/libusb-1.0.0.dylib" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libusb-1.0.0.dylib"
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E copy "${CMAKE_SOURCE_DIR}/src/resource/update.sh" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/update.sh"
|
||||
COMMAND bash -c "install_name_tool -add_rpath @executable_path/../Frameworks ${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/${OUTPUT_NAME}"
|
||||
COMMAND bash -c "install_name_tool -change /usr/local/opt/libusb/lib/libusb-1.0.0.dylib @executable_path/../Frameworks/libusb-1.0.0.dylib ${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/${OUTPUT_NAME}")
|
||||
endif()
|
||||
|
|
|
@ -10,6 +10,7 @@ add_library(CemuCafe
|
|||
Filesystem/fscDeviceRedirect.cpp
|
||||
Filesystem/fscDeviceWua.cpp
|
||||
Filesystem/fscDeviceWud.cpp
|
||||
Filesystem/fscDeviceWuhb.cpp
|
||||
Filesystem/fsc.h
|
||||
Filesystem/FST/FST.cpp
|
||||
Filesystem/FST/FST.h
|
||||
|
@ -18,6 +19,9 @@ add_library(CemuCafe
|
|||
Filesystem/FST/KeyCache.h
|
||||
Filesystem/WUD/wud.cpp
|
||||
Filesystem/WUD/wud.h
|
||||
Filesystem/WUHB/RomFSStructs.h
|
||||
Filesystem/WUHB/WUHBReader.cpp
|
||||
Filesystem/WUHB/WUHBReader.h
|
||||
GamePatch.cpp
|
||||
GamePatch.h
|
||||
GameProfile/GameProfile.cpp
|
||||
|
@ -404,6 +408,8 @@ add_library(CemuCafe
|
|||
OS/libs/nn_ndm/nn_ndm.h
|
||||
OS/libs/nn_spm/nn_spm.cpp
|
||||
OS/libs/nn_spm/nn_spm.h
|
||||
OS/libs/nn_sl/nn_sl.cpp
|
||||
OS/libs/nn_sl/nn_sl.h
|
||||
OS/libs/nn_nfp/AmiiboCrypto.h
|
||||
OS/libs/nn_nfp/nn_nfp.cpp
|
||||
OS/libs/nn_nfp/nn_nfp.h
|
||||
|
|
|
@ -530,6 +530,7 @@ namespace CafeSystem
|
|||
{
|
||||
// entries in this list are ordered by initialization order. Shutdown in reverse order
|
||||
iosu::kernel::GetModule(),
|
||||
iosu::acp::GetModule(),
|
||||
iosu::fpd::GetModule(),
|
||||
iosu::pdm::GetModule(),
|
||||
};
|
||||
|
@ -914,6 +915,27 @@ namespace CafeSystem
|
|||
return sGameInfo_ForegroundTitle.GetBase().GetArgStr();
|
||||
}
|
||||
|
||||
CosCapabilityBits GetForegroundTitleCosCapabilities(CosCapabilityGroup group)
|
||||
{
|
||||
if (sLaunchModeIsStandalone)
|
||||
return CosCapabilityBits::All;
|
||||
auto& update = sGameInfo_ForegroundTitle.GetUpdate();
|
||||
if (update.IsValid())
|
||||
{
|
||||
ParsedCosXml* cosXml = update.GetCosInfo();
|
||||
if (cosXml)
|
||||
return cosXml->GetCapabilityBits(group);
|
||||
}
|
||||
auto& base = sGameInfo_ForegroundTitle.GetBase();
|
||||
if(base.IsValid())
|
||||
{
|
||||
ParsedCosXml* cosXml = base.GetCosInfo();
|
||||
if (cosXml)
|
||||
return cosXml->GetCapabilityBits(group);
|
||||
}
|
||||
return CosCapabilityBits::All;
|
||||
}
|
||||
|
||||
// when switching titles custom parameters can be passed, returns true if override args are used
|
||||
bool GetOverrideArgStr(std::vector<std::string>& args)
|
||||
{
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
#include "Cafe/TitleList/TitleId.h"
|
||||
#include "config/CemuConfig.h"
|
||||
|
||||
enum class CosCapabilityBits : uint64;
|
||||
enum class CosCapabilityGroup : uint32;
|
||||
|
||||
namespace CafeSystem
|
||||
{
|
||||
class SystemImplementation
|
||||
|
@ -41,6 +44,7 @@ namespace CafeSystem
|
|||
std::string GetForegroundTitleName();
|
||||
std::string GetForegroundTitleArgStr();
|
||||
uint32 GetForegroundTitleOlvAccesskey();
|
||||
CosCapabilityBits GetForegroundTitleCosCapabilities(CosCapabilityGroup group);
|
||||
|
||||
void ShutdownTitle();
|
||||
|
||||
|
|
40
src/Cafe/Filesystem/WUHB/RomFSStructs.h
Normal file
40
src/Cafe/Filesystem/WUHB/RomFSStructs.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
struct romfs_header_t
|
||||
{
|
||||
uint32 header_magic;
|
||||
uint32be header_size;
|
||||
uint64be dir_hash_table_ofs;
|
||||
uint64be dir_hash_table_size;
|
||||
uint64be dir_table_ofs;
|
||||
uint64be dir_table_size;
|
||||
uint64be file_hash_table_ofs;
|
||||
uint64be file_hash_table_size;
|
||||
uint64be file_table_ofs;
|
||||
uint64be file_table_size;
|
||||
uint64be file_partition_ofs;
|
||||
};
|
||||
|
||||
struct romfs_direntry_t
|
||||
{
|
||||
uint32be parent;
|
||||
uint32be listNext; // offset to next directory entry in linked list of parent directory (aka "sibling")
|
||||
uint32be dirListHead; // offset to first entry in linked list of directory entries (aka "child")
|
||||
uint32be fileListHead; // offset to first entry in linked list of file entries (aka "file")
|
||||
uint32be hash;
|
||||
uint32be name_size;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct romfs_fentry_t
|
||||
{
|
||||
uint32be parent;
|
||||
uint32be listNext; // offset to next file entry in linked list of parent directory (aka "sibling")
|
||||
uint64be offset;
|
||||
uint64be size;
|
||||
uint32be hash;
|
||||
uint32be name_size;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
#define ROMFS_ENTRY_EMPTY 0xFFFFFFFF
|
224
src/Cafe/Filesystem/WUHB/WUHBReader.cpp
Normal file
224
src/Cafe/Filesystem/WUHB/WUHBReader.cpp
Normal file
|
@ -0,0 +1,224 @@
|
|||
#include "WUHBReader.h"
|
||||
WUHBReader* WUHBReader::FromPath(const fs::path& path)
|
||||
{
|
||||
FileStream* fileIn{FileStream::openFile2(path)};
|
||||
if (!fileIn)
|
||||
return nullptr;
|
||||
|
||||
WUHBReader* ret = new WUHBReader(fileIn);
|
||||
if (!ret->CheckMagicValue())
|
||||
{
|
||||
delete ret;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ret->ReadHeader())
|
||||
{
|
||||
delete ret;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const romfs_direntry_t fallbackDirEntry{
|
||||
.parent = ROMFS_ENTRY_EMPTY,
|
||||
.listNext = ROMFS_ENTRY_EMPTY,
|
||||
.dirListHead = ROMFS_ENTRY_EMPTY,
|
||||
.fileListHead = ROMFS_ENTRY_EMPTY,
|
||||
.hash = ROMFS_ENTRY_EMPTY,
|
||||
.name_size = 0,
|
||||
.name = ""
|
||||
};
|
||||
static const romfs_fentry_t fallbackFileEntry{
|
||||
.parent = ROMFS_ENTRY_EMPTY,
|
||||
.listNext = ROMFS_ENTRY_EMPTY,
|
||||
.offset = 0,
|
||||
.size = 0,
|
||||
.hash = ROMFS_ENTRY_EMPTY,
|
||||
.name_size = 0,
|
||||
.name = ""
|
||||
};
|
||||
template<bool File>
|
||||
const WUHBReader::EntryType<File>& WUHBReader::GetFallback()
|
||||
{
|
||||
if constexpr (File)
|
||||
return fallbackFileEntry;
|
||||
else
|
||||
return fallbackDirEntry;
|
||||
}
|
||||
|
||||
template<bool File>
|
||||
WUHBReader::EntryType<File> WUHBReader::GetEntry(uint32 offset) const
|
||||
{
|
||||
auto fallback = GetFallback<File>();
|
||||
if(offset == ROMFS_ENTRY_EMPTY)
|
||||
return fallback;
|
||||
|
||||
const char* typeName = File ? "fentry" : "direntry";
|
||||
EntryType<File> ret;
|
||||
if (offset >= (File ? m_header.file_table_size : m_header.dir_table_size))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "WUHB {} offset exceeds table size declared in header", typeName);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
// read the entry
|
||||
m_fileIn->SetPosition((File ? m_header.file_table_ofs : m_header.dir_table_ofs) + offset);
|
||||
auto read = m_fileIn->readData(&ret, offsetof(EntryType<File>, name));
|
||||
if (read != offsetof(EntryType<File>, name))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "failed to read WUHB {} at offset: {}", typeName, offset);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
// read the name
|
||||
ret.name.resize(ret.name_size);
|
||||
read = m_fileIn->readData(ret.name.data(), ret.name_size);
|
||||
if (read != ret.name_size)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "failed to read WUHB {} name", typeName);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
romfs_direntry_t WUHBReader::GetDirEntry(uint32 offset) const
|
||||
{
|
||||
return GetEntry<false>(offset);
|
||||
}
|
||||
romfs_fentry_t WUHBReader::GetFileEntry(uint32 offset) const
|
||||
{
|
||||
return GetEntry<true>(offset);
|
||||
}
|
||||
|
||||
uint64 WUHBReader::GetFileSize(uint32 entryOffset) const
|
||||
{
|
||||
return GetFileEntry(entryOffset).size;
|
||||
}
|
||||
|
||||
uint64 WUHBReader::ReadFromFile(uint32 entryOffset, uint64 fileOffset, uint64 length, void* buffer) const
|
||||
{
|
||||
const auto fileEntry = GetFileEntry(entryOffset);
|
||||
if (fileOffset >= fileEntry.size)
|
||||
return 0;
|
||||
const uint64 readAmount = std::min(length, fileEntry.size - fileOffset);
|
||||
const uint64 wuhbOffset = m_header.file_partition_ofs + fileEntry.offset + fileOffset;
|
||||
m_fileIn->SetPosition(wuhbOffset);
|
||||
return m_fileIn->readData(buffer, readAmount);
|
||||
}
|
||||
|
||||
uint32 WUHBReader::GetHashTableEntryOffset(uint32 hash, bool isFile) const
|
||||
{
|
||||
const uint64 hash_table_size = (isFile ? m_header.file_hash_table_size : m_header.dir_hash_table_size);
|
||||
const uint64 hash_table_ofs = (isFile ? m_header.file_hash_table_ofs : m_header.dir_hash_table_ofs);
|
||||
|
||||
const uint64 hash_table_entry_count = hash_table_size / sizeof(uint32);
|
||||
const uint64 hash_table_entry_offset = hash_table_ofs + (hash % hash_table_entry_count) * sizeof(uint32);
|
||||
|
||||
m_fileIn->SetPosition(hash_table_entry_offset);
|
||||
uint32 tableOffset;
|
||||
if (!m_fileIn->readU32(tableOffset))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "failed to read WUHB hash table entry at file offset: {}", hash_table_entry_offset);
|
||||
return ROMFS_ENTRY_EMPTY;
|
||||
}
|
||||
|
||||
return uint32be::from_bevalue(tableOffset);
|
||||
}
|
||||
|
||||
template<bool T>
|
||||
bool WUHBReader::SearchHashList(uint32& entryOffset, const fs::path& targetName) const
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (entryOffset == ROMFS_ENTRY_EMPTY)
|
||||
return false;
|
||||
auto entry = GetEntry<T>(entryOffset);
|
||||
|
||||
if (entry.name == targetName)
|
||||
return true;
|
||||
entryOffset = entry.hash;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 WUHBReader::Lookup(const std::filesystem::path& path, bool isFile) const
|
||||
{
|
||||
uint32 currentEntryOffset = 0;
|
||||
auto look = [&](const fs::path& part, bool lookInFileHT) {
|
||||
const auto partString = part.string();
|
||||
currentEntryOffset = GetHashTableEntryOffset(CalcPathHash(currentEntryOffset, partString.c_str(), 0, partString.size()), lookInFileHT);
|
||||
if (lookInFileHT)
|
||||
return SearchHashList<true>(currentEntryOffset, part);
|
||||
else
|
||||
return SearchHashList<false>(currentEntryOffset, part);
|
||||
};
|
||||
// look for the root entry
|
||||
if (!look("", false))
|
||||
return ROMFS_ENTRY_EMPTY;
|
||||
|
||||
auto it = path.begin();
|
||||
while (it != path.end())
|
||||
{
|
||||
fs::path part = *it;
|
||||
++it;
|
||||
// no need to recurse after trailing forward slash (e.g. directory/)
|
||||
if (part.empty() && !isFile)
|
||||
break;
|
||||
// skip leading forward slash
|
||||
if (part == "/")
|
||||
continue;
|
||||
|
||||
// if the lookup target is a file and this is the last iteration, look in the file hash table instead.
|
||||
if (!look(part, it == path.end() && isFile))
|
||||
return ROMFS_ENTRY_EMPTY;
|
||||
}
|
||||
return currentEntryOffset;
|
||||
}
|
||||
bool WUHBReader::CheckMagicValue() const
|
||||
{
|
||||
uint8 magic[4];
|
||||
m_fileIn->SetPosition(0);
|
||||
int read = m_fileIn->readData(magic, 4);
|
||||
if (read != 4)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Failed to read WUHB magic numbers");
|
||||
return false;
|
||||
}
|
||||
static_assert(sizeof(magic) == s_headerMagicValue.size());
|
||||
return std::memcmp(&magic, s_headerMagicValue.data(), sizeof(magic)) == 0;
|
||||
}
|
||||
bool WUHBReader::ReadHeader()
|
||||
{
|
||||
m_fileIn->SetPosition(0);
|
||||
auto read = m_fileIn->readData(&m_header, sizeof(m_header));
|
||||
auto readSuccess = read == sizeof(m_header);
|
||||
if (!readSuccess)
|
||||
cemuLog_log(LogType::Force, "Failed to read WUHB header");
|
||||
return readSuccess;
|
||||
}
|
||||
unsigned char WUHBReader::NormalizeChar(unsigned char c)
|
||||
{
|
||||
if (c >= 'a' && c <= 'z')
|
||||
{
|
||||
return c + 'A' - 'a';
|
||||
}
|
||||
else
|
||||
{
|
||||
return c;
|
||||
}
|
||||
}
|
||||
uint32 WUHBReader::CalcPathHash(uint32 parent, const char* path, uint32 start, size_t path_len)
|
||||
{
|
||||
cemu_assert(path != nullptr || path_len == 0);
|
||||
uint32 hash = parent ^ 123456789;
|
||||
for (uint32 i = 0; i < path_len; i++)
|
||||
{
|
||||
hash = (hash >> 5) | (hash << 27);
|
||||
hash ^= NormalizeChar(path[start + i]);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
45
src/Cafe/Filesystem/WUHB/WUHBReader.h
Normal file
45
src/Cafe/Filesystem/WUHB/WUHBReader.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
#include <Common/FileStream.h>
|
||||
#include "RomFSStructs.h"
|
||||
class WUHBReader
|
||||
{
|
||||
public:
|
||||
static WUHBReader* FromPath(const fs::path& path);
|
||||
|
||||
romfs_direntry_t GetDirEntry(uint32 offset) const;
|
||||
romfs_fentry_t GetFileEntry(uint32 offset) const;
|
||||
|
||||
uint64 GetFileSize(uint32 entryOffset) const;
|
||||
|
||||
uint64 ReadFromFile(uint32 entryOffset, uint64 fileOffset, uint64 length, void* buffer) const;
|
||||
|
||||
uint32 Lookup(const std::filesystem::path& path, bool isFile) const;
|
||||
|
||||
private:
|
||||
WUHBReader(FileStream* file)
|
||||
: m_fileIn(file)
|
||||
{
|
||||
cemu_assert_debug(file != nullptr);
|
||||
};
|
||||
WUHBReader() = delete;
|
||||
|
||||
romfs_header_t m_header;
|
||||
std::unique_ptr<FileStream> m_fileIn;
|
||||
constexpr static std::string_view s_headerMagicValue = "WUHB";
|
||||
bool ReadHeader();
|
||||
bool CheckMagicValue() const;
|
||||
|
||||
static inline unsigned char NormalizeChar(unsigned char c);
|
||||
static uint32 CalcPathHash(uint32 parent, const char* path, uint32 start, size_t path_len);
|
||||
|
||||
template<bool File>
|
||||
using EntryType = std::conditional_t<File, romfs_fentry_t, romfs_direntry_t>;
|
||||
template<bool File>
|
||||
static const EntryType<File>& GetFallback();
|
||||
template<bool File>
|
||||
EntryType<File> GetEntry(uint32 offset) const;
|
||||
|
||||
template<bool T>
|
||||
bool SearchHashList(uint32& entryOffset, const fs::path& targetName) const;
|
||||
uint32 GetHashTableEntryOffset(uint32 hash, bool isFile) const;
|
||||
};
|
|
@ -204,6 +204,9 @@ bool FSCDeviceWUD_Mount(std::string_view mountPath, std::string_view destination
|
|||
// wua device
|
||||
bool FSCDeviceWUA_Mount(std::string_view mountPath, std::string_view destinationBaseDir, class ZArchiveReader* archive, sint32 priority);
|
||||
|
||||
// wuhb device
|
||||
bool FSCDeviceWUHB_Mount(std::string_view mountPath, std::string_view destinationBaseDir, class WUHBReader* wuhbReader, sint32 priority);
|
||||
|
||||
// hostFS device
|
||||
bool FSCDeviceHostFS_Mount(std::string_view mountPath, std::string_view hostTargetPath, sint32 priority);
|
||||
|
||||
|
|
151
src/Cafe/Filesystem/fscDeviceWuhb.cpp
Normal file
151
src/Cafe/Filesystem/fscDeviceWuhb.cpp
Normal file
|
@ -0,0 +1,151 @@
|
|||
#include "Filesystem/WUHB/WUHBReader.h"
|
||||
#include "Cafe/Filesystem/fsc.h"
|
||||
#include "Cafe/Filesystem/FST/FST.h"
|
||||
|
||||
class FSCDeviceWuhbFileCtx : public FSCVirtualFile
|
||||
{
|
||||
public:
|
||||
FSCDeviceWuhbFileCtx(WUHBReader* reader, uint32 entryOffset, uint32 fscType)
|
||||
: m_wuhbReader(reader), m_entryOffset(entryOffset), m_fscType(fscType)
|
||||
{
|
||||
cemu_assert(entryOffset != ROMFS_ENTRY_EMPTY);
|
||||
if (fscType == FSC_TYPE_DIRECTORY)
|
||||
{
|
||||
romfs_direntry_t entry = reader->GetDirEntry(entryOffset);
|
||||
m_dirIterOffset = entry.dirListHead;
|
||||
m_fileIterOffset = entry.fileListHead;
|
||||
}
|
||||
}
|
||||
sint32 fscGetType() override
|
||||
{
|
||||
return m_fscType;
|
||||
}
|
||||
uint64 fscQueryValueU64(uint32 id) override
|
||||
{
|
||||
if (m_fscType == FSC_TYPE_FILE)
|
||||
{
|
||||
if (id == FSC_QUERY_SIZE)
|
||||
return m_wuhbReader->GetFileSize(m_entryOffset);
|
||||
else if (id == FSC_QUERY_WRITEABLE)
|
||||
return 0; // WUHB images are read-only
|
||||
else
|
||||
cemu_assert_error();
|
||||
}
|
||||
else
|
||||
{
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
uint32 fscWriteData(void* buffer, uint32 size) override
|
||||
{
|
||||
cemu_assert_error();
|
||||
return 0;
|
||||
}
|
||||
uint32 fscReadData(void* buffer, uint32 size) override
|
||||
{
|
||||
if (m_fscType != FSC_TYPE_FILE)
|
||||
return 0;
|
||||
auto read = m_wuhbReader->ReadFromFile(m_entryOffset, m_seek, size, buffer);
|
||||
m_seek += read;
|
||||
return read;
|
||||
}
|
||||
void fscSetSeek(uint64 seek) override
|
||||
{
|
||||
m_seek = seek;
|
||||
}
|
||||
uint64 fscGetSeek() override
|
||||
{
|
||||
if (m_fscType != FSC_TYPE_FILE)
|
||||
return 0;
|
||||
return m_seek;
|
||||
}
|
||||
void fscSetFileLength(uint64 endOffset) override
|
||||
{
|
||||
cemu_assert_error();
|
||||
}
|
||||
bool fscDirNext(FSCDirEntry* dirEntry) override
|
||||
{
|
||||
if (m_dirIterOffset != ROMFS_ENTRY_EMPTY)
|
||||
{
|
||||
romfs_direntry_t entry = m_wuhbReader->GetDirEntry(m_dirIterOffset);
|
||||
m_dirIterOffset = entry.listNext;
|
||||
if(entry.name_size > 0)
|
||||
{
|
||||
dirEntry->isDirectory = true;
|
||||
dirEntry->isFile = false;
|
||||
dirEntry->fileSize = 0;
|
||||
std::strncpy(dirEntry->path, entry.name.c_str(), FSC_MAX_DIR_NAME_LENGTH);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (m_fileIterOffset != ROMFS_ENTRY_EMPTY)
|
||||
{
|
||||
romfs_fentry_t entry = m_wuhbReader->GetFileEntry(m_fileIterOffset);
|
||||
m_fileIterOffset = entry.listNext;
|
||||
if(entry.name_size > 0)
|
||||
{
|
||||
dirEntry->isDirectory = false;
|
||||
dirEntry->isFile = true;
|
||||
dirEntry->fileSize = entry.size;
|
||||
std::strncpy(dirEntry->path, entry.name.c_str(), FSC_MAX_DIR_NAME_LENGTH);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
WUHBReader* m_wuhbReader{};
|
||||
uint32 m_fscType;
|
||||
uint32 m_entryOffset = ROMFS_ENTRY_EMPTY;
|
||||
uint32 m_dirIterOffset = ROMFS_ENTRY_EMPTY;
|
||||
uint32 m_fileIterOffset = ROMFS_ENTRY_EMPTY;
|
||||
uint64 m_seek = 0;
|
||||
};
|
||||
|
||||
class fscDeviceWUHB : public fscDeviceC
|
||||
{
|
||||
FSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override
|
||||
{
|
||||
WUHBReader* reader = (WUHBReader*)ctx;
|
||||
cemu_assert_debug(!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::WRITE_PERMISSION)); // writing to WUHB is not supported
|
||||
|
||||
bool isFile;
|
||||
uint32 table_offset = ROMFS_ENTRY_EMPTY;
|
||||
|
||||
if (table_offset == ROMFS_ENTRY_EMPTY && HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))
|
||||
{
|
||||
table_offset = reader->Lookup(path, false);
|
||||
isFile = false;
|
||||
}
|
||||
if (table_offset == ROMFS_ENTRY_EMPTY && HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE))
|
||||
{
|
||||
table_offset = reader->Lookup(path, true);
|
||||
isFile = true;
|
||||
}
|
||||
|
||||
if (table_offset == ROMFS_ENTRY_EMPTY)
|
||||
{
|
||||
*fscStatus = FSC_STATUS_FILE_NOT_FOUND;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*fscStatus = FSC_STATUS_OK;
|
||||
return new FSCDeviceWuhbFileCtx(reader, table_offset, isFile ? FSC_TYPE_FILE : FSC_TYPE_DIRECTORY);
|
||||
}
|
||||
|
||||
// singleton
|
||||
public:
|
||||
static fscDeviceWUHB& instance()
|
||||
{
|
||||
static fscDeviceWUHB _instance;
|
||||
return _instance;
|
||||
}
|
||||
};
|
||||
|
||||
bool FSCDeviceWUHB_Mount(std::string_view mountPath, std::string_view destinationBaseDir, WUHBReader* wuhbReader, sint32 priority)
|
||||
{
|
||||
return fsc_mount(mountPath, destinationBaseDir, &fscDeviceWUHB::instance(), wuhbReader, priority) == FSC_STATUS_OK;
|
||||
}
|
|
@ -875,11 +875,6 @@ void LatteRenderTarget_getScreenImageArea(sint32* x, sint32* y, sint32* width, s
|
|||
|
||||
void LatteRenderTarget_copyToBackbuffer(LatteTextureView* textureView, bool isPadView)
|
||||
{
|
||||
if (g_renderer->GetType() == RendererAPI::Vulkan)
|
||||
{
|
||||
((VulkanRenderer*)g_renderer.get())->PreparePresentationFrame(!isPadView);
|
||||
}
|
||||
|
||||
// make sure texture is updated to latest data in cache
|
||||
LatteTexture_UpdateDataToLatest(textureView->baseTexture);
|
||||
// mark source texture as still in use
|
||||
|
|
|
@ -187,7 +187,7 @@ int Latte_ThreadEntry()
|
|||
rule.overwrite_settings.width >= 0 || rule.overwrite_settings.height >= 0 || rule.overwrite_settings.depth >= 0)
|
||||
{
|
||||
LatteGPUState.allowFramebufferSizeOptimization = false;
|
||||
cemuLog_log(LogType::Force, "Graphic pack {} prevents rendertarget size optimization.", pack->GetName());
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\" prevents rendertarget size optimization. This warning can be ignored and is intended for graphic pack developers", pack->GetName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -386,7 +386,7 @@ void OpenGLRenderer::GetVendorInformation()
|
|||
cemuLog_log(LogType::Force, "GL_RENDERER: {}", glRendererString ? glRendererString : "unknown");
|
||||
cemuLog_log(LogType::Force, "GL_VERSION: {}", glVersionString ? glVersionString : "unknown");
|
||||
|
||||
if(boost::icontains(glVersionString, "Mesa"))
|
||||
if(glVersionString && boost::icontains(glVersionString, "Mesa"))
|
||||
{
|
||||
m_vendor = GfxVendor::Mesa;
|
||||
return;
|
||||
|
|
|
@ -146,13 +146,6 @@ void SwapchainInfoVk::Create()
|
|||
UnrecoverableError("Failed to create semaphore for swapchain acquire");
|
||||
}
|
||||
|
||||
VkFenceCreateInfo fenceInfo = {};
|
||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
result = vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &m_imageAvailableFence);
|
||||
if (result != VK_SUCCESS)
|
||||
UnrecoverableError("Failed to create fence for swapchain");
|
||||
|
||||
m_acquireIndex = 0;
|
||||
hasDefinedSwapchainImage = false;
|
||||
}
|
||||
|
@ -184,12 +177,6 @@ void SwapchainInfoVk::Cleanup()
|
|||
m_swapchainFramebuffers.clear();
|
||||
|
||||
|
||||
if (m_imageAvailableFence)
|
||||
{
|
||||
WaitAvailableFence();
|
||||
vkDestroyFence(m_logicalDevice, m_imageAvailableFence, nullptr);
|
||||
m_imageAvailableFence = nullptr;
|
||||
}
|
||||
if (m_swapchain)
|
||||
{
|
||||
vkDestroySwapchainKHR(m_logicalDevice, m_swapchain, nullptr);
|
||||
|
@ -202,18 +189,6 @@ bool SwapchainInfoVk::IsValid() const
|
|||
return m_swapchain && !m_acquireSemaphores.empty();
|
||||
}
|
||||
|
||||
void SwapchainInfoVk::WaitAvailableFence()
|
||||
{
|
||||
if(m_awaitableFence != VK_NULL_HANDLE)
|
||||
vkWaitForFences(m_logicalDevice, 1, &m_awaitableFence, VK_TRUE, UINT64_MAX);
|
||||
m_awaitableFence = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void SwapchainInfoVk::ResetAvailableFence() const
|
||||
{
|
||||
vkResetFences(m_logicalDevice, 1, &m_imageAvailableFence);
|
||||
}
|
||||
|
||||
VkSemaphore SwapchainInfoVk::ConsumeAcquireSemaphore()
|
||||
{
|
||||
VkSemaphore ret = m_currentSemaphore;
|
||||
|
@ -221,15 +196,18 @@ VkSemaphore SwapchainInfoVk::ConsumeAcquireSemaphore()
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool SwapchainInfoVk::AcquireImage(uint64 timeout)
|
||||
bool SwapchainInfoVk::AcquireImage()
|
||||
{
|
||||
WaitAvailableFence();
|
||||
ResetAvailableFence();
|
||||
|
||||
VkSemaphore acquireSemaphore = m_acquireSemaphores[m_acquireIndex];
|
||||
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, m_swapchain, timeout, acquireSemaphore, m_imageAvailableFence, &swapchainImageIndex);
|
||||
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, m_swapchain, 1'000'000'000, acquireSemaphore, nullptr, &swapchainImageIndex);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
||||
m_shouldRecreate = true;
|
||||
if (result == VK_TIMEOUT)
|
||||
{
|
||||
swapchainImageIndex = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
swapchainImageIndex = -1;
|
||||
|
@ -238,7 +216,6 @@ bool SwapchainInfoVk::AcquireImage(uint64 timeout)
|
|||
return false;
|
||||
}
|
||||
m_currentSemaphore = acquireSemaphore;
|
||||
m_awaitableFence = m_imageAvailableFence;
|
||||
m_acquireIndex = (m_acquireIndex + 1) % m_swapchainImages.size();
|
||||
|
||||
return true;
|
||||
|
|
|
@ -26,10 +26,7 @@ struct SwapchainInfoVk
|
|||
|
||||
bool IsValid() const;
|
||||
|
||||
void WaitAvailableFence();
|
||||
void ResetAvailableFence() const;
|
||||
|
||||
bool AcquireImage(uint64 timeout);
|
||||
bool AcquireImage();
|
||||
// retrieve semaphore of last acquire for submitting a wait operation
|
||||
// only one wait operation must be submitted per acquire (which submits a single signal operation)
|
||||
// therefore subsequent calls will return a NULL handle
|
||||
|
@ -84,9 +81,7 @@ struct SwapchainInfoVk
|
|||
private:
|
||||
uint32 m_acquireIndex = 0;
|
||||
std::vector<VkSemaphore> m_acquireSemaphores; // indexed by m_acquireIndex
|
||||
VkFence m_imageAvailableFence{};
|
||||
VkSemaphore m_currentSemaphore = VK_NULL_HANDLE;
|
||||
VkFence m_awaitableFence = VK_NULL_HANDLE;
|
||||
|
||||
std::array<uint32, 2> m_swapchainQueueFamilyIndices;
|
||||
VkExtent2D m_actualExtent{};
|
||||
|
|
|
@ -1824,11 +1824,6 @@ void VulkanRenderer::DrawEmptyFrame(bool mainWindow)
|
|||
SwapBuffers(mainWindow, !mainWindow);
|
||||
}
|
||||
|
||||
void VulkanRenderer::PreparePresentationFrame(bool mainWindow)
|
||||
{
|
||||
AcquireNextSwapchainImage(mainWindow);
|
||||
}
|
||||
|
||||
void VulkanRenderer::InitFirstCommandBuffer()
|
||||
{
|
||||
cemu_assert_debug(m_state.currentCommandBuffer == nullptr);
|
||||
|
@ -2599,7 +2594,7 @@ bool VulkanRenderer::AcquireNextSwapchainImage(bool mainWindow)
|
|||
if (!UpdateSwapchainProperties(mainWindow))
|
||||
return false;
|
||||
|
||||
bool result = chainInfo.AcquireImage(UINT64_MAX);
|
||||
bool result = chainInfo.AcquireImage();
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
|
@ -2612,8 +2607,6 @@ void VulkanRenderer::RecreateSwapchain(bool mainWindow, bool skipCreate)
|
|||
SubmitCommandBuffer();
|
||||
WaitDeviceIdle();
|
||||
auto& chainInfo = GetChainInfo(mainWindow);
|
||||
// make sure fence has no signal operation submitted
|
||||
chainInfo.WaitAvailableFence();
|
||||
|
||||
Vector2i size;
|
||||
if (mainWindow)
|
||||
|
|
|
@ -228,7 +228,6 @@ public:
|
|||
uint64 GenUniqueId(); // return unique id (uses incrementing counter)
|
||||
|
||||
void DrawEmptyFrame(bool mainWindow) override;
|
||||
void PreparePresentationFrame(bool mainWindow);
|
||||
|
||||
void InitFirstCommandBuffer();
|
||||
void ProcessFinishedCommandBuffers();
|
||||
|
|
|
@ -8,10 +8,19 @@
|
|||
#include "Cafe/OS/libs/nn_acp/nn_acp.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_FS.h"
|
||||
#include "Cafe/Filesystem/fsc.h"
|
||||
#include "Cafe/HW/Espresso/PPCState.h"
|
||||
//#include "Cafe/HW/Espresso/PPCState.h"
|
||||
|
||||
#include "Cafe/IOSU/iosu_types_common.h"
|
||||
#include "Cafe/IOSU/nn/iosu_nn_service.h"
|
||||
|
||||
#include "Cafe/IOSU/legacy/iosu_act.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
using ACPDeviceType = iosu::acp::ACPDeviceType;
|
||||
|
||||
static_assert(sizeof(acpMetaXml_t) == 0x3440);
|
||||
static_assert(offsetof(acpMetaXml_t, title_id) == 0x0000);
|
||||
static_assert(offsetof(acpMetaXml_t, boss_id) == 0x0008);
|
||||
|
@ -506,48 +515,6 @@ namespace iosu
|
|||
return 0;
|
||||
}
|
||||
|
||||
sint32 ACPCreateSaveDirEx(uint8 accountSlot, uint64 titleId)
|
||||
{
|
||||
uint32 persistentId = 0;
|
||||
nn::save::GetPersistentIdEx(accountSlot, &persistentId);
|
||||
|
||||
uint32 high = GetTitleIdHigh(titleId) & (~0xC);
|
||||
uint32 low = GetTitleIdLow(titleId);
|
||||
|
||||
sint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND;
|
||||
char path[256];
|
||||
|
||||
sprintf(path, "%susr/boss/", "/vol/storage_mlc01/");
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/", "/vol/storage_mlc01/", high);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/common", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/%08x/", "/vol/storage_mlc01/", high, low, persistentId == 0 ? 0x80000001 : persistentId);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
sprintf(path, "%susr/save/%08x/", "/vol/storage_mlc01/", high);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/meta/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/common", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/%08x", "/vol/storage_mlc01/", high, low, persistentId == 0 ? 0x80000001 : persistentId);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
// copy xml meta files
|
||||
nn::acp::CreateSaveMetaFiles(persistentId, titleId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iosuAcp_thread()
|
||||
{
|
||||
SetThreadName("iosuAcp_thread");
|
||||
|
@ -584,7 +551,7 @@ namespace iosu
|
|||
}
|
||||
else if (acpCemuRequest->requestCode == IOSU_ACP_CREATE_SAVE_DIR_EX)
|
||||
{
|
||||
acpCemuRequest->returnCode = ACPCreateSaveDirEx(acpCemuRequest->accountSlot, acpCemuRequest->titleId);
|
||||
acpCemuRequest->returnCode = acp::ACPCreateSaveDirEx(acpCemuRequest->accountSlot, acpCemuRequest->titleId);
|
||||
}
|
||||
else
|
||||
cemu_assert_unimplemented();
|
||||
|
@ -610,5 +577,237 @@ namespace iosu
|
|||
return iosuAcp.isInitialized;
|
||||
}
|
||||
|
||||
/* Above is the legacy implementation. Below is the new style implementation which also matches the official IPC protocol and works with the real nn_acp.rpl */
|
||||
|
||||
}
|
||||
namespace acp
|
||||
{
|
||||
|
||||
uint64 _ACPGetTimestamp()
|
||||
{
|
||||
return coreinit::coreinit_getOSTime() / ESPRESSO_TIMER_CLOCK;
|
||||
}
|
||||
|
||||
nnResult ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType)
|
||||
{
|
||||
if (deviceType == ACPDeviceType::UnknownType)
|
||||
{
|
||||
return (nnResult)0xA030FB80;
|
||||
}
|
||||
|
||||
// create or modify the saveinfo
|
||||
const auto saveinfoPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/meta/saveinfo.xml", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
auto saveinfoData = FileStream::LoadIntoMemory(saveinfoPath);
|
||||
if (saveinfoData && !saveinfoData->empty())
|
||||
{
|
||||
namespace xml = tinyxml2;
|
||||
xml::XMLDocument doc;
|
||||
tinyxml2::XMLError xmlError = doc.Parse((const char*)saveinfoData->data(), saveinfoData->size());
|
||||
if (xmlError == xml::XML_SUCCESS || xmlError == xml::XML_ERROR_EMPTY_DOCUMENT)
|
||||
{
|
||||
xml::XMLNode* child = doc.FirstChild();
|
||||
// check for declaration -> <?xml version="1.0" encoding="utf-8"?>
|
||||
if (!child || !child->ToDeclaration())
|
||||
{
|
||||
xml::XMLDeclaration* decl = doc.NewDeclaration();
|
||||
doc.InsertFirstChild(decl);
|
||||
}
|
||||
|
||||
xml::XMLElement* info = doc.FirstChildElement("info");
|
||||
if (!info)
|
||||
{
|
||||
info = doc.NewElement("info");
|
||||
doc.InsertEndChild(info);
|
||||
}
|
||||
|
||||
// find node with persistentId
|
||||
char tmp[64];
|
||||
sprintf(tmp, "%08x", persistentId);
|
||||
bool foundNode = false;
|
||||
for (xml::XMLElement* account = info->FirstChildElement("account"); account; account = account->NextSiblingElement("account"))
|
||||
{
|
||||
if (account->Attribute("persistentId", tmp))
|
||||
{
|
||||
// found the entry! -> update timestamp
|
||||
xml::XMLElement* timestamp = account->FirstChildElement("timestamp");
|
||||
sprintf(tmp, "%" PRIx64, _ACPGetTimestamp());
|
||||
if (timestamp)
|
||||
timestamp->SetText(tmp);
|
||||
else
|
||||
{
|
||||
timestamp = doc.NewElement("timestamp");
|
||||
account->InsertFirstChild(timestamp);
|
||||
}
|
||||
|
||||
foundNode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundNode)
|
||||
{
|
||||
tinyxml2::XMLElement* account = doc.NewElement("account");
|
||||
{
|
||||
sprintf(tmp, "%08x", persistentId);
|
||||
account->SetAttribute("persistentId", tmp);
|
||||
|
||||
tinyxml2::XMLElement* timestamp = doc.NewElement("timestamp");
|
||||
{
|
||||
sprintf(tmp, "%" PRIx64, _ACPGetTimestamp());
|
||||
timestamp->SetText(tmp);
|
||||
}
|
||||
|
||||
account->InsertFirstChild(timestamp);
|
||||
}
|
||||
|
||||
info->InsertFirstChild(account);
|
||||
}
|
||||
|
||||
// update file
|
||||
tinyxml2::XMLPrinter printer;
|
||||
doc.Print(&printer);
|
||||
FileStream* fs = FileStream::createFile2(saveinfoPath);
|
||||
if (fs)
|
||||
{
|
||||
fs->writeString(printer.CStr());
|
||||
delete fs;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NN_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void CreateSaveMetaFiles(uint32 persistentId, uint64 titleId)
|
||||
{
|
||||
std::string titlePath = CafeSystem::GetMlcStoragePath(CafeSystem::GetForegroundTitleId());
|
||||
|
||||
sint32 fscStatus;
|
||||
FSCVirtualFile* fscFile = fsc_open((titlePath + "/meta/meta.xml").c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus);
|
||||
if (fscFile)
|
||||
{
|
||||
sint32 fileSize = fsc_getFileSize(fscFile);
|
||||
|
||||
std::unique_ptr<uint8[]> fileContent = std::make_unique<uint8[]>(fileSize);
|
||||
fsc_readFile(fscFile, fileContent.get(), fileSize);
|
||||
fsc_close(fscFile);
|
||||
|
||||
const auto outPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/meta/meta.xml", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
|
||||
std::ofstream myFile(outPath, std::ios::out | std::ios::binary);
|
||||
myFile.write((char*)fileContent.get(), fileSize);
|
||||
myFile.close();
|
||||
}
|
||||
|
||||
fscFile = fsc_open((titlePath + "/meta/iconTex.tga").c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus);
|
||||
if (fscFile)
|
||||
{
|
||||
sint32 fileSize = fsc_getFileSize(fscFile);
|
||||
|
||||
std::unique_ptr<uint8[]> fileContent = std::make_unique<uint8[]>(fileSize);
|
||||
fsc_readFile(fscFile, fileContent.get(), fileSize);
|
||||
fsc_close(fscFile);
|
||||
|
||||
const auto outPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/meta/iconTex.tga", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
|
||||
std::ofstream myFile(outPath, std::ios::out | std::ios::binary);
|
||||
myFile.write((char*)fileContent.get(), fileSize);
|
||||
myFile.close();
|
||||
}
|
||||
|
||||
ACPUpdateSaveTimeStamp(persistentId, titleId, iosu::acp::ACPDeviceType::InternalDeviceType);
|
||||
}
|
||||
|
||||
|
||||
sint32 _ACPCreateSaveDir(uint32 persistentId, uint64 titleId, ACPDeviceType type)
|
||||
{
|
||||
uint32 high = GetTitleIdHigh(titleId) & (~0xC);
|
||||
uint32 low = GetTitleIdLow(titleId);
|
||||
|
||||
sint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND;
|
||||
char path[256];
|
||||
|
||||
sprintf(path, "%susr/boss/", "/vol/storage_mlc01/");
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/", "/vol/storage_mlc01/", high);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/common", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/%08x/", "/vol/storage_mlc01/", high, low, persistentId == 0 ? 0x80000001 : persistentId);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
sprintf(path, "%susr/save/%08x/", "/vol/storage_mlc01/", high);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/meta/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/common", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/%08x", "/vol/storage_mlc01/", high, low, persistentId == 0 ? 0x80000001 : persistentId);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
// copy xml meta files
|
||||
CreateSaveMetaFiles(persistentId, titleId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nnResult ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type)
|
||||
{
|
||||
uint64 titleId = CafeSystem::GetForegroundTitleId();
|
||||
return _ACPCreateSaveDir(persistentId, titleId, type);
|
||||
}
|
||||
|
||||
sint32 ACPCreateSaveDirEx(uint8 accountSlot, uint64 titleId)
|
||||
{
|
||||
uint32 persistentId = 0;
|
||||
cemu_assert_debug(accountSlot >= 1 && accountSlot <= 13); // outside valid slot range?
|
||||
bool r = iosu::act::GetPersistentId(accountSlot, &persistentId);
|
||||
cemu_assert_debug(r);
|
||||
return _ACPCreateSaveDir(persistentId, titleId, ACPDeviceType::InternalDeviceType);
|
||||
}
|
||||
|
||||
nnResult ACPGetOlvAccesskey(uint32be* accessKey)
|
||||
{
|
||||
*accessKey = CafeSystem::GetForegroundTitleOlvAccesskey();
|
||||
return 0;
|
||||
}
|
||||
|
||||
class AcpMainService : public iosu::nn::IPCService
|
||||
{
|
||||
public:
|
||||
AcpMainService() : iosu::nn::IPCService("/dev/acp_main") {}
|
||||
|
||||
nnResult ServiceCall(uint32 serviceId, void* request, void* response) override
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Unsupported service call to /dev/acp_main");
|
||||
cemu_assert_unimplemented();
|
||||
return BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACP, 0);
|
||||
}
|
||||
};
|
||||
|
||||
AcpMainService gACPMainService;
|
||||
|
||||
class : public ::IOSUModule
|
||||
{
|
||||
void TitleStart() override
|
||||
{
|
||||
gACPMainService.Start();
|
||||
// gACPMainService.SetTimerUpdate(1000); // call TimerUpdate() once a second
|
||||
}
|
||||
void TitleStop() override
|
||||
{
|
||||
gACPMainService.Stop();
|
||||
}
|
||||
}sIOSUModuleNNACP;
|
||||
|
||||
IOSUModule* GetModule()
|
||||
{
|
||||
return static_cast<IOSUModule*>(&sIOSUModuleNNACP);
|
||||
}
|
||||
} // namespace acp
|
||||
} // namespace iosu
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "Cafe/IOSU/iosu_types_common.h"
|
||||
#include "Cafe/OS/libs/nn_common.h" // for nnResult
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* +0x0000 */ uint64 title_id; // parsed via GetHex64
|
||||
|
@ -192,4 +195,24 @@ typedef struct
|
|||
namespace iosu
|
||||
{
|
||||
void iosuAcp_init();
|
||||
|
||||
namespace acp
|
||||
{
|
||||
enum ACPDeviceType
|
||||
{
|
||||
UnknownType = 0,
|
||||
InternalDeviceType = 1,
|
||||
USBDeviceType = 3,
|
||||
};
|
||||
|
||||
class IOSUModule* GetModule();
|
||||
|
||||
void CreateSaveMetaFiles(uint32 persistentId, uint64 titleId);
|
||||
nnResult ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType);
|
||||
|
||||
nnResult ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type);
|
||||
sint32 ACPCreateSaveDirEx(uint8 accountSlot, uint64 titleId);
|
||||
nnResult ACPGetOlvAccesskey(uint32be* accessKey);
|
||||
}
|
||||
|
||||
}
|
|
@ -21,14 +21,18 @@
|
|||
|
||||
using namespace iosu::kernel;
|
||||
|
||||
using NexToken = NAPI::ACTNexToken;
|
||||
static_assert(sizeof(NexToken) == 0x25C);
|
||||
|
||||
struct
|
||||
{
|
||||
bool isInitialized;
|
||||
std::mutex actMutex;
|
||||
}iosuAct = { };
|
||||
|
||||
// account manager
|
||||
|
||||
typedef struct
|
||||
struct actAccountData_t
|
||||
{
|
||||
bool isValid;
|
||||
// options
|
||||
|
@ -49,7 +53,12 @@ typedef struct
|
|||
// Mii
|
||||
FFLData_t miiData;
|
||||
uint16le miiNickname[ACT_NICKNAME_LENGTH];
|
||||
}actAccountData_t;
|
||||
|
||||
bool IsNetworkAccount() const
|
||||
{
|
||||
return isNetworkAccount; // todo - IOSU only checks if accountId is not empty?
|
||||
}
|
||||
};
|
||||
|
||||
#define IOSU_ACT_ACCOUNT_MAX_COUNT (0xC)
|
||||
|
||||
|
@ -159,149 +168,11 @@ uint32 iosuAct_getAccountIdOfCurrentAccount()
|
|||
|
||||
// IOSU act API interface
|
||||
|
||||
namespace iosu
|
||||
{
|
||||
namespace act
|
||||
{
|
||||
uint8 getCurrentAccountSlot()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool getPrincipalId(uint8 slot, uint32* principalId)
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if (_actAccountData[accountIndex].isValid == false)
|
||||
{
|
||||
*principalId = 0;
|
||||
return false;
|
||||
}
|
||||
*principalId = _actAccountData[accountIndex].principalId;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getAccountId(uint8 slot, char* accountId)
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if (_actAccountData[accountIndex].isValid == false)
|
||||
{
|
||||
*accountId = '\0';
|
||||
return false;
|
||||
}
|
||||
strcpy(accountId, _actAccountData[accountIndex].accountId);
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns empty string if invalid
|
||||
std::string getAccountId2(uint8 slot)
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if (_actAccountData[accountIndex].isValid == false)
|
||||
return {};
|
||||
return {_actAccountData[accountIndex].accountId};
|
||||
}
|
||||
|
||||
bool getMii(uint8 slot, FFLData_t* fflData)
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if (_actAccountData[accountIndex].isValid == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
memcpy(fflData, &_actAccountData[accountIndex].miiData, sizeof(FFLData_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
// return screenname in little-endian wide characters
|
||||
bool getScreenname(uint8 slot, uint16 screenname[ACT_NICKNAME_LENGTH])
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if (_actAccountData[accountIndex].isValid == false)
|
||||
{
|
||||
screenname[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
for (sint32 i = 0; i < ACT_NICKNAME_LENGTH; i++)
|
||||
{
|
||||
screenname[i] = (uint16)_actAccountData[accountIndex].miiNickname[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getCountryIndex(uint8 slot, uint32* countryIndex)
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if (_actAccountData[accountIndex].isValid == false)
|
||||
{
|
||||
*countryIndex = 0;
|
||||
return false;
|
||||
}
|
||||
*countryIndex = _actAccountData[accountIndex].countryIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
class ActService : public iosu::nn::IPCService
|
||||
{
|
||||
public:
|
||||
ActService() : iosu::nn::IPCService("/dev/act") {}
|
||||
|
||||
nnResult ServiceCall(uint32 serviceId, void* request, void* response) override
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Unsupported service call to /dev/act");
|
||||
cemu_assert_unimplemented();
|
||||
return BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACT, 0);
|
||||
}
|
||||
};
|
||||
|
||||
ActService gActService;
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
gActService.Start();
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
gActService.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// IOSU act IO
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* +0x00 */ uint32be ukn00;
|
||||
/* +0x04 */ uint32be ukn04;
|
||||
/* +0x08 */ uint32be ukn08;
|
||||
/* +0x0C */ uint32be subcommandCode;
|
||||
/* +0x10 */ uint8 ukn10;
|
||||
/* +0x11 */ uint8 ukn11;
|
||||
/* +0x12 */ uint8 ukn12;
|
||||
/* +0x13 */ uint8 accountSlot;
|
||||
/* +0x14 */ uint32be unique; // is this command specific?
|
||||
}cmdActRequest00_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32be returnCode;
|
||||
uint8 transferableIdBase[8];
|
||||
}cmdActGetTransferableIDResult_t;
|
||||
|
||||
#define ACT_SUBCMD_GET_TRANSFERABLE_ID 4
|
||||
#define ACT_SUBCMD_INITIALIZE 0x14
|
||||
|
||||
#define _cancelIfAccountDoesNotExist() \
|
||||
if (_actAccountData[accountIndex].isValid == false) \
|
||||
{ \
|
||||
/* account does not exist*/ \
|
||||
ioctlReturnValue = 0; \
|
||||
actCemuRequest->setACTReturnCode(BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_ACT, NN_ACT_RESULT_ACCOUNT_DOES_NOT_EXIST)); /* 0xA071F480 */ \
|
||||
actCemuRequest->resultU64.u64 = 0; \
|
||||
iosuIoctl_completeRequest(ioQueueEntry, ioctlReturnValue); \
|
||||
continue; \
|
||||
}
|
||||
static const auto ACTResult_Ok = 0;
|
||||
static const auto ACTResult_InvalidValue = BUILD_NN_RESULT(NN_RESULT_LEVEL_LVL6, NN_RESULT_MODULE_NN_ACT, 0x12F00); // 0xC0712F00
|
||||
static const auto ACTResult_OutOfRange = BUILD_NN_RESULT(NN_RESULT_LEVEL_LVL6, NN_RESULT_MODULE_NN_ACT, 0x12D80); // 0xC0712D80
|
||||
static const auto ACTResult_AccountDoesNotExist = BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_ACT, NN_ACT_RESULT_ACCOUNT_DOES_NOT_EXIST); // 0xA071F480
|
||||
static const auto ACTResult_NotANetworkAccount = BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_ACT, 0x1FE80); // 0xA071FE80
|
||||
|
||||
nnResult ServerActErrorCodeToNNResult(NAPI::ACT_ERROR_CODE ec)
|
||||
{
|
||||
|
@ -506,6 +377,291 @@ nnResult ServerActErrorCodeToNNResult(NAPI::ACT_ERROR_CODE ec)
|
|||
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, NN_ERROR_CODE::ACT_UNKNOWN_SERVER_ERROR);
|
||||
}
|
||||
|
||||
namespace iosu
|
||||
{
|
||||
namespace act
|
||||
{
|
||||
uint8 getCurrentAccountSlot()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
actAccountData_t* GetAccountBySlotNo(uint8 slotNo)
|
||||
{
|
||||
// only call this while holding actMutex
|
||||
uint8 accIndex;
|
||||
if(slotNo == iosu::act::ACT_SLOT_CURRENT)
|
||||
{
|
||||
accIndex = getCurrentAccountSlot() - 1;
|
||||
cemu_assert_debug(accIndex >= 0 && accIndex < IOSU_ACT_ACCOUNT_MAX_COUNT);
|
||||
}
|
||||
else if(slotNo > 0 && slotNo <= IOSU_ACT_ACCOUNT_MAX_COUNT)
|
||||
accIndex = slotNo - 1;
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if(!_actAccountData[accIndex].isValid)
|
||||
return nullptr;
|
||||
return &_actAccountData[accIndex];
|
||||
}
|
||||
|
||||
// has ownership of account data
|
||||
// while any thread has a LockedAccount in non-null state no other thread can access the account data
|
||||
class LockedAccount
|
||||
{
|
||||
public:
|
||||
LockedAccount(uint8 slotNo)
|
||||
{
|
||||
iosuAct.actMutex.lock();
|
||||
m_account = GetAccountBySlotNo(slotNo);
|
||||
if(!m_account)
|
||||
iosuAct.actMutex.unlock();
|
||||
}
|
||||
|
||||
~LockedAccount()
|
||||
{
|
||||
if(m_account)
|
||||
iosuAct.actMutex.unlock();
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
if(m_account)
|
||||
iosuAct.actMutex.unlock();
|
||||
m_account = nullptr;
|
||||
}
|
||||
|
||||
actAccountData_t* operator->()
|
||||
{
|
||||
return m_account;
|
||||
}
|
||||
|
||||
actAccountData_t& operator*()
|
||||
{
|
||||
return *m_account;
|
||||
}
|
||||
|
||||
LockedAccount(const LockedAccount&) = delete;
|
||||
LockedAccount& operator=(const LockedAccount&) = delete;
|
||||
|
||||
operator bool() const { return m_account != nullptr; }
|
||||
|
||||
private:
|
||||
actAccountData_t* m_account{nullptr};
|
||||
};
|
||||
|
||||
bool getPrincipalId(uint8 slot, uint32* principalId)
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if (_actAccountData[accountIndex].isValid == false)
|
||||
{
|
||||
*principalId = 0;
|
||||
return false;
|
||||
}
|
||||
*principalId = _actAccountData[accountIndex].principalId;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getAccountId(uint8 slot, char* accountId)
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if (_actAccountData[accountIndex].isValid == false)
|
||||
{
|
||||
*accountId = '\0';
|
||||
return false;
|
||||
}
|
||||
strcpy(accountId, _actAccountData[accountIndex].accountId);
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns empty string if invalid
|
||||
std::string getAccountId2(uint8 slot)
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if (_actAccountData[accountIndex].isValid == false)
|
||||
return {};
|
||||
return {_actAccountData[accountIndex].accountId};
|
||||
}
|
||||
|
||||
bool getMii(uint8 slot, FFLData_t* fflData)
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if (_actAccountData[accountIndex].isValid == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
memcpy(fflData, &_actAccountData[accountIndex].miiData, sizeof(FFLData_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
// return screenname in little-endian wide characters
|
||||
bool getScreenname(uint8 slot, uint16 screenname[ACT_NICKNAME_LENGTH])
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if (_actAccountData[accountIndex].isValid == false)
|
||||
{
|
||||
screenname[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
for (sint32 i = 0; i < ACT_NICKNAME_LENGTH; i++)
|
||||
{
|
||||
screenname[i] = (uint16)_actAccountData[accountIndex].miiNickname[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getCountryIndex(uint8 slot, uint32* countryIndex)
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if (_actAccountData[accountIndex].isValid == false)
|
||||
{
|
||||
*countryIndex = 0;
|
||||
return false;
|
||||
}
|
||||
*countryIndex = _actAccountData[accountIndex].countryIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetPersistentId(uint8 slot, uint32* persistentId)
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if(!_actAccountData[accountIndex].isValid)
|
||||
{
|
||||
*persistentId = 0;
|
||||
return false;
|
||||
}
|
||||
*persistentId = _actAccountData[accountIndex].persistentId;
|
||||
return true;
|
||||
}
|
||||
|
||||
nnResult AcquireNexToken(uint8 accountSlot, uint64 titleId, uint16 titleVersion, uint32 serverId, uint8* tokenOut, uint32 tokenLen)
|
||||
{
|
||||
if (accountSlot != ACT_SLOT_CURRENT)
|
||||
return ACTResult_InvalidValue;
|
||||
LockedAccount account(accountSlot);
|
||||
if (!account)
|
||||
return ACTResult_AccountDoesNotExist;
|
||||
if (!account->IsNetworkAccount())
|
||||
return ACTResult_NotANetworkAccount;
|
||||
cemu_assert_debug(ActiveSettings::IsOnlineEnabled());
|
||||
if (tokenLen != sizeof(NexToken))
|
||||
return ACTResult_OutOfRange;
|
||||
|
||||
NAPI::AuthInfo authInfo;
|
||||
NAPI::NAPI_MakeAuthInfoFromCurrentAccount(authInfo);
|
||||
NAPI::ACTGetNexTokenResult nexTokenResult = NAPI::ACT_GetNexToken_WithCache(authInfo, titleId, titleVersion, serverId);
|
||||
if (nexTokenResult.isValid())
|
||||
{
|
||||
memcpy(tokenOut, &nexTokenResult.nexToken, sizeof(NexToken));
|
||||
return ACTResult_Ok;
|
||||
}
|
||||
else if (nexTokenResult.apiError == NAPI_RESULT::SERVICE_ERROR)
|
||||
{
|
||||
nnResult returnCode = ServerActErrorCodeToNNResult(nexTokenResult.serviceError);
|
||||
cemu_assert_debug((returnCode&0x80000000) != 0);
|
||||
return returnCode;
|
||||
}
|
||||
return nnResultStatus(NN_RESULT_MODULE_NN_ACT, NN_ERROR_CODE::ACT_UNKNOWN_SERVER_ERROR);
|
||||
}
|
||||
|
||||
nnResult AcquireIndependentServiceToken(uint8 accountSlot, uint64 titleId, uint16 titleVersion, std::string_view clientId, uint8* tokenOut, uint32 tokenLen)
|
||||
{
|
||||
static constexpr size_t IndependentTokenMaxLength = 512+1; // 512 bytes + null terminator
|
||||
if(accountSlot != ACT_SLOT_CURRENT)
|
||||
return ACTResult_InvalidValue;
|
||||
LockedAccount account(accountSlot);
|
||||
if (!account)
|
||||
return ACTResult_AccountDoesNotExist;
|
||||
if (!account->IsNetworkAccount())
|
||||
return ACTResult_NotANetworkAccount;
|
||||
cemu_assert_debug(ActiveSettings::IsOnlineEnabled());
|
||||
if (tokenLen < IndependentTokenMaxLength)
|
||||
return ACTResult_OutOfRange;
|
||||
NAPI::AuthInfo authInfo;
|
||||
NAPI::NAPI_MakeAuthInfoFromCurrentAccount(authInfo);
|
||||
account.Release();
|
||||
NAPI::ACTGetIndependentTokenResult tokenResult = NAPI::ACT_GetIndependentToken_WithCache(authInfo, titleId, titleVersion, clientId);
|
||||
uint32 returnCode = 0;
|
||||
if (tokenResult.isValid())
|
||||
{
|
||||
for (size_t i = 0; i < std::min(tokenResult.token.size(), (size_t)IndependentTokenMaxLength); i++)
|
||||
{
|
||||
tokenOut[i] = tokenResult.token[i];
|
||||
tokenOut[i + 1] = '\0';
|
||||
}
|
||||
returnCode = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
returnCode = 0x80000000; // todo - proper error codes
|
||||
}
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
class ActService : public iosu::nn::IPCService
|
||||
{
|
||||
public:
|
||||
ActService() : iosu::nn::IPCService("/dev/act") {}
|
||||
|
||||
nnResult ServiceCall(uint32 serviceId, void* request, void* response) override
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Unsupported service call to /dev/act");
|
||||
cemu_assert_unimplemented();
|
||||
return BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACT, 0);
|
||||
}
|
||||
};
|
||||
|
||||
ActService gActService;
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
gActService.Start();
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
gActService.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// IOSU act IO
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* +0x00 */ uint32be ukn00;
|
||||
/* +0x04 */ uint32be ukn04;
|
||||
/* +0x08 */ uint32be ukn08;
|
||||
/* +0x0C */ uint32be subcommandCode;
|
||||
/* +0x10 */ uint8 ukn10;
|
||||
/* +0x11 */ uint8 ukn11;
|
||||
/* +0x12 */ uint8 ukn12;
|
||||
/* +0x13 */ uint8 accountSlot;
|
||||
/* +0x14 */ uint32be unique; // is this command specific?
|
||||
}cmdActRequest00_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32be returnCode;
|
||||
uint8 transferableIdBase[8];
|
||||
}cmdActGetTransferableIDResult_t;
|
||||
|
||||
#define ACT_SUBCMD_GET_TRANSFERABLE_ID 4
|
||||
#define ACT_SUBCMD_INITIALIZE 0x14
|
||||
|
||||
#define _cancelIfAccountDoesNotExist() \
|
||||
if (_actAccountData[accountIndex].isValid == false) \
|
||||
{ \
|
||||
/* account does not exist*/ \
|
||||
ioctlReturnValue = 0; \
|
||||
actCemuRequest->setACTReturnCode(BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_ACT, NN_ACT_RESULT_ACCOUNT_DOES_NOT_EXIST)); /* 0xA071F480 */ \
|
||||
actCemuRequest->resultU64.u64 = 0; \
|
||||
iosuIoctl_completeRequest(ioQueueEntry, ioctlReturnValue); \
|
||||
continue; \
|
||||
}
|
||||
|
||||
int iosuAct_thread()
|
||||
{
|
||||
SetThreadName("iosuAct_thread");
|
||||
|
@ -662,47 +818,13 @@ int iosuAct_thread()
|
|||
}
|
||||
else if (actCemuRequest->requestCode == IOSU_ARC_ACQUIRENEXTOKEN)
|
||||
{
|
||||
NAPI::AuthInfo authInfo;
|
||||
NAPI::NAPI_MakeAuthInfoFromCurrentAccount(authInfo);
|
||||
NAPI::ACTGetNexTokenResult nexTokenResult = NAPI::ACT_GetNexToken_WithCache(authInfo, actCemuRequest->titleId, actCemuRequest->titleVersion, actCemuRequest->serverId);
|
||||
uint32 returnCode = 0;
|
||||
if (nexTokenResult.isValid())
|
||||
{
|
||||
*(NAPI::ACTNexToken*)actCemuRequest->resultBinary.binBuffer = nexTokenResult.nexToken;
|
||||
returnCode = NN_RESULT_SUCCESS;
|
||||
}
|
||||
else if (nexTokenResult.apiError == NAPI_RESULT::SERVICE_ERROR)
|
||||
{
|
||||
returnCode = ServerActErrorCodeToNNResult(nexTokenResult.serviceError);
|
||||
cemu_assert_debug((returnCode&0x80000000) != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnCode = nnResultStatus(NN_RESULT_MODULE_NN_ACT, NN_ERROR_CODE::ACT_UNKNOWN_SERVER_ERROR);
|
||||
}
|
||||
actCemuRequest->setACTReturnCode(returnCode);
|
||||
nnResult r = iosu::act::AcquireNexToken(actCemuRequest->accountSlot, actCemuRequest->titleId, actCemuRequest->titleVersion, actCemuRequest->serverId, actCemuRequest->resultBinary.binBuffer, sizeof(NexToken));
|
||||
actCemuRequest->setACTReturnCode(r);
|
||||
}
|
||||
else if (actCemuRequest->requestCode == IOSU_ARC_ACQUIREINDEPENDENTTOKEN)
|
||||
{
|
||||
NAPI::AuthInfo authInfo;
|
||||
NAPI::NAPI_MakeAuthInfoFromCurrentAccount(authInfo);
|
||||
NAPI::ACTGetIndependentTokenResult tokenResult = NAPI::ACT_GetIndependentToken_WithCache(authInfo, actCemuRequest->titleId, actCemuRequest->titleVersion, actCemuRequest->clientId);
|
||||
|
||||
uint32 returnCode = 0;
|
||||
if (tokenResult.isValid())
|
||||
{
|
||||
for (size_t i = 0; i < std::min(tokenResult.token.size(), (size_t)200); i++)
|
||||
{
|
||||
actCemuRequest->resultBinary.binBuffer[i] = tokenResult.token[i];
|
||||
actCemuRequest->resultBinary.binBuffer[i + 1] = '\0';
|
||||
}
|
||||
returnCode = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
returnCode = 0x80000000; // todo - proper error codes
|
||||
}
|
||||
actCemuRequest->setACTReturnCode(returnCode);
|
||||
nnResult r = iosu::act::AcquireIndependentServiceToken(actCemuRequest->accountSlot, actCemuRequest->titleId, actCemuRequest->titleVersion, actCemuRequest->clientId, actCemuRequest->resultBinary.binBuffer, sizeof(actCemuRequest->resultBinary.binBuffer));
|
||||
actCemuRequest->setACTReturnCode(r);
|
||||
}
|
||||
else if (actCemuRequest->requestCode == IOSU_ARC_ACQUIREPIDBYNNID)
|
||||
{
|
||||
|
|
|
@ -49,10 +49,11 @@ namespace iosu
|
|||
bool getMii(uint8 slot, FFLData_t* fflData);
|
||||
bool getScreenname(uint8 slot, uint16 screenname[ACT_NICKNAME_LENGTH]);
|
||||
bool getCountryIndex(uint8 slot, uint32* countryIndex);
|
||||
bool GetPersistentId(uint8 slot, uint32* persistentId);
|
||||
|
||||
std::string getAccountId2(uint8 slot);
|
||||
|
||||
const uint8 ACT_SLOT_CURRENT = 0xFE;
|
||||
static constexpr uint8 ACT_SLOT_CURRENT = 0xFE;
|
||||
|
||||
void Initialize();
|
||||
void Stop();
|
||||
|
|
|
@ -498,7 +498,7 @@ namespace iosu
|
|||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, task_header_callback);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &(*it));
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 0x3C);
|
||||
if (GetNetworkConfig().disablesslver.GetValue() && ActiveSettings::GetNetworkService() == NetworkService::Custom || ActiveSettings::GetNetworkService() == NetworkService::Pretendo) // remove Pretendo Function once SSL is in the Service
|
||||
if (IsNetworkServiceSSLDisabled(ActiveSettings::GetNetworkService()))
|
||||
{
|
||||
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,0L);
|
||||
}
|
||||
|
|
|
@ -292,16 +292,6 @@ void iosuCrypto_generateDeviceCertificate()
|
|||
BN_CTX_free(context);
|
||||
}
|
||||
|
||||
bool iosuCrypto_hasAllDataForLogin()
|
||||
{
|
||||
if (hasOtpMem == false)
|
||||
return false;
|
||||
if (hasSeepromMem == false)
|
||||
return false;
|
||||
// todo - check if certificates are available
|
||||
return true;
|
||||
}
|
||||
|
||||
sint32 iosuCrypto_getDeviceCertificateBase64Encoded(char* output)
|
||||
{
|
||||
iosuCrypto_base64Encode((uint8*)&g_wiiuDeviceCert, sizeof(g_wiiuDeviceCert), output);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
void iosuCrypto_init();
|
||||
|
||||
bool iosuCrypto_hasAllDataForLogin();
|
||||
bool iosuCrypto_getDeviceId(uint32* deviceId);
|
||||
void iosuCrypto_getDeviceSerialString(char* serialString);
|
||||
|
||||
|
|
|
@ -214,6 +214,12 @@ namespace iosu
|
|||
friendData->friendExtraData.gameKey.ukn08 = frd->presence.gameKey.ukn;
|
||||
NexPresenceToGameMode(&frd->presence, &friendData->friendExtraData.gameMode);
|
||||
|
||||
auto fixed_presence_msg = '\0' + frd->presence.msg; // avoid first character of comment from being cut off
|
||||
friendData->friendExtraData.gameModeDescription.assignFromUTF8(fixed_presence_msg);
|
||||
|
||||
auto fixed_comment = '\0' + frd->comment.commentString; // avoid first character of comment from being cut off
|
||||
friendData->friendExtraData.comment.assignFromUTF8(fixed_comment);
|
||||
|
||||
// set valid dates
|
||||
friendData->uknDate.year = 2018;
|
||||
friendData->uknDate.day = 1;
|
||||
|
@ -750,9 +756,18 @@ namespace iosu
|
|||
{
|
||||
if(numVecIn != 0 || numVecOut != 1)
|
||||
return FPResult_InvalidIPCParam;
|
||||
SelfPlayingGame selfPlayingGame{0};
|
||||
cemuLog_log(LogType::Force, "GetMyPlayingGame is todo");
|
||||
return WriteValueOutput<SelfPlayingGame>(vecOut, selfPlayingGame);
|
||||
GameKey selfPlayingGame
|
||||
{
|
||||
CafeSystem::GetForegroundTitleId(),
|
||||
CafeSystem::GetForegroundTitleVersion(),
|
||||
{0,0,0,0,0,0}
|
||||
};
|
||||
if (GetTitleIdHigh(CafeSystem::GetForegroundTitleId()) != 0x00050000)
|
||||
{
|
||||
selfPlayingGame.titleId = 0;
|
||||
selfPlayingGame.ukn08 = 0;
|
||||
}
|
||||
return WriteValueOutput<GameKey>(vecOut, selfPlayingGame);
|
||||
}
|
||||
|
||||
nnResult CallHandler_GetFriendAccountId(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)
|
||||
|
@ -1410,8 +1425,16 @@ namespace iosu
|
|||
act::getCountryIndex(currentSlot, &countryCode);
|
||||
// init presence
|
||||
g_fpd.myPresence.isOnline = 1;
|
||||
g_fpd.myPresence.gameKey.titleId = CafeSystem::GetForegroundTitleId();
|
||||
g_fpd.myPresence.gameKey.ukn = CafeSystem::GetForegroundTitleVersion();
|
||||
if (GetTitleIdHigh(CafeSystem::GetForegroundTitleId()) == 0x00050000)
|
||||
{
|
||||
g_fpd.myPresence.gameKey.titleId = CafeSystem::GetForegroundTitleId();
|
||||
g_fpd.myPresence.gameKey.ukn = CafeSystem::GetForegroundTitleVersion();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_fpd.myPresence.gameKey.titleId = 0; // icon will not be ??? or invalid to others
|
||||
g_fpd.myPresence.gameKey.ukn = 0;
|
||||
}
|
||||
// resolve potential domain to IP address
|
||||
struct addrinfo hints = {0}, *addrs;
|
||||
hints.ai_family = AF_INET;
|
||||
|
|
|
@ -94,7 +94,7 @@ namespace iosu
|
|||
/* +0x1EC */ uint8 isOnline;
|
||||
/* +0x1ED */ uint8 _padding1ED[3];
|
||||
// some other sub struct?
|
||||
/* +0x1F0 */ char comment[36]; // pops up every few seconds in friend list
|
||||
/* +0x1F0 */ CafeWideString<0x12> comment; // pops up every few seconds in friend list
|
||||
/* +0x214 */ uint32be _padding214;
|
||||
/* +0x218 */ FPDDate approvalTime;
|
||||
/* +0x220 */ FPDDate lastOnline;
|
||||
|
@ -263,4 +263,4 @@ namespace iosu
|
|||
|
||||
IOSUModule* GetModule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -228,7 +228,7 @@ namespace iosu
|
|||
}
|
||||
}
|
||||
|
||||
auto result = NAPI::IDBE_Request(titleId);
|
||||
auto result = NAPI::IDBE_Request(ActiveSettings::GetNetworkService(), titleId);
|
||||
if (!result)
|
||||
{
|
||||
memset(idbeIconOutput, 0, sizeof(NAPI::IDBEIconDataV0));
|
||||
|
|
|
@ -155,7 +155,9 @@ namespace iosu
|
|||
|
||||
void IPCService::ServiceThread()
|
||||
{
|
||||
SetThreadName("IPCService");
|
||||
std::string serviceName = m_devicePath.substr(m_devicePath.find_last_of('/') == std::string::npos ? 0 : m_devicePath.find_last_of('/') + 1);
|
||||
serviceName.insert(0, "NNsvc_");
|
||||
SetThreadName(serviceName.c_str());
|
||||
m_msgQueueId = IOS_CreateMessageQueue(_m_msgBuffer.GetPtr(), _m_msgBuffer.GetCount());
|
||||
cemu_assert(!IOS_ResultIsError((IOS_ERROR)m_msgQueueId));
|
||||
IOS_ERROR r = IOS_RegisterResourceManager(m_devicePath.c_str(), m_msgQueueId);
|
||||
|
@ -208,6 +210,7 @@ namespace iosu
|
|||
IOS_ResourceReply(cmd, IOS_ERROR_INVALID);
|
||||
}
|
||||
}
|
||||
IOS_DestroyMessageQueue(m_msgQueueId);
|
||||
m_threadInitialized = false;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace iosu
|
|||
{
|
||||
namespace nn
|
||||
{
|
||||
// a simple service interface which wraps handle management and Ioctlv/IoctlvAsync
|
||||
// a simple service interface which wraps handle management and Ioctlv/IoctlvAsync (used by /dev/fpd and others are still to be determined)
|
||||
class IPCSimpleService
|
||||
{
|
||||
public:
|
||||
|
@ -88,7 +88,7 @@ namespace iosu
|
|||
uint32be nnResultCode;
|
||||
};
|
||||
|
||||
// a complex service interface which wraps Ioctlv and adds an additional service channel, used by /dev/act, ?
|
||||
// a complex service interface which wraps Ioctlv and adds an additional service channel, used by /dev/act, /dev/acp_main, ?
|
||||
class IPCService
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -50,6 +50,10 @@ typedef struct
|
|||
|
||||
static_assert(sizeof(elfSectionEntry_t) == 0x28, "");
|
||||
|
||||
#define PF_X (1 << 0) /* Segment is executable */
|
||||
#define PF_W (1 << 1) /* Segment is writable */
|
||||
#define PF_R (1 << 2) /* Segment is readable */
|
||||
|
||||
// Map elf into memory
|
||||
uint32 ELF_LoadFromMemory(uint8* elfData, sint32 size, const char* name)
|
||||
{
|
||||
|
@ -68,6 +72,7 @@ uint32 ELF_LoadFromMemory(uint8* elfData, sint32 size, const char* name)
|
|||
uint32 shSize = (uint32)sectionTable[i].shSize;
|
||||
uint32 shOffset = (uint32)sectionTable[i].shOffset;
|
||||
uint32 shType = (uint32)sectionTable[i].shType;
|
||||
uint32 shFlags = (uint32)sectionTable[i].shFlags;
|
||||
|
||||
if (shOffset > (uint32)size)
|
||||
{
|
||||
|
@ -89,6 +94,8 @@ uint32 ELF_LoadFromMemory(uint8* elfData, sint32 size, const char* name)
|
|||
}
|
||||
// SHT_NOBITS
|
||||
}
|
||||
if((shFlags & PF_X) > 0)
|
||||
PPCRecompiler_allocateRange(shAddr, shSize);
|
||||
}
|
||||
return header->entrypoint;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "Cafe/OS/libs/nn_spm/nn_spm.h"
|
||||
#include "Cafe/OS/libs/nn_ec/nn_ec.h"
|
||||
#include "Cafe/OS/libs/nn_boss/nn_boss.h"
|
||||
#include "Cafe/OS/libs/nn_sl/nn_sl.h"
|
||||
#include "Cafe/OS/libs/nn_fp/nn_fp.h"
|
||||
#include "Cafe/OS/libs/nn_olv/nn_olv.h"
|
||||
#include "Cafe/OS/libs/nn_idbe/nn_idbe.h"
|
||||
|
@ -208,6 +209,7 @@ void osLib_load()
|
|||
nn::ndm::load();
|
||||
nn::spm::load();
|
||||
nn::save::load();
|
||||
nnSL_load();
|
||||
nsysnet_load();
|
||||
nn::fp::load();
|
||||
nn::olv::load();
|
||||
|
@ -219,5 +221,5 @@ void osLib_load()
|
|||
nsyskbd::nsyskbd_load();
|
||||
swkbd::load();
|
||||
camera::load();
|
||||
procui_load();
|
||||
proc_ui::load();
|
||||
}
|
||||
|
|
|
@ -35,12 +35,12 @@
|
|||
#include "Cafe/OS/libs/coreinit/coreinit_MEM_BlockHeap.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.h"
|
||||
|
||||
CoreinitSharedData* gCoreinitData = NULL;
|
||||
CoreinitSharedData* gCoreinitData = nullptr;
|
||||
|
||||
sint32 ScoreStackTrace(OSThread_t* thread, MPTR sp)
|
||||
{
|
||||
uint32 stackMinAddr = _swapEndianU32(thread->stackEnd);
|
||||
uint32 stackMaxAddr = _swapEndianU32(thread->stackBase);
|
||||
uint32 stackMinAddr = thread->stackEnd.GetMPTR();
|
||||
uint32 stackMaxAddr = thread->stackBase.GetMPTR();
|
||||
|
||||
sint32 score = 0;
|
||||
uint32 currentStackPtr = sp;
|
||||
|
@ -95,8 +95,8 @@ void DebugLogStackTrace(OSThread_t* thread, MPTR sp)
|
|||
|
||||
// print stack trace
|
||||
uint32 currentStackPtr = highestScoreSP;
|
||||
uint32 stackMinAddr = _swapEndianU32(thread->stackEnd);
|
||||
uint32 stackMaxAddr = _swapEndianU32(thread->stackBase);
|
||||
uint32 stackMinAddr = thread->stackEnd.GetMPTR();
|
||||
uint32 stackMaxAddr = thread->stackBase.GetMPTR();
|
||||
for (sint32 i = 0; i < 20; i++)
|
||||
{
|
||||
uint32 nextStackPtr = memory_readU32(currentStackPtr);
|
||||
|
@ -179,27 +179,6 @@ void coreinitExport_OSGetSharedData(PPCInterpreter_t* hCPU)
|
|||
osLib_returnFromFunction(hCPU, 1);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MPTR getDriverName;
|
||||
MPTR ukn04;
|
||||
MPTR onAcquiredForeground;
|
||||
MPTR onReleaseForeground;
|
||||
MPTR ukn10;
|
||||
}OSDriverCallbacks_t;
|
||||
|
||||
void coreinitExport_OSDriver_Register(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
#ifdef CEMU_DEBUG_ASSERT
|
||||
cemuLog_log(LogType::Force, "OSDriver_Register(0x{:08x},0x{:08x},0x{:08x},0x{:08x},0x{:08x},0x{:08x})", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7], hCPU->gpr[8]);
|
||||
#endif
|
||||
OSDriverCallbacks_t* driverCallbacks = (OSDriverCallbacks_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[5]);
|
||||
|
||||
// todo
|
||||
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
namespace coreinit
|
||||
{
|
||||
sint32 OSGetCoreId()
|
||||
|
@ -379,7 +358,6 @@ void coreinit_load()
|
|||
coreinit::miscInit();
|
||||
osLib_addFunction("coreinit", "OSGetSharedData", coreinitExport_OSGetSharedData);
|
||||
osLib_addFunction("coreinit", "UCReadSysConfig", coreinitExport_UCReadSysConfig);
|
||||
osLib_addFunction("coreinit", "OSDriver_Register", coreinitExport_OSDriver_Register);
|
||||
|
||||
// async callbacks
|
||||
InitializeAsyncCallback();
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
namespace coreinit
|
||||
{
|
||||
enum class RplEntryReason
|
||||
{
|
||||
Loaded = 1,
|
||||
Unloaded = 2,
|
||||
};
|
||||
|
||||
uint32 OSDynLoad_SetAllocator(MPTR allocFunc, MPTR freeFunc);
|
||||
void OSDynLoad_SetTLSAllocator(MPTR allocFunc, MPTR freeFunc);
|
||||
uint32 OSDynLoad_GetAllocator(betype<MPTR>* funcAlloc, betype<MPTR>* funcFree);
|
||||
|
|
|
@ -55,19 +55,18 @@ namespace coreinit
|
|||
{
|
||||
// return full size of foreground bucket area
|
||||
if (offset)
|
||||
*offset = MEMPTR<void>{ (uint32)MEMORY_FGBUCKET_AREA_ADDR };
|
||||
*offset = { (MPTR)MEMORY_FGBUCKET_AREA_ADDR };
|
||||
if (size)
|
||||
*size = MEMORY_FGBUCKET_AREA_SIZE;
|
||||
// return true if in foreground
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OSGetForegroundBucketFreeArea(MPTR* offset, MPTR* size)
|
||||
bool OSGetForegroundBucketFreeArea(MEMPTR<void>* offset, uint32be* size)
|
||||
{
|
||||
uint8* freeAreaAddr = GetFGMemByArea(FG_BUCKET_AREA_FREE).GetPtr();
|
||||
|
||||
*offset = _swapEndianU32(memory_getVirtualOffsetFromPointer(freeAreaAddr));
|
||||
*size = _swapEndianU32(FG_BUCKET_AREA_FREE_SIZE);
|
||||
*offset = freeAreaAddr;
|
||||
*size = FG_BUCKET_AREA_FREE_SIZE;
|
||||
// return true if in foreground
|
||||
return (fgAddr != nullptr);
|
||||
}
|
||||
|
@ -82,15 +81,6 @@ namespace coreinit
|
|||
osLib_returnFromFunction(hCPU, r ? 1 : 0);
|
||||
}
|
||||
|
||||
void coreinitExport_OSGetForegroundBucketFreeArea(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
debug_printf("OSGetForegroundBucketFreeArea(0x%x,0x%x)\n", hCPU->gpr[3], hCPU->gpr[4]);
|
||||
ppcDefineParamMPTR(areaOutput, 0);
|
||||
ppcDefineParamMPTR(areaSize, 1);
|
||||
bool r = OSGetForegroundBucketFreeArea((MPTR*)memory_getPointerFromVirtualOffsetAllowNull(areaOutput), (MPTR*)memory_getPointerFromVirtualOffsetAllowNull(areaSize));
|
||||
osLib_returnFromFunction(hCPU, r ? 1 : 0);
|
||||
}
|
||||
|
||||
void InitForegroundBucket()
|
||||
{
|
||||
uint32be fgSize;
|
||||
|
@ -194,7 +184,8 @@ namespace coreinit
|
|||
void InitializeFG()
|
||||
{
|
||||
osLib_addFunction("coreinit", "OSGetForegroundBucket", coreinitExport_OSGetForegroundBucket);
|
||||
osLib_addFunction("coreinit", "OSGetForegroundBucketFreeArea", coreinitExport_OSGetForegroundBucketFreeArea);
|
||||
cafeExportRegister("coreinit", OSGetForegroundBucket, LogType::CoreinitMem);
|
||||
cafeExportRegister("coreinit", OSGetForegroundBucketFreeArea, LogType::CoreinitMem);
|
||||
osLib_addFunction("coreinit", "OSCopyFromClipboard", coreinitExport_OSCopyFromClipboard);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace coreinit
|
|||
bool __OSResizeCopyData(sint32 length);
|
||||
|
||||
bool OSGetForegroundBucket(MEMPTR<void>* offset, uint32be* size);
|
||||
bool OSGetForegroundBucketFreeArea(MPTR* offset, MPTR* size);
|
||||
bool OSGetForegroundBucketFreeArea(MEMPTR<void>* offset, uint32be* size);
|
||||
|
||||
void InitForegroundBucket();
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "coreinit_IPC.h"
|
||||
#include "Cafe/Filesystem/fsc.h"
|
||||
#include "coreinit_IPCBuf.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
#include "Cafe/TitleList/TitleInfo.h"
|
||||
|
||||
#define FS_CB_PLACEHOLDER_FINISHCMD (MPTR)(0xF122330E)
|
||||
|
||||
|
@ -54,7 +56,7 @@ namespace coreinit
|
|||
OSUnlockMutex(&s_fsGlobalMutex);
|
||||
}
|
||||
|
||||
void _debugVerifyCommand(const char* stage, FSCmdBlockBody_t* fsCmdBlockBody);
|
||||
void _debugVerifyCommand(const char* stage, FSCmdBlockBody* fsCmdBlockBody);
|
||||
|
||||
bool sFSInitialized = true; // this should be false but it seems like some games rely on FSInit being called before main()? Twilight Princess for example reads files before it calls FSInit
|
||||
bool sFSShutdown = false;
|
||||
|
@ -94,6 +96,14 @@ namespace coreinit
|
|||
// so we can just hard code it. Other mount types are not (yet) supported.
|
||||
if (mountSourceType == MOUNT_TYPE::SD)
|
||||
{
|
||||
// check for SD card permissions (from cos.xml)
|
||||
// One Piece relies on failing here, otherwise it will call FSGetMountSource in an infinite loop
|
||||
CosCapabilityBitsFS perms = static_cast<CosCapabilityBitsFS>(CafeSystem::GetForegroundTitleCosCapabilities(CosCapabilityGroup::FS));
|
||||
if(!HAS_FLAG(perms, CosCapabilityBitsFS::SDCARD_MOUNT))
|
||||
{
|
||||
cemuLog_logOnce(LogType::Force, "Title is trying to access SD card mount info without having SD card permissions. This may not be a bug");
|
||||
return FS_RESULT::END_ITERATION;
|
||||
}
|
||||
mountSourceInfo->sourceType = 0;
|
||||
strcpy(mountSourceInfo->path, "/sd");
|
||||
return FS_RESULT::SUCCESS;
|
||||
|
@ -184,12 +194,12 @@ namespace coreinit
|
|||
}
|
||||
|
||||
// return the aligned FSClientBody struct inside a FSClient struct
|
||||
FSCmdBlockBody_t* __FSGetCmdBlockBody(FSCmdBlock_t* fsCmdBlock)
|
||||
FSCmdBlockBody* __FSGetCmdBlockBody(FSCmdBlock_t* fsCmdBlock)
|
||||
{
|
||||
// align pointer to 64 bytes
|
||||
if (fsCmdBlock == nullptr)
|
||||
return nullptr;
|
||||
FSCmdBlockBody_t* fsCmdBlockBody = (FSCmdBlockBody_t*)(((uintptr_t)fsCmdBlock + 0x3F) & ~0x3F);
|
||||
FSCmdBlockBody* fsCmdBlockBody = (FSCmdBlockBody*)(((uintptr_t)fsCmdBlock + 0x3F) & ~0x3F);
|
||||
fsCmdBlockBody->selfCmdBlock = fsCmdBlock;
|
||||
return fsCmdBlockBody;
|
||||
}
|
||||
|
@ -251,8 +261,8 @@ namespace coreinit
|
|||
fsCmdQueueBE->numCommandsInFlight = 0;
|
||||
fsCmdQueueBE->numMaxCommandsInFlight = numMaxCommandsInFlight;
|
||||
coreinit::OSFastMutex_Init(&fsCmdQueueBE->fastMutex, nullptr);
|
||||
fsCmdQueueBE->firstMPTR = _swapEndianU32(0);
|
||||
fsCmdQueueBE->lastMPTR = _swapEndianU32(0);
|
||||
fsCmdQueueBE->first = nullptr;
|
||||
fsCmdQueueBE->last = nullptr;
|
||||
}
|
||||
|
||||
void FSInit()
|
||||
|
@ -372,74 +382,71 @@ namespace coreinit
|
|||
|
||||
Semaphore g_semaphoreQueuedCmds;
|
||||
|
||||
void __FSQueueCmdByPriority(FSCmdQueue* fsCmdQueueBE, FSCmdBlockBody_t* fsCmdBlockBody, bool stopAtEqualPriority)
|
||||
void __FSQueueCmdByPriority(FSCmdQueue* fsCmdQueueBE, FSCmdBlockBody* fsCmdBlockBody, bool stopAtEqualPriority)
|
||||
{
|
||||
MPTR fsCmdBlockBodyMPTR = memory_getVirtualOffsetFromPointer(fsCmdBlockBody);
|
||||
if (_swapEndianU32(fsCmdQueueBE->firstMPTR) == MPTR_NULL)
|
||||
if (!fsCmdQueueBE->first)
|
||||
{
|
||||
// queue is currently empty
|
||||
cemu_assert(fsCmdQueueBE->lastMPTR == MPTR_NULL);
|
||||
fsCmdQueueBE->firstMPTR = _swapEndianU32(fsCmdBlockBodyMPTR);
|
||||
fsCmdQueueBE->lastMPTR = _swapEndianU32(fsCmdBlockBodyMPTR);
|
||||
fsCmdBlockBody->nextMPTR = _swapEndianU32(MPTR_NULL);
|
||||
fsCmdBlockBody->previousMPTR = _swapEndianU32(MPTR_NULL);
|
||||
cemu_assert(!fsCmdQueueBE->last);
|
||||
fsCmdQueueBE->first = fsCmdBlockBody;
|
||||
fsCmdQueueBE->last = fsCmdBlockBody;
|
||||
fsCmdBlockBody->next = nullptr;
|
||||
fsCmdBlockBody->previous = nullptr;
|
||||
return;
|
||||
}
|
||||
// iterate from last to first element as long as iterated priority is lower
|
||||
FSCmdBlockBody_t* fsCmdBlockBodyItrPrev = NULL;
|
||||
FSCmdBlockBody_t* fsCmdBlockBodyItr = (FSCmdBlockBody_t*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(fsCmdQueueBE->lastMPTR));
|
||||
FSCmdBlockBody* fsCmdBlockBodyItrPrev = nullptr;
|
||||
FSCmdBlockBody* fsCmdBlockBodyItr = fsCmdQueueBE->last;
|
||||
while (true)
|
||||
{
|
||||
if (fsCmdBlockBodyItr == NULL)
|
||||
if (!fsCmdBlockBodyItr)
|
||||
{
|
||||
// insert at the head of the list
|
||||
fsCmdQueueBE->firstMPTR = _swapEndianU32(fsCmdBlockBodyMPTR);
|
||||
fsCmdBlockBody->nextMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBodyItrPrev));
|
||||
fsCmdBlockBody->previousMPTR = _swapEndianU32(MPTR_NULL);
|
||||
fsCmdBlockBodyItrPrev->previousMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody));
|
||||
fsCmdQueueBE->first = fsCmdBlockBody;
|
||||
fsCmdBlockBody->next = fsCmdBlockBodyItrPrev;
|
||||
fsCmdBlockBody->previous = nullptr;
|
||||
fsCmdBlockBodyItrPrev->previous = fsCmdBlockBody;
|
||||
return;
|
||||
}
|
||||
// compare priority
|
||||
if ((stopAtEqualPriority && fsCmdBlockBodyItr->priority >= fsCmdBlockBody->priority) || (stopAtEqualPriority == false && fsCmdBlockBodyItr->priority > fsCmdBlockBody->priority))
|
||||
{
|
||||
// insert cmd here
|
||||
if (fsCmdBlockBodyItrPrev != NULL)
|
||||
if (fsCmdBlockBodyItrPrev)
|
||||
{
|
||||
fsCmdBlockBody->nextMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBodyItrPrev));
|
||||
fsCmdBlockBody->next = fsCmdBlockBodyItrPrev;
|
||||
}
|
||||
else
|
||||
{
|
||||
fsCmdBlockBody->nextMPTR = _swapEndianU32(MPTR_NULL);
|
||||
fsCmdQueueBE->lastMPTR = _swapEndianU32(fsCmdBlockBodyMPTR);
|
||||
fsCmdBlockBody->next = nullptr;
|
||||
fsCmdQueueBE->last = fsCmdBlockBody;
|
||||
}
|
||||
fsCmdBlockBody->previousMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBodyItr));
|
||||
fsCmdBlockBody->previous = fsCmdBlockBodyItr;
|
||||
if (fsCmdBlockBodyItrPrev)
|
||||
fsCmdBlockBodyItrPrev->previousMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody));
|
||||
fsCmdBlockBodyItr->nextMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody));
|
||||
fsCmdBlockBodyItrPrev->previous = fsCmdBlockBody;
|
||||
fsCmdBlockBodyItr->next = fsCmdBlockBody;
|
||||
return;
|
||||
}
|
||||
// next
|
||||
fsCmdBlockBodyItrPrev = fsCmdBlockBodyItr;
|
||||
fsCmdBlockBodyItr = (FSCmdBlockBody_t*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(fsCmdBlockBodyItr->previousMPTR));
|
||||
fsCmdBlockBodyItr = fsCmdBlockBodyItr->previous;
|
||||
}
|
||||
}
|
||||
|
||||
FSCmdBlockBody_t* __FSTakeCommandFromQueue(FSCmdQueue* cmdQueue)
|
||||
FSCmdBlockBody* __FSTakeCommandFromQueue(FSCmdQueue* cmdQueue)
|
||||
{
|
||||
FSCmdBlockBody_t* dequeuedCmd = nullptr;
|
||||
if (_swapEndianU32(cmdQueue->firstMPTR) != MPTR_NULL)
|
||||
if (!cmdQueue->first)
|
||||
return nullptr;
|
||||
// dequeue cmd
|
||||
FSCmdBlockBody* dequeuedCmd = cmdQueue->first;
|
||||
if (cmdQueue->first == cmdQueue->last)
|
||||
cmdQueue->last = nullptr;
|
||||
cmdQueue->first = dequeuedCmd->next;
|
||||
dequeuedCmd->next = nullptr;
|
||||
if (dequeuedCmd->next)
|
||||
{
|
||||
dequeuedCmd = (FSCmdBlockBody_t*)memory_getPointerFromVirtualOffset(_swapEndianU32(cmdQueue->firstMPTR));
|
||||
// dequeue cmd
|
||||
if (cmdQueue->firstMPTR == cmdQueue->lastMPTR)
|
||||
cmdQueue->lastMPTR = _swapEndianU32(MPTR_NULL);
|
||||
cmdQueue->firstMPTR = dequeuedCmd->nextMPTR;
|
||||
dequeuedCmd->nextMPTR = _swapEndianU32(MPTR_NULL);
|
||||
if (_swapEndianU32(dequeuedCmd->nextMPTR) != MPTR_NULL)
|
||||
{
|
||||
FSCmdBlockBody_t* fsCmdBodyNext = (FSCmdBlockBody_t*)memory_getPointerFromVirtualOffset(_swapEndianU32(dequeuedCmd->nextMPTR));
|
||||
fsCmdBodyNext->previousMPTR = _swapEndianU32(MPTR_NULL);
|
||||
}
|
||||
FSCmdBlockBody* fsCmdBodyNext = dequeuedCmd->next;
|
||||
fsCmdBodyNext->previous = nullptr;
|
||||
}
|
||||
return dequeuedCmd;
|
||||
}
|
||||
|
@ -489,7 +496,7 @@ namespace coreinit
|
|||
FSLockMutex();
|
||||
if (cmdQueue->numCommandsInFlight < cmdQueue->numMaxCommandsInFlight)
|
||||
{
|
||||
FSCmdBlockBody_t* dequeuedCommand = __FSTakeCommandFromQueue(cmdQueue);
|
||||
FSCmdBlockBody* dequeuedCommand = __FSTakeCommandFromQueue(cmdQueue);
|
||||
if (dequeuedCommand)
|
||||
{
|
||||
cmdQueue->numCommandsInFlight += 1;
|
||||
|
@ -502,7 +509,7 @@ namespace coreinit
|
|||
FSUnlockMutex();
|
||||
}
|
||||
|
||||
void __FSQueueDefaultFinishFunc(FSCmdBlockBody_t* fsCmdBlockBody, FS_RESULT result)
|
||||
void __FSQueueDefaultFinishFunc(FSCmdBlockBody* fsCmdBlockBody, FS_RESULT result)
|
||||
{
|
||||
switch ((FSA_CMD_OPERATION_TYPE)fsCmdBlockBody->fsaShimBuffer.operationType.value())
|
||||
{
|
||||
|
@ -584,13 +591,13 @@ namespace coreinit
|
|||
|
||||
void export___FSQueueDefaultFinishFunc(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamPtr(cmd, FSCmdBlockBody_t, 0);
|
||||
ppcDefineParamPtr(cmd, FSCmdBlockBody, 0);
|
||||
FS_RESULT result = (FS_RESULT)PPCInterpreter_getCallParamU32(hCPU, 1);
|
||||
__FSQueueDefaultFinishFunc(cmd, static_cast<FS_RESULT>(result));
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
void __FSQueueCmd(FSCmdQueue* cmdQueue, FSCmdBlockBody_t* fsCmdBlockBody, MPTR finishCmdFunc)
|
||||
void __FSQueueCmd(FSCmdQueue* cmdQueue, FSCmdBlockBody* fsCmdBlockBody, MPTR finishCmdFunc)
|
||||
{
|
||||
fsCmdBlockBody->cmdFinishFuncMPTR = finishCmdFunc;
|
||||
FSLockMutex();
|
||||
|
@ -666,7 +673,7 @@ namespace coreinit
|
|||
return FS_RESULT::FATAL_ERROR;
|
||||
}
|
||||
|
||||
void __FSCmdSubmitResult(FSCmdBlockBody_t* fsCmdBlockBody, FS_RESULT result)
|
||||
void __FSCmdSubmitResult(FSCmdBlockBody* fsCmdBlockBody, FS_RESULT result)
|
||||
{
|
||||
_debugVerifyCommand("FSCmdSubmitResult", fsCmdBlockBody);
|
||||
|
||||
|
@ -710,7 +717,7 @@ namespace coreinit
|
|||
void __FSAIoctlResponseCallback(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamU32(iosResult, 0);
|
||||
ppcDefineParamPtr(cmd, FSCmdBlockBody_t, 1);
|
||||
ppcDefineParamPtr(cmd, FSCmdBlockBody, 1);
|
||||
|
||||
FSA_RESULT fsaStatus = _FSIosErrorToFSAStatus((IOS_ERROR)iosResult);
|
||||
|
||||
|
@ -744,25 +751,25 @@ namespace coreinit
|
|||
void FSInitCmdBlock(FSCmdBlock_t* fsCmdBlock)
|
||||
{
|
||||
memset(fsCmdBlock, 0x00, sizeof(FSCmdBlock_t));
|
||||
FSCmdBlockBody_t* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);
|
||||
FSCmdBlockBody* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);
|
||||
fsCmdBlockBody->statusCode = _swapEndianU32(FSA_CMD_STATUS_CODE_D900A21);
|
||||
fsCmdBlockBody->priority = 0x10;
|
||||
}
|
||||
|
||||
void __FSAsyncToSyncInit(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSAsyncParamsNew_t* asyncParams)
|
||||
void __FSAsyncToSyncInit(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSAsyncParams* asyncParams)
|
||||
{
|
||||
if (fsClient == nullptr || fsCmdBlock == nullptr || asyncParams == nullptr)
|
||||
assert_dbg();
|
||||
FSCmdBlockBody_t* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);
|
||||
FSCmdBlockBody* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);
|
||||
coreinit::OSInitMessageQueue(&fsCmdBlockBody->syncTaskMsgQueue, fsCmdBlockBody->_syncTaskMsg, 1);
|
||||
asyncParams->userCallback = nullptr;
|
||||
asyncParams->userContext = nullptr;
|
||||
asyncParams->ioMsgQueue = &fsCmdBlockBody->syncTaskMsgQueue;
|
||||
}
|
||||
|
||||
void __FSPrepareCmdAsyncResult(FSClientBody_t* fsClientBody, FSCmdBlockBody_t* fsCmdBlockBody, FSAsyncResult* fsCmdBlockAsyncResult, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
void __FSPrepareCmdAsyncResult(FSClientBody_t* fsClientBody, FSCmdBlockBody* fsCmdBlockBody, FSAsyncResult* fsCmdBlockAsyncResult, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
memcpy(&fsCmdBlockAsyncResult->fsAsyncParamsNew, fsAsyncParams, sizeof(FSAsyncParamsNew_t));
|
||||
memcpy(&fsCmdBlockAsyncResult->fsAsyncParamsNew, fsAsyncParams, sizeof(FSAsyncParams));
|
||||
|
||||
fsCmdBlockAsyncResult->fsClient = fsClientBody->selfClient;
|
||||
fsCmdBlockAsyncResult->fsCmdBlock = fsCmdBlockBody->selfCmdBlock;
|
||||
|
@ -771,7 +778,7 @@ namespace coreinit
|
|||
fsCmdBlockAsyncResult->msgUnion.fsMsg.commandType = _swapEndianU32(8);
|
||||
}
|
||||
|
||||
sint32 __FSPrepareCmd(FSClientBody_t* fsClientBody, FSCmdBlockBody_t* fsCmdBlockBody, uint32 errHandling, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 __FSPrepareCmd(FSClientBody_t* fsClientBody, FSCmdBlockBody* fsCmdBlockBody, uint32 errHandling, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
if (sFSInitialized == false || sFSShutdown == true)
|
||||
return -0x400;
|
||||
|
@ -803,18 +810,18 @@ namespace coreinit
|
|||
|
||||
#define _FSCmdIntro() \
|
||||
FSClientBody_t* fsClientBody = __FSGetClientBody(fsClient); \
|
||||
FSCmdBlockBody_t* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock); \
|
||||
FSCmdBlockBody* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock); \
|
||||
sint32 fsError = __FSPrepareCmd(fsClientBody, fsCmdBlockBody, errorMask, fsAsyncParams); \
|
||||
if (fsError != 0) \
|
||||
return fsError;
|
||||
|
||||
void _debugVerifyCommand(const char* stage, FSCmdBlockBody_t* fsCmdBlockBody)
|
||||
void _debugVerifyCommand(const char* stage, FSCmdBlockBody* fsCmdBlockBody)
|
||||
{
|
||||
if (fsCmdBlockBody->asyncResult.msgUnion.fsMsg.commandType != _swapEndianU32(8))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Corrupted FS command detected in stage {}", stage);
|
||||
cemuLog_log(LogType::Force, "Printing CMD block: ");
|
||||
for (uint32 i = 0; i < (sizeof(FSCmdBlockBody_t) + 31) / 32; i++)
|
||||
for (uint32 i = 0; i < (sizeof(FSCmdBlockBody) + 31) / 32; i++)
|
||||
{
|
||||
uint8* p = ((uint8*)fsCmdBlockBody) + i * 32;
|
||||
cemuLog_log(LogType::Force, "{:04x}: {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} | {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x}",
|
||||
|
@ -827,7 +834,7 @@ namespace coreinit
|
|||
|
||||
FSAsyncResult* FSGetAsyncResult(OSMessage* msg)
|
||||
{
|
||||
return (FSAsyncResult*)memory_getPointerFromVirtualOffset(_swapEndianU32(msg->message));
|
||||
return (FSAsyncResult*)memory_getPointerFromVirtualOffset(msg->message);
|
||||
}
|
||||
|
||||
sint32 __FSProcessAsyncResult(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, sint32 fsStatus, uint32 errHandling)
|
||||
|
@ -835,7 +842,7 @@ namespace coreinit
|
|||
// a positive result (or zero) means success. Most operations return zero in case of success. Read and write operations return the number of transferred units
|
||||
if (fsStatus >= 0)
|
||||
{
|
||||
FSCmdBlockBody_t* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);
|
||||
FSCmdBlockBody* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);
|
||||
OSMessage msg;
|
||||
OSReceiveMessage(&fsCmdBlockBody->syncTaskMsgQueue, &msg, OS_MESSAGE_BLOCK);
|
||||
_debugVerifyCommand("handleAsyncResult", fsCmdBlockBody);
|
||||
|
@ -896,12 +903,12 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSOpenFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandleDepr_t* outFileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSOpenFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandlePtr outFileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
if (outFileHandle == nullptr || path == nullptr || mode == nullptr)
|
||||
return -0x400;
|
||||
fsCmdBlockBody->returnValues.cmdOpenFile.handlePtr = &outFileHandle->fileHandle;
|
||||
fsCmdBlockBody->returnValues.cmdOpenFile.handlePtr = outFileHandle;
|
||||
fsError = (FSStatus)__FSPrepareCmd_OpenFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, path, mode, 0x660, 0, 0);
|
||||
if (fsError != (FSStatus)FS_RESULT::SUCCESS)
|
||||
return fsError;
|
||||
|
@ -909,15 +916,15 @@ namespace coreinit
|
|||
return (FSStatus)FS_RESULT::SUCCESS;
|
||||
}
|
||||
|
||||
sint32 FSOpenFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandleDepr_t* fileHandle, uint32 errHandling)
|
||||
sint32 FSOpenFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandlePtr outFileHandle, uint32 errHandling)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSOpenFileAsync(fsClient, fsCmdBlock, path, mode, fileHandle, errHandling, &asyncParams);
|
||||
sint32 fsAsyncRet = FSOpenFileAsync(fsClient, fsCmdBlock, path, mode, outFileHandle, errHandling, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);
|
||||
}
|
||||
|
||||
sint32 FSOpenFileExAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, uint32 createMode, uint32 openFlag, uint32 preallocSize, FSFileHandleDepr_t* outFileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSOpenFileExAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, uint32 createMode, uint32 openFlag, uint32 preallocSize, FSFileHandlePtr outFileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
if (openFlag != 0)
|
||||
{
|
||||
|
@ -928,7 +935,7 @@ namespace coreinit
|
|||
_FSCmdIntro();
|
||||
if (outFileHandle == nullptr || path == nullptr || mode == nullptr)
|
||||
return -0x400;
|
||||
fsCmdBlockBody->returnValues.cmdOpenFile.handlePtr = &outFileHandle->fileHandle;
|
||||
fsCmdBlockBody->returnValues.cmdOpenFile.handlePtr = outFileHandle;
|
||||
|
||||
FSA_RESULT prepareResult = __FSPrepareCmd_OpenFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, path, mode, createMode, openFlag, preallocSize);
|
||||
if (prepareResult != FSA_RESULT::OK)
|
||||
|
@ -938,11 +945,11 @@ namespace coreinit
|
|||
return (FSStatus)FS_RESULT::SUCCESS;
|
||||
}
|
||||
|
||||
sint32 FSOpenFileEx(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, uint32 createMode, uint32 openFlag, uint32 preallocSize, FSFileHandleDepr_t* fileHandle, uint32 errHandling)
|
||||
sint32 FSOpenFileEx(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, uint32 createMode, uint32 openFlag, uint32 preallocSize, FSFileHandlePtr outFileHandle, uint32 errHandling)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSOpenFileExAsync(fsClient, fsCmdBlock, path, mode, createMode, openFlag, preallocSize, fileHandle, errHandling, &asyncParams);
|
||||
sint32 fsAsyncRet = FSOpenFileExAsync(fsClient, fsCmdBlock, path, mode, createMode, openFlag, preallocSize, outFileHandle, errHandling, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);
|
||||
}
|
||||
|
||||
|
@ -960,7 +967,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSCloseFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSCloseFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
|
||||
|
@ -974,7 +981,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSCloseFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errHandling)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSCloseFileAsync(fsClient, fsCmdBlock, fileHandle, errHandling, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);
|
||||
|
@ -994,7 +1001,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSFlushFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSFlushFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
|
||||
|
@ -1008,7 +1015,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSFlushFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errHandling)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSFlushFileAsync(fsClient, fsCmdBlock, fileHandle, errHandling, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);
|
||||
|
@ -1050,7 +1057,7 @@ namespace coreinit
|
|||
|
||||
SysAllocator<uint8, 128, 64> _tempFSSpace;
|
||||
|
||||
sint32 __FSReadFileAsyncEx(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dest, uint32 size, uint32 count, bool usePos, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 __FSReadFileAsyncEx(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dest, uint32 size, uint32 count, bool usePos, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
if (size == 0 || count == 0 || dest == NULL)
|
||||
|
@ -1081,7 +1088,7 @@ namespace coreinit
|
|||
return (FSStatus)FS_RESULT::SUCCESS;
|
||||
}
|
||||
|
||||
sint32 FSReadFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSReadFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
cemu_assert_debug(flag == 0); // todo
|
||||
return __FSReadFileAsyncEx(fsClient, fsCmdBlock, dst, size, count, false, 0, fileHandle, flag, errorMask, fsAsyncParams);
|
||||
|
@ -1089,13 +1096,13 @@ namespace coreinit
|
|||
|
||||
sint32 FSReadFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSReadFileAsync(fsClient, fsCmdBlock, dst, size, count, fileHandle, flag, errorMask, asyncParams.GetPointer());
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
}
|
||||
|
||||
sint32 FSReadFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSReadFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
cemu_assert_debug(flag == 0); // todo
|
||||
sint32 fsStatus = __FSReadFileAsyncEx(fsClient, fsCmdBlock, dst, size, count, true, filePos, fileHandle, flag, errorMask, fsAsyncParams);
|
||||
|
@ -1104,7 +1111,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSReadFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSReadFileWithPosAsync(fsClient, fsCmdBlock, dst, size, count, filePos, fileHandle, flag, errorMask, asyncParams.GetPointer());
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1144,7 +1151,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 __FSWriteFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dest, uint32 size, uint32 count, bool useFilePos, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 __FSWriteFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dest, uint32 size, uint32 count, bool useFilePos, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
if (size == 0 || count == 0 || dest == nullptr)
|
||||
|
@ -1175,27 +1182,27 @@ namespace coreinit
|
|||
return (FSStatus)FS_RESULT::SUCCESS;
|
||||
}
|
||||
|
||||
sint32 FSWriteFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSWriteFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
return __FSWriteFileWithPosAsync(fsClient, fsCmdBlock, src, size, count, false, 0, fileHandle, flag, errorMask, fsAsyncParams);
|
||||
}
|
||||
|
||||
sint32 FSWriteFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSWriteFileAsync(fsClient, fsCmdBlock, src, size, count, fileHandle, flag, errorMask, asyncParams.GetPointer());
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
}
|
||||
|
||||
sint32 FSWriteFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSWriteFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
return __FSWriteFileWithPosAsync(fsClient, fsCmdBlock, src, size, count, true, filePos, fileHandle, flag, errorMask, fsAsyncParams);
|
||||
}
|
||||
|
||||
sint32 FSWriteFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSWriteFileWithPosAsync(fsClient, fsCmdBlock, src, size, count, filePos, fileHandle, flag, errorMask, asyncParams.GetPointer());
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1214,7 +1221,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSSetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 filePos, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSSetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 filePos, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
FSA_RESULT prepareResult = __FSPrepareCmd_SetPosFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle, filePos);
|
||||
|
@ -1227,7 +1234,7 @@ namespace coreinit
|
|||
sint32 FSSetPosFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 filePos, uint32 errorMask)
|
||||
{
|
||||
// used by games: Mario Kart 8
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSSetPosFileAsync(fsClient, fsCmdBlock, fileHandle, filePos, errorMask, asyncParams.GetPointer());
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1244,7 +1251,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSGetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSGetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
// games using this: Darksiders Warmastered Edition
|
||||
_FSCmdIntro();
|
||||
|
@ -1258,7 +1265,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSGetPosFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSGetPosFileAsync(fsClient, fsCmdBlock, fileHandle, returnedFilePos, errorMask, asyncParams.GetPointer());
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1292,7 +1299,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSOpenDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSOpenDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
cemu_assert(dirHandleOut && path);
|
||||
|
@ -1306,7 +1313,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSOpenDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSOpenDirAsync(fsClient, fsCmdBlock, path, dirHandleOut, errorMask, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1323,7 +1330,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSReadDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSReadDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
FSA_RESULT prepareResult = __FSPrepareCmd_ReadDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dirHandle);
|
||||
|
@ -1334,9 +1341,9 @@ namespace coreinit
|
|||
return (FSStatus)FS_RESULT::SUCCESS;
|
||||
}
|
||||
|
||||
sint32 FSReadDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSReadDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSReadDirAsync(fsClient, fsCmdBlock, dirHandle, dirEntryOut, errorMask, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1353,7 +1360,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSCloseDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSCloseDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
FSA_RESULT prepareResult = __FSPrepareCmd_CloseDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dirHandle);
|
||||
|
@ -1366,7 +1373,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSCloseDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSCloseDirAsync(fsClient, fsCmdBlock, dirHandle, errorMask, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1386,7 +1393,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSRewindDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSRewindDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
FSA_RESULT prepareResult = __FSPrepareCmd_RewindDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dirHandle);
|
||||
|
@ -1399,7 +1406,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSRewindDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSRewindDirAsync(fsClient, fsCmdBlock, dirHandle, errorMask, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1421,7 +1428,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSAppendFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 size, uint32 count, uint32 fileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSAppendFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 size, uint32 count, uint32 fileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
FSA_RESULT prepareResult = __FSPrepareCmd_AppendFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, size, count, fileHandle, 0);
|
||||
|
@ -1434,7 +1441,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSAppendFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 size, uint32 count, uint32 fileHandle, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t> asyncParams;
|
||||
StackAllocator<FSAsyncParams> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSAppendFileAsync(fsClient, fsCmdBlock, size, count, fileHandle, errorMask, asyncParams.GetPointer());
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1453,7 +1460,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSTruncateFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSTruncateFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
FSA_RESULT prepareResult = __FSPrepareCmd_TruncateFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle);
|
||||
|
@ -1466,7 +1473,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSTruncateFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t> asyncParams;
|
||||
StackAllocator<FSAsyncParams> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSTruncateFileAsync(fsClient, fsCmdBlock, fileHandle, errorMask, asyncParams.GetPointer());
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1511,7 +1518,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSRenameAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSRenameAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
// used by titles: XCX (via SAVERenameAsync)
|
||||
_FSCmdIntro();
|
||||
|
@ -1530,7 +1537,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSRename(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t> asyncParams;
|
||||
StackAllocator<FSAsyncParams> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSRenameAsync(fsClient, fsCmdBlock, srcPath, dstPath, errorMask, asyncParams.GetPointer());
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1562,7 +1569,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSRemoveAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSRemoveAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
// used by titles: XCX (via SAVERemoveAsync)
|
||||
_FSCmdIntro();
|
||||
|
@ -1581,7 +1588,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSRemove(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t> asyncParams;
|
||||
StackAllocator<FSAsyncParams> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSRemoveAsync(fsClient, fsCmdBlock, filePath, errorMask, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1614,7 +1621,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSMakeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* dirPath, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSMakeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* dirPath, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
// used by titles: XCX (via SAVEMakeDirAsync)
|
||||
_FSCmdIntro();
|
||||
|
@ -1633,7 +1640,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSMakeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t> asyncParams;
|
||||
StackAllocator<FSAsyncParams> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSMakeDirAsync(fsClient, fsCmdBlock, path, errorMask, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1664,7 +1671,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSChangeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSChangeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
if (path == NULL)
|
||||
|
@ -1682,7 +1689,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSChangeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t> asyncParams;
|
||||
StackAllocator<FSAsyncParams> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSChangeDirAsync(fsClient, fsCmdBlock, path, errorMask, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1700,7 +1707,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSGetCwdAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSGetCwdAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
// used by titles: Super Mario Maker
|
||||
_FSCmdIntro();
|
||||
|
@ -1717,7 +1724,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSGetCwd(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t> asyncParams;
|
||||
StackAllocator<FSAsyncParams> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSGetCwdAsync(fsClient, fsCmdBlock, dirPathOut, dirPathMaxLen, errorMask, &asyncParams);
|
||||
auto r = __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1748,7 +1755,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSFlushQuotaAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSFlushQuotaAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
|
||||
|
@ -1762,7 +1769,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSFlushQuota(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t> asyncParams;
|
||||
StackAllocator<FSAsyncParams> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSFlushQuotaAsync(fsClient, fsCmdBlock, path, errorMask, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1798,7 +1805,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 __FSQueryInfoAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* queryString, uint32 queryType, void* queryResult, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 __FSQueryInfoAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* queryString, uint32 queryType, void* queryResult, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
cemu_assert(queryString && queryResult); // query string and result must not be null
|
||||
|
@ -1812,7 +1819,7 @@ namespace coreinit
|
|||
return (FSStatus)FS_RESULT::SUCCESS;
|
||||
}
|
||||
|
||||
sint32 FSGetStatAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSStat_t* statOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSGetStatAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSStat_t* statOut, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
sint32 fsStatus = __FSQueryInfoAsync(fsClient, fsCmdBlock, (uint8*)path, FSA_QUERY_TYPE_STAT, statOut, errorMask, fsAsyncParams);
|
||||
return fsStatus;
|
||||
|
@ -1820,7 +1827,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSGetStat(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSStat_t* statOut, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSGetStatAsync(fsClient, fsCmdBlock, path, statOut, errorMask, &asyncParams);
|
||||
sint32 ret = __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1841,7 +1848,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSGetStatFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, FSStat_t* statOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSGetStatFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, FSStat_t* statOut, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
_FSCmdIntro();
|
||||
cemu_assert(statOut); // statOut must not be null
|
||||
|
@ -1857,13 +1864,13 @@ namespace coreinit
|
|||
|
||||
sint32 FSGetStatFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, FSStat_t* statOut, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSGetStatFileAsync(fsClient, fsCmdBlock, fileHandle, statOut, errorMask, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
}
|
||||
|
||||
sint32 FSGetFreeSpaceSizeAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSGetFreeSpaceSizeAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
// used by: Wii U system settings app, Art Academy, Unity (e.g. Snoopy's Grand Adventure), Super Smash Bros
|
||||
sint32 fsStatus = __FSQueryInfoAsync(fsClient, fsCmdBlock, (uint8*)path, FSA_QUERY_TYPE_FREESPACE, returnedFreeSize, errorMask, fsAsyncParams);
|
||||
|
@ -1872,7 +1879,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSGetFreeSpaceSize(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSGetFreeSpaceSizeAsync(fsClient, fsCmdBlock, path, returnedFreeSize, errorMask, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1892,7 +1899,7 @@ namespace coreinit
|
|||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
sint32 FSIsEofAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
|
||||
sint32 FSIsEofAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)
|
||||
{
|
||||
// used by Paper Monsters Recut
|
||||
_FSCmdIntro();
|
||||
|
@ -1907,7 +1914,7 @@ namespace coreinit
|
|||
|
||||
sint32 FSIsEof(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask)
|
||||
{
|
||||
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
|
||||
StackAllocator<FSAsyncParams, 1> asyncParams;
|
||||
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
|
||||
sint32 fsAsyncRet = FSIsEofAsync(fsClient, fsCmdBlock, fileHandle, errorMask, &asyncParams);
|
||||
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
|
||||
|
@ -1915,14 +1922,14 @@ namespace coreinit
|
|||
|
||||
void FSSetUserData(FSCmdBlock_t* fsCmdBlock, void* userData)
|
||||
{
|
||||
FSCmdBlockBody_t* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);
|
||||
FSCmdBlockBody* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);
|
||||
if (fsCmdBlockBody)
|
||||
fsCmdBlockBody->userData = userData;
|
||||
}
|
||||
|
||||
void* FSGetUserData(FSCmdBlock_t* fsCmdBlock)
|
||||
{
|
||||
FSCmdBlockBody_t* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);
|
||||
FSCmdBlockBody* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);
|
||||
void* userData = nullptr;
|
||||
if (fsCmdBlockBody)
|
||||
userData = fsCmdBlockBody->userData.GetPtr();
|
||||
|
@ -1946,7 +1953,7 @@ namespace coreinit
|
|||
FSClientBody_t* fsClientBody = __FSGetClientBody(fsClient);
|
||||
if (!fsClientBody)
|
||||
return nullptr;
|
||||
FSCmdBlockBody_t* cmdBlockBody = fsClientBody->currentCmdBlockBody;
|
||||
FSCmdBlockBody* cmdBlockBody = fsClientBody->currentCmdBlockBody;
|
||||
if (!cmdBlockBody)
|
||||
return nullptr;
|
||||
return cmdBlockBody->selfCmdBlock;
|
||||
|
|
|
@ -5,33 +5,23 @@
|
|||
#include "Cafe/IOSU/fsa/iosu_fsa.h"
|
||||
#include "coreinit_MessageQueue.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32be fileHandle;
|
||||
} FSFileHandleDepr_t;
|
||||
|
||||
typedef MEMPTR<betype<FSFileHandle2>> FSFileHandlePtr;
|
||||
typedef MEMPTR<betype<FSDirHandle2>> FSDirHandlePtr;
|
||||
|
||||
typedef uint32 FSAClientHandle;
|
||||
|
||||
typedef struct
|
||||
struct FSAsyncParams
|
||||
{
|
||||
MEMPTR<void> userCallback;
|
||||
MEMPTR<void> userContext;
|
||||
MEMPTR<coreinit::OSMessageQueue> ioMsgQueue;
|
||||
} FSAsyncParamsNew_t;
|
||||
|
||||
static_assert(sizeof(FSAsyncParamsNew_t) == 0xC);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MPTR userCallback; // 0x96C
|
||||
MPTR userContext;
|
||||
MPTR ioMsgQueue;
|
||||
} FSAsyncParams_t; // legacy struct. Replace with FSAsyncParamsNew_t
|
||||
};
|
||||
static_assert(sizeof(FSAsyncParams) == 0xC);
|
||||
|
||||
namespace coreinit
|
||||
{
|
||||
struct FSCmdBlockBody;
|
||||
|
||||
struct FSCmdQueue
|
||||
{
|
||||
enum class QUEUE_FLAG : uint32
|
||||
|
@ -40,8 +30,8 @@ namespace coreinit
|
|||
CANCEL_ALL = (1 << 4),
|
||||
};
|
||||
|
||||
/* +0x00 */ MPTR firstMPTR;
|
||||
/* +0x04 */ MPTR lastMPTR;
|
||||
/* +0x00 */ MEMPTR<FSCmdBlockBody> first;
|
||||
/* +0x04 */ MEMPTR<FSCmdBlockBody> last;
|
||||
/* +0x08 */ OSFastMutex fastMutex;
|
||||
/* +0x34 */ MPTR dequeueHandlerFuncMPTR;
|
||||
/* +0x38 */ uint32be numCommandsInFlight;
|
||||
|
@ -108,7 +98,7 @@ namespace coreinit
|
|||
uint8 ukn1460[0x10];
|
||||
uint8 ukn1470[0x10];
|
||||
FSCmdQueue fsCmdQueue;
|
||||
/* +0x14C4 */ MEMPTR<struct FSCmdBlockBody_t> currentCmdBlockBody; // set to currently active cmd
|
||||
/* +0x14C4 */ MEMPTR<struct FSCmdBlockBody> currentCmdBlockBody; // set to currently active cmd
|
||||
uint32 ukn14C8;
|
||||
uint32 ukn14CC;
|
||||
uint8 ukn14D0[0x10];
|
||||
|
@ -128,7 +118,7 @@ namespace coreinit
|
|||
|
||||
struct FSAsyncResult
|
||||
{
|
||||
/* +0x00 */ FSAsyncParamsNew_t fsAsyncParamsNew;
|
||||
/* +0x00 */ FSAsyncParams fsAsyncParamsNew;
|
||||
|
||||
// fs message storage
|
||||
struct FSMessage
|
||||
|
@ -159,7 +149,7 @@ namespace coreinit
|
|||
uint8 ukn0[0x14];
|
||||
struct
|
||||
{
|
||||
MEMPTR<uint32be> handlePtr;
|
||||
MEMPTR<betype<FSResHandle>> handlePtr;
|
||||
} cmdOpenFile;
|
||||
struct
|
||||
{
|
||||
|
@ -205,7 +195,7 @@ namespace coreinit
|
|||
|
||||
static_assert(sizeof(FSCmdBlockReturnValues_t) == 0x14);
|
||||
|
||||
struct FSCmdBlockBody_t
|
||||
struct FSCmdBlockBody
|
||||
{
|
||||
iosu::fsa::FSAShimBuffer fsaShimBuffer;
|
||||
/* +0x0938 */ MEMPTR<FSClientBody_t> fsClientBody;
|
||||
|
@ -213,9 +203,8 @@ namespace coreinit
|
|||
/* +0x0940 */ uint32be cancelState; // bitmask. Bit 0 -> If set command has been canceled
|
||||
FSCmdBlockReturnValues_t returnValues;
|
||||
// link for cmd queue
|
||||
MPTR nextMPTR; // points towards FSCmdQueue->first
|
||||
MPTR previousMPTR; // points towards FSCmdQueue->last
|
||||
|
||||
MEMPTR<FSCmdBlockBody> next;
|
||||
MEMPTR<FSCmdBlockBody> previous;
|
||||
/* +0x960 */ betype<FSA_RESULT> lastFSAStatus;
|
||||
uint32 ukn0964;
|
||||
/* +0x0968 */ uint8 errHandling; // return error flag mask
|
||||
|
@ -235,7 +224,6 @@ namespace coreinit
|
|||
uint32 ukn9FC;
|
||||
};
|
||||
|
||||
static_assert(sizeof(FSAsyncParams_t) == 0xC);
|
||||
static_assert(sizeof(FSCmdBlock_t) == 0xA80);
|
||||
|
||||
#define FSA_CMD_FLAG_SET_POS (1 << 0)
|
||||
|
@ -251,7 +239,7 @@ namespace coreinit
|
|||
};
|
||||
|
||||
// internal interface
|
||||
sint32 __FSQueryInfoAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* queryString, uint32 queryType, void* queryResult, uint32 errHandling, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 __FSQueryInfoAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* queryString, uint32 queryType, void* queryResult, uint32 errHandling, FSAsyncParams* fsAsyncParams);
|
||||
|
||||
// coreinit exports
|
||||
FS_RESULT FSAddClientEx(FSClient_t* fsClient, uint32 uknR4, uint32 errHandling);
|
||||
|
@ -260,52 +248,52 @@ namespace coreinit
|
|||
|
||||
void FSInitCmdBlock(FSCmdBlock_t* fsCmdBlock);
|
||||
|
||||
sint32 FSOpenFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandleDepr_t* fileHandle, uint32 errHandling, FSAsyncParamsNew_t* asyncParams);
|
||||
sint32 FSOpenFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandleDepr_t* fileHandle, uint32 errHandling);
|
||||
sint32 FSOpenFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandlePtr outFileHandle, uint32 errHandling, FSAsyncParams* asyncParams);
|
||||
sint32 FSOpenFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandlePtr outFileHandle, uint32 errHandling);
|
||||
|
||||
sint32 FSReadFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSReadFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSReadFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask);
|
||||
sint32 FSReadFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSReadFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSReadFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask);
|
||||
|
||||
sint32 FSWriteFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSWriteFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSWriteFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask);
|
||||
sint32 FSWriteFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSWriteFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSWriteFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask);
|
||||
|
||||
sint32 FSSetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 filePos, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSSetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 filePos, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSSetPosFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 filePos, uint32 errorMask);
|
||||
sint32 FSGetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSGetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSGetPosFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask);
|
||||
|
||||
sint32 FSAppendFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 size, uint32 count, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSAppendFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 size, uint32 count, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSAppendFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 size, uint32 count, uint32 errorMask);
|
||||
|
||||
sint32 FSIsEofAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSIsEofAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSIsEof(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask);
|
||||
|
||||
sint32 FSRenameAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSRenameAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSRename(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask);
|
||||
sint32 FSRemoveAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSRemoveAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSRemove(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask);
|
||||
sint32 FSMakeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* dirPath, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSMakeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* dirPath, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSMakeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, uint32 errorMask);
|
||||
sint32 FSChangeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSChangeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSChangeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask);
|
||||
sint32 FSGetCwdAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSGetCwdAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSGetCwd(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask);
|
||||
|
||||
sint32 FSGetFreeSpaceSizeAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSGetFreeSpaceSizeAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSGetFreeSpaceSize(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask);
|
||||
|
||||
sint32 FSOpenDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSOpenDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSOpenDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask);
|
||||
sint32 FSReadDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSReadDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSCloseDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSReadDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSReadDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSCloseDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSCloseDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask);
|
||||
|
||||
sint32 FSFlushQuotaAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams);
|
||||
sint32 FSFlushQuotaAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParams* fsAsyncParams);
|
||||
sint32 FSFlushQuota(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask);
|
||||
|
||||
FS_VOLSTATE FSGetVolumeState(FSClient_t* fsClient);
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace coreinit
|
|||
MPTR _iob_lock[GHS_FOPEN_MAX];
|
||||
uint16be __gh_FOPEN_MAX;
|
||||
MEMPTR<void> ghs_environ;
|
||||
uint32 ghs_Errno; // exposed by __gh_errno_ptr() or via 'errno' data export
|
||||
uint32 ghs_Errno; // exposed as 'errno' data export
|
||||
};
|
||||
|
||||
SysAllocator<GHSAccessibleData> g_ghs_data;
|
||||
|
@ -159,7 +159,7 @@ namespace coreinit
|
|||
void* __gh_errno_ptr()
|
||||
{
|
||||
OSThread_t* currentThread = coreinit::OSGetCurrentThread();
|
||||
return ¤tThread->context.error;
|
||||
return ¤tThread->context.ghs_errno;
|
||||
}
|
||||
|
||||
void* __get_eh_store_globals()
|
||||
|
|
|
@ -204,7 +204,7 @@ namespace coreinit
|
|||
// and a message queue large enough to hold the maximum number of commands (IPC_NUM_RESOURCE_BUFFERS)
|
||||
OSInitMessageQueue(gIPCThreadMsgQueue.GetPtr() + coreIndex, _gIPCThreadSemaphoreStorage.GetPtr() + coreIndex * IPC_NUM_RESOURCE_BUFFERS, IPC_NUM_RESOURCE_BUFFERS);
|
||||
OSThread_t* ipcThread = gIPCThread.GetPtr() + coreIndex;
|
||||
OSCreateThreadType(ipcThread, PPCInterpreter_makeCallableExportDepr(__IPCDriverThreadFunc), 0, nullptr, _gIPCThreadStack.GetPtr() + 0x4000 * coreIndex + 0x4000, 0x4000, 15, (1 << coreIndex), OSThread_t::THREAD_TYPE::TYPE_DRIVER);
|
||||
__OSCreateThreadType(ipcThread, PPCInterpreter_makeCallableExportDepr(__IPCDriverThreadFunc), 0, nullptr, _gIPCThreadStack.GetPtr() + 0x4000 * coreIndex + 0x4000, 0x4000, 15, (1 << coreIndex), OSThread_t::THREAD_TYPE::TYPE_DRIVER);
|
||||
sprintf((char*)_gIPCThreadNameStorage.GetPtr()+coreIndex*0x18, "{SYS IPC Core %d}", coreIndex);
|
||||
OSSetThreadName(ipcThread, (char*)_gIPCThreadNameStorage.GetPtr() + coreIndex * 0x18);
|
||||
OSResumeThread(ipcThread);
|
||||
|
|
|
@ -415,6 +415,12 @@ namespace coreinit
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint32 MCP_GetTitleId(uint32 mcpHandle, uint64be* outTitleId)
|
||||
{
|
||||
*outTitleId = CafeSystem::GetForegroundTitleId();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void InitializeMCP()
|
||||
{
|
||||
osLib_addFunction("coreinit", "MCP_Open", coreinitExport_MCP_Open);
|
||||
|
@ -442,6 +448,8 @@ namespace coreinit
|
|||
cafeExportRegister("coreinit", MCP_RightCheckLaunchable, LogType::Placeholder);
|
||||
|
||||
cafeExportRegister("coreinit", MCP_GetEcoSettings, LogType::Placeholder);
|
||||
|
||||
cafeExportRegister("coreinit", MCP_GetTitleId, LogType::Placeholder);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ namespace coreinit
|
|||
{
|
||||
MEMPTR<void> memBound;
|
||||
uint32be memBoundSize;
|
||||
OSGetMemBound(1, (MPTR*)memBound.GetBEPtr(), (uint32*)&memBoundSize);
|
||||
OSGetMemBound(1, &memBound, &memBoundSize);
|
||||
|
||||
MEMPTR<void> bucket;
|
||||
uint32be bucketSize;
|
||||
|
@ -257,7 +257,7 @@ namespace coreinit
|
|||
{
|
||||
MEMPTR<void> memBound;
|
||||
uint32be memBoundSize;
|
||||
OSGetMemBound(1, (MPTR*)memBound.GetBEPtr(), (uint32*)&memBoundSize);
|
||||
OSGetMemBound(1, &memBound, &memBoundSize);
|
||||
|
||||
MEMPTR<void> bucket;
|
||||
uint32be bucketSize;
|
||||
|
@ -593,16 +593,16 @@ namespace coreinit
|
|||
{
|
||||
MEMPTR<void> memBound;
|
||||
uint32be memBoundSize;
|
||||
OSGetMemBound(1, (MPTR*)memBound.GetBEPtr(), (uint32*)&memBoundSize);
|
||||
OSGetMemBound(1, &memBound, &memBoundSize);
|
||||
mem1Heap = MEMCreateFrmHeapEx(memBound.GetPtr(), (uint32)memBoundSize, 0);
|
||||
|
||||
OSGetForegroundBucketFreeArea((MPTR*)memBound.GetBEPtr(), (MPTR*)&memBoundSize);
|
||||
OSGetForegroundBucketFreeArea(&memBound, &memBoundSize);
|
||||
memFGHeap = MEMCreateFrmHeapEx(memBound.GetPtr(), (uint32)memBoundSize, 0);
|
||||
}
|
||||
|
||||
MEMPTR<void> memBound;
|
||||
uint32be memBoundSize;
|
||||
OSGetMemBound(2, (MPTR*)memBound.GetBEPtr(), (uint32*)&memBoundSize);
|
||||
OSGetMemBound(2, &memBound, &memBoundSize);
|
||||
mem2Heap = MEMDefaultHeap_Init(memBound.GetPtr(), (uint32)memBoundSize);
|
||||
|
||||
// set DynLoad allocators
|
||||
|
|
|
@ -126,12 +126,12 @@ namespace coreinit
|
|||
return physicalAddr;
|
||||
}
|
||||
|
||||
void OSMemoryBarrier(PPCInterpreter_t* hCPU)
|
||||
void OSMemoryBarrier()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
void OSGetMemBound(sint32 memType, MPTR* offsetOutput, uint32* sizeOutput)
|
||||
void OSGetMemBound(sint32 memType, MEMPTR<void>* offsetOutput, uint32be* sizeOutput)
|
||||
{
|
||||
MPTR memAddr = MPTR_NULL;
|
||||
uint32 memSize = 0;
|
||||
|
@ -195,9 +195,9 @@ namespace coreinit
|
|||
cemu_assert_debug(false);
|
||||
}
|
||||
if (offsetOutput)
|
||||
*offsetOutput = _swapEndianU32(memAddr);
|
||||
*offsetOutput = memAddr;
|
||||
if (sizeOutput)
|
||||
*sizeOutput = _swapEndianU32(memSize);
|
||||
*sizeOutput = memSize;
|
||||
}
|
||||
|
||||
void InitializeMemory()
|
||||
|
|
|
@ -4,5 +4,10 @@ namespace coreinit
|
|||
{
|
||||
void InitializeMemory();
|
||||
|
||||
void OSGetMemBound(sint32 memType, MPTR* offsetOutput, uint32* sizeOutput);
|
||||
void OSGetMemBound(sint32 memType, MEMPTR<void>* offsetOutput, uint32be* sizeOutput);
|
||||
|
||||
void* OSBlockMove(MEMPTR<void> dst, MEMPTR<void> src, uint32 size, bool flushDC);
|
||||
void* OSBlockSet(MEMPTR<void> dst, uint32 value, uint32 size);
|
||||
|
||||
void OSMemoryBarrier();
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
namespace coreinit
|
||||
{
|
||||
void UpdateSystemMessageQueue();
|
||||
void HandleReceivedSystemMessage(OSMessage* msg);
|
||||
|
||||
SysAllocator<OSMessageQueue> g_systemMessageQueue;
|
||||
SysAllocator<OSMessage, 16> _systemMessageQueueArray;
|
||||
|
@ -27,6 +29,9 @@ namespace coreinit
|
|||
|
||||
bool OSReceiveMessage(OSMessageQueue* msgQueue, OSMessage* msg, uint32 flags)
|
||||
{
|
||||
bool isSystemMessageQueue = (msgQueue == g_systemMessageQueue);
|
||||
if(isSystemMessageQueue)
|
||||
UpdateSystemMessageQueue();
|
||||
__OSLockScheduler(msgQueue);
|
||||
while (msgQueue->usedCount == (uint32be)0)
|
||||
{
|
||||
|
@ -50,6 +55,8 @@ namespace coreinit
|
|||
if (!msgQueue->threadQueueSend.isEmpty())
|
||||
msgQueue->threadQueueSend.wakeupSingleThreadWaitQueue(true);
|
||||
__OSUnlockScheduler(msgQueue);
|
||||
if(isSystemMessageQueue)
|
||||
HandleReceivedSystemMessage(msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,21 @@
|
|||
|
||||
namespace coreinit
|
||||
{
|
||||
enum class SysMessageId : uint32
|
||||
{
|
||||
MsgAcquireForeground = 0xFACEF000,
|
||||
MsgReleaseForeground = 0xFACEBACC,
|
||||
MsgExit = 0xD1E0D1E0,
|
||||
HomeButtonDenied = 0xCCC0FFEE,
|
||||
NetIoStartOrStop = 0xAAC0FFEE,
|
||||
};
|
||||
|
||||
struct OSMessage
|
||||
{
|
||||
MPTR message;
|
||||
uint32 data0;
|
||||
uint32 data1;
|
||||
uint32 data2;
|
||||
uint32be message;
|
||||
uint32be data0;
|
||||
uint32be data1;
|
||||
uint32be data2;
|
||||
};
|
||||
|
||||
struct OSMessageQueue
|
||||
|
@ -36,5 +45,7 @@ namespace coreinit
|
|||
bool OSPeekMessage(OSMessageQueue* msgQueue, OSMessage* msg);
|
||||
sint32 OSSendMessage(OSMessageQueue* msgQueue, OSMessage* msg, uint32 flags);
|
||||
|
||||
OSMessageQueue* OSGetSystemMessageQueue();
|
||||
|
||||
void InitializeMessageQueue();
|
||||
};
|
|
@ -1,5 +1,6 @@
|
|||
#include "Cafe/OS/common/OSCommon.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Misc.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_MessageQueue.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
#include "Cafe/Filesystem/fsc.h"
|
||||
#include <pugixml.hpp>
|
||||
|
@ -371,6 +372,23 @@ namespace coreinit
|
|||
return true;
|
||||
}
|
||||
|
||||
uint32 OSGetPFID()
|
||||
{
|
||||
return 15; // hardcoded as game
|
||||
}
|
||||
|
||||
uint32 OSGetUPID()
|
||||
{
|
||||
return OSGetPFID();
|
||||
}
|
||||
|
||||
uint64 s_currentTitleId;
|
||||
|
||||
uint64 OSGetTitleID()
|
||||
{
|
||||
return s_currentTitleId;
|
||||
}
|
||||
|
||||
uint32 s_sdkVersion;
|
||||
|
||||
uint32 __OSGetProcessSDKVersion()
|
||||
|
@ -470,9 +488,78 @@ namespace coreinit
|
|||
return 0;
|
||||
}
|
||||
|
||||
void OSReleaseForeground()
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "OSReleaseForeground not implemented");
|
||||
}
|
||||
|
||||
bool s_transitionToBackground = false;
|
||||
bool s_transitionToForeground = false;
|
||||
|
||||
void StartBackgroundForegroundTransition()
|
||||
{
|
||||
s_transitionToBackground = true;
|
||||
s_transitionToForeground = true;
|
||||
}
|
||||
|
||||
// called at the beginning of OSReceiveMessage if the queue is the system message queue
|
||||
void UpdateSystemMessageQueue()
|
||||
{
|
||||
if(!OSIsInterruptEnabled())
|
||||
return;
|
||||
cemu_assert_debug(!__OSHasSchedulerLock());
|
||||
// normally syscall 0x2E is used to get the next message
|
||||
// for now we just have some preliminary logic here to allow a fake transition to background & foreground
|
||||
if(s_transitionToBackground)
|
||||
{
|
||||
// add transition to background message
|
||||
OSMessage msg{};
|
||||
msg.data0 = stdx::to_underlying(SysMessageId::MsgReleaseForeground);
|
||||
msg.data1 = 0; // 1 -> System is shutting down 0 -> Begin transitioning to background
|
||||
OSMessageQueue* systemMessageQueue = coreinit::OSGetSystemMessageQueue();
|
||||
if(OSSendMessage(systemMessageQueue, &msg, 0))
|
||||
s_transitionToBackground = false;
|
||||
return;
|
||||
}
|
||||
if(s_transitionToForeground)
|
||||
{
|
||||
// add transition to foreground message
|
||||
OSMessage msg{};
|
||||
msg.data0 = stdx::to_underlying(SysMessageId::MsgAcquireForeground);
|
||||
msg.data1 = 1; // ?
|
||||
msg.data2 = 1; // ?
|
||||
OSMessageQueue* systemMessageQueue = coreinit::OSGetSystemMessageQueue();
|
||||
if(OSSendMessage(systemMessageQueue, &msg, 0))
|
||||
s_transitionToForeground = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// called when OSReceiveMessage returns a message from the system message queue
|
||||
void HandleReceivedSystemMessage(OSMessage* msg)
|
||||
{
|
||||
cemu_assert_debug(!__OSHasSchedulerLock());
|
||||
cemuLog_log(LogType::Force, "Receiving message: {:08x}", (uint32)msg->data0);
|
||||
}
|
||||
|
||||
uint32 OSDriver_Register(uint32 moduleHandle, sint32 priority, OSDriverInterface* driverCallbacks, sint32 driverId, uint32be* outUkn1, uint32be* outUkn2, uint32be* outUkn3)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "OSDriver_Register stubbed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 OSDriver_Deregister(uint32 moduleHandle, sint32 driverId)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "OSDriver_Deregister stubbed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void miscInit()
|
||||
{
|
||||
s_currentTitleId = CafeSystem::GetForegroundTitleId();
|
||||
s_sdkVersion = CafeSystem::GetForegroundTitleSDKVersion();
|
||||
s_transitionToBackground = false;
|
||||
s_transitionToForeground = false;
|
||||
|
||||
cafeExportRegister("coreinit", __os_snprintf, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSReport, LogType::Placeholder);
|
||||
|
@ -480,6 +567,10 @@ namespace coreinit
|
|||
cafeExportRegister("coreinit", COSWarn, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSLogPrintf, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSConsoleWrite, LogType::Placeholder);
|
||||
|
||||
cafeExportRegister("coreinit", OSGetPFID, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSGetUPID, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSGetTitleID, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", __OSGetProcessSDKVersion, LogType::Placeholder);
|
||||
|
||||
g_homeButtonMenuEnabled = true; // enabled by default
|
||||
|
@ -489,6 +580,11 @@ namespace coreinit
|
|||
|
||||
cafeExportRegister("coreinit", OSLaunchTitleByPathl, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSRestartGame, LogType::Placeholder);
|
||||
|
||||
cafeExportRegister("coreinit", OSReleaseForeground, LogType::Placeholder);
|
||||
|
||||
cafeExportRegister("coreinit", OSDriver_Register, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSDriver_Deregister, LogType::Placeholder);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -2,9 +2,29 @@
|
|||
|
||||
namespace coreinit
|
||||
{
|
||||
uint32 OSGetUPID();
|
||||
uint32 OSGetPFID();
|
||||
uint64 OSGetTitleID();
|
||||
uint32 __OSGetProcessSDKVersion();
|
||||
uint32 OSLaunchTitleByPathl(const char* path, uint32 pathLength, uint32 argc);
|
||||
uint32 OSRestartGame(uint32 argc, MEMPTR<char>* argv);
|
||||
|
||||
void OSReleaseForeground();
|
||||
|
||||
void StartBackgroundForegroundTransition();
|
||||
|
||||
struct OSDriverInterface
|
||||
{
|
||||
MEMPTR<void> getDriverName;
|
||||
MEMPTR<void> init;
|
||||
MEMPTR<void> onAcquireForeground;
|
||||
MEMPTR<void> onReleaseForeground;
|
||||
MEMPTR<void> done;
|
||||
};
|
||||
static_assert(sizeof(OSDriverInterface) == 0x14);
|
||||
|
||||
uint32 OSDriver_Register(uint32 moduleHandle, sint32 priority, OSDriverInterface* driverCallbacks, sint32 driverId, uint32be* outUkn1, uint32be* outUkn2, uint32be* outUkn3);
|
||||
uint32 OSDriver_Deregister(uint32 moduleHandle, sint32 driverId);
|
||||
|
||||
void miscInit();
|
||||
};
|
|
@ -215,14 +215,171 @@ namespace coreinit
|
|||
hCPU->spr.LR = lr;
|
||||
hCPU->gpr[3] = r3;
|
||||
hCPU->gpr[4] = r4;
|
||||
hCPU->instructionPointer = _swapEndianU32(currentThread->entrypoint);
|
||||
hCPU->instructionPointer = currentThread->entrypoint.GetMPTR();
|
||||
}
|
||||
|
||||
void coreinitExport_OSExitThreadDepr(PPCInterpreter_t* hCPU);
|
||||
|
||||
void OSCreateThreadInternal(OSThread_t* thread, uint32 entryPoint, MPTR stackLowerBaseAddr, uint32 stackSize, uint8 affinityMask, OSThread_t::THREAD_TYPE threadType)
|
||||
void __OSInitContext(OSContext_t* ctx, MEMPTR<void> initialIP, MEMPTR<void> initialStackPointer)
|
||||
{
|
||||
ctx->SetContextMagic();
|
||||
ctx->gpr[0] = 0; // r0 is left uninitialized on console?
|
||||
for(auto& it : ctx->gpr)
|
||||
it = 0;
|
||||
ctx->gpr[1] = _swapEndianU32(initialStackPointer.GetMPTR());
|
||||
ctx->gpr[2] = _swapEndianU32(RPLLoader_GetSDA2Base());
|
||||
ctx->gpr[13] = _swapEndianU32(RPLLoader_GetSDA1Base());
|
||||
ctx->srr0 = initialIP.GetMPTR();
|
||||
ctx->cr = 0;
|
||||
ctx->ukn0A8 = 0;
|
||||
ctx->ukn0AC = 0;
|
||||
ctx->gqr[0] = 0;
|
||||
ctx->gqr[1] = 0;
|
||||
ctx->gqr[2] = 0;
|
||||
ctx->gqr[3] = 0;
|
||||
ctx->gqr[4] = 0;
|
||||
ctx->gqr[5] = 0;
|
||||
ctx->gqr[6] = 0;
|
||||
ctx->gqr[7] = 0;
|
||||
ctx->dsi_dar = 0;
|
||||
ctx->srr1 = 0x9032;
|
||||
ctx->xer = 0;
|
||||
ctx->dsi_dsisr = 0;
|
||||
ctx->upir = 0;
|
||||
ctx->boostCount = 0;
|
||||
ctx->state = 0;
|
||||
for(auto& it : ctx->coretime)
|
||||
it = 0;
|
||||
ctx->starttime = 0;
|
||||
ctx->ghs_errno = 0;
|
||||
ctx->upmc1 = 0;
|
||||
ctx->upmc2 = 0;
|
||||
ctx->upmc3 = 0;
|
||||
ctx->upmc4 = 0;
|
||||
ctx->ummcr0 = 0;
|
||||
ctx->ummcr1 = 0;
|
||||
}
|
||||
|
||||
void __OSThreadInit(OSThread_t* thread, MEMPTR<void> entrypoint, uint32 argInt, MEMPTR<void> argPtr, MEMPTR<void> stackTop, uint32 stackSize, sint32 priority, uint32 upirCoreIndex, OSThread_t::THREAD_TYPE threadType)
|
||||
{
|
||||
thread->effectivePriority = priority;
|
||||
thread->type = threadType;
|
||||
thread->basePriority = priority;
|
||||
thread->SetThreadMagic();
|
||||
thread->id = 0x8000;
|
||||
thread->waitAlarm = nullptr;
|
||||
thread->entrypoint = entrypoint;
|
||||
thread->quantumTicks = 0;
|
||||
if(entrypoint)
|
||||
{
|
||||
thread->state = OSThread_t::THREAD_STATE::STATE_READY;
|
||||
thread->suspendCounter = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->state = OSThread_t::THREAD_STATE::STATE_NONE;
|
||||
thread->suspendCounter = 0;
|
||||
}
|
||||
thread->exitValue = (uint32)-1;
|
||||
thread->requestFlags = OSThread_t::REQUEST_FLAG_BIT::REQUEST_FLAG_NONE;
|
||||
thread->pendingSuspend = 0;
|
||||
thread->suspendResult = 0xFFFFFFFF;
|
||||
thread->coretimeSumQuantumStart = 0;
|
||||
thread->deallocatorFunc = nullptr;
|
||||
thread->cleanupCallback = nullptr;
|
||||
thread->waitingForFastMutex = nullptr;
|
||||
thread->stateFlags = 0;
|
||||
thread->waitingForMutex = nullptr;
|
||||
memset(&thread->crt, 0, sizeof(thread->crt));
|
||||
static_assert(sizeof(thread->crt) == 0x1D8);
|
||||
thread->tlsBlocksMPTR = 0;
|
||||
thread->numAllocatedTLSBlocks = 0;
|
||||
thread->tlsStatus = 0;
|
||||
OSInitThreadQueueEx(&thread->joinQueue, thread);
|
||||
OSInitThreadQueueEx(&thread->suspendQueue, thread);
|
||||
thread->mutexQueue.ukn08 = thread;
|
||||
thread->mutexQueue.ukn0C = 0;
|
||||
thread->mutexQueue.tail = nullptr;
|
||||
thread->mutexQueue.head = nullptr;
|
||||
thread->ownedFastMutex.next = nullptr;
|
||||
thread->ownedFastMutex.prev = nullptr;
|
||||
thread->contendedFastMutex.next = nullptr;
|
||||
thread->contendedFastMutex.prev = nullptr;
|
||||
|
||||
MEMPTR<void> alignedStackTop{MEMPTR<void>(stackTop).GetMPTR() & 0xFFFFFFF8};
|
||||
MEMPTR<uint32be> alignedStackTop32{alignedStackTop};
|
||||
alignedStackTop32[-1] = 0;
|
||||
alignedStackTop32[-2] = 0;
|
||||
|
||||
__OSInitContext(&thread->context, MEMPTR<void>(PPCInterpreter_makeCallableExportDepr(threadEntry)), (void*)(alignedStackTop32.GetPtr() - 2));
|
||||
thread->stackBase = stackTop; // without alignment
|
||||
thread->stackEnd = ((uint8*)stackTop.GetPtr() - stackSize);
|
||||
thread->context.upir = upirCoreIndex;
|
||||
thread->context.lr = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(coreinitExport_OSExitThreadDepr));
|
||||
thread->context.gpr[3] = _swapEndianU32(argInt);
|
||||
thread->context.gpr[4] = _swapEndianU32(argPtr.GetMPTR());
|
||||
|
||||
*(uint32be*)((uint8*)stackTop.GetPtr() - stackSize) = 0xDEADBABE;
|
||||
thread->alarmRelatedUkn = 0;
|
||||
for(auto& it : thread->specificArray)
|
||||
it = nullptr;
|
||||
thread->context.fpscr.fpscr = 4;
|
||||
for(sint32 i=0; i<32; i++)
|
||||
{
|
||||
thread->context.fp_ps0[i] = 0.0;
|
||||
thread->context.fp_ps1[i] = 0.0;
|
||||
}
|
||||
thread->context.gqr[2] = 0x40004;
|
||||
thread->context.gqr[3] = 0x50005;
|
||||
thread->context.gqr[4] = 0x60006;
|
||||
thread->context.gqr[5] = 0x70007;
|
||||
|
||||
for(sint32 i=0; i<Espresso::CORE_COUNT; i++)
|
||||
thread->context.coretime[i] = 0;
|
||||
|
||||
// currentRunQueue and waitQueueLink is not initialized by COS and instead overwritten without validation
|
||||
// since we already have integrity checks in other functions, lets initialize it here
|
||||
for(sint32 i=0; i<Espresso::CORE_COUNT; i++)
|
||||
thread->currentRunQueue[i] = nullptr;
|
||||
thread->waitQueueLink.prev = nullptr;
|
||||
thread->waitQueueLink.next = nullptr;
|
||||
|
||||
thread->wakeTimeRelatedUkn2 = 0;
|
||||
thread->wakeUpCount = 0;
|
||||
thread->wakeUpTime = 0;
|
||||
thread->wakeTimeRelatedUkn1 = 0x7FFFFFFFFFFFFFFF;
|
||||
thread->quantumTicks = 0;
|
||||
thread->coretimeSumQuantumStart = 0;
|
||||
thread->totalCycles = 0;
|
||||
|
||||
for(auto& it : thread->padding68C)
|
||||
it = 0;
|
||||
}
|
||||
|
||||
void SetThreadAffinityToCore(OSThread_t* thread, uint32 coreIndex)
|
||||
{
|
||||
cemu_assert_debug(coreIndex < 3);
|
||||
thread->attr &= ~(OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE0 | OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE1 | OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE2 | OSThread_t::ATTR_BIT::ATTR_UKN_010);
|
||||
thread->context.affinity &= 0xFFFFFFF8;
|
||||
if (coreIndex == 0)
|
||||
{
|
||||
thread->attr |= OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE0;
|
||||
thread->context.affinity |= (1<<0);
|
||||
}
|
||||
else if (coreIndex == 1)
|
||||
{
|
||||
thread->attr |= OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE1;
|
||||
thread->context.affinity |= (1<<1);
|
||||
}
|
||||
else // if (coreIndex == 2)
|
||||
{
|
||||
thread->attr |= OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE2;
|
||||
thread->context.affinity |= (1<<2);
|
||||
}
|
||||
}
|
||||
|
||||
void __OSCreateThreadOnActiveThreadWorkaround(OSThread_t* thread)
|
||||
{
|
||||
cemu_assert_debug(thread != nullptr); // make thread struct mandatory. Caller can always use SysAllocator
|
||||
__OSLockScheduler();
|
||||
bool isThreadStillActive = __OSIsThreadActive(thread);
|
||||
if (isThreadStillActive)
|
||||
|
@ -248,78 +405,97 @@ namespace coreinit
|
|||
}
|
||||
cemu_assert_debug(__OSIsThreadActive(thread) == false);
|
||||
__OSUnlockScheduler();
|
||||
memset(thread, 0x00, sizeof(OSThread_t));
|
||||
// init signatures
|
||||
thread->SetMagic();
|
||||
thread->type = threadType;
|
||||
thread->state = (entryPoint != MPTR_NULL) ? OSThread_t::THREAD_STATE::STATE_READY : OSThread_t::THREAD_STATE::STATE_NONE;
|
||||
thread->entrypoint = _swapEndianU32(entryPoint);
|
||||
__OSSetThreadBasePriority(thread, 0);
|
||||
__OSUpdateThreadEffectivePriority(thread);
|
||||
// untested, but seems to work (Batman Arkham City uses these values to calculate the stack size for duplicated threads)
|
||||
thread->stackBase = _swapEndianU32(stackLowerBaseAddr + stackSize); // these fields are quite important and lots of games rely on them being accurate (Examples: Darksiders 2, SMW3D, Batman Arkham City)
|
||||
thread->stackEnd = _swapEndianU32(stackLowerBaseAddr);
|
||||
// init stackpointer
|
||||
thread->context.gpr[GPR_SP] = _swapEndianU32(stackLowerBaseAddr + stackSize - 0x20); // how many free bytes should there be at the beginning of the stack?
|
||||
// init misc stuff
|
||||
thread->attr = affinityMask;
|
||||
thread->context.setAffinity(affinityMask);
|
||||
thread->context.srr0 = PPCInterpreter_makeCallableExportDepr(threadEntry);
|
||||
thread->context.lr = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(coreinitExport_OSExitThreadDepr));
|
||||
thread->id = 0x8000; // Warriors Orochi 3 softlocks if this is zero due to confusing threads (_OSActivateThread should set this?)
|
||||
// init ugqr
|
||||
thread->context.gqr[0] = 0x00000000;
|
||||
thread->context.gqr[1] = 0x00000000;
|
||||
thread->context.gqr[2] = 0x00040004;
|
||||
thread->context.gqr[3] = 0x00050005;
|
||||
thread->context.gqr[4] = 0x00060006;
|
||||
thread->context.gqr[5] = 0x00070007;
|
||||
thread->context.gqr[6] = 0x00000000;
|
||||
thread->context.gqr[7] = 0x00000000;
|
||||
// init r2 (SDA2) and r3 (SDA)
|
||||
thread->context.gpr[2] = _swapEndianU32(RPLLoader_GetSDA2Base());
|
||||
thread->context.gpr[13] = _swapEndianU32(RPLLoader_GetSDA1Base());
|
||||
// GHS related thread init?
|
||||
|
||||
__OSLockScheduler();
|
||||
// if entrypoint is non-zero then put the thread on the active list and suspend it
|
||||
if (entryPoint != MPTR_NULL)
|
||||
{
|
||||
thread->suspendCounter = 1;
|
||||
__OSActivateThread(thread);
|
||||
thread->state = OSThread_t::THREAD_STATE::STATE_READY;
|
||||
}
|
||||
else
|
||||
thread->suspendCounter = 0;
|
||||
__OSUnlockScheduler();
|
||||
}
|
||||
|
||||
bool OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop2, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType)
|
||||
bool __OSCreateThreadInternal2(OSThread_t* thread, MEMPTR<void> entrypoint, uint32 argInt, MEMPTR<void> argPtr, MEMPTR<void> stackBase, uint32 stackSize, sint32 priority, uint32 attrBits, OSThread_t::THREAD_TYPE threadType)
|
||||
{
|
||||
OSCreateThreadInternal(thread, entryPoint, memory_getVirtualOffsetFromPointer(stackTop2) - stackSize, stackSize, attr, threadType);
|
||||
thread->context.gpr[3] = _swapEndianU32(numParam); // num arguments
|
||||
thread->context.gpr[4] = _swapEndianU32(memory_getVirtualOffsetFromPointer(ptrParam)); // arguments pointer
|
||||
__OSSetThreadBasePriority(thread, priority);
|
||||
__OSUpdateThreadEffectivePriority(thread);
|
||||
// set affinity
|
||||
uint8 affinityMask = 0;
|
||||
affinityMask = attr & 0x7;
|
||||
// if no core is selected -> set current one
|
||||
if (affinityMask == 0)
|
||||
affinityMask |= (1 << PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance()));
|
||||
// set attr
|
||||
// todo: Support for other attr bits
|
||||
thread->attr = (affinityMask & 0xFF) | (attr & OSThread_t::ATTR_BIT::ATTR_DETACHED);
|
||||
thread->context.setAffinity(affinityMask);
|
||||
__OSCreateThreadOnActiveThreadWorkaround(thread);
|
||||
OSThread_t* currentThread = OSGetCurrentThread();
|
||||
if (priority < 0 || priority >= 32)
|
||||
{
|
||||
cemuLog_log(LogType::APIErrors, "OSCreateThreadInternal: Thread priority must be in range 0-31");
|
||||
return false;
|
||||
}
|
||||
if (threadType == OSThread_t::THREAD_TYPE::TYPE_IO)
|
||||
{
|
||||
priority = priority + 0x20;
|
||||
}
|
||||
else if (threadType == OSThread_t::THREAD_TYPE::TYPE_APP)
|
||||
{
|
||||
priority = priority + 0x40;
|
||||
}
|
||||
if(attrBits >= 0x20 || stackBase == nullptr || stackSize == 0)
|
||||
{
|
||||
cemuLog_logDebug(LogType::APIErrors, "OSCreateThreadInternal: Invalid attributes, stack base or size");
|
||||
return false;
|
||||
}
|
||||
uint32 im = OSDisableInterrupts();
|
||||
__OSLockScheduler(thread);
|
||||
|
||||
uint32 coreIndex = PPCInterpreter_getCurrentInstance() ? OSGetCoreId() : 1;
|
||||
__OSThreadInit(thread, entrypoint, argInt, argPtr, stackBase, stackSize, priority, coreIndex, threadType);
|
||||
thread->threadName = nullptr;
|
||||
thread->context.affinity = attrBits & 7;
|
||||
thread->attr = attrBits;
|
||||
if ((attrBits & 7) == 0) // if no explicit affinity is given, use the current core
|
||||
SetThreadAffinityToCore(thread, OSGetCoreId());
|
||||
if(currentThread)
|
||||
{
|
||||
for(sint32 i=0; i<Espresso::CORE_COUNT; i++)
|
||||
{
|
||||
thread->dsiCallback[i] = currentThread->dsiCallback[i];
|
||||
thread->isiCallback[i] = currentThread->isiCallback[i];
|
||||
thread->programCallback[i] = currentThread->programCallback[i];
|
||||
thread->perfMonCallback[i] = currentThread->perfMonCallback[i];
|
||||
thread->alignmentExceptionCallback[i] = currentThread->alignmentExceptionCallback[i];
|
||||
}
|
||||
thread->context.srr1 = thread->context.srr1 | (currentThread->context.srr1 & 0x900);
|
||||
thread->context.fpscr.fpscr = thread->context.fpscr.fpscr | (currentThread->context.fpscr.fpscr & 0xF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(sint32 i=0; i<Espresso::CORE_COUNT; i++)
|
||||
{
|
||||
thread->dsiCallback[i] = 0;
|
||||
thread->isiCallback[i] = 0;
|
||||
thread->programCallback[i] = 0;
|
||||
thread->perfMonCallback[i] = 0;
|
||||
thread->alignmentExceptionCallback[i] = nullptr;
|
||||
}
|
||||
}
|
||||
if (entrypoint)
|
||||
{
|
||||
thread->id = 0x8000;
|
||||
__OSActivateThread(thread); // also handles adding the thread to g_activeThreadQueue
|
||||
}
|
||||
__OSUnlockScheduler(thread);
|
||||
OSRestoreInterrupts(im);
|
||||
// recompile entry point function
|
||||
if (entryPoint != MPTR_NULL)
|
||||
PPCRecompiler_recompileIfUnvisited(entryPoint);
|
||||
if (entrypoint)
|
||||
PPCRecompiler_recompileIfUnvisited(entrypoint.GetMPTR());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OSCreateThread(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop2, sint32 stackSize, sint32 priority, uint32 attr)
|
||||
bool OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType)
|
||||
{
|
||||
return OSCreateThreadType(thread, entryPoint, numParam, ptrParam, stackTop2, stackSize, priority, attr, OSThread_t::THREAD_TYPE::TYPE_APP);
|
||||
if(threadType != OSThread_t::THREAD_TYPE::TYPE_APP && threadType != OSThread_t::THREAD_TYPE::TYPE_IO)
|
||||
{
|
||||
cemuLog_logDebug(LogType::APIErrors, "OSCreateThreadType: Invalid thread type");
|
||||
cemu_assert_suspicious();
|
||||
return false;
|
||||
}
|
||||
return __OSCreateThreadInternal2(thread, MEMPTR<void>(entryPoint), numParam, ptrParam, stackTop, stackSize, priority, attr, threadType);
|
||||
}
|
||||
|
||||
bool OSCreateThread(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr)
|
||||
{
|
||||
return __OSCreateThreadInternal2(thread, MEMPTR<void>(entryPoint), numParam, ptrParam, stackTop, stackSize, priority, attr, OSThread_t::THREAD_TYPE::TYPE_APP);
|
||||
}
|
||||
|
||||
// similar to OSCreateThreadType, but can be used to create any type of thread
|
||||
bool __OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType)
|
||||
{
|
||||
return __OSCreateThreadInternal2(thread, MEMPTR<void>(entryPoint), numParam, ptrParam, stackTop, stackSize, priority, attr, threadType);
|
||||
}
|
||||
|
||||
bool OSRunThread(OSThread_t* thread, MPTR funcAddress, sint32 numParam, void* ptrParam)
|
||||
|
@ -346,7 +522,7 @@ namespace coreinit
|
|||
// set thread state
|
||||
// todo - this should fully reinitialize the thread?
|
||||
|
||||
thread->entrypoint = _swapEndianU32(funcAddress);
|
||||
thread->entrypoint = funcAddress;
|
||||
thread->context.srr0 = PPCInterpreter_makeCallableExportDepr(threadEntry);
|
||||
thread->context.lr = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(coreinitExport_OSExitThreadDepr));
|
||||
thread->context.gpr[3] = _swapEndianU32(numParam);
|
||||
|
@ -372,10 +548,10 @@ namespace coreinit
|
|||
OSThread_t* currentThread = coreinit::OSGetCurrentThread();
|
||||
|
||||
// thread cleanup callback
|
||||
if (!currentThread->cleanupCallback2.IsNull())
|
||||
if (currentThread->cleanupCallback)
|
||||
{
|
||||
currentThread->stateFlags = _swapEndianU32(_swapEndianU32(currentThread->stateFlags) | 0x00000001);
|
||||
PPCCoreCallback(currentThread->cleanupCallback2.GetMPTR(), currentThread, _swapEndianU32(currentThread->stackEnd));
|
||||
PPCCoreCallback(currentThread->cleanupCallback.GetMPTR(), currentThread, currentThread->stackEnd);
|
||||
}
|
||||
// cpp exception cleanup
|
||||
if (gCoreinitData->__cpp_exception_cleanup_ptr != 0 && currentThread->crt.eh_globals != nullptr)
|
||||
|
@ -445,12 +621,12 @@ namespace coreinit
|
|||
return currentThread->specificArray[index].GetPtr();
|
||||
}
|
||||
|
||||
void OSSetThreadName(OSThread_t* thread, char* name)
|
||||
void OSSetThreadName(OSThread_t* thread, const char* name)
|
||||
{
|
||||
thread->threadName = name;
|
||||
}
|
||||
|
||||
char* OSGetThreadName(OSThread_t* thread)
|
||||
const char* OSGetThreadName(OSThread_t* thread)
|
||||
{
|
||||
return thread->threadName.GetPtr();
|
||||
}
|
||||
|
@ -587,6 +763,11 @@ namespace coreinit
|
|||
uint32 coreIndex = OSGetCoreId();
|
||||
if (!newThread->context.hasCoreAffinitySet(coreIndex))
|
||||
return false;
|
||||
// special case: if current and new thread are running only on the same core then reschedule even if priority is equal
|
||||
// this resolves a deadlock in Just Dance 2019 where one thread would always reacquire the same mutex within it's timeslice, blocking another thread on the same core from acquiring it
|
||||
if ((1<<coreIndex) == newThread->context.affinity && currentThread->context.affinity == newThread->context.affinity && currentThread->effectivePriority == newThread->effectivePriority)
|
||||
return true;
|
||||
// otherwise reschedule if new thread has higher priority
|
||||
return newThread->effectivePriority < currentThread->effectivePriority;
|
||||
}
|
||||
|
||||
|
@ -596,7 +777,10 @@ namespace coreinit
|
|||
sint32 previousSuspendCount = thread->suspendCounter;
|
||||
cemu_assert_debug(previousSuspendCount >= 0);
|
||||
if (previousSuspendCount == 0)
|
||||
{
|
||||
cemuLog_log(LogType::APIErrors, "OSResumeThread: Resuming thread 0x{:08x} which isn't suspended", MEMPTR<OSThread_t>(thread).GetMPTR());
|
||||
return 0;
|
||||
}
|
||||
thread->suspendCounter = previousSuspendCount - resumeCount;
|
||||
if (thread->suspendCounter < 0)
|
||||
thread->suspendCounter = 0;
|
||||
|
@ -726,8 +910,8 @@ namespace coreinit
|
|||
void* OSSetThreadCleanupCallback(OSThread_t* thread, void* cleanupCallback)
|
||||
{
|
||||
__OSLockScheduler();
|
||||
void* previousFunc = thread->cleanupCallback2.GetPtr();
|
||||
thread->cleanupCallback2 = cleanupCallback;
|
||||
void* previousFunc = thread->cleanupCallback.GetPtr();
|
||||
thread->cleanupCallback = cleanupCallback;
|
||||
__OSUnlockScheduler();
|
||||
return previousFunc;
|
||||
}
|
||||
|
@ -1335,7 +1519,7 @@ namespace coreinit
|
|||
void __OSQueueThreadDeallocation(OSThread_t* thread)
|
||||
{
|
||||
uint32 coreIndex = OSGetCoreId();
|
||||
TerminatorThread::DeallocatorQueueEntry queueEntry(thread, memory_getPointerFromVirtualOffset(_swapEndianU32(thread->stackEnd)), thread->deallocatorFunc);
|
||||
TerminatorThread::DeallocatorQueueEntry queueEntry(thread, thread->stackEnd, thread->deallocatorFunc);
|
||||
s_terminatorThreads[coreIndex].queueDeallocators.push(queueEntry);
|
||||
OSSignalSemaphoreInternal(s_terminatorThreads[coreIndex].semaphoreQueuedDeallocators.GetPtr(), false); // do not reschedule here! Current thread must not be interrupted otherwise deallocator will run too early
|
||||
}
|
||||
|
@ -1371,6 +1555,7 @@ namespace coreinit
|
|||
{
|
||||
cafeExportRegister("coreinit", OSCreateThreadType, LogType::CoreinitThread);
|
||||
cafeExportRegister("coreinit", OSCreateThread, LogType::CoreinitThread);
|
||||
cafeExportRegister("coreinit", __OSCreateThreadType, LogType::CoreinitThread);
|
||||
cafeExportRegister("coreinit", OSExitThread, LogType::CoreinitThread);
|
||||
|
||||
cafeExportRegister("coreinit", OSGetCurrentThread, LogType::CoreinitThread);
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
#include "Cafe/HW/Espresso/Const.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Scheduler.h"
|
||||
|
||||
#define OS_CONTEXT_MAGIC_0 'OSCo'
|
||||
#define OS_CONTEXT_MAGIC_1 'ntxt'
|
||||
|
||||
struct OSThread_t;
|
||||
|
||||
struct OSContextRegFPSCR_t
|
||||
|
@ -16,6 +13,9 @@ struct OSContextRegFPSCR_t
|
|||
|
||||
struct OSContext_t
|
||||
{
|
||||
static constexpr uint32 OS_CONTEXT_MAGIC_0 = 0x4f53436f; // "OSCo"
|
||||
static constexpr uint32 OS_CONTEXT_MAGIC_1 = 0x6e747874; // "ntxt"
|
||||
|
||||
/* +0x000 */ betype<uint32> magic0;
|
||||
/* +0x004 */ betype<uint32> magic1;
|
||||
/* +0x008 */ uint32 gpr[32];
|
||||
|
@ -36,24 +36,29 @@ struct OSContext_t
|
|||
/* +0x1BC */ uint32 gqr[8]; // GQR/UGQR
|
||||
/* +0x1DC */ uint32be upir; // set to current core index
|
||||
/* +0x1E0 */ uint64be fp_ps1[32];
|
||||
/* +0x2E0 */ uint64 uknTime2E0;
|
||||
/* +0x2E8 */ uint64 uknTime2E8;
|
||||
/* +0x2F0 */ uint64 uknTime2F0;
|
||||
/* +0x2F8 */ uint64 uknTime2F8;
|
||||
/* +0x300 */ uint32 error; // returned by __gh_errno_ptr() (used by socketlasterr)
|
||||
/* +0x2E0 */ uint64be coretime[3];
|
||||
/* +0x2F8 */ uint64be starttime;
|
||||
/* +0x300 */ uint32be ghs_errno; // returned by __gh_errno_ptr() (used by socketlasterr)
|
||||
/* +0x304 */ uint32be affinity;
|
||||
/* +0x308 */ uint32 ukn0308;
|
||||
/* +0x30C */ uint32 ukn030C;
|
||||
/* +0x310 */ uint32 ukn0310;
|
||||
/* +0x314 */ uint32 ukn0314;
|
||||
/* +0x318 */ uint32 ukn0318;
|
||||
/* +0x31C */ uint32 ukn031C;
|
||||
/* +0x308 */ uint32be upmc1;
|
||||
/* +0x30C */ uint32be upmc2;
|
||||
/* +0x310 */ uint32be upmc3;
|
||||
/* +0x314 */ uint32be upmc4;
|
||||
/* +0x318 */ uint32be ummcr0;
|
||||
/* +0x31C */ uint32be ummcr1;
|
||||
|
||||
bool checkMagic()
|
||||
{
|
||||
return magic0 == (uint32)OS_CONTEXT_MAGIC_0 && magic1 == (uint32)OS_CONTEXT_MAGIC_1;
|
||||
}
|
||||
|
||||
void SetContextMagic()
|
||||
{
|
||||
magic0 = OS_CONTEXT_MAGIC_0;
|
||||
magic1 = OS_CONTEXT_MAGIC_1;
|
||||
}
|
||||
|
||||
|
||||
bool hasCoreAffinitySet(uint32 coreIndex) const
|
||||
{
|
||||
return (((uint32)affinity >> coreIndex) & 1) != 0;
|
||||
|
@ -361,6 +366,8 @@ namespace coreinit
|
|||
|
||||
struct OSThread_t
|
||||
{
|
||||
static constexpr uint32 MAGIC_THREAD = 0x74487244; // "tHrD"
|
||||
|
||||
enum class THREAD_TYPE : uint32
|
||||
{
|
||||
TYPE_DRIVER = 0,
|
||||
|
@ -383,7 +390,7 @@ struct OSThread_t
|
|||
ATTR_AFFINITY_CORE1 = 0x2,
|
||||
ATTR_AFFINITY_CORE2 = 0x4,
|
||||
ATTR_DETACHED = 0x8,
|
||||
// more flags?
|
||||
ATTR_UKN_010 = 0x10,
|
||||
};
|
||||
|
||||
enum REQUEST_FLAG_BIT : uint32
|
||||
|
@ -404,23 +411,21 @@ struct OSThread_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
void SetMagic()
|
||||
void SetThreadMagic()
|
||||
{
|
||||
context.magic0 = OS_CONTEXT_MAGIC_0;
|
||||
context.magic1 = OS_CONTEXT_MAGIC_1;
|
||||
magic = 'tHrD';
|
||||
magic = MAGIC_THREAD;
|
||||
}
|
||||
|
||||
bool IsValidMagic() const
|
||||
{
|
||||
return magic == 'tHrD' && context.magic0 == OS_CONTEXT_MAGIC_0 && context.magic1 == OS_CONTEXT_MAGIC_1;
|
||||
return magic == MAGIC_THREAD && context.magic0 == OSContext_t::OS_CONTEXT_MAGIC_0 && context.magic1 == OSContext_t::OS_CONTEXT_MAGIC_1;
|
||||
}
|
||||
|
||||
/* +0x000 */ OSContext_t context;
|
||||
/* +0x320 */ uint32be magic; // 'tHrD'
|
||||
/* +0x320 */ uint32be magic; // "tHrD" (0x74487244)
|
||||
/* +0x324 */ betype<THREAD_STATE> state;
|
||||
/* +0x325 */ uint8 attr;
|
||||
/* +0x326 */ uint16be id; // Warriors Orochi 3 uses this to identify threads. Seems like this is always set to 0x8000 ?
|
||||
/* +0x326 */ uint16be id; // Warriors Orochi 3 uses this to identify threads
|
||||
/* +0x328 */ betype<sint32> suspendCounter;
|
||||
/* +0x32C */ sint32be effectivePriority; // effective priority (lower is higher)
|
||||
/* +0x330 */ sint32be basePriority; // base priority (lower is higher)
|
||||
|
@ -440,21 +445,21 @@ struct OSThread_t
|
|||
|
||||
/* +0x38C */ coreinit::OSThreadLink activeThreadChain; // queue of active threads (g_activeThreadQueue)
|
||||
|
||||
/* +0x394 */ MPTR stackBase; // upper limit of stack
|
||||
/* +0x398 */ MPTR stackEnd; // lower limit of stack
|
||||
/* +0x394 */ MEMPTR<void> stackBase; // upper limit of stack
|
||||
/* +0x398 */ MEMPTR<void> stackEnd; // lower limit of stack
|
||||
|
||||
/* +0x39C */ MPTR entrypoint;
|
||||
/* +0x39C */ MEMPTR<void> entrypoint;
|
||||
/* +0x3A0 */ crt_t crt;
|
||||
|
||||
/* +0x578 */ sint32 alarmRelatedUkn;
|
||||
/* +0x57C */ std::array<MEMPTR<void>, 16> specificArray;
|
||||
/* +0x5BC */ betype<THREAD_TYPE> type;
|
||||
/* +0x5C0 */ MEMPTR<char> threadName;
|
||||
/* +0x5C4 */ MPTR waitAlarm; // used only by OSWaitEventWithTimeout/OSSignalEvent ?
|
||||
/* +0x5C0 */ MEMPTR<const char> threadName;
|
||||
/* +0x5C4 */ MEMPTR<void> waitAlarm; // used only by OSWaitEventWithTimeout/OSSignalEvent ?
|
||||
|
||||
/* +0x5C8 */ uint32 userStackPointer;
|
||||
|
||||
/* +0x5CC */ MEMPTR<void> cleanupCallback2;
|
||||
/* +0x5CC */ MEMPTR<void> cleanupCallback;
|
||||
/* +0x5D0 */ MEMPTR<void> deallocatorFunc;
|
||||
|
||||
/* +0x5D4 */ uint32 stateFlags; // 0x5D4 | various flags? Controls if canceling/suspension is allowed (at cancel points) or not? If 1 -> Cancel/Suspension not allowed, if 0 -> Cancel/Suspension allowed
|
||||
|
@ -480,19 +485,21 @@ struct OSThread_t
|
|||
|
||||
/* +0x660 */ uint32 ukn660;
|
||||
|
||||
// todo - some of the members towards the end of the struct were only added in later COS versions. Figure out the mapping between version and members
|
||||
|
||||
// TLS
|
||||
/* +0x664 */ uint16 numAllocatedTLSBlocks;
|
||||
/* +0x666 */ sint16 tlsStatus;
|
||||
/* +0x668 */ MPTR tlsBlocksMPTR;
|
||||
|
||||
|
||||
/* +0x66C */ MEMPTR<coreinit::OSFastMutex> waitingForFastMutex;
|
||||
/* +0x670 */ coreinit::OSFastMutexLink contendedFastMutex;
|
||||
/* +0x678 */ coreinit::OSFastMutexLink ownedFastMutex;
|
||||
/* +0x680 */ MEMPTR<void> alignmentExceptionCallback[Espresso::CORE_COUNT];
|
||||
|
||||
/* +0x680 */ uint32 padding680[28 / 4];
|
||||
/* +0x68C */ uint32 padding68C[20 / 4];
|
||||
};
|
||||
|
||||
static_assert(sizeof(OSThread_t) == 0x6A0-4); // todo - determine correct size
|
||||
static_assert(sizeof(OSThread_t) == 0x6A0);
|
||||
|
||||
namespace coreinit
|
||||
{
|
||||
|
@ -505,6 +512,7 @@ namespace coreinit
|
|||
void* OSGetDefaultThreadStack(sint32 coreIndex, uint32& size);
|
||||
|
||||
bool OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop2, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType);
|
||||
bool __OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType);
|
||||
void OSCreateThreadInternal(OSThread_t* thread, uint32 entryPoint, MPTR stackLowerBaseAddr, uint32 stackSize, uint8 affinityMask, OSThread_t::THREAD_TYPE threadType);
|
||||
bool OSRunThread(OSThread_t* thread, MPTR funcAddress, sint32 numParam, void* ptrParam);
|
||||
void OSExitThread(sint32 exitValue);
|
||||
|
@ -519,8 +527,8 @@ namespace coreinit
|
|||
bool OSSetThreadPriority(OSThread_t* thread, sint32 newPriority);
|
||||
uint32 OSGetThreadAffinity(OSThread_t* thread);
|
||||
|
||||
void OSSetThreadName(OSThread_t* thread, char* name);
|
||||
char* OSGetThreadName(OSThread_t* thread);
|
||||
void OSSetThreadName(OSThread_t* thread, const char* name);
|
||||
const char* OSGetThreadName(OSThread_t* thread);
|
||||
|
||||
sint32 __OSResumeThreadInternal(OSThread_t* thread, sint32 resumeCount);
|
||||
sint32 OSResumeThread(OSThread_t* thread);
|
||||
|
@ -530,6 +538,7 @@ namespace coreinit
|
|||
void OSSuspendThread(OSThread_t* thread);
|
||||
void OSSleepThread(OSThreadQueue* threadQueue);
|
||||
void OSWakeupThread(OSThreadQueue* threadQueue);
|
||||
bool OSJoinThread(OSThread_t* thread, uint32be* exitValue);
|
||||
|
||||
void OSTestThreadCancelInternal();
|
||||
|
||||
|
|
|
@ -22,10 +22,9 @@ namespace coreinit
|
|||
osLib_returnFromFunction(hCPU, (uint32)osTime);
|
||||
}
|
||||
|
||||
void export_OSGetTime(PPCInterpreter_t* hCPU)
|
||||
uint64 OSGetTime()
|
||||
{
|
||||
uint64 osTime = coreinit_getOSTime();
|
||||
osLib_returnFromFunction64(hCPU, osTime);
|
||||
return coreinit_getOSTime();
|
||||
}
|
||||
|
||||
void export_OSGetSystemTime(PPCInterpreter_t* hCPU)
|
||||
|
@ -360,7 +359,7 @@ namespace coreinit
|
|||
|
||||
void InitializeTimeAndCalendar()
|
||||
{
|
||||
osLib_addFunction("coreinit", "OSGetTime", export_OSGetTime);
|
||||
cafeExportRegister("coreinit", OSGetTime, LogType::Placeholder);
|
||||
osLib_addFunction("coreinit", "OSGetSystemTime", export_OSGetSystemTime);
|
||||
osLib_addFunction("coreinit", "OSGetTick", export_OSGetTick);
|
||||
osLib_addFunction("coreinit", "OSGetSystemTick", export_OSGetSystemTick);
|
||||
|
|
|
@ -45,7 +45,8 @@ namespace coreinit
|
|||
};
|
||||
|
||||
void OSTicksToCalendarTime(uint64 ticks, OSCalendarTime_t* calenderStruct);
|
||||
|
||||
uint64 OSGetTime();
|
||||
|
||||
uint64 coreinit_getOSTime();
|
||||
uint64 coreinit_getTimerTick();
|
||||
|
||||
|
|
|
@ -9,8 +9,29 @@ namespace drmapp
|
|||
return 1;
|
||||
}
|
||||
|
||||
uint32 PatchChkIsFinished()
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "drmapp.PatchChkIsFinished() - placeholder");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32 AocChkIsFinished()
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "drmapp.AocChkIsFinished() - placeholder");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32 TicketChkIsFinished()
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "drmapp.TicketChkIsFinished__3RplFv() - placeholder");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
cafeExportRegisterFunc(NupChkIsFinished, "drmapp", "NupChkIsFinished__3RplFv", LogType::Placeholder);
|
||||
cafeExportRegisterFunc(PatchChkIsFinished, "drmapp", "PatchChkIsFinished__3RplFv", LogType::Placeholder);
|
||||
cafeExportRegisterFunc(AocChkIsFinished, "drmapp", "AocChkIsFinished__3RplFv", LogType::Placeholder);
|
||||
cafeExportRegisterFunc(TicketChkIsFinished, "drmapp", "TicketChkIsFinished__3RplFv", LogType::Placeholder);
|
||||
}
|
||||
}
|
||||
} // namespace drmapp
|
||||
|
|
|
@ -277,10 +277,11 @@ namespace erreula
|
|||
ImGui::SetNextWindowBgAlpha(0.9f);
|
||||
ImGui::PushFont(font);
|
||||
|
||||
std::string title = "ErrEula";
|
||||
std::string title;
|
||||
if (appearArg.title)
|
||||
title = boost::nowide::narrow(GetText(appearArg.title.GetPtr()));
|
||||
|
||||
if(title.empty()) // ImGui doesn't allow empty titles, so set one if appearArg.title is not set or empty
|
||||
title = "ErrEula";
|
||||
if (ImGui::Begin(title.c_str(), nullptr, kPopupFlags))
|
||||
{
|
||||
const float startx = ImGui::GetWindowSize().x / 2.0f;
|
||||
|
|
|
@ -19,5 +19,7 @@ namespace GX2
|
|||
void GX2SetTVBuffer(void* imageBuffePtr, uint32 imageBufferSize, E_TVRES tvResolutionMode, uint32 surfaceFormat, E_TVBUFFERMODE bufferMode);
|
||||
void GX2SetTVGamma(float gamma);
|
||||
|
||||
void GX2Invalidate(uint32 invalidationFlags, MPTR invalidationAddr, uint32 invalidationSize);
|
||||
|
||||
void GX2MiscInit();
|
||||
};
|
|
@ -1,4 +1,5 @@
|
|||
#include "Cafe/OS/common/OSCommon.h"
|
||||
#include "Cafe/OS/common/OSUtil.h"
|
||||
#include "Cafe/HW/Espresso/PPCCallback.h"
|
||||
#include "nlibcurl.h"
|
||||
|
||||
|
@ -6,6 +7,8 @@
|
|||
#include "openssl/x509.h"
|
||||
#include "openssl/ssl.h"
|
||||
|
||||
#define CURL_STRICTER
|
||||
|
||||
#include "curl/curl.h"
|
||||
#include <unordered_map>
|
||||
#include <atomic>
|
||||
|
@ -98,6 +101,17 @@ struct MEMPTRHash_t
|
|||
}
|
||||
};
|
||||
|
||||
struct WU_curl_slist
|
||||
{
|
||||
MEMPTR<char> data;
|
||||
MEMPTR<WU_curl_slist> next;
|
||||
};
|
||||
|
||||
enum class WU_CURLcode
|
||||
{
|
||||
placeholder = 0,
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
sint32 initialized;
|
||||
|
@ -110,8 +124,53 @@ struct
|
|||
MEMPTR<curl_calloc_callback> calloc;
|
||||
} g_nlibcurl = {};
|
||||
|
||||
using WU_CURL_off_t = uint64be;
|
||||
|
||||
#pragma pack(1)
|
||||
enum class WU_HTTPREQ : uint32
|
||||
{
|
||||
HTTPREQ_GET = 0x1,
|
||||
HTTPREQ_POST = 0x2,
|
||||
UKN_3 = 0x3,
|
||||
};
|
||||
|
||||
struct WU_UserDefined
|
||||
{
|
||||
// starting at 0xD8 (probably) in CURL_t
|
||||
/* 0x0D8 / +0x00 */ uint32be ukn0D8;
|
||||
/* 0x0DC / +0x04 */ uint32be ukn0DC;
|
||||
/* 0x0E0 / +0x08 */ MEMPTR<WU_curl_slist> headers;
|
||||
/* 0x0E4 / +0x0C */ uint32be ukn0E4;
|
||||
/* 0x0E8 / +0x10 */ uint32be ukn0E8;
|
||||
/* 0x0EC / +0x14 */ uint32be ukn0EC;
|
||||
/* 0x0F0 / +0x18 */ uint32be ukn0F0[4];
|
||||
/* 0x100 / +0x28 */ uint32be ukn100[4];
|
||||
/* 0x110 / +0x38 */ uint32be ukn110[4]; // +0x40 -> WU_CURL_off_t postfieldsize ?
|
||||
/* 0x120 / +0x48 */ uint32be ukn120[4];
|
||||
/* 0x130 / +0x58 */ uint32be ukn130[4];
|
||||
/* 0x140 / +0x68 */ uint32be ukn140[4];
|
||||
/* 0x150 / +0x78 */ uint32be ukn150[4];
|
||||
/* 0x160 / +0x88 */ uint32be ukn160[4];
|
||||
/* 0x170 / +0x98 */ uint32be ukn170[4];
|
||||
/* 0x180 / +0xA8 */ uint32be ukn180[4];
|
||||
/* 0x190 / +0xB0 */ sint64be infilesize_190{0};
|
||||
/* 0x198 / +0xB8 */ uint32be ukn198;
|
||||
/* 0x19C / +0xBC */ uint32be ukn19C;
|
||||
/* 0x1A0 / +0xC8 */ uint32be ukn1A0[4];
|
||||
/* 0x1B0 / +0xD8 */ uint32be ukn1B0[4];
|
||||
/* 0x1C0 / +0xE8 */ uint32be ukn1C0[4];
|
||||
/* 0x1D0 / +0xF8 */ uint32be ukn1D0[4];
|
||||
/* 0x1E0 / +0x108 */ uint32be ukn1E0;
|
||||
/* 0x1E4 / +0x108 */ uint32be ukn1E4;
|
||||
/* 0x1E8 / +0x108 */ uint32be ukn1E8;
|
||||
/* 0x1EC / +0x108 */ betype<WU_HTTPREQ> httpreq_1EC;
|
||||
/* 0x1F0 / +0x118 */ uint32be ukn1F0[4];
|
||||
|
||||
void SetToDefault()
|
||||
{
|
||||
memset(this, 0, sizeof(WU_UserDefined));
|
||||
httpreq_1EC = WU_HTTPREQ::HTTPREQ_GET;
|
||||
}
|
||||
};
|
||||
|
||||
struct CURL_t
|
||||
{
|
||||
|
@ -137,6 +196,7 @@ struct CURL_t
|
|||
OSThread_t* curlThread;
|
||||
MEMPTR<char> info_redirectUrl; // stores CURLINFO_REDIRECT_URL ptr
|
||||
MEMPTR<char> info_contentType; // stores CURLINFO_CONTENT_TYPE ptr
|
||||
bool isDirty{true};
|
||||
|
||||
// debug
|
||||
struct
|
||||
|
@ -149,10 +209,44 @@ struct CURL_t
|
|||
FileStream* file_responseRaw{};
|
||||
}debug;
|
||||
|
||||
// fields below match the actual memory layout, above still needs refactoring
|
||||
/* 0x78 */ uint32be ukn078;
|
||||
/* 0x7C */ uint32be ukn07C;
|
||||
/* 0x80 */ uint32be ukn080;
|
||||
/* 0x84 */ uint32be ukn084;
|
||||
/* 0x88 */ uint32be ukn088;
|
||||
/* 0x8C */ uint32be ukn08C;
|
||||
/* 0x90 */ uint32be ukn090[4];
|
||||
/* 0xA0 */ uint32be ukn0A0[4];
|
||||
/* 0xB0 */ uint32be ukn0B0[4];
|
||||
/* 0xC0 */ uint32be ukn0C0[4];
|
||||
/* 0xD0 */ uint32be ukn0D0;
|
||||
/* 0xD4 */ uint32be ukn0D4;
|
||||
/* 0xD8 */ WU_UserDefined set;
|
||||
/* 0x200 */ uint32be ukn200[4];
|
||||
/* 0x210 */ uint32be ukn210[4];
|
||||
/* 0x220 */ uint32be ukn220[4];
|
||||
/* 0x230 */ uint32be ukn230[4];
|
||||
/* 0x240 */ uint32be ukn240[4];
|
||||
/* 0x250 */ uint32be ukn250[4];
|
||||
/* 0x260 */ uint32be ukn260[4];
|
||||
/* 0x270 */ uint32be ukn270[4];
|
||||
/* 0x280 */ uint8be ukn280;
|
||||
/* 0x281 */ uint8be opt_no_body_281;
|
||||
/* 0x282 */ uint8be ukn282;
|
||||
/* 0x283 */ uint8be upload_283;
|
||||
};
|
||||
static_assert(sizeof(CURL_t) <= 0x8698);
|
||||
static_assert(offsetof(CURL_t, ukn078) == 0x78);
|
||||
static_assert(offsetof(CURL_t, set) == 0xD8);
|
||||
static_assert(offsetof(CURL_t, set) + offsetof(WU_UserDefined, headers) == 0xE0);
|
||||
static_assert(offsetof(CURL_t, set) + offsetof(WU_UserDefined, infilesize_190) == 0x190);
|
||||
static_assert(offsetof(CURL_t, set) + offsetof(WU_UserDefined, httpreq_1EC) == 0x1EC);
|
||||
static_assert(offsetof(CURL_t, opt_no_body_281) == 0x281);
|
||||
typedef MEMPTR<CURL_t> CURLPtr;
|
||||
|
||||
#pragma pack(1) // may affect structs below, we can probably remove this but lets keep it for now as the code below is fragile
|
||||
|
||||
typedef struct
|
||||
{
|
||||
//uint32be specifier; // 0x00
|
||||
|
@ -173,18 +267,12 @@ typedef MEMPTR<CURLSH_t> CURLSHPtr;
|
|||
typedef struct
|
||||
{
|
||||
CURLM* curlm;
|
||||
std::vector< MEMPTR<CURL> > curl;
|
||||
std::vector<MEMPTR<CURL_t>> curl;
|
||||
}CURLM_t;
|
||||
static_assert(sizeof(CURLM_t) <= 0x80, "sizeof(CURLM_t)");
|
||||
typedef MEMPTR<CURLM_t> CURLMPtr;
|
||||
|
||||
struct curl_slist_t
|
||||
{
|
||||
MEMPTR<char> data;
|
||||
MEMPTR<curl_slist_t> next;
|
||||
};
|
||||
|
||||
static_assert(sizeof(curl_slist_t) <= 0x8, "sizeof(curl_slist_t)");
|
||||
static_assert(sizeof(WU_curl_slist) <= 0x8, "sizeof(curl_slist_t)");
|
||||
|
||||
struct CURLMsg_t
|
||||
{
|
||||
|
@ -298,6 +386,94 @@ uint32 SendOrderToWorker(CURL_t* curl, QueueOrder order, uint32 arg1 = 0)
|
|||
return result;
|
||||
}
|
||||
|
||||
static int curl_closesocket(void *clientp, curl_socket_t item)
|
||||
{
|
||||
nsysnet_notifyCloseSharedSocket((SOCKET)item);
|
||||
closesocket(item);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _curl_set_default_parameters(CURL_t* curl)
|
||||
{
|
||||
curl->set.SetToDefault();
|
||||
|
||||
// default parameters
|
||||
curl_easy_setopt(curl->curl, CURLOPT_HEADERFUNCTION, header_callback);
|
||||
curl_easy_setopt(curl->curl, CURLOPT_HEADERDATA, curl);
|
||||
|
||||
curl_easy_setopt(curl->curl, CURLOPT_CLOSESOCKETFUNCTION, curl_closesocket);
|
||||
curl_easy_setopt(curl->curl, CURLOPT_CLOSESOCKETDATA, nullptr);
|
||||
}
|
||||
|
||||
void _curl_sync_parameters(CURL_t* curl)
|
||||
{
|
||||
// sync ppc curl to actual curl state
|
||||
// not all parameters are covered yet, many are still set directly in easy_setopt
|
||||
bool isPost = curl->set.httpreq_1EC == WU_HTTPREQ::HTTPREQ_POST;
|
||||
// http request type
|
||||
if(curl->set.httpreq_1EC == WU_HTTPREQ::HTTPREQ_GET)
|
||||
{
|
||||
::curl_easy_setopt(curl->curl, CURLOPT_HTTPGET, 1);
|
||||
cemu_assert_debug(curl->opt_no_body_281 == 0);
|
||||
cemu_assert_debug(curl->upload_283 == 0);
|
||||
}
|
||||
else if(curl->set.httpreq_1EC == WU_HTTPREQ::HTTPREQ_POST)
|
||||
{
|
||||
::curl_easy_setopt(curl->curl, CURLOPT_POST, 1);
|
||||
cemu_assert_debug(curl->upload_283 == 0);
|
||||
::curl_easy_setopt(curl->curl, CURLOPT_NOBODY, curl->opt_no_body_281 ? 1 : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
|
||||
// CURLOPT_HTTPHEADER
|
||||
std::optional<uint64> manualHeaderContentLength;
|
||||
if (curl->set.headers)
|
||||
{
|
||||
struct curl_slist* list = nullptr;
|
||||
WU_curl_slist* ppcList = curl->set.headers;
|
||||
while(ppcList)
|
||||
{
|
||||
if(isPost)
|
||||
{
|
||||
// for recent libcurl manually adding Content-Length header is undefined behavior. Instead CURLOPT_INFILESIZE(_LARGE) should be set
|
||||
// here we remove Content-Length and instead substitute it with CURLOPT_INFILESIZE (NEX DataStore in Super Mario Maker requires this)
|
||||
if(strncmp(ppcList->data.GetPtr(), "Content-Length:", 15) == 0)
|
||||
{
|
||||
manualHeaderContentLength = std::stoull(ppcList->data.GetPtr() + 15);
|
||||
ppcList = ppcList->next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
cemuLog_logDebug(LogType::Force, "curl_slist_append: {}", ppcList->data.GetPtr());
|
||||
curlDebug_logEasySetOptStr(curl, "CURLOPT_HTTPHEADER", (const char*)ppcList->data.GetPtr());
|
||||
list = ::curl_slist_append(list, ppcList->data.GetPtr());
|
||||
ppcList = ppcList->next;
|
||||
}
|
||||
::curl_easy_setopt(curl->curl, CURLOPT_HTTPHEADER, list);
|
||||
// todo - prevent leaking of list (maybe store in host curl object, similar to how our zlib implementation does stuff)
|
||||
}
|
||||
else
|
||||
::curl_easy_setopt(curl->curl, CURLOPT_HTTPHEADER, nullptr);
|
||||
|
||||
// infile size (post data size)
|
||||
if (curl->set.infilesize_190)
|
||||
{
|
||||
cemu_assert_debug(manualHeaderContentLength == 0); // should not have both?
|
||||
::curl_easy_setopt(curl->curl, CURLOPT_INFILESIZE_LARGE, curl->set.infilesize_190);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isPost && manualHeaderContentLength > 0)
|
||||
::curl_easy_setopt(curl->curl, CURLOPT_INFILESIZE_LARGE, manualHeaderContentLength);
|
||||
else
|
||||
::curl_easy_setopt(curl->curl, CURLOPT_INFILESIZE_LARGE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void export_malloc(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamU32(size, 0);
|
||||
|
@ -340,7 +516,6 @@ void export_realloc(PPCInterpreter_t* hCPU)
|
|||
osLib_returnFromFunction(hCPU, result.GetMPTR());
|
||||
}
|
||||
|
||||
|
||||
CURLcode curl_global_init(uint32 flags)
|
||||
{
|
||||
if (g_nlibcurl.initialized++)
|
||||
|
@ -436,6 +611,18 @@ void export_curl_multi_perform(PPCInterpreter_t* hCPU)
|
|||
|
||||
//cemuLog_logDebug(LogType::Force, "curl_multi_perform(0x{:08x}, 0x{:08x})", curlm.GetMPTR(), runningHandles.GetMPTR());
|
||||
|
||||
//curl_multi_get_handles(curlm->curlm);
|
||||
|
||||
for(auto _curl : curlm->curl)
|
||||
{
|
||||
CURL_t* curl = (CURL_t*)_curl.GetPtr();
|
||||
if(curl->isDirty)
|
||||
{
|
||||
curl->isDirty = false;
|
||||
_curl_sync_parameters(curl);
|
||||
}
|
||||
}
|
||||
|
||||
//g_callerQueue = curlm->callerQueue;
|
||||
//g_threadQueue = curlm->threadQueue;
|
||||
int tempRunningHandles = 0;
|
||||
|
@ -555,7 +742,7 @@ void export_curl_multi_info_read(PPCInterpreter_t* hCPU)
|
|||
if (msg->easy_handle)
|
||||
{
|
||||
const auto it = find_if(curlm->curl.cbegin(), curlm->curl.cend(),
|
||||
[msg](const MEMPTR<void>& curl)
|
||||
[msg](const MEMPTR<CURL_t>& curl)
|
||||
{
|
||||
const MEMPTR<CURL_t> _curl{ curl };
|
||||
return _curl->curl = msg->easy_handle;
|
||||
|
@ -661,63 +848,30 @@ void export_curl_share_cleanup(PPCInterpreter_t* hCPU)
|
|||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
int my_trace(CURL *handle, curl_infotype type, char *ptr, size_t size,
|
||||
void *userp)
|
||||
{
|
||||
FILE* f = (FILE*)userp;
|
||||
|
||||
//if (type == CURLINFO_TEXT)
|
||||
{
|
||||
char tmp[1024] = {};
|
||||
sprintf(tmp, "0x%p: ", handle);
|
||||
fwrite(tmp, 1, strlen(tmp), f);
|
||||
|
||||
memcpy(tmp, ptr, std::min(size, (size_t)990));
|
||||
fwrite(tmp, 1, std::min(size + 1, (size_t)991), f);
|
||||
|
||||
fflush(f);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int curl_closesocket(void *clientp, curl_socket_t item)
|
||||
{
|
||||
nsysnet_notifyCloseSharedSocket((SOCKET)item);
|
||||
closesocket(item);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void export_curl_easy_init(PPCInterpreter_t* hCPU)
|
||||
CURL_t* curl_easy_init()
|
||||
{
|
||||
if (g_nlibcurl.initialized == 0)
|
||||
{
|
||||
if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK)
|
||||
{
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Curl_open
|
||||
CURLPtr result{ PPCCoreCallback(g_nlibcurl.calloc.GetMPTR(), (uint32)1, ppcsizeof<CURL_t>()) };
|
||||
MEMPTR<CURL_t> result{ PPCCoreCallback(g_nlibcurl.calloc.GetMPTR(), (uint32)1, ppcsizeof<CURL_t>()) };
|
||||
cemuLog_logDebug(LogType::Force, "curl_easy_init() -> 0x{:08x}", result.GetMPTR());
|
||||
if (result)
|
||||
{
|
||||
memset(result.GetPtr(), 0, sizeof(CURL_t));
|
||||
*result = {};
|
||||
result->curl = curl_easy_init();
|
||||
result->curl = ::curl_easy_init();
|
||||
result->curlThread = coreinit::OSGetCurrentThread();
|
||||
|
||||
result->info_contentType = nullptr;
|
||||
result->info_redirectUrl = nullptr;
|
||||
|
||||
// default parameters
|
||||
curl_easy_setopt(result->curl, CURLOPT_HEADERFUNCTION, header_callback);
|
||||
curl_easy_setopt(result->curl, CURLOPT_HEADERDATA, result.GetPtr());
|
||||
|
||||
curl_easy_setopt(result->curl, CURLOPT_CLOSESOCKETFUNCTION, curl_closesocket);
|
||||
curl_easy_setopt(result->curl, CURLOPT_CLOSESOCKETDATA, nullptr);
|
||||
_curl_set_default_parameters(result.GetPtr());
|
||||
|
||||
if (g_nlibcurl.proxyConfig)
|
||||
{
|
||||
|
@ -725,7 +879,12 @@ void export_curl_easy_init(PPCInterpreter_t* hCPU)
|
|||
}
|
||||
}
|
||||
|
||||
osLib_returnFromFunction(hCPU, result.GetMPTR());
|
||||
return result;
|
||||
}
|
||||
|
||||
CURL_t* mw_curl_easy_init()
|
||||
{
|
||||
return curl_easy_init();
|
||||
}
|
||||
|
||||
void export_curl_easy_pause(PPCInterpreter_t* hCPU)
|
||||
|
@ -971,18 +1130,47 @@ void export_curl_easy_setopt(PPCInterpreter_t* hCPU)
|
|||
ppcDefineParamU64(parameterU64, 2);
|
||||
|
||||
CURL* curlObj = curl->curl;
|
||||
curl->isDirty = true;
|
||||
|
||||
CURLcode result = CURLE_OK;
|
||||
switch (option)
|
||||
{
|
||||
case CURLOPT_NOSIGNAL:
|
||||
case CURLOPT_POST:
|
||||
{
|
||||
if(parameter)
|
||||
{
|
||||
curl->set.httpreq_1EC = WU_HTTPREQ::HTTPREQ_POST;
|
||||
curl->opt_no_body_281 = 0;
|
||||
}
|
||||
else
|
||||
curl->set.httpreq_1EC = WU_HTTPREQ::HTTPREQ_GET;
|
||||
break;
|
||||
}
|
||||
case CURLOPT_HTTPGET:
|
||||
{
|
||||
if (parameter)
|
||||
{
|
||||
curl->set.httpreq_1EC = WU_HTTPREQ::HTTPREQ_GET;
|
||||
curl->opt_no_body_281 = 0;
|
||||
curl->upload_283 = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CURLOPT_INFILESIZE:
|
||||
{
|
||||
curl->set.infilesize_190 = (sint64)(sint32)(uint32)parameter.GetBEValue();
|
||||
break;
|
||||
}
|
||||
case CURLOPT_INFILESIZE_LARGE:
|
||||
{
|
||||
curl->set.infilesize_190 = (sint64)(uint64)parameterU64;
|
||||
break;
|
||||
}
|
||||
case CURLOPT_NOSIGNAL:
|
||||
case CURLOPT_FOLLOWLOCATION:
|
||||
case CURLOPT_BUFFERSIZE:
|
||||
case CURLOPT_TIMEOUT:
|
||||
case CURLOPT_CONNECTTIMEOUT_MS:
|
||||
case CURLOPT_POST:
|
||||
case CURLOPT_INFILESIZE:
|
||||
case CURLOPT_NOPROGRESS:
|
||||
case CURLOPT_LOW_SPEED_LIMIT:
|
||||
case CURLOPT_LOW_SPEED_TIME:
|
||||
|
@ -1068,8 +1256,6 @@ void export_curl_easy_setopt(PPCInterpreter_t* hCPU)
|
|||
curlSh->curl = curl;
|
||||
shObj = curlSh->curlsh;
|
||||
}
|
||||
|
||||
|
||||
result = ::curl_easy_setopt(curlObj, CURLOPT_SHARE, shObj);
|
||||
break;
|
||||
}
|
||||
|
@ -1101,17 +1287,8 @@ void export_curl_easy_setopt(PPCInterpreter_t* hCPU)
|
|||
}
|
||||
case CURLOPT_HTTPHEADER:
|
||||
{
|
||||
struct curl_slist* list = nullptr;
|
||||
bool isFirst = true;
|
||||
for (curl_slist_t* ppcList = (curl_slist_t*)parameter.GetPtr(); ppcList; ppcList = ppcList->next.GetPtr())
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "curl_slist_append: {}", ppcList->data.GetPtr());
|
||||
curlDebug_logEasySetOptStr(curl.GetPtr(), isFirst?"CURLOPT_HTTPHEADER" : "CURLOPT_HTTPHEADER(continue)", (const char*)ppcList->data.GetPtr());
|
||||
list = ::curl_slist_append(list, ppcList->data.GetPtr());
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
result = ::curl_easy_setopt(curlObj, CURLOPT_HTTPHEADER, list);
|
||||
curl->set.headers = (WU_curl_slist*)parameter.GetPtr();
|
||||
result = CURLE_OK;
|
||||
break;
|
||||
}
|
||||
case CURLOPT_SOCKOPTFUNCTION:
|
||||
|
@ -1163,15 +1340,18 @@ void export_curl_easy_setopt(PPCInterpreter_t* hCPU)
|
|||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
void export_curl_easy_perform(PPCInterpreter_t* hCPU)
|
||||
WU_CURLcode curl_easy_perform(CURL_t* curl)
|
||||
{
|
||||
ppcDefineParamMEMPTR(curl, CURL_t, 0);
|
||||
curlDebug_markActiveRequest(curl.GetPtr());
|
||||
curlDebug_notifySubmitRequest(curl.GetPtr());
|
||||
cemuLog_logDebug(LogType::Force, "curl_easy_perform(0x{:08x})", curl.GetMPTR());
|
||||
const uint32 result = SendOrderToWorker(curl.GetPtr(), QueueOrder_Perform);
|
||||
cemuLog_logDebug(LogType::Force, "curl_easy_perform(0x{:08x}) -> 0x{:x} DONE", curl.GetMPTR(), result);
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
curlDebug_markActiveRequest(curl);
|
||||
curlDebug_notifySubmitRequest(curl);
|
||||
|
||||
if(curl->isDirty)
|
||||
{
|
||||
curl->isDirty = false;
|
||||
_curl_sync_parameters(curl);
|
||||
}
|
||||
const uint32 result = SendOrderToWorker(curl, QueueOrder_Perform);
|
||||
return static_cast<WU_CURLcode>(result);
|
||||
}
|
||||
|
||||
void _updateGuestString(CURL_t* curl, MEMPTR<char>& ppcStr, char* hostStr)
|
||||
|
@ -1221,12 +1401,10 @@ void export_curl_easy_getinfo(PPCInterpreter_t* hCPU)
|
|||
}
|
||||
case CURLINFO_CONTENT_TYPE:
|
||||
{
|
||||
//cemuLog_logDebug(LogType::Force, "CURLINFO_CONTENT_TYPE not supported");
|
||||
//*(uint32*)parameter.GetPtr() = MPTR_NULL;
|
||||
char* contentType = nullptr;
|
||||
result = curl_easy_getinfo(curlObj, CURLINFO_REDIRECT_URL, &contentType);
|
||||
_updateGuestString(curl.GetPtr(), curl->info_contentType, contentType);
|
||||
*(uint32*)parameter.GetPtr() = curl->info_contentType.GetMPTRBE();
|
||||
*(MEMPTR<char>*)parameter.GetPtr() = curl->info_contentType;
|
||||
break;
|
||||
}
|
||||
case CURLINFO_REDIRECT_URL:
|
||||
|
@ -1234,7 +1412,7 @@ void export_curl_easy_getinfo(PPCInterpreter_t* hCPU)
|
|||
char* redirectUrl = nullptr;
|
||||
result = curl_easy_getinfo(curlObj, CURLINFO_REDIRECT_URL, &redirectUrl);
|
||||
_updateGuestString(curl.GetPtr(), curl->info_redirectUrl, redirectUrl);
|
||||
*(uint32*)parameter.GetPtr() = curl->info_redirectUrl.GetMPTRBE();
|
||||
*(MEMPTR<char>*)parameter.GetPtr() = curl->info_redirectUrl;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -1246,14 +1424,6 @@ void export_curl_easy_getinfo(PPCInterpreter_t* hCPU)
|
|||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void export_curl_global_init(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamU32(flags, 0);
|
||||
osLib_returnFromFunction(hCPU, curl_global_init(flags));
|
||||
}
|
||||
|
||||
void export_curl_easy_strerror(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamU32(code, 0);
|
||||
|
@ -1270,21 +1440,16 @@ void export_curl_easy_strerror(PPCInterpreter_t* hCPU)
|
|||
osLib_returnFromFunction(hCPU, result.GetMPTR());
|
||||
}
|
||||
|
||||
void export_curl_slist_append(PPCInterpreter_t* hCPU)
|
||||
WU_curl_slist* curl_slist_append(WU_curl_slist* list, const char* data)
|
||||
{
|
||||
ppcDefineParamMEMPTR(list, curl_slist_t, 0);
|
||||
ppcDefineParamMEMPTR(data, const char, 1);
|
||||
|
||||
|
||||
MEMPTR<char> dupdata{ PPCCoreCallback(g_nlibcurl.strdup.GetMPTR(), data.GetMPTR()) };
|
||||
MEMPTR<char> dupdata{ PPCCoreCallback(g_nlibcurl.strdup.GetMPTR(), data) };
|
||||
if (!dupdata)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "curl_slist_append(0x{:08x}, 0x{:08x} [{}]) -> 0x00000000", list.GetMPTR(), data.GetMPTR(), data.GetPtr());
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
return;
|
||||
cemuLog_logDebug(LogType::Force, "curl_slist_append(): Failed to duplicate string");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MEMPTR<curl_slist_t> result{ PPCCoreCallback(g_nlibcurl.malloc.GetMPTR(), ppcsizeof<curl_slist_t>()) };
|
||||
MEMPTR<WU_curl_slist> result{ PPCCoreCallback(g_nlibcurl.malloc.GetMPTR(), ppcsizeof<WU_curl_slist>()) };
|
||||
if (result)
|
||||
{
|
||||
result->data = dupdata;
|
||||
|
@ -1293,7 +1458,7 @@ void export_curl_slist_append(PPCInterpreter_t* hCPU)
|
|||
// update last obj of list
|
||||
if (list)
|
||||
{
|
||||
MEMPTR<curl_slist_t> tmp = list;
|
||||
MEMPTR<WU_curl_slist> tmp = list;
|
||||
while (tmp->next)
|
||||
{
|
||||
tmp = tmp->next;
|
||||
|
@ -1303,38 +1468,24 @@ void export_curl_slist_append(PPCInterpreter_t* hCPU)
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "curl_slist_append(): Failed to allocate memory");
|
||||
PPCCoreCallback(g_nlibcurl.free.GetMPTR(), dupdata.GetMPTR());
|
||||
|
||||
cemuLog_logDebug(LogType::Force, "curl_slist_append(0x{:08x}, 0x{:08x} [{}]) -> 0x{:08x}", list.GetMPTR(), data.GetMPTR(), data.GetPtr(), result.GetMPTR());
|
||||
}
|
||||
if(list)
|
||||
osLib_returnFromFunction(hCPU, list.GetMPTR());
|
||||
else
|
||||
osLib_returnFromFunction(hCPU, result.GetMPTR());
|
||||
return list;
|
||||
return result;
|
||||
}
|
||||
|
||||
void export_curl_slist_free_all(PPCInterpreter_t* hCPU)
|
||||
void curl_slist_free_all(WU_curl_slist* list)
|
||||
{
|
||||
ppcDefineParamMEMPTR(list, curl_slist_t, 0);
|
||||
|
||||
cemuLog_logDebug(LogType::Force, "export_curl_slist_free_all: TODO");
|
||||
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
void export_curl_global_init_mem(PPCInterpreter_t* hCPU)
|
||||
CURLcode curl_global_init_mem(uint32 flags, MEMPTR<curl_malloc_callback> malloc_callback, MEMPTR<curl_free_callback> free_callback, MEMPTR<curl_realloc_callback> realloc_callback, MEMPTR<curl_strdup_callback> strdup_callback, MEMPTR<curl_calloc_callback> calloc_callback)
|
||||
{
|
||||
ppcDefineParamU32(flags, 0);
|
||||
ppcDefineParamMEMPTR(m, curl_malloc_callback, 1);
|
||||
ppcDefineParamMEMPTR(f, curl_free_callback, 2);
|
||||
ppcDefineParamMEMPTR(r, curl_realloc_callback, 3);
|
||||
ppcDefineParamMEMPTR(s, curl_strdup_callback, 4);
|
||||
ppcDefineParamMEMPTR(c, curl_calloc_callback, 5);
|
||||
|
||||
if (!m || !f || !r || !s || !c)
|
||||
{
|
||||
osLib_returnFromFunction(hCPU, CURLE_FAILED_INIT);
|
||||
return;
|
||||
}
|
||||
if(!malloc_callback || !free_callback || !realloc_callback || !strdup_callback || !calloc_callback)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
CURLcode result = CURLE_OK;
|
||||
if (g_nlibcurl.initialized == 0)
|
||||
|
@ -1342,31 +1493,30 @@ void export_curl_global_init_mem(PPCInterpreter_t* hCPU)
|
|||
result = curl_global_init(flags);
|
||||
if (result == CURLE_OK)
|
||||
{
|
||||
g_nlibcurl.malloc = m;
|
||||
g_nlibcurl.free = f;
|
||||
g_nlibcurl.realloc = r;
|
||||
g_nlibcurl.strdup = s;
|
||||
g_nlibcurl.calloc = c;
|
||||
g_nlibcurl.malloc = malloc_callback;
|
||||
g_nlibcurl.free = free_callback;
|
||||
g_nlibcurl.realloc = realloc_callback;
|
||||
g_nlibcurl.strdup = strdup_callback;
|
||||
g_nlibcurl.calloc = calloc_callback;
|
||||
}
|
||||
}
|
||||
|
||||
cemuLog_logDebug(LogType::Force, "curl_global_init_mem(0x{:x}, 0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x}) -> 0x{:08x}", flags, m.GetMPTR(), f.GetMPTR(), r.GetMPTR(), s.GetMPTR(), c.GetMPTR(), result);
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void load()
|
||||
{
|
||||
osLib_addFunction("nlibcurl", "curl_global_init_mem", export_curl_global_init_mem);
|
||||
osLib_addFunction("nlibcurl", "curl_global_init", export_curl_global_init);
|
||||
cafeExportRegister("nlibcurl", curl_global_init_mem, LogType::nlibcurl);
|
||||
cafeExportRegister("nlibcurl", curl_global_init, LogType::nlibcurl);
|
||||
|
||||
osLib_addFunction("nlibcurl", "curl_slist_append", export_curl_slist_append);
|
||||
osLib_addFunction("nlibcurl", "curl_slist_free_all", export_curl_slist_free_all);
|
||||
cafeExportRegister("nlibcurl", curl_slist_append, LogType::nlibcurl);
|
||||
cafeExportRegister("nlibcurl", curl_slist_free_all, LogType::nlibcurl);
|
||||
osLib_addFunction("nlibcurl", "curl_easy_strerror", export_curl_easy_strerror);
|
||||
|
||||
osLib_addFunction("nlibcurl", "curl_share_init", export_curl_share_init);
|
||||
osLib_addFunction("nlibcurl", "curl_share_setopt", export_curl_share_setopt);
|
||||
osLib_addFunction("nlibcurl", "curl_share_cleanup", export_curl_share_cleanup);
|
||||
|
||||
cafeExportRegister("nlibcurl", mw_curl_easy_init, LogType::nlibcurl);
|
||||
osLib_addFunction("nlibcurl", "curl_multi_init", export_curl_multi_init);
|
||||
osLib_addFunction("nlibcurl", "curl_multi_add_handle", export_curl_multi_add_handle);
|
||||
osLib_addFunction("nlibcurl", "curl_multi_perform", export_curl_multi_perform);
|
||||
|
@ -1377,12 +1527,14 @@ void load()
|
|||
osLib_addFunction("nlibcurl", "curl_multi_cleanup", export_curl_multi_cleanup);
|
||||
osLib_addFunction("nlibcurl", "curl_multi_timeout", export_curl_multi_timeout);
|
||||
|
||||
osLib_addFunction("nlibcurl", "curl_easy_init", export_curl_easy_init);
|
||||
osLib_addFunction("nlibcurl", "mw_curl_easy_init", export_curl_easy_init);
|
||||
cafeExportRegister("nlibcurl", curl_easy_init, LogType::nlibcurl);
|
||||
osLib_addFunction("nlibcurl", "curl_easy_reset", export_curl_easy_reset);
|
||||
osLib_addFunction("nlibcurl", "curl_easy_setopt", export_curl_easy_setopt);
|
||||
osLib_addFunction("nlibcurl", "curl_easy_getinfo", export_curl_easy_getinfo);
|
||||
osLib_addFunction("nlibcurl", "curl_easy_perform", export_curl_easy_perform);
|
||||
cafeExportRegister("nlibcurl", curl_easy_perform, LogType::nlibcurl);
|
||||
|
||||
|
||||
|
||||
osLib_addFunction("nlibcurl", "curl_easy_cleanup", export_curl_easy_cleanup);
|
||||
osLib_addFunction("nlibcurl", "curl_easy_pause", export_curl_easy_pause);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "Common/FileStream.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
|
||||
using ACPDeviceType = iosu::acp::ACPDeviceType;
|
||||
|
||||
#define acpPrepareRequest() \
|
||||
StackAllocator<iosuAcpCemuRequest_t> _buf_acpRequest; \
|
||||
StackAllocator<ioBufferVector_t> _buf_bufferVector; \
|
||||
|
@ -30,12 +32,14 @@ namespace nn
|
|||
{
|
||||
namespace acp
|
||||
{
|
||||
ACPStatus _ACPConvertResultToACPStatus(uint32* nnResult, const char* functionName, uint32 someConstant)
|
||||
ACPStatus ACPConvertResultToACPStatus(uint32* nnResult, const char* functionName, uint32 lineNumber)
|
||||
{
|
||||
// todo
|
||||
return ACPStatus::SUCCESS;
|
||||
}
|
||||
|
||||
#define _ACPConvertResultToACPStatus(nnResult) ACPConvertResultToACPStatus(nnResult, __func__, __LINE__)
|
||||
|
||||
ACPStatus ACPGetApplicationBox(uint32be* applicationBox, uint64 titleId)
|
||||
{
|
||||
// todo
|
||||
|
@ -43,6 +47,12 @@ namespace acp
|
|||
return ACPStatus::SUCCESS;
|
||||
}
|
||||
|
||||
ACPStatus ACPGetOlvAccesskey(uint32be* accessKey)
|
||||
{
|
||||
nnResult r = iosu::acp::ACPGetOlvAccesskey(accessKey);
|
||||
return _ACPConvertResultToACPStatus(&r);
|
||||
}
|
||||
|
||||
bool sSaveDirMounted{false};
|
||||
|
||||
ACPStatus ACPMountSaveDir()
|
||||
|
@ -56,7 +66,7 @@ namespace acp
|
|||
const auto mlc = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/user/", high, low);
|
||||
FSCDeviceHostFS_Mount("/vol/save/", _pathToUtf8(mlc), FSC_PRIORITY_BASE);
|
||||
nnResult mountResult = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACP, 0);
|
||||
return _ACPConvertResultToACPStatus(&mountResult, "ACPMountSaveDir", 0x60);
|
||||
return _ACPConvertResultToACPStatus(&mountResult);
|
||||
}
|
||||
|
||||
ACPStatus ACPUnmountSaveDir()
|
||||
|
@ -66,201 +76,24 @@ namespace acp
|
|||
return ACPStatus::SUCCESS;
|
||||
}
|
||||
|
||||
uint64 _acpGetTimestamp()
|
||||
{
|
||||
return coreinit::coreinit_getOSTime() / ESPRESSO_TIMER_CLOCK;
|
||||
}
|
||||
|
||||
nnResult __ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType)
|
||||
{
|
||||
if (deviceType == UnknownType)
|
||||
{
|
||||
return (nnResult)0xA030FB80;
|
||||
}
|
||||
|
||||
// create or modify the saveinfo
|
||||
const auto saveinfoPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/meta/saveinfo.xml", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
auto saveinfoData = FileStream::LoadIntoMemory(saveinfoPath);
|
||||
if (saveinfoData && !saveinfoData->empty())
|
||||
{
|
||||
namespace xml = tinyxml2;
|
||||
xml::XMLDocument doc;
|
||||
tinyxml2::XMLError xmlError = doc.Parse((const char*)saveinfoData->data(), saveinfoData->size());
|
||||
if (xmlError == xml::XML_SUCCESS || xmlError == xml::XML_ERROR_EMPTY_DOCUMENT)
|
||||
{
|
||||
xml::XMLNode* child = doc.FirstChild();
|
||||
// check for declaration -> <?xml version="1.0" encoding="utf-8"?>
|
||||
if (!child || !child->ToDeclaration())
|
||||
{
|
||||
xml::XMLDeclaration* decl = doc.NewDeclaration();
|
||||
doc.InsertFirstChild(decl);
|
||||
}
|
||||
|
||||
xml::XMLElement* info = doc.FirstChildElement("info");
|
||||
if (!info)
|
||||
{
|
||||
info = doc.NewElement("info");
|
||||
doc.InsertEndChild(info);
|
||||
}
|
||||
|
||||
// find node with persistentId
|
||||
char tmp[64];
|
||||
sprintf(tmp, "%08x", persistentId);
|
||||
bool foundNode = false;
|
||||
for (xml::XMLElement* account = info->FirstChildElement("account"); account; account = account->NextSiblingElement("account"))
|
||||
{
|
||||
if (account->Attribute("persistentId", tmp))
|
||||
{
|
||||
// found the entry! -> update timestamp
|
||||
xml::XMLElement* timestamp = account->FirstChildElement("timestamp");
|
||||
sprintf(tmp, "%" PRIx64, _acpGetTimestamp());
|
||||
if (timestamp)
|
||||
timestamp->SetText(tmp);
|
||||
else
|
||||
{
|
||||
timestamp = doc.NewElement("timestamp");
|
||||
account->InsertFirstChild(timestamp);
|
||||
}
|
||||
|
||||
foundNode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundNode)
|
||||
{
|
||||
tinyxml2::XMLElement* account = doc.NewElement("account");
|
||||
{
|
||||
sprintf(tmp, "%08x", persistentId);
|
||||
account->SetAttribute("persistentId", tmp);
|
||||
|
||||
tinyxml2::XMLElement* timestamp = doc.NewElement("timestamp");
|
||||
{
|
||||
sprintf(tmp, "%" PRIx64, _acpGetTimestamp());
|
||||
timestamp->SetText(tmp);
|
||||
}
|
||||
|
||||
account->InsertFirstChild(timestamp);
|
||||
}
|
||||
|
||||
info->InsertFirstChild(account);
|
||||
}
|
||||
|
||||
// update file
|
||||
tinyxml2::XMLPrinter printer;
|
||||
doc.Print(&printer);
|
||||
FileStream* fs = FileStream::createFile2(saveinfoPath);
|
||||
if (fs)
|
||||
{
|
||||
fs->writeString(printer.CStr());
|
||||
delete fs;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NN_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ACPStatus ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType)
|
||||
{
|
||||
nnResult r = __ACPUpdateSaveTimeStamp(persistentId, titleId, deviceType);
|
||||
nnResult r = iosu::acp::ACPUpdateSaveTimeStamp(persistentId, titleId, deviceType);
|
||||
return ACPStatus::SUCCESS;
|
||||
}
|
||||
|
||||
void CreateSaveMetaFiles(uint32 persistentId, uint64 titleId)
|
||||
{
|
||||
std::string titlePath = CafeSystem::GetMlcStoragePath(CafeSystem::GetForegroundTitleId());
|
||||
|
||||
sint32 fscStatus;
|
||||
FSCVirtualFile* fscFile = fsc_open((titlePath + "/meta/meta.xml").c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus);
|
||||
if (fscFile)
|
||||
{
|
||||
sint32 fileSize = fsc_getFileSize(fscFile);
|
||||
|
||||
std::unique_ptr<uint8[]> fileContent = std::make_unique<uint8[]>(fileSize);
|
||||
fsc_readFile(fscFile, fileContent.get(), fileSize);
|
||||
fsc_close(fscFile);
|
||||
|
||||
const auto outPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/meta/meta.xml", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
|
||||
std::ofstream myFile(outPath, std::ios::out | std::ios::binary);
|
||||
myFile.write((char*)fileContent.get(), fileSize);
|
||||
myFile.close();
|
||||
}
|
||||
|
||||
fscFile = fsc_open((titlePath + "/meta/iconTex.tga").c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus);
|
||||
if (fscFile)
|
||||
{
|
||||
sint32 fileSize = fsc_getFileSize(fscFile);
|
||||
|
||||
std::unique_ptr<uint8[]> fileContent = std::make_unique<uint8[]>(fileSize);
|
||||
fsc_readFile(fscFile, fileContent.get(), fileSize);
|
||||
fsc_close(fscFile);
|
||||
|
||||
const auto outPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/meta/iconTex.tga", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
|
||||
std::ofstream myFile(outPath, std::ios::out | std::ios::binary);
|
||||
myFile.write((char*)fileContent.get(), fileSize);
|
||||
myFile.close();
|
||||
}
|
||||
|
||||
ACPUpdateSaveTimeStamp(persistentId, titleId, InternalDeviceType);
|
||||
}
|
||||
|
||||
nnResult CreateSaveDir(uint32 persistentId, ACPDeviceType type)
|
||||
{
|
||||
uint64 titleId = CafeSystem::GetForegroundTitleId();
|
||||
uint32 high = GetTitleIdHigh(titleId) & (~0xC);
|
||||
uint32 low = GetTitleIdLow(titleId);
|
||||
|
||||
sint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND;
|
||||
char path[256];
|
||||
|
||||
sprintf(path, "%susr/save/%08x/", "/vol/storage_mlc01/", high);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/meta/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/common", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/%08x", "/vol/storage_mlc01/", high, low, persistentId == 0 ? 0x80000001 : persistentId);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
// not sure about this
|
||||
sprintf(path, "%susr/boss/", "/vol/storage_mlc01/");
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/", "/vol/storage_mlc01/", high);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/common", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/%08x/", "/vol/storage_mlc01/", high, low, persistentId == 0 ? 0x80000001 : persistentId);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
// copy xml meta files
|
||||
CreateSaveMetaFiles(persistentId, titleId);
|
||||
|
||||
nnResult result = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACP, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
ACPStatus ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type)
|
||||
{
|
||||
nnResult result = CreateSaveDir(persistentId, type);
|
||||
return _ACPConvertResultToACPStatus(&result, "ACPCreateSaveDir", 0x2FA);
|
||||
}
|
||||
|
||||
ACPStatus ACPCheckApplicationDeviceEmulation(uint32be* isEmulated)
|
||||
{
|
||||
*isEmulated = 0;
|
||||
return ACPStatus::SUCCESS;
|
||||
}
|
||||
|
||||
ACPStatus ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type)
|
||||
{
|
||||
nnResult result = iosu::acp::ACPCreateSaveDir(persistentId, type);
|
||||
return _ACPConvertResultToACPStatus(&result);
|
||||
}
|
||||
|
||||
nnResult ACPCreateSaveDirEx(uint8 accountSlot, uint64 titleId)
|
||||
{
|
||||
acpPrepareRequest();
|
||||
|
@ -279,7 +112,7 @@ namespace acp
|
|||
ppcDefineParamU8(accountSlot, 0);
|
||||
ppcDefineParamU64(titleId, 2); // index 2 because of alignment -> guessed parameters
|
||||
nnResult result = ACPCreateSaveDirEx(accountSlot, titleId);
|
||||
osLib_returnFromFunction(hCPU, _ACPConvertResultToACPStatus(&result, "ACPCreateSaveDirEx", 0x300));
|
||||
osLib_returnFromFunction(hCPU, _ACPConvertResultToACPStatus(&result));
|
||||
}
|
||||
|
||||
void export_ACPGetSaveDataTitleIdList(PPCInterpreter_t* hCPU)
|
||||
|
@ -456,6 +289,18 @@ namespace acp
|
|||
osLib_returnFromFunction(hCPU, acpRequest->returnCode);
|
||||
}
|
||||
|
||||
uint32 ACPGetTitleMetaXml(uint64 titleId, acpMetaXml_t* acpMetaXml)
|
||||
{
|
||||
acpPrepareRequest();
|
||||
acpRequest->requestCode = IOSU_ACP_GET_TITLE_META_XML;
|
||||
acpRequest->ptr = acpMetaXml;
|
||||
acpRequest->titleId = titleId;
|
||||
|
||||
__depr__IOS_Ioctlv(IOS_DEVICE_ACP_MAIN, IOSU_ACP_REQUEST_CEMU, 1, 1, acpBufferVector);
|
||||
|
||||
return acpRequest->returnCode;
|
||||
}
|
||||
|
||||
void export_ACPIsOverAgeEx(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamU32(age, 0);
|
||||
|
@ -508,9 +353,12 @@ namespace acp
|
|||
|
||||
osLib_addFunction("nn_acp", "ACPGetTitleMetaDirByDevice", export_ACPGetTitleMetaDirByDevice);
|
||||
osLib_addFunction("nn_acp", "ACPGetTitleMetaXmlByDevice", export_ACPGetTitleMetaXmlByDevice);
|
||||
cafeExportRegister("nn_acp", ACPGetTitleMetaXml, LogType::Placeholder);
|
||||
|
||||
cafeExportRegister("nn_acp", ACPGetApplicationBox, LogType::Placeholder);
|
||||
|
||||
cafeExportRegister("nn_acp", ACPGetOlvAccesskey, LogType::Placeholder);
|
||||
|
||||
osLib_addFunction("nn_acp", "ACPIsOverAgeEx", export_ACPIsOverAgeEx);
|
||||
|
||||
osLib_addFunction("nn_acp", "ACPGetNetworkTime", export_ACPGetNetworkTime);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#include "Cafe/IOSU/legacy/iosu_acp.h"
|
||||
|
||||
namespace nn
|
||||
{
|
||||
|
@ -9,20 +10,13 @@ namespace acp
|
|||
SUCCESS = 0,
|
||||
};
|
||||
|
||||
enum ACPDeviceType
|
||||
{
|
||||
UnknownType = 0,
|
||||
InternalDeviceType = 1,
|
||||
USBDeviceType = 3,
|
||||
};
|
||||
|
||||
void CreateSaveMetaFiles(uint32 persistentId, uint64 titleId);
|
||||
using ACPDeviceType = iosu::acp::ACPDeviceType;
|
||||
|
||||
ACPStatus ACPGetApplicationBox(uint32be* applicationBox, uint64 titleId);
|
||||
ACPStatus ACPMountSaveDir();
|
||||
ACPStatus ACPUnmountSaveDir();
|
||||
ACPStatus ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type);
|
||||
ACPStatus ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType);;
|
||||
ACPStatus ACPCreateSaveDir(uint32 persistentId, iosu::acp::ACPDeviceType type);
|
||||
ACPStatus ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, iosu::acp::ACPDeviceType deviceType);
|
||||
|
||||
void load();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "nn_act.h"
|
||||
#include "Cafe/OS/libs/nn_common.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
#include "Common/CafeString.h"
|
||||
|
||||
sint32 numAccounts = 1;
|
||||
|
||||
|
@ -113,6 +114,7 @@ namespace act
|
|||
{
|
||||
memset(token, 0, sizeof(independentServiceToken_t));
|
||||
actPrepareRequest();
|
||||
actRequest->accountSlot = iosu::act::ACT_SLOT_CURRENT;
|
||||
actRequest->requestCode = IOSU_ARC_ACQUIREINDEPENDENTTOKEN;
|
||||
actRequest->titleId = CafeSystem::GetForegroundTitleId();
|
||||
actRequest->titleVersion = CafeSystem::GetForegroundTitleVersion();
|
||||
|
@ -140,6 +142,14 @@ namespace act
|
|||
return 0;
|
||||
}
|
||||
|
||||
nnResult GetTimeZoneId(CafeString<65>* outTimezoneId)
|
||||
{
|
||||
// return a placeholder timezone id for now
|
||||
// in the future we should emulated this correctly and read the timezone from the account via IOSU
|
||||
outTimezoneId->assign("Europe/London");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sint32 g_initializeCount = 0; // inc in Initialize and dec in Finalize
|
||||
uint32 Initialize()
|
||||
{
|
||||
|
@ -162,7 +172,6 @@ namespace act
|
|||
NN_ERROR_CODE errCode = NNResultToErrorCode(*nnResult, NN_RESULT_MODULE_NN_ACT);
|
||||
return errCode;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,6 +308,22 @@ void nnActExport_GetPrincipalIdEx(PPCInterpreter_t* hCPU)
|
|||
osLib_returnFromFunction(hCPU, 0); // ResultSuccess
|
||||
}
|
||||
|
||||
void nnActExport_GetTransferableId(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamU32(unique, 0);
|
||||
|
||||
cemuLog_logDebug(LogType::Force, "nn_act.GetTransferableId(0x{:08x})", hCPU->gpr[3]);
|
||||
|
||||
uint64 transferableId;
|
||||
uint32 r = nn::act::GetTransferableIdEx(&transferableId, unique, iosu::act::ACT_SLOT_CURRENT);
|
||||
if (NN_RESULT_IS_FAILURE(r))
|
||||
{
|
||||
transferableId = 0;
|
||||
}
|
||||
|
||||
osLib_returnFromFunction64(hCPU, _swapEndianU64(transferableId));
|
||||
}
|
||||
|
||||
void nnActExport_GetTransferableIdEx(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamStructPtr(transferableId, uint64, 0);
|
||||
|
@ -603,6 +628,7 @@ void nnActExport_AcquireNexServiceToken(PPCInterpreter_t* hCPU)
|
|||
ppcDefineParamU32(serverId, 1);
|
||||
memset(token, 0, sizeof(nexServiceToken_t));
|
||||
actPrepareRequest();
|
||||
actRequest->accountSlot = iosu::act::ACT_SLOT_CURRENT;
|
||||
actRequest->requestCode = IOSU_ARC_ACQUIRENEXTOKEN;
|
||||
actRequest->titleId = CafeSystem::GetForegroundTitleId();
|
||||
actRequest->titleVersion = CafeSystem::GetForegroundTitleVersion();
|
||||
|
@ -619,10 +645,8 @@ void nnActExport_AcquireNexServiceToken(PPCInterpreter_t* hCPU)
|
|||
void nnActExport_AcquireIndependentServiceToken(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamMEMPTR(token, independentServiceToken_t, 0);
|
||||
ppcDefineParamMEMPTR(serviceToken, const char, 1);
|
||||
uint32 result = nn::act::AcquireIndependentServiceToken(token.GetPtr(), serviceToken.GetPtr(), 0);
|
||||
cemuLog_logDebug(LogType::Force, "nn_act.AcquireIndependentServiceToken(0x{}, {}) -> {:x}", (void*)token.GetPtr(), serviceToken.GetPtr(), result);
|
||||
cemuLog_logDebug(LogType::Force, "Token: {}", serviceToken.GetPtr());
|
||||
ppcDefineParamMEMPTR(clientId, const char, 1);
|
||||
uint32 result = nn::act::AcquireIndependentServiceToken(token.GetPtr(), clientId.GetPtr(), 0);
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
|
@ -632,7 +656,6 @@ void nnActExport_AcquireIndependentServiceToken2(PPCInterpreter_t* hCPU)
|
|||
ppcDefineParamMEMPTR(clientId, const char, 1);
|
||||
ppcDefineParamU32(cacheDurationInSeconds, 2);
|
||||
uint32 result = nn::act::AcquireIndependentServiceToken(token, clientId.GetPtr(), cacheDurationInSeconds);
|
||||
cemuLog_logDebug(LogType::Force, "Called nn_act.AcquireIndependentServiceToken2");
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
|
@ -640,7 +663,6 @@ void nnActExport_AcquireEcServiceToken(PPCInterpreter_t* hCPU)
|
|||
{
|
||||
ppcDefineParamMEMPTR(pEcServiceToken, independentServiceToken_t, 0);
|
||||
uint32 result = nn::act::AcquireIndependentServiceToken(pEcServiceToken.GetPtr(), "71a6f5d6430ea0183e3917787d717c46", 0);
|
||||
cemuLog_logDebug(LogType::Force, "Called nn_act.AcquireEcServiceToken");
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
|
@ -685,12 +707,15 @@ void nnAct_load()
|
|||
osLib_addFunction("nn_act", "GetPrincipalId__Q2_2nn3actFv", nnActExport_GetPrincipalId);
|
||||
osLib_addFunction("nn_act", "GetPrincipalIdEx__Q2_2nn3actFPUiUc", nnActExport_GetPrincipalIdEx);
|
||||
// transferable id
|
||||
osLib_addFunction("nn_act", "GetTransferableId__Q2_2nn3actFUi", nnActExport_GetTransferableId);
|
||||
osLib_addFunction("nn_act", "GetTransferableIdEx__Q2_2nn3actFPULUiUc", nnActExport_GetTransferableIdEx);
|
||||
// persistent id
|
||||
osLib_addFunction("nn_act", "GetPersistentId__Q2_2nn3actFv", nnActExport_GetPersistentId);
|
||||
osLib_addFunction("nn_act", "GetPersistentIdEx__Q2_2nn3actFUc", nnActExport_GetPersistentIdEx);
|
||||
// country
|
||||
osLib_addFunction("nn_act", "GetCountry__Q2_2nn3actFPc", nnActExport_GetCountry);
|
||||
// timezone
|
||||
cafeExportRegisterFunc(nn::act::GetTimeZoneId, "nn_act", "GetTimeZoneId__Q2_2nn3actFPc", LogType::Placeholder);
|
||||
|
||||
// parental
|
||||
osLib_addFunction("nn_act", "EnableParentalControlCheck__Q2_2nn3actFb", nnActExport_EnableParentalControlCheck);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "Cafe/CafeSystem.h"
|
||||
#include "Cafe/Filesystem/fsc.h"
|
||||
|
||||
namespace nn
|
||||
namespace nn
|
||||
{
|
||||
typedef uint32 Result;
|
||||
namespace boss
|
||||
|
@ -782,9 +782,9 @@ bossBufferVector->buffer = (uint8*)bossRequest;
|
|||
bossRequest->taskId = _thisptr->taskId.id;
|
||||
bossRequest->titleId = _thisptr->titleId.u64;
|
||||
bossRequest->bool_parameter = isForegroundRun != 0;
|
||||
|
||||
|
||||
__depr__IOS_Ioctlv(IOS_DEVICE_BOSS, IOSU_BOSS_REQUEST_CEMU, 1, 1, bossBufferVector);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -796,9 +796,9 @@ bossBufferVector->buffer = (uint8*)bossRequest;
|
|||
bossRequest->taskId = _thisptr->taskId.id;
|
||||
bossRequest->titleId = _thisptr->titleId.u64;
|
||||
bossRequest->bool_parameter = executeImmediately != 0;
|
||||
|
||||
|
||||
__depr__IOS_Ioctlv(IOS_DEVICE_BOSS, IOSU_BOSS_REQUEST_CEMU, 1, 1, bossBufferVector);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -809,9 +809,9 @@ bossBufferVector->buffer = (uint8*)bossRequest;
|
|||
bossRequest->accountId = _thisptr->accountId;
|
||||
bossRequest->taskId = _thisptr->taskId.id;
|
||||
bossRequest->titleId = _thisptr->titleId.u64;
|
||||
|
||||
|
||||
__depr__IOS_Ioctlv(IOS_DEVICE_BOSS, IOSU_BOSS_REQUEST_CEMU, 1, 1, bossBufferVector);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1001,7 +1001,7 @@ bossBufferVector->buffer = (uint8*)bossRequest;
|
|||
}
|
||||
};
|
||||
static_assert(sizeof(PrivilegedTask) == 0x20);
|
||||
|
||||
|
||||
struct AlmightyTask : PrivilegedTask
|
||||
{
|
||||
struct VTableAlmightyTask : public VTablePrivilegedTask
|
||||
|
@ -1169,14 +1169,17 @@ bossBufferVector->buffer = (uint8*)bossRequest;
|
|||
// initialize titleId of storage if not already done
|
||||
nnBossStorage_prepareTitleId(storage);
|
||||
|
||||
cemu_assert_debug(startIndex == 0); // non-zero index is todo
|
||||
if(startIndex >= FAD_ENTRY_MAX_COUNT) {
|
||||
*outputEntryCount = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// load fad.db
|
||||
BossStorageFadEntry* fadTable = nnBossStorageFad_getTable(storage);
|
||||
if (fadTable)
|
||||
{
|
||||
sint32 validEntryCount = 0;
|
||||
for (sint32 i = 0; i < FAD_ENTRY_MAX_COUNT; i++)
|
||||
for (sint32 i = startIndex; i < FAD_ENTRY_MAX_COUNT; i++)
|
||||
{
|
||||
if( fadTable[i].name[0] == '\0' )
|
||||
continue;
|
||||
|
@ -1612,7 +1615,7 @@ bossBufferVector->buffer = (uint8*)bossRequest;
|
|||
};
|
||||
static_assert(sizeof(NsData) == 0x58);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
void nnBoss_load()
|
||||
{
|
||||
|
@ -1663,7 +1666,7 @@ void nnBoss_load()
|
|||
cafeExportRegisterFunc(nn::boss::NbdlTaskSetting::dtor, "nn_boss", "__dt__Q3_2nn4boss15NbdlTaskSettingFv", LogType::NN_BOSS);
|
||||
cafeExportRegisterFunc(nn::boss::NbdlTaskSetting::Initialize, "nn_boss", "Initialize__Q3_2nn4boss15NbdlTaskSettingFPCcLT1", LogType::NN_BOSS);
|
||||
cafeExportRegisterFunc(nn::boss::NbdlTaskSetting::SetFileName, "nn_boss", "SetFileName__Q3_2nn4boss15NbdlTaskSettingFPCc", LogType::NN_BOSS);
|
||||
|
||||
|
||||
// PlayReportSetting
|
||||
nn::boss::PlayReportSetting::InitVTable();
|
||||
cafeExportRegisterFunc(nn::boss::PlayReportSetting::ctor, "nn_boss", "__ct__Q3_2nn4boss17PlayReportSettingFv", LogType::NN_BOSS);
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace nn
|
|||
|
||||
void asyncDownloadIconFile(uint64 titleId, nnIdbeEncryptedIcon_t* iconOut, OSThread_t* thread)
|
||||
{
|
||||
std::vector<uint8> idbeData = NAPI::IDBE_RequestRawEncrypted(titleId);
|
||||
std::vector<uint8> idbeData = NAPI::IDBE_RequestRawEncrypted(ActiveSettings::GetNetworkService(), titleId);
|
||||
if (idbeData.size() != sizeof(nnIdbeEncryptedIcon_t))
|
||||
{
|
||||
// icon does not exist or has the wrong size
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "Cafe/OS/libs/proc_ui/proc_ui.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Time.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Misc.h"
|
||||
|
||||
namespace nn
|
||||
{
|
||||
|
@ -37,7 +38,7 @@ namespace nn
|
|||
void StubPostAppReleaseBackground(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
coreinit::OSSleepTicks(ESPRESSO_TIMER_CLOCK * 2); // Sleep 2s
|
||||
ProcUI_SendForegroundMessage();
|
||||
coreinit::StartBackgroundForegroundTransition();
|
||||
}
|
||||
|
||||
sint32 StubPostApp(void* pAnyPostParam)
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace nn
|
|||
return res;
|
||||
|
||||
CurlRequestHelper req;
|
||||
req.initate(reqUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);
|
||||
req.initate(ActiveSettings::GetNetworkService(), reqUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);
|
||||
InitializeOliveRequest(req);
|
||||
|
||||
StackAllocator<coreinit::OSEvent> requestDoneEvent;
|
||||
|
|
|
@ -195,7 +195,7 @@ namespace nn
|
|||
break;
|
||||
}
|
||||
|
||||
req.initate(requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);
|
||||
req.initate(ActiveSettings::GetNetworkService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);
|
||||
InitializeOliveRequest(req);
|
||||
|
||||
StackAllocator<coreinit::OSEvent> requestDoneEvent;
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace nn
|
|||
|
||||
|
||||
CurlRequestHelper req;
|
||||
req.initate(requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);
|
||||
req.initate(ActiveSettings::GetNetworkService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);
|
||||
InitializeOliveRequest(req);
|
||||
|
||||
StackAllocator<coreinit::OSEvent> requestDoneEvent;
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace nn
|
|||
snprintf(requestUrl, sizeof(requestUrl), "%s/v1/communities/%lu.favorite", g_DiscoveryResults.apiEndpoint, pParam->communityId.value());
|
||||
|
||||
CurlRequestHelper req;
|
||||
req.initate(requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);
|
||||
req.initate(ActiveSettings::GetNetworkService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);
|
||||
InitializeOliveRequest(req);
|
||||
|
||||
StackAllocator<coreinit::OSEvent> requestDoneEvent;
|
||||
|
|
|
@ -72,11 +72,11 @@ namespace save
|
|||
return result != 0;
|
||||
}
|
||||
|
||||
bool GetCurrentTitleApplicationBox(acp::ACPDeviceType* deviceType)
|
||||
bool GetCurrentTitleApplicationBox(nn::acp::ACPDeviceType* deviceType)
|
||||
{
|
||||
if (deviceType)
|
||||
{
|
||||
*deviceType = acp::InternalDeviceType;
|
||||
*deviceType = nn::acp::ACPDeviceType::InternalDeviceType;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -84,7 +84,7 @@ namespace save
|
|||
|
||||
void UpdateSaveTimeStamp(uint32 persistentId)
|
||||
{
|
||||
acp::ACPDeviceType deviceType;
|
||||
nn::acp::ACPDeviceType deviceType;
|
||||
if (GetCurrentTitleApplicationBox(&deviceType))
|
||||
ACPUpdateSaveTimeStamp(persistentId, CafeSystem::GetForegroundTitleId(), deviceType);
|
||||
}
|
||||
|
@ -118,11 +118,11 @@ namespace save
|
|||
return false;
|
||||
}
|
||||
|
||||
SAVEStatus GetAbsoluteFullPathOtherApplication(uint32 persistentId, uint64 titleId, const char* subDir, char* outPath)
|
||||
FS_RESULT GetAbsoluteFullPathOtherApplication(uint32 persistentId, uint64 titleId, const char* subDir, char* outPath)
|
||||
{
|
||||
uint32be applicationBox;
|
||||
if(acp::ACPGetApplicationBox(&applicationBox, titleId) != acp::ACPStatus::SUCCESS)
|
||||
return (FSStatus)FS_RESULT::NOT_FOUND;
|
||||
return FS_RESULT::NOT_FOUND;
|
||||
|
||||
sint32 written = 0;
|
||||
if(applicationBox == 3)
|
||||
|
@ -151,13 +151,13 @@ namespace save
|
|||
cemu_assert_unimplemented();
|
||||
}
|
||||
else
|
||||
return (FSStatus)FS_RESULT::NOT_FOUND;
|
||||
return FS_RESULT::NOT_FOUND;
|
||||
|
||||
if (written < SAVE_MAX_PATH_SIZE - 1)
|
||||
return (FSStatus)FS_RESULT::SUCCESS;
|
||||
return FS_RESULT::SUCCESS;
|
||||
|
||||
cemu_assert_suspicious();
|
||||
return (FSStatus)(FS_RESULT::FATAL_ERROR);
|
||||
return FS_RESULT::FATAL_ERROR;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
|
@ -314,13 +314,13 @@ namespace save
|
|||
sprintf(path, "%susr/save/%08x/%08x/meta/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
acp::CreateSaveMetaFiles(ActiveSettings::GetPersistentId(), titleId);
|
||||
iosu::acp::CreateSaveMetaFiles(ActiveSettings::GetPersistentId(), titleId);
|
||||
}
|
||||
|
||||
return SAVE_STATUS_OK;
|
||||
}
|
||||
|
||||
SAVEStatus SAVERemoveAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVERemoveAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
SAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);
|
||||
|
||||
|
@ -331,7 +331,7 @@ namespace save
|
|||
{
|
||||
char fullPath[SAVE_MAX_PATH_SIZE];
|
||||
if (GetAbsoluteFullPath(persistentId, path, fullPath))
|
||||
result = coreinit::FSRemoveAsync(client, block, (uint8*)fullPath, errHandling, (FSAsyncParamsNew_t*)asyncParams);
|
||||
result = coreinit::FSRemoveAsync(client, block, (uint8*)fullPath, errHandling, (FSAsyncParams*)asyncParams);
|
||||
}
|
||||
else
|
||||
result = (FSStatus)FS_RESULT::NOT_FOUND;
|
||||
|
@ -340,7 +340,7 @@ namespace save
|
|||
return result;
|
||||
}
|
||||
|
||||
SAVEStatus SAVEMakeDirAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEMakeDirAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
SAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);
|
||||
|
||||
|
@ -351,7 +351,7 @@ namespace save
|
|||
{
|
||||
char fullPath[SAVE_MAX_PATH_SIZE];
|
||||
if (GetAbsoluteFullPath(persistentId, path, fullPath))
|
||||
result = coreinit::FSMakeDirAsync(client, block, fullPath, errHandling, (FSAsyncParamsNew_t*)asyncParams);
|
||||
result = coreinit::FSMakeDirAsync(client, block, fullPath, errHandling, (FSAsyncParams*)asyncParams);
|
||||
}
|
||||
else
|
||||
result = (FSStatus)FS_RESULT::NOT_FOUND;
|
||||
|
@ -361,7 +361,7 @@ namespace save
|
|||
return result;
|
||||
}
|
||||
|
||||
SAVEStatus SAVEOpenDirAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEOpenDirAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
SAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);
|
||||
|
||||
|
@ -372,7 +372,7 @@ namespace save
|
|||
{
|
||||
char fullPath[SAVE_MAX_PATH_SIZE];
|
||||
if (GetAbsoluteFullPath(persistentId, path, fullPath))
|
||||
result = coreinit::FSOpenDirAsync(client, block, fullPath, hDir, errHandling, (FSAsyncParamsNew_t*)asyncParams);
|
||||
result = coreinit::FSOpenDirAsync(client, block, fullPath, hDir, errHandling, (FSAsyncParams*)asyncParams);
|
||||
|
||||
}
|
||||
else
|
||||
|
@ -383,7 +383,7 @@ namespace save
|
|||
return result;
|
||||
}
|
||||
|
||||
SAVEStatus SAVEOpenFileAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, const char* mode, FSFileHandleDepr_t* hFile, FS_ERROR_MASK errHandling, const FSAsyncParamsNew_t* asyncParams)
|
||||
SAVEStatus SAVEOpenFileAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
SAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);
|
||||
|
||||
|
@ -394,7 +394,7 @@ namespace save
|
|||
{
|
||||
char fullPath[SAVE_MAX_PATH_SIZE];
|
||||
if (GetAbsoluteFullPath(persistentId, path, fullPath))
|
||||
result = coreinit::FSOpenFileAsync(client, block, fullPath, (char*)mode, hFile, errHandling, (FSAsyncParamsNew_t*)asyncParams);
|
||||
result = coreinit::FSOpenFileAsync(client, block, fullPath, (char*)mode, outFileHandle, errHandling, (FSAsyncParams*)asyncParams);
|
||||
}
|
||||
else
|
||||
result = (FSStatus)FS_RESULT::NOT_FOUND;
|
||||
|
@ -404,7 +404,7 @@ namespace save
|
|||
return result;
|
||||
}
|
||||
|
||||
SAVEStatus SAVEOpenFileOtherApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, const char* mode, FSFileHandleDepr_t* hFile, FS_ERROR_MASK errHandling, const FSAsyncParamsNew_t* asyncParams)
|
||||
SAVEStatus SAVEOpenFileOtherApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
if (strcmp(mode, "r") != 0)
|
||||
return (SAVEStatus)(FS_RESULT::PERMISSION_ERROR);
|
||||
|
@ -417,8 +417,8 @@ namespace save
|
|||
if (GetPersistentIdEx(accountSlot, &persistentId))
|
||||
{
|
||||
char fullPath[SAVE_MAX_PATH_SIZE];
|
||||
if (GetAbsoluteFullPathOtherApplication(persistentId, titleId, path, fullPath))
|
||||
result = coreinit::FSOpenFileAsync(client, block, fullPath, (char*)mode, hFile, errHandling, (FSAsyncParamsNew_t*)asyncParams);
|
||||
if (GetAbsoluteFullPathOtherApplication(persistentId, titleId, path, fullPath) == FS_RESULT::SUCCESS)
|
||||
result = coreinit::FSOpenFileAsync(client, block, fullPath, (char*)mode, outFileHandle, errHandling, (FSAsyncParams*)asyncParams);
|
||||
}
|
||||
else
|
||||
result = (FSStatus)FS_RESULT::NOT_FOUND;
|
||||
|
@ -428,26 +428,10 @@ namespace save
|
|||
return result;
|
||||
}
|
||||
|
||||
void export_SAVEOpenFileOtherApplicationAsync(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamMEMPTR(fsClient, coreinit::FSClient_t, 0);
|
||||
ppcDefineParamMEMPTR(fsCmdBlock, coreinit::FSCmdBlock_t, 1);
|
||||
ppcDefineParamU64(titleId, 2);
|
||||
ppcDefineParamU8(accountSlot, 4);
|
||||
ppcDefineParamMEMPTR(path, const char, 5);
|
||||
ppcDefineParamMEMPTR(mode, const char, 6);
|
||||
ppcDefineParamMEMPTR(hFile, FSFileHandleDepr_t, 7);
|
||||
ppcDefineParamU32(errHandling, 8);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParamsNew_t, 9);
|
||||
|
||||
const SAVEStatus result = SAVEOpenFileOtherApplicationAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), titleId, accountSlot, path.GetPtr(), mode.GetPtr(), hFile.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEOpenFileOtherApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, const char* mode, FSFileHandleDepr_t* hFile, FS_ERROR_MASK errHandling)
|
||||
SAVEStatus SAVEOpenFileOtherApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
MEMPTR<OSThread_t> currentThread{coreinit::OSGetCurrentThread()};
|
||||
FSAsyncParamsNew_t asyncParams;
|
||||
FSAsyncParams asyncParams;
|
||||
asyncParams.ioMsgQueue = nullptr;
|
||||
asyncParams.userCallback = PPCInterpreter_makeCallableExportDepr(AsyncCallback);
|
||||
|
||||
|
@ -456,7 +440,7 @@ namespace save
|
|||
param->returnStatus = (FSStatus)FS_RESULT::SUCCESS;
|
||||
asyncParams.userContext = param.GetPointer();
|
||||
|
||||
SAVEStatus status = SAVEOpenFileOtherApplicationAsync(client, block, titleId, accountSlot, path, mode, hFile, errHandling, &asyncParams);
|
||||
SAVEStatus status = SAVEOpenFileOtherApplicationAsync(client, block, titleId, accountSlot, path, mode, outFileHandle, errHandling, &asyncParams);
|
||||
if (status == (FSStatus)FS_RESULT::SUCCESS)
|
||||
{
|
||||
coreinit_suspendThread(currentThread, 1000);
|
||||
|
@ -467,113 +451,31 @@ namespace save
|
|||
return status;
|
||||
}
|
||||
|
||||
void export_SAVEOpenFileOtherApplication(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamMEMPTR(fsClient, coreinit::FSClient_t, 0);
|
||||
ppcDefineParamMEMPTR(fsCmdBlock, coreinit::FSCmdBlock_t, 1);
|
||||
ppcDefineParamU64(titleId, 2);
|
||||
ppcDefineParamU8(accountSlot, 4);
|
||||
ppcDefineParamMEMPTR(path, const char, 5);
|
||||
ppcDefineParamMEMPTR(mode, const char, 6);
|
||||
ppcDefineParamMEMPTR(hFile, FSFileHandleDepr_t, 7);
|
||||
ppcDefineParamU32(errHandling, 8);
|
||||
|
||||
const SAVEStatus result = SAVEOpenFileOtherApplication(fsClient.GetPtr(), fsCmdBlock.GetPtr(), titleId, accountSlot, path.GetPtr(), mode.GetPtr(), hFile.GetPtr(), errHandling);
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEOpenFileOtherNormalApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, const char* mode, FSFileHandleDepr_t* hFile, FS_ERROR_MASK errHandling, const FSAsyncParamsNew_t* asyncParams)
|
||||
SAVEStatus SAVEOpenFileOtherNormalApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
uint64 titleId = SAVE_UNIQUE_TO_TITLE_ID(uniqueId);
|
||||
return SAVEOpenFileOtherApplicationAsync(client, block, titleId, accountSlot, path, mode, hFile, errHandling, asyncParams);
|
||||
return SAVEOpenFileOtherApplicationAsync(client, block, titleId, accountSlot, path, mode, outFileHandle, errHandling, asyncParams);
|
||||
}
|
||||
|
||||
void export_SAVEOpenFileOtherNormalApplicationAsync(PPCInterpreter_t* hCPU)
|
||||
SAVEStatus SAVEOpenFileOtherNormalApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
ppcDefineParamMEMPTR(fsClient, coreinit::FSClient_t, 0);
|
||||
ppcDefineParamMEMPTR(fsCmdBlock, coreinit::FSCmdBlock_t, 1);
|
||||
ppcDefineParamU32(uniqueId, 2);
|
||||
ppcDefineParamU8(accountSlot, 3);
|
||||
ppcDefineParamMEMPTR(path, const char, 4);
|
||||
ppcDefineParamMEMPTR(mode, const char, 5);
|
||||
ppcDefineParamMEMPTR(hFile, FSFileHandleDepr_t, 6);
|
||||
ppcDefineParamU32(errHandling, 7);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParamsNew_t, 8);
|
||||
|
||||
const SAVEStatus result = SAVEOpenFileOtherNormalApplicationAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), uniqueId, accountSlot, path.GetPtr(), mode.GetPtr(), hFile.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
SAVEStatus SAVEOpenFileOtherNormalApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, const char* mode, FSFileHandleDepr_t* hFile, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
//peterBreak();
|
||||
|
||||
uint64 titleId = SAVE_UNIQUE_TO_TITLE_ID(uniqueId);
|
||||
return SAVEOpenFileOtherApplication(client, block, titleId, accountSlot, path, mode, hFile, errHandling);
|
||||
return SAVEOpenFileOtherApplication(client, block, titleId, accountSlot, path, mode, outFileHandle, errHandling);
|
||||
}
|
||||
|
||||
void export_SAVEOpenFileOtherNormalApplication(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamMEMPTR(fsClient, coreinit::FSClient_t, 0);
|
||||
ppcDefineParamMEMPTR(fsCmdBlock, coreinit::FSCmdBlock_t, 1);
|
||||
ppcDefineParamU32(uniqueId, 2);
|
||||
ppcDefineParamU8(accountSlot, 3);
|
||||
ppcDefineParamMEMPTR(path, const char, 4);
|
||||
ppcDefineParamMEMPTR(mode, const char, 5);
|
||||
ppcDefineParamMEMPTR(hFile, FSFileHandleDepr_t, 6);
|
||||
ppcDefineParamU32(errHandling, 7);
|
||||
|
||||
const SAVEStatus result = SAVEOpenFileOtherNormalApplication(fsClient.GetPtr(), fsCmdBlock.GetPtr(), uniqueId, accountSlot, path.GetPtr(), mode.GetPtr(), hFile.GetPtr(), errHandling);
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEOpenFileOtherNormalApplicationVariationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, const char* mode, FSFileHandleDepr_t* hFile, FS_ERROR_MASK errHandling, const FSAsyncParamsNew_t* asyncParams)
|
||||
{
|
||||
//peterBreak();
|
||||
|
||||
uint64 titleId = SAVE_UNIQUE_TO_TITLE_ID_VARIATION(uniqueId, variation);
|
||||
return SAVEOpenFileOtherApplicationAsync(client, block, titleId, accountSlot, path, mode, hFile, errHandling, asyncParams);
|
||||
}
|
||||
|
||||
void export_SAVEOpenFileOtherNormalApplicationVariationAsync(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamMEMPTR(fsClient, coreinit::FSClient_t, 0);
|
||||
ppcDefineParamMEMPTR(fsCmdBlock, coreinit::FSCmdBlock_t, 1);
|
||||
ppcDefineParamU32(uniqueId, 2);
|
||||
ppcDefineParamU8(variation, 3);
|
||||
ppcDefineParamU8(accountSlot, 4);
|
||||
ppcDefineParamMEMPTR(path, const char, 5);
|
||||
ppcDefineParamMEMPTR(mode, const char, 6);
|
||||
ppcDefineParamMEMPTR(hFile, FSFileHandleDepr_t, 7);
|
||||
ppcDefineParamU32(errHandling, 8);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParamsNew_t, 9);
|
||||
|
||||
const SAVEStatus result = SAVEOpenFileOtherNormalApplicationVariationAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), uniqueId, variation, accountSlot, path.GetPtr(), mode.GetPtr(), hFile.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEOpenFileOtherNormalApplicationVariation(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, const char* mode, FSFileHandleDepr_t* hFile, FS_ERROR_MASK errHandling)
|
||||
SAVEStatus SAVEOpenFileOtherNormalApplicationVariationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
uint64 titleId = SAVE_UNIQUE_TO_TITLE_ID_VARIATION(uniqueId, variation);
|
||||
return SAVEOpenFileOtherApplication(client, block, titleId, accountSlot, path, mode, hFile, errHandling);
|
||||
return SAVEOpenFileOtherApplicationAsync(client, block, titleId, accountSlot, path, mode, outFileHandle, errHandling, asyncParams);
|
||||
}
|
||||
|
||||
void export_SAVEOpenFileOtherNormalApplicationVariation(PPCInterpreter_t* hCPU)
|
||||
SAVEStatus SAVEOpenFileOtherNormalApplicationVariation(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
ppcDefineParamMEMPTR(fsClient, coreinit::FSClient_t, 0);
|
||||
ppcDefineParamMEMPTR(fsCmdBlock, coreinit::FSCmdBlock_t, 1);
|
||||
ppcDefineParamU32(uniqueId, 2);
|
||||
ppcDefineParamU8(variation, 3);
|
||||
ppcDefineParamU8(accountSlot, 4);
|
||||
ppcDefineParamMEMPTR(path, const char, 5);
|
||||
ppcDefineParamMEMPTR(mode, const char, 6);
|
||||
ppcDefineParamMEMPTR(hFile, FSFileHandleDepr_t, 7);
|
||||
ppcDefineParamU32(errHandling, 8);
|
||||
|
||||
const SAVEStatus result = SAVEOpenFileOtherNormalApplicationVariation(fsClient.GetPtr(), fsCmdBlock.GetPtr(), uniqueId, variation, accountSlot, path.GetPtr(), mode.GetPtr(), hFile.GetPtr(), errHandling);
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
uint64 titleId = SAVE_UNIQUE_TO_TITLE_ID_VARIATION(uniqueId, variation);
|
||||
return SAVEOpenFileOtherApplication(client, block, titleId, accountSlot, path, mode, outFileHandle, errHandling);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEGetFreeSpaceSizeAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, FSLargeSize* freeSize, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEGetFreeSpaceSizeAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, FSLargeSize* freeSize, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
SAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);
|
||||
|
||||
|
@ -583,9 +485,8 @@ namespace save
|
|||
if (GetPersistentIdEx(accountSlot, &persistentId))
|
||||
{
|
||||
char fullPath[SAVE_MAX_PATH_SIZE];
|
||||
// usually a pointer with '\0' instead of nullptr, but it's basically the same
|
||||
if (GetAbsoluteFullPath(persistentId, nullptr, fullPath))
|
||||
result = coreinit::FSGetFreeSpaceSizeAsync(client, block, fullPath, freeSize, errHandling, (FSAsyncParamsNew_t*)asyncParams);
|
||||
result = coreinit::FSGetFreeSpaceSizeAsync(client, block, fullPath, freeSize, errHandling, (FSAsyncParams*)asyncParams);
|
||||
}
|
||||
else
|
||||
result = (FSStatus)FS_RESULT::NOT_FOUND;
|
||||
|
@ -595,7 +496,7 @@ namespace save
|
|||
return result;
|
||||
}
|
||||
|
||||
SAVEStatus SAVEGetStatAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEGetStatAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
SAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);
|
||||
|
||||
|
@ -606,7 +507,7 @@ namespace save
|
|||
{
|
||||
char fullPath[SAVE_MAX_PATH_SIZE];
|
||||
if (GetAbsoluteFullPath(persistentId, path, fullPath))
|
||||
result = coreinit::__FSQueryInfoAsync(client, block, (uint8*)fullPath, FSA_QUERY_TYPE_STAT, stat, errHandling, (FSAsyncParamsNew_t*)asyncParams); // FSGetStatAsync(...)
|
||||
result = coreinit::__FSQueryInfoAsync(client, block, (uint8*)fullPath, FSA_QUERY_TYPE_STAT, stat, errHandling, (FSAsyncParams*)asyncParams); // FSGetStatAsync(...)
|
||||
}
|
||||
else
|
||||
result = (FSStatus)FS_RESULT::NOT_FOUND;
|
||||
|
@ -616,7 +517,7 @@ namespace save
|
|||
return result;
|
||||
}
|
||||
|
||||
SAVEStatus SAVEGetStatOtherApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEGetStatOtherApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
SAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);
|
||||
|
||||
|
@ -626,8 +527,8 @@ namespace save
|
|||
if (GetPersistentIdEx(accountSlot, &persistentId))
|
||||
{
|
||||
char fullPath[SAVE_MAX_PATH_SIZE];
|
||||
if (GetAbsoluteFullPathOtherApplication(persistentId, titleId, path, fullPath) == (FSStatus)FS_RESULT::SUCCESS)
|
||||
result = coreinit::__FSQueryInfoAsync(client, block, (uint8*)fullPath, FSA_QUERY_TYPE_STAT, stat, errHandling, (FSAsyncParamsNew_t*)asyncParams); // FSGetStatAsync(...)
|
||||
if (GetAbsoluteFullPathOtherApplication(persistentId, titleId, path, fullPath) == FS_RESULT::SUCCESS)
|
||||
result = coreinit::__FSQueryInfoAsync(client, block, (uint8*)fullPath, FSA_QUERY_TYPE_STAT, stat, errHandling, (FSAsyncParams*)asyncParams); // FSGetStatAsync(...)
|
||||
}
|
||||
else
|
||||
result = (FSStatus)FS_RESULT::NOT_FOUND;
|
||||
|
@ -637,25 +538,25 @@ namespace save
|
|||
return result;
|
||||
}
|
||||
|
||||
SAVEStatus SAVEGetStatOtherNormalApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEGetStatOtherNormalApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
uint64 titleId = SAVE_UNIQUE_TO_TITLE_ID(uniqueId);
|
||||
return SAVEGetStatOtherApplicationAsync(client, block, titleId, accountSlot, path, stat, errHandling, asyncParams);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEGetStatOtherDemoApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEGetStatOtherDemoApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
uint64 titleId = SAVE_UNIQUE_DEMO_TO_TITLE_ID(uniqueId);
|
||||
return SAVEGetStatOtherApplicationAsync(client, block, titleId, accountSlot, path, stat, errHandling, asyncParams);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEGetStatOtherNormalApplicationVariationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEGetStatOtherNormalApplicationVariationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
uint64 titleId = SAVE_UNIQUE_TO_TITLE_ID_VARIATION(uniqueId, variation);
|
||||
return SAVEGetStatOtherApplicationAsync(client, block, titleId, accountSlot, path, stat, errHandling, asyncParams);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEGetStatOtherDemoApplicationVariationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEGetStatOtherDemoApplicationVariationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
uint64 titleId = SAVE_UNIQUE_DEMO_TO_TITLE_ID_VARIATION(uniqueId, variation);
|
||||
return SAVEGetStatOtherApplicationAsync(client, block, titleId, accountSlot, path, stat, errHandling, asyncParams);
|
||||
|
@ -669,7 +570,7 @@ namespace save
|
|||
uint32 persistentId;
|
||||
if (GetPersistentIdEx(accountSlot, &persistentId))
|
||||
{
|
||||
acp::ACPStatus status = ACPCreateSaveDir(persistentId, acp::InternalDeviceType);
|
||||
acp::ACPStatus status = nn::acp::ACPCreateSaveDir(persistentId, iosu::acp::ACPDeviceType::InternalDeviceType);
|
||||
result = ConvertACPToSaveStatus(status);
|
||||
}
|
||||
else
|
||||
|
@ -682,14 +583,14 @@ namespace save
|
|||
SAVEStatus SAVEGetFreeSpaceSize(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, FSLargeSize* freeSize, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
MEMPTR<OSThread_t> currentThread{coreinit::OSGetCurrentThread()};
|
||||
FSAsyncParams_t asyncParams;
|
||||
asyncParams.ioMsgQueue = MPTR_NULL;
|
||||
asyncParams.userCallback = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(AsyncCallback));
|
||||
FSAsyncParams asyncParams;
|
||||
asyncParams.ioMsgQueue = nullptr;
|
||||
asyncParams.userCallback = RPLLoader_MakePPCCallable(AsyncCallback);
|
||||
|
||||
StackAllocator<AsyncCallbackParam_t> param;
|
||||
param->thread = currentThread;
|
||||
param->returnStatus = (FSStatus)FS_RESULT::SUCCESS;
|
||||
asyncParams.userContext = param.GetMPTRBE();
|
||||
asyncParams.userContext = ¶m;
|
||||
|
||||
SAVEStatus status = SAVEGetFreeSpaceSizeAsync(client, block, accountSlot, freeSize, errHandling, &asyncParams);
|
||||
if (status == (FSStatus)FS_RESULT::SUCCESS)
|
||||
|
@ -722,7 +623,7 @@ namespace save
|
|||
ppcDefineParamU8(accountSlot, 2);
|
||||
ppcDefineParamMEMPTR(returnedFreeSize, FSLargeSize, 3);
|
||||
ppcDefineParamU32(errHandling, 4);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 5);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 5);
|
||||
|
||||
const SAVEStatus result = SAVEGetFreeSpaceSizeAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), accountSlot, returnedFreeSize.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
cemuLog_log(LogType::Save, "SAVEGetFreeSpaceSizeAsync(0x{:08x}, 0x{:08x}, {:x}, {:x}) -> {:x}", fsClient.GetMPTR(), fsCmdBlock.GetMPTR(), accountSlot, errHandling, result);
|
||||
|
@ -743,7 +644,7 @@ namespace save
|
|||
ppcDefineParamU8(accountSlot, 2);
|
||||
ppcDefineParamMEMPTR(path, const char, 3);
|
||||
ppcDefineParamU32(errHandling, 4);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 5);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 5);
|
||||
|
||||
const SAVEStatus result = SAVERemoveAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), accountSlot, path.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
|
@ -752,14 +653,14 @@ namespace save
|
|||
SAVEStatus SAVERemove(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
MEMPTR<OSThread_t> currentThread{coreinit::OSGetCurrentThread()};
|
||||
FSAsyncParams_t asyncParams;
|
||||
asyncParams.ioMsgQueue = MPTR_NULL;
|
||||
asyncParams.userCallback = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(AsyncCallback));
|
||||
FSAsyncParams asyncParams;
|
||||
asyncParams.ioMsgQueue = nullptr;
|
||||
asyncParams.userCallback = RPLLoader_MakePPCCallable(AsyncCallback);
|
||||
|
||||
StackAllocator<AsyncCallbackParam_t> param;
|
||||
param->thread = currentThread;
|
||||
param->returnStatus = (FSStatus)FS_RESULT::SUCCESS;
|
||||
asyncParams.userContext = param.GetMPTRBE();
|
||||
asyncParams.userContext = ¶m;
|
||||
|
||||
SAVEStatus status = SAVERemoveAsync(client, block, accountSlot, path, errHandling, &asyncParams);
|
||||
if (status == (FSStatus)FS_RESULT::SUCCESS)
|
||||
|
@ -784,7 +685,7 @@ namespace save
|
|||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
SAVEStatus SAVERenameAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* oldPath, const char* newPath, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVERenameAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* oldPath, const char* newPath, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
SAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);
|
||||
|
||||
|
@ -798,7 +699,7 @@ namespace save
|
|||
{
|
||||
char fullNewPath[SAVE_MAX_PATH_SIZE];
|
||||
if (GetAbsoluteFullPath(persistentId, newPath, fullNewPath))
|
||||
result = coreinit::FSRenameAsync(client, block, fullOldPath, fullNewPath, errHandling, (FSAsyncParamsNew_t*)asyncParams);
|
||||
result = coreinit::FSRenameAsync(client, block, fullOldPath, fullNewPath, errHandling, (FSAsyncParams*)asyncParams);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -817,7 +718,7 @@ namespace save
|
|||
ppcDefineParamMEMPTR(oldPath, const char, 3);
|
||||
ppcDefineParamMEMPTR(newPath, const char, 4);
|
||||
ppcDefineParamU32(errHandling, 5);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 6);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 6);
|
||||
|
||||
const SAVEStatus result = SAVERenameAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), accountSlot, oldPath.GetPtr(), newPath.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
cemuLog_log(LogType::Save, "SAVERenameAsync(0x{:08x}, 0x{:08x}, {:x}, {}, {}, {:x}) -> {:x}", fsClient.GetMPTR(), fsCmdBlock.GetMPTR(), accountSlot, oldPath.GetPtr(), newPath.GetPtr(), errHandling, result);
|
||||
|
@ -855,7 +756,7 @@ namespace save
|
|||
ppcDefineParamMEMPTR(path, const char, 3);
|
||||
ppcDefineParamMEMPTR(hDir, betype<FSDirHandle2>, 4);
|
||||
ppcDefineParamU32(errHandling, 5);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 6);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 6);
|
||||
|
||||
const SAVEStatus result = SAVEOpenDirAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), accountSlot, path.GetPtr(), hDir, errHandling, asyncParams.GetPtr());
|
||||
cemuLog_log(LogType::Save, "SAVEOpenDirAsync(0x{:08x}, 0x{:08x}, {:x}, {}, 0x{:08x} ({:x}), {:x}) -> {:x}", fsClient.GetMPTR(), fsCmdBlock.GetMPTR(), accountSlot, path.GetPtr(), hDir.GetMPTR(),
|
||||
|
@ -866,14 +767,14 @@ namespace save
|
|||
SAVEStatus SAVEOpenDir(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
MEMPTR<OSThread_t> currentThread{coreinit::OSGetCurrentThread()};
|
||||
FSAsyncParams_t asyncParams;
|
||||
asyncParams.ioMsgQueue = MPTR_NULL;
|
||||
asyncParams.userCallback = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(AsyncCallback));
|
||||
FSAsyncParams asyncParams;
|
||||
asyncParams.ioMsgQueue = nullptr;
|
||||
asyncParams.userCallback = RPLLoader_MakePPCCallable(AsyncCallback);
|
||||
|
||||
StackAllocator<AsyncCallbackParam_t> param;
|
||||
param->thread = currentThread;
|
||||
param->returnStatus = (FSStatus)FS_RESULT::SUCCESS;
|
||||
asyncParams.userContext = param.GetMPTRBE();
|
||||
asyncParams.userContext = ¶m;
|
||||
|
||||
SAVEStatus status = SAVEOpenDirAsync(client, block, accountSlot, path, hDir, errHandling, &asyncParams);
|
||||
if (status == (FSStatus)FS_RESULT::SUCCESS)
|
||||
|
@ -901,7 +802,7 @@ namespace save
|
|||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEOpenDirOtherApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEOpenDirOtherApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
SAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);
|
||||
|
||||
|
@ -910,8 +811,8 @@ namespace save
|
|||
if (GetPersistentIdEx(accountSlot, &persistentId))
|
||||
{
|
||||
char fullPath[SAVE_MAX_PATH_SIZE];
|
||||
if (GetAbsoluteFullPathOtherApplication(persistentId, titleId, path, fullPath))
|
||||
result = coreinit::FSOpenDirAsync(client, block, fullPath, hDir, errHandling, (FSAsyncParamsNew_t*)asyncParams);
|
||||
if (GetAbsoluteFullPathOtherApplication(persistentId, titleId, path, fullPath) == FS_RESULT::SUCCESS)
|
||||
result = coreinit::FSOpenDirAsync(client, block, fullPath, hDir, errHandling, (FSAsyncParams*)asyncParams);
|
||||
}
|
||||
else
|
||||
result = (FSStatus)FS_RESULT::NOT_FOUND;
|
||||
|
@ -929,7 +830,7 @@ namespace save
|
|||
ppcDefineParamMEMPTR(path, const char, 4);
|
||||
ppcDefineParamMEMPTR(hDir, betype<FSDirHandle2>, 5);
|
||||
ppcDefineParamU32(errHandling, 6);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 7);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 7);
|
||||
|
||||
const SAVEStatus result = SAVEOpenDirOtherApplicationAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), titleId, accountSlot, path.GetPtr(), hDir, errHandling, asyncParams.GetPtr());
|
||||
cemuLog_log(LogType::Save, "SAVEOpenDirOtherApplicationAsync(0x{:08x}, 0x{:08x}, {:x}, {:x}, {}, 0x{:08x} ({:x}), {:x}) -> {:x}", fsClient.GetMPTR(), fsCmdBlock.GetMPTR(), titleId, accountSlot, path.GetPtr(), hDir.GetMPTR(),
|
||||
|
@ -940,14 +841,14 @@ namespace save
|
|||
SAVEStatus SAVEOpenDirOtherApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
MEMPTR<OSThread_t> currentThread{coreinit::OSGetCurrentThread()};
|
||||
FSAsyncParams_t asyncParams;
|
||||
asyncParams.ioMsgQueue = MPTR_NULL;
|
||||
asyncParams.userCallback = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(AsyncCallback));
|
||||
FSAsyncParams asyncParams;
|
||||
asyncParams.ioMsgQueue = nullptr;
|
||||
asyncParams.userCallback = RPLLoader_MakePPCCallable(AsyncCallback);
|
||||
|
||||
StackAllocator<AsyncCallbackParam_t> param;
|
||||
param->thread = currentThread;
|
||||
param->returnStatus = (FSStatus)FS_RESULT::SUCCESS;
|
||||
asyncParams.userContext = param.GetMPTRBE();
|
||||
asyncParams.userContext = ¶m;
|
||||
|
||||
SAVEStatus status = SAVEOpenDirOtherApplicationAsync(client, block, titleId, accountSlot, path, hDir, errHandling, &asyncParams);
|
||||
if (status == (FSStatus)FS_RESULT::SUCCESS)
|
||||
|
@ -976,7 +877,7 @@ namespace save
|
|||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEOpenDirOtherNormalApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEOpenDirOtherNormalApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
uint64 titleId = SAVE_UNIQUE_TO_TITLE_ID(uniqueId);
|
||||
return SAVEOpenDirOtherApplicationAsync(client, block, titleId, accountSlot, path, hDir, errHandling, asyncParams);
|
||||
|
@ -991,7 +892,7 @@ namespace save
|
|||
ppcDefineParamMEMPTR(path, const char, 4);
|
||||
ppcDefineParamMEMPTR(hDir, betype<FSDirHandle2>, 5);
|
||||
ppcDefineParamU32(errHandling, 6);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 7);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 7);
|
||||
|
||||
const SAVEStatus result = SAVEOpenDirOtherNormalApplicationAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), uniqueId, accountSlot, path.GetPtr(), hDir, errHandling, asyncParams.GetPtr());
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
|
@ -1017,7 +918,7 @@ namespace save
|
|||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEOpenDirOtherNormalApplicationVariationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEOpenDirOtherNormalApplicationVariationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
uint64 titleId = SAVE_UNIQUE_TO_TITLE_ID_VARIATION(uniqueId, variation);
|
||||
return SAVEOpenDirOtherApplicationAsync(client, block, titleId, accountSlot, path, hDir, errHandling, asyncParams);
|
||||
|
@ -1033,7 +934,7 @@ namespace save
|
|||
ppcDefineParamMEMPTR(path, const char, 5);
|
||||
ppcDefineParamMEMPTR(hDir, betype<FSDirHandle2>, 6);
|
||||
ppcDefineParamU32(errHandling, 7);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 8);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 8);
|
||||
|
||||
const SAVEStatus result = SAVEOpenDirOtherNormalApplicationVariationAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), uniqueId, variation, accountSlot, path.GetPtr(), hDir, errHandling, asyncParams.GetPtr());
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
|
@ -1067,7 +968,7 @@ namespace save
|
|||
ppcDefineParamU8(accountSlot, 2);
|
||||
ppcDefineParamMEMPTR(path, const char, 3);
|
||||
ppcDefineParamU32(errHandling, 4);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 5);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 5);
|
||||
|
||||
const SAVEStatus result = SAVEMakeDirAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), accountSlot, path.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
cemuLog_log(LogType::Save, "SAVEMakeDirAsync(0x{:08x}, 0x{:08x}, {:x}, {}, {:x}) -> {:x}", fsClient.GetMPTR(), fsCmdBlock.GetMPTR(), accountSlot, path.GetPtr(), errHandling, result);
|
||||
|
@ -1077,14 +978,14 @@ namespace save
|
|||
SAVEStatus SAVEMakeDir(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
MEMPTR<OSThread_t> currentThread{coreinit::OSGetCurrentThread()};
|
||||
FSAsyncParams_t asyncParams;
|
||||
asyncParams.ioMsgQueue = MPTR_NULL;
|
||||
asyncParams.userCallback = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(AsyncCallback));
|
||||
FSAsyncParams asyncParams;
|
||||
asyncParams.ioMsgQueue = nullptr;
|
||||
asyncParams.userCallback = RPLLoader_MakePPCCallable(AsyncCallback);
|
||||
|
||||
StackAllocator<AsyncCallbackParam_t> param;
|
||||
param->thread = currentThread;
|
||||
param->returnStatus = (FSStatus)FS_RESULT::SUCCESS;
|
||||
asyncParams.userContext = param.GetMPTRBE();
|
||||
asyncParams.userContext = ¶m;
|
||||
|
||||
SAVEStatus status = SAVEMakeDirAsync(client, block, accountSlot, path, errHandling, &asyncParams);
|
||||
if (status == (FSStatus)FS_RESULT::SUCCESS)
|
||||
|
@ -1110,26 +1011,10 @@ namespace save
|
|||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
void export_SAVEOpenFileAsync(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamMEMPTR(fsClient, coreinit::FSClient_t, 0);
|
||||
ppcDefineParamMEMPTR(fsCmdBlock, coreinit::FSCmdBlock_t, 1);
|
||||
ppcDefineParamU8(accountSlot, 2);
|
||||
ppcDefineParamMEMPTR(path, const char, 3);
|
||||
ppcDefineParamMEMPTR(mode, const char, 4);
|
||||
ppcDefineParamMEMPTR(hFile, FSFileHandleDepr_t, 5);
|
||||
ppcDefineParamU32(errHandling, 6);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParamsNew_t, 7);
|
||||
|
||||
const SAVEStatus result = SAVEOpenFileAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), accountSlot, path.GetPtr(), mode.GetPtr(), hFile.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
cemuLog_log(LogType::Save, "SAVEOpenFileAsync(0x{:08x}, 0x{:08x}, {:x}, {}, {}, 0x{:08x}, {:x}) -> {:x}", fsClient.GetMPTR(), fsCmdBlock.GetMPTR(), accountSlot, path.GetPtr(), mode.GetPtr(), hFile.GetMPTR(), errHandling, result);
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEOpenFile(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, const char* mode, FSFileHandleDepr_t* hFile, FS_ERROR_MASK errHandling)
|
||||
SAVEStatus SAVEOpenFile(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
MEMPTR<OSThread_t> currentThread{coreinit::OSGetCurrentThread()};
|
||||
FSAsyncParamsNew_t asyncParams;
|
||||
FSAsyncParams asyncParams;
|
||||
asyncParams.ioMsgQueue = nullptr;
|
||||
asyncParams.userCallback = PPCInterpreter_makeCallableExportDepr(AsyncCallback);
|
||||
|
||||
|
@ -1138,7 +1023,7 @@ namespace save
|
|||
param->returnStatus = (FSStatus)FS_RESULT::SUCCESS;
|
||||
asyncParams.userContext = param.GetPointer();
|
||||
|
||||
SAVEStatus status = SAVEOpenFileAsync(client, block, accountSlot, path, mode, hFile, errHandling, &asyncParams);
|
||||
SAVEStatus status = SAVEOpenFileAsync(client, block, accountSlot, path, mode, outFileHandle, errHandling, &asyncParams);
|
||||
if (status == (FSStatus)FS_RESULT::SUCCESS)
|
||||
{
|
||||
coreinit_suspendThread(currentThread, 1000);
|
||||
|
@ -1149,21 +1034,6 @@ namespace save
|
|||
return status;
|
||||
}
|
||||
|
||||
void export_SAVEOpenFile(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamMEMPTR(fsClient, coreinit::FSClient_t, 0);
|
||||
ppcDefineParamMEMPTR(fsCmdBlock, coreinit::FSCmdBlock_t, 1);
|
||||
ppcDefineParamU8(accountSlot, 2);
|
||||
ppcDefineParamMEMPTR(path, const char, 3);
|
||||
ppcDefineParamMEMPTR(mode, const char, 4);
|
||||
ppcDefineParamMEMPTR(hFile, FSFileHandleDepr_t, 5);
|
||||
ppcDefineParamU32(errHandling, 6);
|
||||
|
||||
const SAVEStatus result = SAVEOpenFile(fsClient.GetPtr(), fsCmdBlock.GetPtr(), accountSlot, path.GetPtr(), mode.GetPtr(), hFile.GetPtr(), errHandling);
|
||||
cemuLog_log(LogType::Save, "SAVEOpenFile(0x{:08x}, 0x{:08x}, {:x}, {}, {}, 0x{:08x}, {:x}) -> {:x}", fsClient.GetMPTR(), fsCmdBlock.GetMPTR(), accountSlot, path.GetPtr(), mode.GetPtr(), hFile.GetMPTR(), errHandling, result);
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
void export_SAVEInitSaveDir(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamU8(accountSlot, 0);
|
||||
|
@ -1180,7 +1050,7 @@ namespace save
|
|||
ppcDefineParamMEMPTR(path, const char, 3);
|
||||
ppcDefineParamMEMPTR(stat, FSStat_t, 4);
|
||||
ppcDefineParamU32(errHandling, 5);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 6);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 6);
|
||||
|
||||
const SAVEStatus result = SAVEGetStatAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), accountSlot, path.GetPtr(), stat.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
cemuLog_log(LogType::Save, "SAVEGetStatAsync(0x{:08x}, 0x{:08x}, {:x}, {}, 0x{:08x}, {:x}) -> {:x}", fsClient.GetMPTR(), fsCmdBlock.GetMPTR(), accountSlot, path.GetPtr(), stat.GetMPTR(), errHandling, result);
|
||||
|
@ -1190,14 +1060,14 @@ namespace save
|
|||
SAVEStatus SAVEGetStat(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
MEMPTR<OSThread_t> currentThread{coreinit::OSGetCurrentThread()};
|
||||
FSAsyncParams_t asyncParams;
|
||||
asyncParams.ioMsgQueue = MPTR_NULL;
|
||||
asyncParams.userCallback = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(AsyncCallback));
|
||||
FSAsyncParams asyncParams;
|
||||
asyncParams.ioMsgQueue = nullptr;
|
||||
asyncParams.userCallback = RPLLoader_MakePPCCallable(AsyncCallback);
|
||||
|
||||
StackAllocator<AsyncCallbackParam_t> param;
|
||||
param->thread = currentThread;
|
||||
param->returnStatus = (FSStatus)FS_RESULT::SUCCESS;
|
||||
asyncParams.userContext = param.GetMPTRBE();
|
||||
asyncParams.userContext = ¶m;
|
||||
|
||||
SAVEStatus status = SAVEGetStatAsync(client, block, accountSlot, path, stat, errHandling, &asyncParams);
|
||||
if (status == (FSStatus)FS_RESULT::SUCCESS)
|
||||
|
@ -1233,7 +1103,7 @@ namespace save
|
|||
ppcDefineParamMEMPTR(path, const char, 5);
|
||||
ppcDefineParamMEMPTR(stat, FSStat_t, 6);
|
||||
ppcDefineParamU32(errHandling, 7);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 8);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 8);
|
||||
|
||||
const SAVEStatus result = SAVEGetStatOtherApplicationAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), titleId, accountSlot, path.GetPtr(), stat.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
|
@ -1242,14 +1112,14 @@ namespace save
|
|||
SAVEStatus SAVEGetStatOtherApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
MEMPTR<OSThread_t> currentThread{coreinit::OSGetCurrentThread()};
|
||||
FSAsyncParams_t asyncParams;
|
||||
asyncParams.ioMsgQueue = MPTR_NULL;
|
||||
asyncParams.userCallback = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(AsyncCallback));
|
||||
FSAsyncParams asyncParams;
|
||||
asyncParams.ioMsgQueue = nullptr;
|
||||
asyncParams.userCallback = RPLLoader_MakePPCCallable(AsyncCallback);
|
||||
|
||||
StackAllocator<AsyncCallbackParam_t> param;
|
||||
param->thread = currentThread;
|
||||
param->returnStatus = (FSStatus)FS_RESULT::SUCCESS;
|
||||
asyncParams.userContext = param.GetMPTRBE();
|
||||
asyncParams.userContext = ¶m;
|
||||
|
||||
SAVEStatus status = SAVEGetStatOtherApplicationAsync(client, block, titleId, accountSlot, path, stat, errHandling, &asyncParams);
|
||||
if (status == (FSStatus)FS_RESULT::SUCCESS)
|
||||
|
@ -1286,7 +1156,7 @@ namespace save
|
|||
ppcDefineParamMEMPTR(path, const char, 4);
|
||||
ppcDefineParamMEMPTR(stat, FSStat_t, 5);
|
||||
ppcDefineParamU32(errHandling, 6);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 8);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 8);
|
||||
|
||||
const SAVEStatus result = SAVEGetStatOtherNormalApplicationAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), uniqueId, accountSlot, path.GetPtr(), stat.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
|
@ -1294,8 +1164,6 @@ namespace save
|
|||
|
||||
SAVEStatus SAVEGetStatOtherNormalApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
//peterBreak();
|
||||
|
||||
uint64 titleId = SAVE_UNIQUE_TO_TITLE_ID(uniqueId);
|
||||
return SAVEGetStatOtherApplication(client, block, titleId, accountSlot, path, stat, errHandling);
|
||||
}
|
||||
|
@ -1326,7 +1194,7 @@ namespace save
|
|||
ppcDefineParamMEMPTR(path, const char, 5);
|
||||
ppcDefineParamMEMPTR(stat, FSStat_t, 6);
|
||||
ppcDefineParamU32(errHandling, 7);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 8);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 8);
|
||||
|
||||
const SAVEStatus result = SAVEGetStatOtherNormalApplicationVariationAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), uniqueId, variation, accountSlot, path.GetPtr(), stat.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
|
@ -1397,7 +1265,7 @@ namespace save
|
|||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEChangeDirAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEChangeDirAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
SAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);
|
||||
|
||||
|
@ -1407,7 +1275,7 @@ namespace save
|
|||
{
|
||||
char fullPath[SAVE_MAX_PATH_SIZE];
|
||||
if (GetAbsoluteFullPath(persistentId, path, fullPath))
|
||||
result = coreinit::FSChangeDirAsync(client, block, fullPath, errHandling, (FSAsyncParamsNew_t*)asyncParams);
|
||||
result = coreinit::FSChangeDirAsync(client, block, fullPath, errHandling, (FSAsyncParams*)asyncParams);
|
||||
}
|
||||
else
|
||||
result = (FSStatus)FS_RESULT::NOT_FOUND;
|
||||
|
@ -1423,7 +1291,7 @@ namespace save
|
|||
ppcDefineParamU8(accountSlot, 2);
|
||||
ppcDefineParamMEMPTR(path, const char, 3);
|
||||
ppcDefineParamU32(errHandling, 4);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 5);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 5);
|
||||
const SAVEStatus result = SAVEChangeDirAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), accountSlot, path.GetPtr(), errHandling, asyncParams.GetPtr());
|
||||
cemuLog_log(LogType::Save, "SAVEChangeDirAsync(0x{:08x}, 0x{:08x}, {:x}, {}, {:x}) -> {:x}", fsClient.GetMPTR(), fsCmdBlock.GetMPTR(), accountSlot, path.GetPtr(), errHandling, result);
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
|
@ -1432,14 +1300,14 @@ namespace save
|
|||
SAVEStatus SAVEChangeDir(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
MEMPTR<OSThread_t> currentThread{coreinit::OSGetCurrentThread()};
|
||||
FSAsyncParams_t asyncParams;
|
||||
asyncParams.ioMsgQueue = MPTR_NULL;
|
||||
asyncParams.userCallback = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(AsyncCallback));
|
||||
FSAsyncParams asyncParams;
|
||||
asyncParams.ioMsgQueue = nullptr;
|
||||
asyncParams.userCallback = RPLLoader_MakePPCCallable(AsyncCallback);
|
||||
|
||||
StackAllocator<AsyncCallbackParam_t> param;
|
||||
param->thread = currentThread;
|
||||
param->returnStatus = (FSStatus)FS_RESULT::SUCCESS;
|
||||
asyncParams.userContext = param.GetMPTRBE();
|
||||
asyncParams.userContext = ¶m;
|
||||
|
||||
SAVEStatus status = SAVEChangeDirAsync(client, block, accountSlot, path, errHandling, &asyncParams);
|
||||
if (status == (FSStatus)FS_RESULT::SUCCESS)
|
||||
|
@ -1464,7 +1332,7 @@ namespace save
|
|||
osLib_returnFromFunction(hCPU, result);
|
||||
}
|
||||
|
||||
SAVEStatus SAVEFlushQuotaAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, FS_ERROR_MASK errHandling, const FSAsyncParams_t* asyncParams)
|
||||
SAVEStatus SAVEFlushQuotaAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)
|
||||
{
|
||||
SAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);
|
||||
|
||||
|
@ -1475,7 +1343,7 @@ namespace save
|
|||
char fullPath[SAVE_MAX_PATH_SIZE];
|
||||
if (GetAbsoluteFullPath(persistentId, nullptr, fullPath))
|
||||
{
|
||||
result = coreinit::FSFlushQuotaAsync(client, block, fullPath, errHandling, (FSAsyncParamsNew_t*)asyncParams);
|
||||
result = coreinit::FSFlushQuotaAsync(client, block, fullPath, errHandling, (FSAsyncParams*)asyncParams);
|
||||
// if(OSGetUPID != 0xF)
|
||||
UpdateSaveTimeStamp(persistentId);
|
||||
}
|
||||
|
@ -1493,7 +1361,7 @@ namespace save
|
|||
ppcDefineParamMEMPTR(fsCmdBlock, coreinit::FSCmdBlock_t, 1);
|
||||
ppcDefineParamU8(accountSlot, 2);
|
||||
ppcDefineParamU32(errHandling, 3);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams_t, 4);
|
||||
ppcDefineParamMEMPTR(asyncParams, FSAsyncParams, 4);
|
||||
const SAVEStatus result = SAVEFlushQuotaAsync(fsClient.GetPtr(), fsCmdBlock.GetPtr(), accountSlot, errHandling, asyncParams.GetPtr());
|
||||
cemuLog_log(LogType::Save, "SAVEFlushQuotaAsync(0x{:08x}, 0x{:08x}, {:x}, {:x}) -> {:x}", fsClient.GetMPTR(), fsCmdBlock.GetMPTR(), accountSlot, errHandling, result);
|
||||
osLib_returnFromFunction(hCPU, result);
|
||||
|
@ -1502,14 +1370,14 @@ namespace save
|
|||
SAVEStatus SAVEFlushQuota(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, FS_ERROR_MASK errHandling)
|
||||
{
|
||||
MEMPTR<OSThread_t> currentThread{coreinit::OSGetCurrentThread()};
|
||||
FSAsyncParams_t asyncParams;
|
||||
asyncParams.ioMsgQueue = MPTR_NULL;
|
||||
asyncParams.userCallback = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(AsyncCallback));
|
||||
FSAsyncParams asyncParams;
|
||||
asyncParams.ioMsgQueue = nullptr;
|
||||
asyncParams.userCallback = RPLLoader_MakePPCCallable(AsyncCallback);
|
||||
|
||||
StackAllocator<AsyncCallbackParam_t> param;
|
||||
param->thread = currentThread;
|
||||
param->returnStatus = (FSStatus)FS_RESULT::SUCCESS;
|
||||
asyncParams.userContext = param.GetMPTRBE();
|
||||
asyncParams.userContext = ¶m;
|
||||
|
||||
SAVEStatus status = SAVEFlushQuotaAsync(client, block, accountSlot, errHandling, &asyncParams);
|
||||
if (status == (FSStatus)FS_RESULT::SUCCESS)
|
||||
|
@ -1553,10 +1421,14 @@ namespace save
|
|||
osLib_addFunction("nn_save", "SAVEGetStatOtherNormalApplication", export_SAVEGetStatOtherNormalApplication);
|
||||
osLib_addFunction("nn_save", "SAVEGetStatOtherNormalApplicationVariation", export_SAVEGetStatOtherNormalApplicationVariation);
|
||||
|
||||
osLib_addFunction("nn_save", "SAVEOpenFile", export_SAVEOpenFile);
|
||||
osLib_addFunction("nn_save", "SAVEOpenFileOtherApplication", export_SAVEOpenFileOtherApplication);
|
||||
osLib_addFunction("nn_save", "SAVEOpenFileOtherNormalApplication", export_SAVEOpenFileOtherNormalApplication);
|
||||
osLib_addFunction("nn_save", "SAVEOpenFileOtherNormalApplicationVariation", export_SAVEOpenFileOtherNormalApplicationVariation);
|
||||
cafeExportRegister("nn_save", SAVEOpenFile, LogType::Save);
|
||||
cafeExportRegister("nn_save", SAVEOpenFileAsync, LogType::Save);
|
||||
cafeExportRegister("nn_save", SAVEOpenFileOtherApplication, LogType::Save);
|
||||
cafeExportRegister("nn_save", SAVEOpenFileOtherApplicationAsync, LogType::Save);
|
||||
cafeExportRegister("nn_save", SAVEOpenFileOtherNormalApplication, LogType::Save);
|
||||
cafeExportRegister("nn_save", SAVEOpenFileOtherNormalApplicationAsync, LogType::Save);
|
||||
cafeExportRegister("nn_save", SAVEOpenFileOtherNormalApplicationVariation, LogType::Save);
|
||||
cafeExportRegister("nn_save", SAVEOpenFileOtherNormalApplicationVariationAsync, LogType::Save);
|
||||
|
||||
osLib_addFunction("nn_save", "SAVEOpenDir", export_SAVEOpenDir);
|
||||
osLib_addFunction("nn_save", "SAVEOpenDirOtherApplication", export_SAVEOpenDirOtherApplication);
|
||||
|
@ -1578,11 +1450,6 @@ namespace save
|
|||
osLib_addFunction("nn_save", "SAVEGetStatOtherNormalApplicationAsync", export_SAVEGetStatOtherNormalApplicationAsync);
|
||||
osLib_addFunction("nn_save", "SAVEGetStatOtherNormalApplicationVariationAsync", export_SAVEGetStatOtherNormalApplicationVariationAsync);
|
||||
|
||||
osLib_addFunction("nn_save", "SAVEOpenFileAsync", export_SAVEOpenFileAsync);
|
||||
osLib_addFunction("nn_save", "SAVEOpenFileOtherApplicationAsync", export_SAVEOpenFileOtherApplicationAsync);
|
||||
osLib_addFunction("nn_save", "SAVEOpenFileOtherNormalApplicationAsync", export_SAVEOpenFileOtherNormalApplicationAsync);
|
||||
osLib_addFunction("nn_save", "SAVEOpenFileOtherNormalApplicationVariationAsync", export_SAVEOpenFileOtherNormalApplicationVariationAsync);
|
||||
|
||||
osLib_addFunction("nn_save", "SAVEOpenDirAsync", export_SAVEOpenDirAsync);
|
||||
osLib_addFunction("nn_save", "SAVEOpenDirOtherApplicationAsync", export_SAVEOpenDirOtherApplicationAsync);
|
||||
osLib_addFunction("nn_save", "SAVEOpenDirOtherNormalApplicationAsync", export_SAVEOpenDirOtherNormalApplicationAsync);
|
||||
|
|
115
src/Cafe/OS/libs/nn_sl/nn_sl.cpp
Normal file
115
src/Cafe/OS/libs/nn_sl/nn_sl.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
#include "Cafe/OS/common/OSCommon.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_IOS.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_MEM.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
|
||||
namespace nn
|
||||
{
|
||||
typedef uint32 Result;
|
||||
namespace sl
|
||||
{
|
||||
struct VTableEntry
|
||||
{
|
||||
uint16be offsetA{0};
|
||||
uint16be offsetB{0};
|
||||
MEMPTR<void> ptr;
|
||||
};
|
||||
static_assert(sizeof(VTableEntry) == 8);
|
||||
|
||||
constexpr uint32 SL_MEM_MAGIC = 0xCAFE4321;
|
||||
|
||||
#define DTOR_WRAPPER(__TYPE) RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) { dtor(MEMPTR<__TYPE>(hCPU->gpr[3]), hCPU->gpr[4]); osLib_returnFromFunction(hCPU, 0); })
|
||||
|
||||
template<typename T>
|
||||
MEMPTR<T> sl_new()
|
||||
{
|
||||
uint32 objSize = sizeof(T);
|
||||
uint32be* basePtr = (uint32be*)coreinit::_weak_MEMAllocFromDefaultHeapEx(objSize + 8, 0x8);
|
||||
basePtr[0] = SL_MEM_MAGIC;
|
||||
basePtr[1] = objSize;
|
||||
return (T*)(basePtr + 2);
|
||||
}
|
||||
|
||||
void sl_delete(MEMPTR<void> mem)
|
||||
{
|
||||
if (!mem)
|
||||
return;
|
||||
uint32be* basePtr = (uint32be*)mem.GetPtr() - 2;
|
||||
if (basePtr[0] != SL_MEM_MAGIC)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "nn_sl: Detected memory corruption");
|
||||
cemu_assert_suspicious();
|
||||
}
|
||||
coreinit::_weak_MEMFreeToDefaultHeap(basePtr);
|
||||
}
|
||||
|
||||
#pragma pack(1)
|
||||
struct WhiteList
|
||||
{
|
||||
uint32be titleTypes[50];
|
||||
uint32be titleTypesCount;
|
||||
uint32be padding;
|
||||
uint64be titleIds[50];
|
||||
uint32be titleIdCount;
|
||||
};
|
||||
static_assert(sizeof(WhiteList) == 0x264);
|
||||
#pragma pack()
|
||||
|
||||
struct WhiteListAccessor
|
||||
{
|
||||
MEMPTR<void> vTablePtr{}; // 0x00
|
||||
|
||||
struct VTable
|
||||
{
|
||||
VTableEntry rtti;
|
||||
VTableEntry dtor;
|
||||
VTableEntry get;
|
||||
};
|
||||
static inline SysAllocator<VTable> s_titleVTable;
|
||||
|
||||
static WhiteListAccessor* ctor(WhiteListAccessor* _this)
|
||||
{
|
||||
if (!_this)
|
||||
_this = sl_new<WhiteListAccessor>();
|
||||
*_this = {};
|
||||
_this->vTablePtr = s_titleVTable;
|
||||
return _this;
|
||||
}
|
||||
|
||||
static void dtor(WhiteListAccessor* _this, uint32 options)
|
||||
{
|
||||
if (_this && (options & 1))
|
||||
sl_delete(_this);
|
||||
}
|
||||
|
||||
static void Get(WhiteListAccessor* _this, nn::sl::WhiteList* outWhiteList)
|
||||
{
|
||||
*outWhiteList = {};
|
||||
}
|
||||
|
||||
static void InitVTable()
|
||||
{
|
||||
s_titleVTable->rtti.ptr = nullptr; // todo
|
||||
s_titleVTable->dtor.ptr = DTOR_WRAPPER(WhiteListAccessor);
|
||||
s_titleVTable->get.ptr = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) { Get(MEMPTR<WhiteListAccessor>(hCPU->gpr[3]), MEMPTR<WhiteList>(hCPU->gpr[4])); osLib_returnFromFunction(hCPU, 0); });
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(WhiteListAccessor) == 0x04);
|
||||
|
||||
SysAllocator<WhiteListAccessor> s_defaultWhiteListAccessor;
|
||||
|
||||
WhiteListAccessor* GetDefaultWhiteListAccessor()
|
||||
{
|
||||
return s_defaultWhiteListAccessor;
|
||||
}
|
||||
} // namespace sl
|
||||
} // namespace nn
|
||||
|
||||
void nnSL_load()
|
||||
{
|
||||
nn::sl::WhiteListAccessor::InitVTable();
|
||||
nn::sl::WhiteListAccessor::ctor(nn::sl::s_defaultWhiteListAccessor);
|
||||
|
||||
cafeExportRegisterFunc(nn::sl::GetDefaultWhiteListAccessor, "nn_sl", "GetDefaultWhiteListAccessor__Q2_2nn2slFv", LogType::NN_SL);
|
||||
}
|
1
src/Cafe/OS/libs/nn_sl/nn_sl.h
Normal file
1
src/Cafe/OS/libs/nn_sl/nn_sl.h
Normal file
|
@ -0,0 +1 @@
|
|||
void nnSL_load();
|
|
@ -36,15 +36,46 @@
|
|||
|
||||
#define WU_SO_REUSEADDR 0x0004
|
||||
#define WU_SO_KEEPALIVE 0x0008
|
||||
#define WU_SO_DONTROUTE 0x0010
|
||||
#define WU_SO_BROADCAST 0x0020
|
||||
#define WU_SO_LINGER 0x0080
|
||||
#define WU_SO_OOBINLINE 0x0100
|
||||
#define WU_SO_TCPSACK 0x0200
|
||||
#define WU_SO_WINSCALE 0x0400
|
||||
#define WU_SO_SNDBUF 0x1001
|
||||
#define WU_SO_RCVBUF 0x1002
|
||||
#define WU_SO_SNDLOWAT 0x1003
|
||||
#define WU_SO_RCVLOWAT 0x1004
|
||||
#define WU_SO_LASTERROR 0x1007
|
||||
#define WU_SO_TYPE 0x1008
|
||||
#define WU_SO_HOPCNT 0x1009
|
||||
#define WU_SO_MAXMSG 0x1010
|
||||
#define WU_SO_RXDATA 0x1011
|
||||
#define WU_SO_TXDATA 0x1012
|
||||
#define WU_SO_MYADDR 0x1013
|
||||
#define WU_SO_NBIO 0x1014
|
||||
#define WU_SO_BIO 0x1015
|
||||
#define WU_SO_NONBLOCK 0x1016
|
||||
#define WU_SO_UNKNOWN1019 0x1019 // tcp related
|
||||
#define WU_SO_UNKNOWN101A 0x101A // tcp related
|
||||
#define WU_SO_UNKNOWN101B 0x101B // tcp related
|
||||
#define WU_SO_NOSLOWSTART 0x4000
|
||||
#define WU_SO_RUSRBUF 0x10000
|
||||
|
||||
#define WU_TCP_NODELAY 0x2004
|
||||
#define WU_TCP_ACKDELAYTIME 0x2001
|
||||
#define WU_TCP_NOACKDELAY 0x2002
|
||||
#define WU_TCP_MAXSEG 0x2003
|
||||
#define WU_TCP_NODELAY 0x2004
|
||||
#define WU_TCP_UNKNOWN 0x2005 // amount of mss received before sending an ack
|
||||
|
||||
#define WU_IP_TOS 3
|
||||
#define WU_IP_TTL 4
|
||||
#define WU_IP_MULTICAST_IF 9
|
||||
#define WU_IP_MULTICAST_TTL 10
|
||||
#define WU_IP_MULTICAST_LOOP 11
|
||||
#define WU_IP_ADD_MEMBERSHIP 12
|
||||
#define WU_IP_DROP_MEMBERSHIP 13
|
||||
#define WU_IP_UNKNOWN 14
|
||||
|
||||
#define WU_SOL_SOCKET -1 // this constant differs from Win32 socket API
|
||||
|
||||
|
@ -86,10 +117,10 @@ void nsysnetExport_socket_lib_finish(PPCInterpreter_t* hCPU)
|
|||
osLib_returnFromFunction(hCPU, 0); // 0 -> Success
|
||||
}
|
||||
|
||||
uint32* __gh_errno_ptr()
|
||||
static uint32be* __gh_errno_ptr()
|
||||
{
|
||||
OSThread_t* osThread = coreinit::OSGetCurrentThread();
|
||||
return &osThread->context.error;
|
||||
return &osThread->context.ghs_errno;
|
||||
}
|
||||
|
||||
void _setSockError(sint32 errCode)
|
||||
|
@ -548,7 +579,7 @@ void nsysnetExport_setsockopt(PPCInterpreter_t* hCPU)
|
|||
}
|
||||
else
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "setsockopt(): Unsupported optname 0x{:08x}", optname);
|
||||
cemuLog_logDebug(LogType::Force, "setsockopt(WU_SOL_SOCKET): Unsupported optname 0x{:08x}", optname);
|
||||
}
|
||||
}
|
||||
else if (level == WU_IPPROTO_TCP)
|
||||
|
@ -564,18 +595,22 @@ void nsysnetExport_setsockopt(PPCInterpreter_t* hCPU)
|
|||
assert_dbg();
|
||||
}
|
||||
else
|
||||
assert_dbg();
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "setsockopt(WU_IPPROTO_TCP): Unsupported optname 0x{:08x}", optname);
|
||||
}
|
||||
}
|
||||
else if (level == WU_IPPROTO_IP)
|
||||
{
|
||||
hostLevel = IPPROTO_IP;
|
||||
if (optname == 0xC)
|
||||
if (optname == WU_IP_MULTICAST_IF || optname == WU_IP_MULTICAST_TTL ||
|
||||
optname == WU_IP_MULTICAST_LOOP || optname == WU_IP_ADD_MEMBERSHIP ||
|
||||
optname == WU_IP_DROP_MEMBERSHIP)
|
||||
{
|
||||
// unknown
|
||||
cemuLog_logDebug(LogType::Socket, "todo: setsockopt() for multicast");
|
||||
}
|
||||
else if( optname == 0x4 )
|
||||
else if(optname == WU_IP_TTL || optname == WU_IP_TOS)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "setsockopt with unsupported opname 4 for IPPROTO_IP");
|
||||
cemuLog_logDebug(LogType::Force, "setsockopt(WU_IPPROTO_IP): Unsupported optname 0x{:08x}", optname);
|
||||
}
|
||||
else
|
||||
assert_dbg();
|
||||
|
@ -649,6 +684,16 @@ void nsysnetExport_getsockopt(PPCInterpreter_t* hCPU)
|
|||
*(uint32*)optval = _swapEndianU32(optvalLE);
|
||||
// used by Lost Reavers after some loading screens
|
||||
}
|
||||
else if (optname == WU_SO_TYPE)
|
||||
{
|
||||
if (memory_readU32(optlenMPTR) != 4)
|
||||
assert_dbg();
|
||||
int optvalLE = 0;
|
||||
socklen_t optlenLE = 4;
|
||||
memory_writeU32(optlenMPTR, 4);
|
||||
*(uint32*)optval = _swapEndianU32(vs->type);
|
||||
r = WU_SO_SUCCESS;
|
||||
}
|
||||
else if (optname == WU_SO_NONBLOCK)
|
||||
{
|
||||
if (memory_readU32(optlenMPTR) != 4)
|
||||
|
@ -661,12 +706,12 @@ void nsysnetExport_getsockopt(PPCInterpreter_t* hCPU)
|
|||
}
|
||||
else
|
||||
{
|
||||
cemu_assert_debug(false);
|
||||
cemuLog_logDebug(LogType::Force, "getsockopt(WU_SOL_SOCKET): Unsupported optname 0x{:08x}", optname);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cemu_assert_debug(false);
|
||||
cemuLog_logDebug(LogType::Force, "getsockopt(): Unsupported level 0x{:08x}", level);
|
||||
}
|
||||
|
||||
osLib_returnFromFunction(hCPU, r);
|
||||
|
@ -1533,7 +1578,7 @@ void nsysnetExport_getaddrinfo(PPCInterpreter_t* hCPU)
|
|||
|
||||
void nsysnetExport_recvfrom(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
cemuLog_log(LogType::Socket, "recvfrom({},0x{:08x},{},0x{:x})", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);
|
||||
cemuLog_log(LogType::Socket, "recvfrom({},0x{:08x},{},0x{:x},0x{:x},0x{:x})", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7], hCPU->gpr[8]);
|
||||
ppcDefineParamS32(s, 0);
|
||||
ppcDefineParamStr(msg, 1);
|
||||
ppcDefineParamS32(len, 2);
|
||||
|
@ -1562,8 +1607,8 @@ void nsysnetExport_recvfrom(PPCInterpreter_t* hCPU)
|
|||
if (vs->isNonBlocking)
|
||||
requestIsNonBlocking = vs->isNonBlocking;
|
||||
|
||||
socklen_t fromLenHost = *fromLen;
|
||||
sockaddr fromAddrHost;
|
||||
socklen_t fromLenHost = sizeof(fromAddrHost);
|
||||
sint32 wsaError = 0;
|
||||
|
||||
while( true )
|
||||
|
@ -1605,9 +1650,13 @@ void nsysnetExport_recvfrom(PPCInterpreter_t* hCPU)
|
|||
if (r < 0)
|
||||
cemu_assert_debug(false);
|
||||
cemuLog_logDebug(LogType::Force, "recvfrom returned {} bytes", r);
|
||||
*fromLen = fromLenHost;
|
||||
fromAddr->sa_family = _swapEndianU16(fromAddrHost.sa_family);
|
||||
memcpy(fromAddr->sa_data, fromAddrHost.sa_data, 14);
|
||||
|
||||
// fromAddr and fromLen can be NULL
|
||||
if (fromAddr && fromLen) {
|
||||
*fromLen = fromLenHost;
|
||||
fromAddr->sa_family = _swapEndianU16(fromAddrHost.sa_family);
|
||||
memcpy(fromAddr->sa_data, fromAddrHost.sa_data, 14);
|
||||
}
|
||||
|
||||
_setSockError(0);
|
||||
osLib_returnFromFunction(hCPU, r);
|
||||
|
@ -1657,9 +1706,12 @@ void nsysnetExport_recvfrom(PPCInterpreter_t* hCPU)
|
|||
assert_dbg();
|
||||
}
|
||||
|
||||
*fromLen = fromLenHost;
|
||||
fromAddr->sa_family = _swapEndianU16(fromAddrHost.sa_family);
|
||||
memcpy(fromAddr->sa_data, fromAddrHost.sa_data, 14);
|
||||
// fromAddr and fromLen can be NULL
|
||||
if (fromAddr && fromLen) {
|
||||
*fromLen = fromLenHost;
|
||||
fromAddr->sa_family = _swapEndianU16(fromAddrHost.sa_family);
|
||||
memcpy(fromAddr->sa_data, fromAddrHost.sa_data, 14);
|
||||
}
|
||||
|
||||
_translateError(r <= 0 ? -1 : 0, wsaError);
|
||||
|
||||
|
|
|
@ -1,57 +1,908 @@
|
|||
#include "Cafe/OS/common/OSCommon.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Alarm.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Thread.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_MessageQueue.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Misc.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Memory.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Time.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_FG.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_DynLoad.h"
|
||||
#include "Cafe/OS/libs/gx2/GX2_Misc.h"
|
||||
#include "Cafe/OS/RPL/rpl.h"
|
||||
#include "Common/CafeString.h"
|
||||
#include "proc_ui.h"
|
||||
|
||||
#define PROCUI_STATUS_FOREGROUND 0
|
||||
#define PROCUI_STATUS_BACKGROUND 1
|
||||
#define PROCUI_STATUS_RELEASING 2
|
||||
#define PROCUI_STATUS_EXIT 3
|
||||
// proc_ui is a utility wrapper to help apps with the transition between foreground and background
|
||||
// some games (like Xenoblades Chronicles X) bypass proc_ui.rpl and listen to OSGetSystemMessageQueue() directly
|
||||
|
||||
uint32 ProcUIProcessMessages()
|
||||
using namespace coreinit;
|
||||
|
||||
namespace proc_ui
|
||||
{
|
||||
return PROCUI_STATUS_FOREGROUND;
|
||||
}
|
||||
enum class ProcUICoreThreadCommand
|
||||
{
|
||||
AcquireForeground = 0x0,
|
||||
ReleaseForeground = 0x1,
|
||||
Exit = 0x2,
|
||||
NetIoStart = 0x3,
|
||||
NetIoStop = 0x4,
|
||||
HomeButtonDenied = 0x5,
|
||||
Initial = 0x6
|
||||
};
|
||||
|
||||
struct ProcUIInternalCallbackEntry
|
||||
{
|
||||
coreinit::OSAlarm_t alarm;
|
||||
uint64be tickDelay;
|
||||
MEMPTR<void> funcPtr;
|
||||
MEMPTR<void> userParam;
|
||||
sint32be priority;
|
||||
MEMPTR<ProcUIInternalCallbackEntry> next;
|
||||
};
|
||||
static_assert(sizeof(ProcUIInternalCallbackEntry) == 0x70);
|
||||
|
||||
struct ProcUICallbackList
|
||||
{
|
||||
MEMPTR<ProcUIInternalCallbackEntry> first;
|
||||
};
|
||||
static_assert(sizeof(ProcUICallbackList) == 0x4);
|
||||
|
||||
std::atomic_bool s_isInitialized;
|
||||
bool s_isInForeground;
|
||||
bool s_isInShutdown;
|
||||
bool s_isForegroundProcess;
|
||||
bool s_previouslyWasBlocking;
|
||||
ProcUIStatus s_currentProcUIStatus;
|
||||
MEMPTR<void> s_saveCallback; // no param and no return value, set by ProcUIInit()
|
||||
MEMPTR<void> s_saveCallbackEx; // with custom param and return value, set by ProcUIInitEx()
|
||||
MEMPTR<void> s_saveCallbackExUserParam;
|
||||
MEMPTR<coreinit::OSMessageQueue> s_systemMessageQueuePtr;
|
||||
SysAllocator<coreinit::OSEvent> s_eventStateMessageReceived;
|
||||
SysAllocator<coreinit::OSEvent> s_eventWaitingBeforeReleaseForeground;
|
||||
SysAllocator<coreinit::OSEvent> s_eventBackgroundThreadGotMessage;
|
||||
// procUI core threads
|
||||
uint32 s_coreThreadStackSize;
|
||||
bool s_coreThreadsCreated;
|
||||
std::atomic<ProcUICoreThreadCommand> s_commandForCoreThread;
|
||||
SysAllocator<OSThread_t> s_coreThreadArray[Espresso::CORE_COUNT];
|
||||
MEMPTR<void> s_coreThreadStackPerCore[Espresso::CORE_COUNT];
|
||||
SysAllocator<CafeString<22>> s_coreThread0NameBuffer;
|
||||
SysAllocator<CafeString<22>> s_coreThread1NameBuffer;
|
||||
SysAllocator<CafeString<22>> s_coreThread2NameBuffer;
|
||||
SysAllocator<coreinit::OSEvent> s_eventCoreThreadsNewCommandReady;
|
||||
SysAllocator<coreinit::OSEvent> s_eventCoreThreadsCommandDone;
|
||||
SysAllocator<coreinit::OSRendezvous> s_coreThreadRendezvousA;
|
||||
SysAllocator<coreinit::OSRendezvous> s_coreThreadRendezvousB;
|
||||
SysAllocator<coreinit::OSRendezvous> s_coreThreadRendezvousC;
|
||||
// background thread
|
||||
MEMPTR<void> s_backgroundThreadStack;
|
||||
SysAllocator<OSThread_t> s_backgroundThread;
|
||||
// user defined heap
|
||||
MEMPTR<void> s_memoryPoolHeapPtr;
|
||||
MEMPTR<void> s_memAllocPtr;
|
||||
MEMPTR<void> s_memFreePtr;
|
||||
// draw done release
|
||||
bool s_drawDoneReleaseCalled;
|
||||
// memory storage
|
||||
MEMPTR<void> s_bucketStorageBasePtr;
|
||||
MEMPTR<void> s_mem1StorageBasePtr;
|
||||
// callbacks
|
||||
ProcUICallbackList s_callbacksType0_AcquireForeground[Espresso::CORE_COUNT];
|
||||
ProcUICallbackList s_callbacksType1_ReleaseForeground[Espresso::CORE_COUNT];
|
||||
ProcUICallbackList s_callbacksType2_Exit[Espresso::CORE_COUNT];
|
||||
ProcUICallbackList s_callbacksType3_NetIoStart[Espresso::CORE_COUNT];
|
||||
ProcUICallbackList s_callbacksType4_NetIoStop[Espresso::CORE_COUNT];
|
||||
ProcUICallbackList s_callbacksType5_HomeButtonDenied[Espresso::CORE_COUNT];
|
||||
ProcUICallbackList* const s_CallbackTables[stdx::to_underlying(ProcUICallbackId::COUNT)] =
|
||||
{s_callbacksType0_AcquireForeground, s_callbacksType1_ReleaseForeground, s_callbacksType2_Exit, s_callbacksType3_NetIoStart, s_callbacksType4_NetIoStop, s_callbacksType5_HomeButtonDenied};
|
||||
ProcUICallbackList s_backgroundCallbackList;
|
||||
// driver
|
||||
bool s_driverIsActive;
|
||||
uint32be s_driverArgUkn1;
|
||||
uint32be s_driverArgUkn2;
|
||||
bool s_driverInBackground;
|
||||
SysAllocator<OSDriverInterface> s_ProcUIDriver;
|
||||
SysAllocator<CafeString<16>> s_ProcUIDriverName;
|
||||
|
||||
|
||||
uint32 ProcUIInForeground(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
return 1; // true means application is in foreground
|
||||
}
|
||||
void* _AllocMem(uint32 size)
|
||||
{
|
||||
MEMPTR<void> r{PPCCoreCallback(s_memAllocPtr, size)};
|
||||
return r.GetPtr();
|
||||
}
|
||||
|
||||
struct ProcUICallback
|
||||
{
|
||||
MPTR callback;
|
||||
void* data;
|
||||
sint32 priority;
|
||||
void _FreeMem(void* ptr)
|
||||
{
|
||||
PPCCoreCallback(s_memFreePtr.GetMPTR(), ptr);
|
||||
}
|
||||
|
||||
void ClearCallbacksWithoutMemFree()
|
||||
{
|
||||
for (sint32 coreIndex = 0; coreIndex < Espresso::CORE_COUNT; coreIndex++)
|
||||
{
|
||||
for (sint32 i = 0; i < stdx::to_underlying(ProcUICallbackId::COUNT); i++)
|
||||
s_CallbackTables[i][coreIndex].first = nullptr;
|
||||
}
|
||||
s_backgroundCallbackList.first = nullptr;
|
||||
}
|
||||
|
||||
void ShutdownThreads()
|
||||
{
|
||||
if ( !s_coreThreadsCreated)
|
||||
return;
|
||||
s_commandForCoreThread = ProcUICoreThreadCommand::Initial;
|
||||
coreinit::OSMemoryBarrier();
|
||||
OSSignalEvent(&s_eventCoreThreadsNewCommandReady);
|
||||
for (sint32 coreIndex = 0; coreIndex < Espresso::CORE_COUNT; coreIndex++)
|
||||
{
|
||||
coreinit::OSJoinThread(&s_coreThreadArray[coreIndex], nullptr);
|
||||
for (sint32 i = 0; i < stdx::to_underlying(ProcUICallbackId::COUNT); i++)
|
||||
{
|
||||
s_CallbackTables[i][coreIndex].first = nullptr; // memory is not cleanly released?
|
||||
}
|
||||
}
|
||||
OSResetEvent(&s_eventCoreThreadsNewCommandReady);
|
||||
for (sint32 coreIndex = 0; coreIndex < Espresso::CORE_COUNT; coreIndex++)
|
||||
{
|
||||
_FreeMem(s_coreThreadStackPerCore[coreIndex]);
|
||||
s_coreThreadStackPerCore[coreIndex] = nullptr;
|
||||
}
|
||||
_FreeMem(s_backgroundThreadStack);
|
||||
s_backgroundThreadStack = nullptr;
|
||||
s_backgroundCallbackList.first = nullptr; // memory is not cleanly released?
|
||||
s_coreThreadsCreated = false;
|
||||
}
|
||||
|
||||
void DoCallbackChain(ProcUIInternalCallbackEntry* entry)
|
||||
{
|
||||
while (entry)
|
||||
{
|
||||
uint32 r = PPCCoreCallback(entry->funcPtr, entry->userParam);
|
||||
if ( r )
|
||||
cemuLog_log(LogType::APIErrors, "ProcUI: Callback returned error {}\n", r);
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
void AlarmDoBackgroundCallback(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
coreinit::OSAlarm_t* arg = MEMPTR<coreinit::OSAlarm_t>(hCPU->gpr[3]);
|
||||
ProcUIInternalCallbackEntry* entry = (ProcUIInternalCallbackEntry*)arg;
|
||||
uint32 r = PPCCoreCallback(entry->funcPtr, entry->userParam);
|
||||
if ( r )
|
||||
cemuLog_log(LogType::APIErrors, "ProcUI: Background callback returned error {}\n", r);
|
||||
osLib_returnFromFunction(hCPU, 0); // return type is void
|
||||
}
|
||||
|
||||
void StartBackgroundAlarms()
|
||||
{
|
||||
ProcUIInternalCallbackEntry* cb = s_backgroundCallbackList.first;
|
||||
while(cb)
|
||||
{
|
||||
coreinit::OSCreateAlarm(&cb->alarm);
|
||||
uint64 currentTime = coreinit::OSGetTime();
|
||||
coreinit::OSSetPeriodicAlarm(&cb->alarm, currentTime, cb->tickDelay, RPLLoader_MakePPCCallable(AlarmDoBackgroundCallback));
|
||||
cb = cb->next;
|
||||
}
|
||||
}
|
||||
|
||||
void CancelBackgroundAlarms()
|
||||
{
|
||||
ProcUIInternalCallbackEntry* entry = s_backgroundCallbackList.first;
|
||||
while (entry)
|
||||
{
|
||||
OSCancelAlarm(&entry->alarm);
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
void ProcUICoreThread(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
uint32 coreIndex = hCPU->gpr[3];
|
||||
cemu_assert_debug(coreIndex == OSGetCoreId());
|
||||
while (true)
|
||||
{
|
||||
OSWaitEvent(&s_eventCoreThreadsNewCommandReady);
|
||||
ProcUIInternalCallbackEntry* cbChain = nullptr;
|
||||
cemuLog_logDebug(LogType::Force, "ProcUI: Core {} got command {}", coreIndex, (uint32)s_commandForCoreThread.load());
|
||||
auto cmd = s_commandForCoreThread.load();
|
||||
switch(cmd)
|
||||
{
|
||||
case ProcUICoreThreadCommand::Initial:
|
||||
{
|
||||
// signal to shut down thread
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
return;
|
||||
}
|
||||
case ProcUICoreThreadCommand::AcquireForeground:
|
||||
cbChain = s_callbacksType0_AcquireForeground[coreIndex].first;
|
||||
break;
|
||||
case ProcUICoreThreadCommand::ReleaseForeground:
|
||||
cbChain = s_callbacksType1_ReleaseForeground[coreIndex].first;
|
||||
break;
|
||||
case ProcUICoreThreadCommand::Exit:
|
||||
cbChain = s_callbacksType2_Exit[coreIndex].first;
|
||||
break;
|
||||
case ProcUICoreThreadCommand::NetIoStart:
|
||||
cbChain = s_callbacksType3_NetIoStart[coreIndex].first;
|
||||
break;
|
||||
case ProcUICoreThreadCommand::NetIoStop:
|
||||
cbChain = s_callbacksType4_NetIoStop[coreIndex].first;
|
||||
break;
|
||||
case ProcUICoreThreadCommand::HomeButtonDenied:
|
||||
cbChain = s_callbacksType5_HomeButtonDenied[coreIndex].first;
|
||||
break;
|
||||
default:
|
||||
cemu_assert_suspicious(); // invalid command
|
||||
}
|
||||
if(cmd == ProcUICoreThreadCommand::AcquireForeground)
|
||||
{
|
||||
if (coreIndex == 2)
|
||||
CancelBackgroundAlarms();
|
||||
cbChain = s_callbacksType0_AcquireForeground[coreIndex].first;
|
||||
}
|
||||
else if(cmd == ProcUICoreThreadCommand::ReleaseForeground)
|
||||
{
|
||||
if (coreIndex == 2)
|
||||
StartBackgroundAlarms();
|
||||
cbChain = s_callbacksType1_ReleaseForeground[coreIndex].first;
|
||||
}
|
||||
DoCallbackChain(cbChain);
|
||||
OSWaitRendezvous(&s_coreThreadRendezvousA, 7);
|
||||
if ( !coreIndex )
|
||||
{
|
||||
OSInitRendezvous(&s_coreThreadRendezvousC);
|
||||
OSResetEvent(&s_eventCoreThreadsNewCommandReady);
|
||||
}
|
||||
OSWaitRendezvous(&s_coreThreadRendezvousB, 7);
|
||||
if ( !coreIndex )
|
||||
{
|
||||
OSInitRendezvous(&s_coreThreadRendezvousA);
|
||||
OSSignalEvent(&s_eventCoreThreadsCommandDone);
|
||||
}
|
||||
OSWaitRendezvous(&s_coreThreadRendezvousC, 7);
|
||||
if ( !coreIndex )
|
||||
OSInitRendezvous(&s_coreThreadRendezvousB);
|
||||
if (cmd == ProcUICoreThreadCommand::ReleaseForeground)
|
||||
{
|
||||
OSWaitEvent(&s_eventWaitingBeforeReleaseForeground);
|
||||
OSReleaseForeground();
|
||||
}
|
||||
}
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
void RecreateProcUICoreThreads()
|
||||
{
|
||||
ShutdownThreads();
|
||||
for (sint32 coreIndex = 0; coreIndex < Espresso::CORE_COUNT; coreIndex++)
|
||||
{
|
||||
s_coreThreadStackPerCore[coreIndex] = _AllocMem(s_coreThreadStackSize);
|
||||
}
|
||||
s_backgroundThreadStack = _AllocMem(s_coreThreadStackSize);
|
||||
for (sint32 coreIndex = 0; coreIndex < Espresso::CORE_COUNT; coreIndex++)
|
||||
{
|
||||
__OSCreateThreadType(&s_coreThreadArray[coreIndex], RPLLoader_MakePPCCallable(ProcUICoreThread), coreIndex, nullptr,
|
||||
(uint8*)s_coreThreadStackPerCore[coreIndex].GetPtr() + s_coreThreadStackSize, s_coreThreadStackSize, 16,
|
||||
(1<<coreIndex), OSThread_t::THREAD_TYPE::TYPE_DRIVER);
|
||||
OSResumeThread(&s_coreThreadArray[coreIndex]);
|
||||
}
|
||||
s_coreThread0NameBuffer->assign("{SYS ProcUI Core 0}");
|
||||
s_coreThread1NameBuffer->assign("{SYS ProcUI Core 1}");
|
||||
s_coreThread2NameBuffer->assign("{SYS ProcUI Core 2}");
|
||||
OSSetThreadName(&s_coreThreadArray[0], s_coreThread0NameBuffer->c_str());
|
||||
OSSetThreadName(&s_coreThreadArray[1], s_coreThread1NameBuffer->c_str());
|
||||
OSSetThreadName(&s_coreThreadArray[2], s_coreThread2NameBuffer->c_str());
|
||||
s_coreThreadsCreated = true;
|
||||
}
|
||||
|
||||
void _SubmitCommandToCoreThreads(ProcUICoreThreadCommand cmd)
|
||||
{
|
||||
s_commandForCoreThread = cmd;
|
||||
OSMemoryBarrier();
|
||||
OSResetEvent(&s_eventCoreThreadsCommandDone);
|
||||
OSSignalEvent(&s_eventCoreThreadsNewCommandReady);
|
||||
OSWaitEvent(&s_eventCoreThreadsCommandDone);
|
||||
}
|
||||
|
||||
void ProcUIInitInternal()
|
||||
{
|
||||
if( s_isInitialized.exchange(true) )
|
||||
return;
|
||||
if (!s_memoryPoolHeapPtr)
|
||||
{
|
||||
// user didn't specify a custom heap, use default heap instead
|
||||
s_memAllocPtr = gCoreinitData->MEMAllocFromDefaultHeap.GetMPTR();
|
||||
s_memFreePtr = gCoreinitData->MEMFreeToDefaultHeap.GetMPTR();
|
||||
}
|
||||
OSInitEvent(&s_eventStateMessageReceived, OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_MANUAL);
|
||||
OSInitEvent(&s_eventCoreThreadsNewCommandReady, OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_MANUAL);
|
||||
OSInitEvent(&s_eventWaitingBeforeReleaseForeground, OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_MANUAL);
|
||||
OSInitEvent(&s_eventCoreThreadsCommandDone, OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_MANUAL);
|
||||
OSInitRendezvous(&s_coreThreadRendezvousA);
|
||||
OSInitRendezvous(&s_coreThreadRendezvousB);
|
||||
OSInitRendezvous(&s_coreThreadRendezvousC);
|
||||
OSInitEvent(&s_eventBackgroundThreadGotMessage, OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_MANUAL);
|
||||
s_currentProcUIStatus = ProcUIStatus::Foreground;
|
||||
s_drawDoneReleaseCalled = false;
|
||||
s_isInForeground = true;
|
||||
s_coreThreadStackSize = 0x2000;
|
||||
s_systemMessageQueuePtr = coreinit::OSGetSystemMessageQueue();
|
||||
uint32 upid = coreinit::OSGetUPID();
|
||||
s_isForegroundProcess = upid == 2 || upid == 15; // either Wii U Menu or game title, both are RAMPID 7 (foreground process)
|
||||
RecreateProcUICoreThreads();
|
||||
ClearCallbacksWithoutMemFree();
|
||||
}
|
||||
|
||||
void ProcUIInit(MEMPTR<void> callbackReadyToRelease)
|
||||
{
|
||||
s_saveCallback = callbackReadyToRelease;
|
||||
s_saveCallbackEx = nullptr;
|
||||
s_saveCallbackExUserParam = nullptr;
|
||||
ProcUIInitInternal();
|
||||
}
|
||||
|
||||
void ProcUIInitEx(MEMPTR<void> callbackReadyToReleaseEx, MEMPTR<void> userParam)
|
||||
{
|
||||
s_saveCallback = nullptr;
|
||||
s_saveCallbackEx = callbackReadyToReleaseEx;
|
||||
s_saveCallbackExUserParam = userParam;
|
||||
ProcUIInitInternal();
|
||||
}
|
||||
|
||||
void ProcUIShutdown()
|
||||
{
|
||||
if (!s_isInitialized.exchange(false))
|
||||
return;
|
||||
if ( !s_isInForeground )
|
||||
CancelBackgroundAlarms();
|
||||
for (sint32 i = 0; i < Espresso::CORE_COUNT; i++)
|
||||
OSSetThreadPriority(&s_coreThreadArray[i], 0);
|
||||
_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::Exit);
|
||||
ProcUIClearCallbacks();
|
||||
ShutdownThreads();
|
||||
}
|
||||
|
||||
bool ProcUIIsRunning()
|
||||
{
|
||||
return s_isInitialized;
|
||||
}
|
||||
|
||||
bool ProcUIInForeground()
|
||||
{
|
||||
return s_isInForeground;
|
||||
}
|
||||
|
||||
bool ProcUIInShutdown()
|
||||
{
|
||||
return s_isInShutdown;
|
||||
}
|
||||
|
||||
void AddCallbackInternal(void* funcPtr, void* userParam, uint64 tickDelay, sint32 priority, ProcUICallbackList& callbackList)
|
||||
{
|
||||
if ( __OSGetProcessSDKVersion() < 21102 )
|
||||
{
|
||||
// in earlier COS versions it was possible/allowed to register a callback before initializing ProcUI
|
||||
s_memAllocPtr = gCoreinitData->MEMAllocFromDefaultHeap.GetMPTR();
|
||||
s_memFreePtr = gCoreinitData->MEMFreeToDefaultHeap.GetMPTR();
|
||||
}
|
||||
else if ( !s_isInitialized )
|
||||
{
|
||||
cemuLog_log(LogType::Force, "ProcUI: Trying to register callback before init");
|
||||
cemu_assert_suspicious();
|
||||
// this shouldn't happen but lets set the memory pointers anyway to prevent a crash in case the user has incorrect meta info
|
||||
s_memAllocPtr = gCoreinitData->MEMAllocFromDefaultHeap.GetMPTR();
|
||||
s_memFreePtr = gCoreinitData->MEMFreeToDefaultHeap.GetMPTR();
|
||||
}
|
||||
ProcUIInternalCallbackEntry* entry = (ProcUIInternalCallbackEntry*)_AllocMem(sizeof(ProcUIInternalCallbackEntry));
|
||||
entry->funcPtr = funcPtr;
|
||||
entry->userParam = userParam;
|
||||
entry->tickDelay = tickDelay;
|
||||
entry->priority = priority;
|
||||
ProcUIInternalCallbackEntry* cur = callbackList.first;
|
||||
cur = callbackList.first;
|
||||
if (!cur || cur->priority > priority)
|
||||
{
|
||||
// insert as the first element
|
||||
entry->next = cur;
|
||||
callbackList.first = entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
// find the correct position to insert
|
||||
while (cur->next && cur->next->priority < priority)
|
||||
cur = cur->next;
|
||||
entry->next = cur->next;
|
||||
cur->next = entry;
|
||||
}
|
||||
}
|
||||
|
||||
void ProcUIRegisterCallbackCore(ProcUICallbackId callbackType, void* funcPtr, void* userParam, sint32 priority, uint32 coreIndex)
|
||||
{
|
||||
if(callbackType >= ProcUICallbackId::COUNT)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "ProcUIRegisterCallback: Invalid callback type {}", stdx::to_underlying(callbackType));
|
||||
return;
|
||||
}
|
||||
if(callbackType != ProcUICallbackId::AcquireForeground)
|
||||
priority = -priority;
|
||||
AddCallbackInternal(funcPtr, userParam, priority, 0, s_CallbackTables[stdx::to_underlying(callbackType)][coreIndex]);
|
||||
}
|
||||
|
||||
void ProcUIRegisterCallback(ProcUICallbackId callbackType, void* funcPtr, void* userParam, sint32 priority)
|
||||
{
|
||||
ProcUIRegisterCallbackCore(callbackType, funcPtr, userParam, priority, OSGetCoreId());
|
||||
}
|
||||
|
||||
void ProcUIRegisterBackgroundCallback(void* funcPtr, void* userParam, uint64 tickDelay)
|
||||
{
|
||||
AddCallbackInternal(funcPtr, userParam, 0, tickDelay, s_backgroundCallbackList);
|
||||
}
|
||||
|
||||
void FreeCallbackChain(ProcUICallbackList& callbackList)
|
||||
{
|
||||
ProcUIInternalCallbackEntry* entry = callbackList.first;
|
||||
while (entry)
|
||||
{
|
||||
ProcUIInternalCallbackEntry* next = entry->next;
|
||||
_FreeMem(entry);
|
||||
entry = next;
|
||||
}
|
||||
callbackList.first = nullptr;
|
||||
}
|
||||
|
||||
void ProcUIClearCallbacks()
|
||||
{
|
||||
for (sint32 coreIndex = 0; coreIndex < Espresso::CORE_COUNT; coreIndex++)
|
||||
{
|
||||
for (sint32 i = 0; i < stdx::to_underlying(ProcUICallbackId::COUNT); i++)
|
||||
{
|
||||
FreeCallbackChain(s_CallbackTables[i][coreIndex]);
|
||||
}
|
||||
}
|
||||
if (!s_isInForeground)
|
||||
CancelBackgroundAlarms();
|
||||
FreeCallbackChain(s_backgroundCallbackList);
|
||||
}
|
||||
|
||||
void ProcUISetSaveCallback(void* funcPtr, void* userParam)
|
||||
{
|
||||
s_saveCallback = nullptr;
|
||||
s_saveCallbackEx = funcPtr;
|
||||
s_saveCallbackExUserParam = userParam;
|
||||
}
|
||||
|
||||
void ProcUISetCallbackStackSize(uint32 newStackSize)
|
||||
{
|
||||
s_coreThreadStackSize = newStackSize;
|
||||
if( s_isInitialized )
|
||||
RecreateProcUICoreThreads();
|
||||
}
|
||||
|
||||
uint32 ProcUICalcMemorySize(uint32 numCallbacks)
|
||||
{
|
||||
// each callback entry is 0x70 bytes with 0x14 bytes of allocator overhead (for ExpHeap). But for some reason proc_ui on 5.5.5 seems to reserve 0x8C0 bytes per callback?
|
||||
uint32 stackReserveSize = (Espresso::CORE_COUNT + 1) * s_coreThreadStackSize; // 3 core threads + 1 message receive thread
|
||||
uint32 callbackReserveSize = 0x8C0 * numCallbacks;
|
||||
return stackReserveSize + callbackReserveSize + 100;
|
||||
}
|
||||
|
||||
void _MemAllocFromMemoryPool(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
uint32 size = hCPU->gpr[3];
|
||||
MEMPTR<void> r = MEMAllocFromExpHeapEx((MEMHeapHandle)s_memoryPoolHeapPtr.GetPtr(), size, 4);
|
||||
osLib_returnFromFunction(hCPU, r.GetMPTR());
|
||||
}
|
||||
|
||||
void _FreeToMemoryPoolExpHeap(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
MEMPTR<void> mem{hCPU->gpr[3]};
|
||||
MEMFreeToExpHeap((MEMHeapHandle)s_memoryPoolHeapPtr.GetPtr(), mem.GetPtr());
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
sint32 ProcUISetMemoryPool(void* memBase, uint32 size)
|
||||
{
|
||||
s_memAllocPtr = RPLLoader_MakePPCCallable(_MemAllocFromMemoryPool);
|
||||
s_memFreePtr = RPLLoader_MakePPCCallable(_FreeToMemoryPoolExpHeap);
|
||||
s_memoryPoolHeapPtr = MEMCreateExpHeapEx(memBase, size, MEM_HEAP_OPTION_THREADSAFE);
|
||||
return s_memoryPoolHeapPtr ? 0 : -1;
|
||||
}
|
||||
|
||||
void ProcUISetBucketStorage(void* memBase, uint32 size)
|
||||
{
|
||||
MEMPTR<void> fgBase;
|
||||
uint32be fgFreeSize;
|
||||
OSGetForegroundBucketFreeArea(&fgBase, &fgFreeSize);
|
||||
if(fgFreeSize < size)
|
||||
cemuLog_log(LogType::Force, "ProcUISetBucketStorage: Buffer size too small");
|
||||
s_bucketStorageBasePtr = memBase;
|
||||
}
|
||||
|
||||
void ProcUISetMEM1Storage(void* memBase, uint32 size)
|
||||
{
|
||||
MEMPTR<void> memBound;
|
||||
uint32be memBoundSize;
|
||||
OSGetMemBound(1, &memBound, &memBoundSize);
|
||||
if(memBoundSize < size)
|
||||
cemuLog_log(LogType::Force, "ProcUISetMEM1Storage: Buffer size too small");
|
||||
s_mem1StorageBasePtr = memBase;
|
||||
}
|
||||
|
||||
void ProcUIDrawDoneRelease()
|
||||
{
|
||||
s_drawDoneReleaseCalled = true;
|
||||
}
|
||||
|
||||
OSMessage g_lastMsg;
|
||||
|
||||
void ProcUI_BackgroundThread_ReceiveSingleMessage(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
// the background thread receives messages in a loop until the title is either exited or foreground is acquired
|
||||
while ( true )
|
||||
{
|
||||
OSReceiveMessage(s_systemMessageQueuePtr, &g_lastMsg, OS_MESSAGE_BLOCK); // blocking receive
|
||||
SysMessageId lastMsgId = static_cast<SysMessageId>((uint32)g_lastMsg.data0);
|
||||
if(lastMsgId == SysMessageId::MsgExit || lastMsgId == SysMessageId::MsgAcquireForeground)
|
||||
break;
|
||||
else if (lastMsgId == SysMessageId::HomeButtonDenied)
|
||||
{
|
||||
cemu_assert_suspicious(); // Home button denied should not be sent to background app
|
||||
}
|
||||
else if ( lastMsgId == SysMessageId::NetIoStartOrStop )
|
||||
{
|
||||
if (g_lastMsg.data1 )
|
||||
{
|
||||
// NetIo start message
|
||||
for (sint32 i = 0; i < Espresso::CORE_COUNT; i++)
|
||||
DoCallbackChain(s_callbacksType3_NetIoStart[i].first);
|
||||
}
|
||||
else
|
||||
{
|
||||
// NetIo stop message
|
||||
for (sint32 i = 0; i < Espresso::CORE_COUNT; i++)
|
||||
DoCallbackChain(s_callbacksType4_NetIoStop[i].first);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cemuLog_log(LogType::Force, "ProcUI: BackgroundThread received invalid message 0x{:08x}", lastMsgId);
|
||||
}
|
||||
}
|
||||
OSSignalEvent(&s_eventBackgroundThreadGotMessage);
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
// handle received message
|
||||
// if the message is Exit this function returns false, in all other cases it returns true
|
||||
bool ProcessSysMessage(OSMessage* msg)
|
||||
{
|
||||
SysMessageId lastMsgId = static_cast<SysMessageId>((uint32)msg->data0);
|
||||
if ( lastMsgId == SysMessageId::MsgAcquireForeground )
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "ProcUI: Received Acquire Foreground message");
|
||||
s_isInShutdown = false;
|
||||
_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::AcquireForeground);
|
||||
s_currentProcUIStatus = ProcUIStatus::Foreground;
|
||||
s_isInForeground = true;
|
||||
OSMemoryBarrier();
|
||||
OSSignalEvent(&s_eventStateMessageReceived);
|
||||
return true;
|
||||
}
|
||||
else if (lastMsgId == SysMessageId::MsgExit)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "ProcUI: Received Exit message");
|
||||
s_isInShutdown = true;
|
||||
_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::Exit);
|
||||
for (sint32 i = 0; i < Espresso::CORE_COUNT; i++)
|
||||
FreeCallbackChain(s_callbacksType2_Exit[i]);
|
||||
s_currentProcUIStatus = ProcUIStatus::Exit;
|
||||
OSMemoryBarrier();
|
||||
OSSignalEvent(&s_eventStateMessageReceived);
|
||||
return 0;
|
||||
}
|
||||
if (lastMsgId == SysMessageId::MsgReleaseForeground)
|
||||
{
|
||||
if (msg->data1 != 0)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "ProcUI: Received Release Foreground message as part of shutdown initiation");
|
||||
s_isInShutdown = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "ProcUI: Received Release Foreground message");
|
||||
}
|
||||
s_currentProcUIStatus = ProcUIStatus::Releasing;
|
||||
OSResetEvent(&s_eventStateMessageReceived);
|
||||
// dont submit a command for the core threads yet, we need to wait for ProcUIDrawDoneRelease()
|
||||
}
|
||||
else if (lastMsgId == SysMessageId::HomeButtonDenied)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "ProcUI: Received Home Button Denied message");
|
||||
_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::HomeButtonDenied);
|
||||
}
|
||||
else if ( lastMsgId == SysMessageId::NetIoStartOrStop )
|
||||
{
|
||||
if (msg->data1 != 0)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "ProcUI: Received Net IO Start message");
|
||||
_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::NetIoStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "ProcUI: Received Net IO Stop message");
|
||||
_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::NetIoStop);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cemuLog_log(LogType::Force, "ProcUI: Received unknown message 0x{:08x}", (uint32)lastMsgId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ProcUIStatus ProcUIProcessMessages(bool isBlockingInBackground)
|
||||
{
|
||||
OSMessage msg;
|
||||
if (!s_isInitialized)
|
||||
{
|
||||
cemuLog_logOnce(LogType::Force, "ProcUIProcessMessages: ProcUI not initialized");
|
||||
cemu_assert_suspicious();
|
||||
return ProcUIStatus::Foreground;
|
||||
}
|
||||
if ( !isBlockingInBackground && OSGetCoreId() != 2 )
|
||||
{
|
||||
cemuLog_logOnce(LogType::Force, "ProcUIProcessMessages: Non-blocking call must run on core 2");
|
||||
}
|
||||
if (s_previouslyWasBlocking && isBlockingInBackground )
|
||||
{
|
||||
cemuLog_logOnce(LogType::Force, "ProcUIProcessMessages: Cannot switch to blocking mode when in background");
|
||||
}
|
||||
s_currentProcUIStatus = s_isInForeground ? ProcUIStatus::Foreground : ProcUIStatus::Background;
|
||||
if (s_drawDoneReleaseCalled)
|
||||
{
|
||||
s_isInForeground = false;
|
||||
s_currentProcUIStatus = ProcUIStatus::Background;
|
||||
_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::ReleaseForeground);
|
||||
OSResetEvent(&s_eventWaitingBeforeReleaseForeground);
|
||||
if(s_saveCallback)
|
||||
PPCCoreCallback(s_saveCallback);
|
||||
if(s_saveCallbackEx)
|
||||
PPCCoreCallback(s_saveCallbackEx, s_saveCallbackExUserParam);
|
||||
if (s_isForegroundProcess && isBlockingInBackground)
|
||||
{
|
||||
// start background thread
|
||||
__OSCreateThreadType(&s_backgroundThread, RPLLoader_MakePPCCallable(ProcUI_BackgroundThread_ReceiveSingleMessage),
|
||||
0, nullptr, (uint8*)s_backgroundThreadStack.GetPtr() + s_coreThreadStackSize, s_coreThreadStackSize,
|
||||
16, (1<<2), OSThread_t::THREAD_TYPE::TYPE_DRIVER);
|
||||
OSResumeThread(&s_backgroundThread);
|
||||
s_previouslyWasBlocking = true;
|
||||
}
|
||||
cemuLog_logDebug(LogType::Force, "ProcUI: Releasing foreground");
|
||||
OSSignalEvent(&s_eventWaitingBeforeReleaseForeground);
|
||||
s_drawDoneReleaseCalled = false;
|
||||
}
|
||||
if (s_isInForeground || !isBlockingInBackground)
|
||||
{
|
||||
// non-blocking mode
|
||||
if ( OSReceiveMessage(s_systemMessageQueuePtr, &msg, 0) )
|
||||
{
|
||||
s_previouslyWasBlocking = false;
|
||||
if ( !ProcessSysMessage(&msg) )
|
||||
return s_currentProcUIStatus;
|
||||
// continue below, if we are now in background then ProcUIProcessMessages enters blocking mode
|
||||
}
|
||||
}
|
||||
// blocking mode (if in background and param is true)
|
||||
while (!s_isInForeground && isBlockingInBackground)
|
||||
{
|
||||
if ( !s_isForegroundProcess)
|
||||
{
|
||||
OSReceiveMessage(s_systemMessageQueuePtr, &msg, OS_MESSAGE_BLOCK);
|
||||
s_previouslyWasBlocking = false;
|
||||
if ( !ProcessSysMessage(&msg) )
|
||||
return s_currentProcUIStatus;
|
||||
}
|
||||
// this code should only run if the background thread was started? Maybe rearrange the code to make this more clear
|
||||
OSWaitEvent(&s_eventBackgroundThreadGotMessage);
|
||||
OSResetEvent(&s_eventBackgroundThreadGotMessage);
|
||||
OSJoinThread(&s_backgroundThread, nullptr);
|
||||
msg = g_lastMsg; // g_lastMsg is set by the background thread
|
||||
s_previouslyWasBlocking = false;
|
||||
if ( !ProcessSysMessage(&msg) )
|
||||
return s_currentProcUIStatus;
|
||||
}
|
||||
return s_currentProcUIStatus;
|
||||
}
|
||||
|
||||
ProcUIStatus ProcUISubProcessMessages(bool isBlockingInBackground)
|
||||
{
|
||||
if (isBlockingInBackground)
|
||||
{
|
||||
while (s_currentProcUIStatus == ProcUIStatus::Background)
|
||||
OSWaitEvent(&s_eventStateMessageReceived);
|
||||
}
|
||||
return s_currentProcUIStatus;
|
||||
}
|
||||
|
||||
const char* ProcUIDriver_GetName()
|
||||
{
|
||||
s_ProcUIDriverName->assign("ProcUI");
|
||||
return s_ProcUIDriverName->c_str();
|
||||
}
|
||||
|
||||
void ProcUIDriver_Init(/* parameters unknown */)
|
||||
{
|
||||
s_driverIsActive = true;
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
|
||||
void ProcUIDriver_OnDone(/* parameters unknown */)
|
||||
{
|
||||
if (s_driverIsActive)
|
||||
{
|
||||
ProcUIShutdown();
|
||||
s_driverIsActive = false;
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
}
|
||||
|
||||
void StoreMEM1AndFGBucket()
|
||||
{
|
||||
if (s_mem1StorageBasePtr)
|
||||
{
|
||||
MEMPTR<void> memBound;
|
||||
uint32be memBoundSize;
|
||||
OSGetMemBound(1, &memBound, &memBoundSize);
|
||||
OSBlockMove(s_mem1StorageBasePtr.GetPtr(), memBound.GetPtr(), memBoundSize, true);
|
||||
}
|
||||
if (s_bucketStorageBasePtr)
|
||||
{
|
||||
MEMPTR<void> memBound;
|
||||
uint32be memBoundSize;
|
||||
OSGetForegroundBucketFreeArea(&memBound, &memBoundSize);
|
||||
OSBlockMove(s_bucketStorageBasePtr.GetPtr(), memBound.GetPtr(), memBoundSize, true);
|
||||
}
|
||||
}
|
||||
|
||||
void RestoreMEM1AndFGBucket()
|
||||
{
|
||||
if (s_mem1StorageBasePtr)
|
||||
{
|
||||
MEMPTR<void> memBound;
|
||||
uint32be memBoundSize;
|
||||
OSGetMemBound(1, &memBound, &memBoundSize);
|
||||
OSBlockMove(memBound.GetPtr(), s_mem1StorageBasePtr, memBoundSize, true);
|
||||
GX2::GX2Invalidate(0x40, s_mem1StorageBasePtr.GetMPTR(), memBoundSize);
|
||||
}
|
||||
if (s_bucketStorageBasePtr)
|
||||
{
|
||||
MEMPTR<void> memBound;
|
||||
uint32be memBoundSize;
|
||||
OSGetForegroundBucketFreeArea(&memBound, &memBoundSize);
|
||||
OSBlockMove(memBound.GetPtr(), s_bucketStorageBasePtr, memBoundSize, true);
|
||||
GX2::GX2Invalidate(0x40, memBound.GetMPTR(), memBoundSize);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcUIDriver_OnAcquiredForeground(/* parameters unknown */)
|
||||
{
|
||||
if (s_driverInBackground)
|
||||
{
|
||||
ProcUIDriver_Init();
|
||||
s_driverInBackground = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
RestoreMEM1AndFGBucket();
|
||||
s_driverIsActive = true;
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
}
|
||||
|
||||
void ProcUIDriver_OnReleaseForeground(/* parameters unknown */)
|
||||
{
|
||||
StoreMEM1AndFGBucket();
|
||||
s_driverIsActive = false;
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
|
||||
sint32 rpl_entry(uint32 moduleHandle, RplEntryReason reason)
|
||||
{
|
||||
if ( reason == RplEntryReason::Loaded )
|
||||
{
|
||||
s_ProcUIDriver->getDriverName = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) {MEMPTR<const char> namePtr(ProcUIDriver_GetName()); osLib_returnFromFunction(hCPU, namePtr.GetMPTR()); });
|
||||
s_ProcUIDriver->init = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) {ProcUIDriver_Init(); osLib_returnFromFunction(hCPU, 0); });
|
||||
s_ProcUIDriver->onAcquireForeground = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) {ProcUIDriver_OnAcquiredForeground(); osLib_returnFromFunction(hCPU, 0); });
|
||||
s_ProcUIDriver->onReleaseForeground = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) {ProcUIDriver_OnReleaseForeground(); osLib_returnFromFunction(hCPU, 0); });
|
||||
s_ProcUIDriver->done = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) {ProcUIDriver_OnDone(); osLib_returnFromFunction(hCPU, 0); });
|
||||
|
||||
s_driverIsActive = false;
|
||||
s_driverArgUkn1 = 0;
|
||||
s_driverArgUkn2 = 0;
|
||||
s_driverInBackground = false;
|
||||
uint32be ukn3;
|
||||
OSDriver_Register(moduleHandle, 200, &s_ProcUIDriver, 0, &s_driverArgUkn1, &s_driverArgUkn2, &ukn3);
|
||||
if ( ukn3 )
|
||||
{
|
||||
if ( OSGetForegroundBucket(nullptr, nullptr) )
|
||||
{
|
||||
ProcUIDriver_Init();
|
||||
OSMemoryBarrier();
|
||||
return 0;
|
||||
}
|
||||
s_driverInBackground = true;
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
else if ( reason == RplEntryReason::Unloaded )
|
||||
{
|
||||
ProcUIDriver_OnDone();
|
||||
OSDriver_Deregister(moduleHandle, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
// set variables to their initial state as if the RPL was just loaded
|
||||
s_isInitialized = false;
|
||||
s_isInShutdown = false;
|
||||
s_isInForeground = false; // ProcUIInForeground returns false until ProcUIInit(Ex) is called
|
||||
s_isForegroundProcess = true;
|
||||
s_saveCallback = nullptr;
|
||||
s_saveCallbackEx = nullptr;
|
||||
s_systemMessageQueuePtr = nullptr;
|
||||
ClearCallbacksWithoutMemFree();
|
||||
s_currentProcUIStatus = ProcUIStatus::Foreground;
|
||||
s_bucketStorageBasePtr = nullptr;
|
||||
s_mem1StorageBasePtr = nullptr;
|
||||
s_drawDoneReleaseCalled = false;
|
||||
s_previouslyWasBlocking = false;
|
||||
// core threads
|
||||
s_coreThreadStackSize = 0;
|
||||
s_coreThreadsCreated = false;
|
||||
s_commandForCoreThread = ProcUICoreThreadCommand::Initial;
|
||||
// background thread
|
||||
s_backgroundThreadStack = nullptr;
|
||||
// user defined heap
|
||||
s_memoryPoolHeapPtr = nullptr;
|
||||
s_memAllocPtr = nullptr;
|
||||
s_memFreePtr = nullptr;
|
||||
// driver
|
||||
s_driverIsActive = false;
|
||||
s_driverInBackground = false;
|
||||
}
|
||||
|
||||
void load()
|
||||
{
|
||||
reset();
|
||||
|
||||
cafeExportRegister("proc_ui", ProcUIInit, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUIInitEx, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUIShutdown, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUIIsRunning, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUIInForeground, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUIInShutdown, LogType::ProcUi);
|
||||
|
||||
cafeExportRegister("proc_ui", ProcUIRegisterCallbackCore, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUIRegisterCallback, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUIRegisterBackgroundCallback, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUIClearCallbacks, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUISetSaveCallback, LogType::ProcUi);
|
||||
|
||||
cafeExportRegister("proc_ui", ProcUISetCallbackStackSize, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUICalcMemorySize, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUISetMemoryPool, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUISetBucketStorage, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUISetMEM1Storage, LogType::ProcUi);
|
||||
|
||||
cafeExportRegister("proc_ui", ProcUIDrawDoneRelease, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUIProcessMessages, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUISubProcessMessages, LogType::ProcUi);
|
||||
|
||||
// manually call rpl_entry for now
|
||||
rpl_entry(-1, RplEntryReason::Loaded);
|
||||
}
|
||||
};
|
||||
std::unordered_map<uint32, ProcUICallback> g_Callbacks;
|
||||
|
||||
uint32 ProcUIRegisterCallback(uint32 message, MPTR callback, void* data, sint32 priority)
|
||||
{
|
||||
g_Callbacks.insert_or_assign(message, ProcUICallback{ .callback = callback, .data = data, .priority = priority });
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ProcUI_SendBackgroundMessage()
|
||||
{
|
||||
if (g_Callbacks.contains(PROCUI_STATUS_BACKGROUND))
|
||||
{
|
||||
ProcUICallback& callback = g_Callbacks[PROCUI_STATUS_BACKGROUND];
|
||||
PPCCoreCallback(callback.callback, callback.data);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcUI_SendForegroundMessage()
|
||||
{
|
||||
if (g_Callbacks.contains(PROCUI_STATUS_FOREGROUND))
|
||||
{
|
||||
ProcUICallback& callback = g_Callbacks[PROCUI_STATUS_FOREGROUND];
|
||||
PPCCoreCallback(callback.callback, callback.data);
|
||||
}
|
||||
}
|
||||
|
||||
void procui_load()
|
||||
{
|
||||
cafeExportRegister("proc_ui", ProcUIRegisterCallback, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUIProcessMessages, LogType::ProcUi);
|
||||
cafeExportRegister("proc_ui", ProcUIInForeground, LogType::ProcUi);
|
||||
}
|
|
@ -1,5 +1,44 @@
|
|||
|
||||
void procui_load();
|
||||
namespace proc_ui
|
||||
{
|
||||
enum class ProcUIStatus
|
||||
{
|
||||
Foreground = 0,
|
||||
Background = 1,
|
||||
Releasing = 2,
|
||||
Exit = 3
|
||||
};
|
||||
|
||||
void ProcUI_SendForegroundMessage();
|
||||
void ProcUI_SendBackgroundMessage();
|
||||
enum class ProcUICallbackId
|
||||
{
|
||||
AcquireForeground = 0,
|
||||
ReleaseForeground = 1,
|
||||
Exit = 2,
|
||||
NetIoStart = 3,
|
||||
NetIoStop = 4,
|
||||
HomeButtonDenied = 5,
|
||||
COUNT = 6
|
||||
};
|
||||
|
||||
void ProcUIInit(MEMPTR<void> callbackReadyToRelease);
|
||||
void ProcUIInitEx(MEMPTR<void> callbackReadyToReleaseEx, MEMPTR<void> userParam);
|
||||
void ProcUIShutdown();
|
||||
bool ProcUIIsRunning();
|
||||
bool ProcUIInForeground();
|
||||
bool ProcUIInShutdown();
|
||||
void ProcUIRegisterCallback(ProcUICallbackId callbackType, void* funcPtr, void* userParam, sint32 priority);
|
||||
void ProcUIRegisterCallbackCore(ProcUICallbackId callbackType, void* funcPtr, void* userParam, sint32 priority, uint32 coreIndex);
|
||||
void ProcUIRegisterBackgroundCallback(void* funcPtr, void* userParam, uint64 tickDelay);
|
||||
void ProcUIClearCallbacks();
|
||||
void ProcUISetSaveCallback(void* funcPtr, void* userParam);
|
||||
void ProcUISetCallbackStackSize(uint32 newStackSize);
|
||||
uint32 ProcUICalcMemorySize(uint32 numCallbacks);
|
||||
sint32 ProcUISetMemoryPool(void* memBase, uint32 size);
|
||||
void ProcUISetBucketStorage(void* memBase, uint32 size);
|
||||
void ProcUISetMEM1Storage(void* memBase, uint32 size);
|
||||
void ProcUIDrawDoneRelease();
|
||||
ProcUIStatus ProcUIProcessMessages(bool isBlockingInBackground);
|
||||
ProcUIStatus ProcUISubProcessMessages(bool isBlockingInBackground);
|
||||
|
||||
void load();
|
||||
}
|
|
@ -218,21 +218,36 @@ namespace snd_core
|
|||
// validate parameters
|
||||
if (deviceId == AX_DEV_TV)
|
||||
{
|
||||
cemu_assert(inputChannelCount <= AX_TV_CHANNEL_COUNT);
|
||||
cemu_assert(outputChannelCount == 1 || outputChannelCount == 2 || outputChannelCount == 6);
|
||||
if(inputChannelCount > AX_TV_CHANNEL_COUNT)
|
||||
{
|
||||
cemuLog_log(LogType::APIErrors, "AXSetDeviceRemixMatrix: Input channel count must be smaller or equal to 6 for TV device");
|
||||
return -7;
|
||||
}
|
||||
if(outputChannelCount != 1 && outputChannelCount != 2 && outputChannelCount != 6)
|
||||
{
|
||||
// seems like Watch Dogs uses 4 as outputChannelCount for some reason?
|
||||
cemuLog_log(LogType::APIErrors, "AXSetDeviceRemixMatrix: Output channel count must be 1, 2 or 6 for TV device");
|
||||
return -8;
|
||||
}
|
||||
}
|
||||
else if (deviceId == AX_DEV_DRC)
|
||||
{
|
||||
cemu_assert(inputChannelCount <= AX_DRC_CHANNEL_COUNT);
|
||||
cemu_assert(outputChannelCount == 1 || outputChannelCount == 2 || outputChannelCount == 4);
|
||||
}
|
||||
else if (deviceId == AX_DEV_RMT)
|
||||
{
|
||||
cemu_assert(false);
|
||||
if(inputChannelCount > AX_DRC_CHANNEL_COUNT)
|
||||
{
|
||||
cemuLog_log(LogType::APIErrors, "AXSetDeviceRemixMatrix: Input channel count must be smaller or equal to 4 for DRC device");
|
||||
return -7;
|
||||
}
|
||||
if(outputChannelCount != 1 && outputChannelCount != 2 && outputChannelCount != 4)
|
||||
{
|
||||
cemuLog_log(LogType::APIErrors, "AXSetDeviceRemixMatrix: Output channel count must be 1, 2 or 4 for DRC device");
|
||||
return -8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cemuLog_log(LogType::APIErrors, "AXSetDeviceRemixMatrix: Only TV (0) and DRC (1) device are supported");
|
||||
return -1;
|
||||
|
||||
}
|
||||
auto matrices = g_remix_matrices.GetPtr();
|
||||
|
||||
// test if we already have an entry and just need to update the matrix data
|
||||
|
@ -963,7 +978,7 @@ namespace snd_core
|
|||
OSInitMessageQueue(__AXIstThreadMsgQueue.GetPtr(), __AXIstThreadMsgArray.GetPtr(), 0x10);
|
||||
// create thread
|
||||
uint8 istThreadAttr = 0;
|
||||
coreinit::OSCreateThreadType(__AXIstThread.GetPtr(), PPCInterpreter_makeCallableExportDepr(AXIst_ThreadEntry), 0, &__AXIstThreadMsgQueue, __AXIstThreadStack.GetPtr() + 0x4000, 0x4000, 14, istThreadAttr, OSThread_t::THREAD_TYPE::TYPE_DRIVER);
|
||||
coreinit::__OSCreateThreadType(__AXIstThread.GetPtr(), PPCInterpreter_makeCallableExportDepr(AXIst_ThreadEntry), 0, &__AXIstThreadMsgQueue, __AXIstThreadStack.GetPtr() + 0x4000, 0x4000, 14, istThreadAttr, OSThread_t::THREAD_TYPE::TYPE_DRIVER);
|
||||
coreinit::OSResumeThread(__AXIstThread.GetPtr());
|
||||
}
|
||||
|
||||
|
|
|
@ -639,11 +639,34 @@ namespace sysapp
|
|||
return coreinit::OSRestartGame(argc, argv);
|
||||
}
|
||||
|
||||
struct EManualArgs
|
||||
{
|
||||
sysStandardArguments_t stdArgs;
|
||||
uint64be titleId;
|
||||
};
|
||||
static_assert(sizeof(EManualArgs) == 0x10);
|
||||
|
||||
void _SYSSwitchToEManual(EManualArgs* args)
|
||||
{
|
||||
// the struct has the titleId at offset 8 and standard args at 0 (total size is most likely 0x10)
|
||||
cemuLog_log(LogType::Force, "SYSSwitchToEManual called. Opening the manual is not supported");
|
||||
coreinit::StartBackgroundForegroundTransition();
|
||||
}
|
||||
|
||||
void SYSSwitchToEManual()
|
||||
{
|
||||
EManualArgs args{};
|
||||
args.titleId = coreinit::OSGetTitleID();
|
||||
_SYSSwitchToEManual(&args);
|
||||
}
|
||||
|
||||
void load()
|
||||
{
|
||||
cafeExportRegisterFunc(SYSClearSysArgs, "sysapp", "SYSClearSysArgs", LogType::Placeholder);
|
||||
cafeExportRegisterFunc(_SYSLaunchTitleByPathFromLauncher, "sysapp", "_SYSLaunchTitleByPathFromLauncher", LogType::Placeholder);
|
||||
cafeExportRegisterFunc(SYSRelaunchTitle, "sysapp", "SYSRelaunchTitle", LogType::Placeholder);
|
||||
cafeExportRegister("sysapp", _SYSSwitchToEManual, LogType::Placeholder);
|
||||
cafeExportRegister("sysapp", SYSSwitchToEManual, LogType::Placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -213,6 +213,32 @@ void zlib125Export_inflateReset2(PPCInterpreter_t* hCPU)
|
|||
osLib_returnFromFunction(hCPU, r);
|
||||
}
|
||||
|
||||
void zlib125Export_deflateInit_(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);
|
||||
ppcDefineParamS32(level, 1);
|
||||
ppcDefineParamStr(version, 2);
|
||||
ppcDefineParamS32(streamsize, 3);
|
||||
|
||||
z_stream hzs;
|
||||
zlib125_setupHostZStream(zstream, &hzs, false);
|
||||
|
||||
// setup internal memory allocator if requested
|
||||
if (zstream->zalloc == nullptr)
|
||||
zstream->zalloc = PPCInterpreter_makeCallableExportDepr(zlib125_zcalloc);
|
||||
if (zstream->zfree == nullptr)
|
||||
zstream->zfree = PPCInterpreter_makeCallableExportDepr(zlib125_zcfree);
|
||||
|
||||
if (streamsize != sizeof(z_stream_ppc2))
|
||||
assert_dbg();
|
||||
|
||||
sint32 r = deflateInit_(&hzs, level, version, sizeof(z_stream));
|
||||
|
||||
zlib125_setupUpdateZStream(&hzs, zstream);
|
||||
|
||||
osLib_returnFromFunction(hCPU, r);
|
||||
}
|
||||
|
||||
void zlib125Export_deflateInit2_(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
ppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);
|
||||
|
@ -345,6 +371,7 @@ namespace zlib
|
|||
osLib_addFunction("zlib125", "inflateReset", zlib125Export_inflateReset);
|
||||
osLib_addFunction("zlib125", "inflateReset2", zlib125Export_inflateReset2);
|
||||
|
||||
osLib_addFunction("zlib125", "deflateInit_", zlib125Export_deflateInit_);
|
||||
osLib_addFunction("zlib125", "deflateInit2_", zlib125Export_deflateInit2_);
|
||||
osLib_addFunction("zlib125", "deflateBound", zlib125Export_deflateBound);
|
||||
osLib_addFunction("zlib125", "deflate", zlib125Export_deflate);
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#include "TitleInfo.h"
|
||||
|
||||
#include "Cafe/Filesystem/fscDeviceHostFS.h"
|
||||
#include "Cafe/Filesystem/WUHB/WUHBReader.h"
|
||||
#include "Cafe/Filesystem/FST/FST.h"
|
||||
|
||||
#include "pugixml.hpp"
|
||||
#include "Common/FileStream.h"
|
||||
|
||||
#include <zarchive/zarchivereader.h>
|
||||
#include "util/IniParser/IniParser.h"
|
||||
#include "util/crypto/crc32.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "util/helpers/helpers.h"
|
||||
|
||||
// detect format by reading file header/footer
|
||||
CafeTitleFileType DetermineCafeSystemFileType(fs::path filePath)
|
||||
|
@ -99,6 +100,7 @@ TitleInfo::TitleInfo(const TitleInfo::CachedInfo& cachedInfo)
|
|||
m_isValid = false;
|
||||
if (cachedInfo.titleDataFormat != TitleDataFormat::HOST_FS &&
|
||||
cachedInfo.titleDataFormat != TitleDataFormat::WIIU_ARCHIVE &&
|
||||
cachedInfo.titleDataFormat != TitleDataFormat::WUHB &&
|
||||
cachedInfo.titleDataFormat != TitleDataFormat::WUD &&
|
||||
cachedInfo.titleDataFormat != TitleDataFormat::NUS &&
|
||||
cachedInfo.titleDataFormat != TitleDataFormat::INVALID_STRUCTURE)
|
||||
|
@ -247,6 +249,16 @@ bool TitleInfo::DetectFormat(const fs::path& path, fs::path& pathOut, TitleDataF
|
|||
delete zar;
|
||||
return foundBase;
|
||||
}
|
||||
else if (boost::iends_with(filenameStr, ".wuhb"))
|
||||
{
|
||||
std::unique_ptr<WUHBReader> reader{WUHBReader::FromPath(path)};
|
||||
if(reader)
|
||||
{
|
||||
formatOut = TitleDataFormat::WUHB;
|
||||
pathOut = path;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// note: Since a Wii U archive file (.wua) contains multiple titles we shouldn't auto-detect them here
|
||||
// instead TitleInfo has a second constructor which takes a subpath
|
||||
// unable to determine type by extension, check contents
|
||||
|
@ -438,6 +450,23 @@ bool TitleInfo::Mount(std::string_view virtualPath, std::string_view subfolder,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_titleFormat == TitleDataFormat::WUHB)
|
||||
{
|
||||
if (!m_wuhbreader)
|
||||
{
|
||||
m_wuhbreader = WUHBReader::FromPath(m_fullPath);
|
||||
if (!m_wuhbreader)
|
||||
return false;
|
||||
}
|
||||
bool r = FSCDeviceWUHB_Mount(virtualPath, subfolder, m_wuhbreader, mountPriority);
|
||||
if (!r)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Failed to mount {} to {}", virtualPath, subfolder);
|
||||
delete m_wuhbreader;
|
||||
m_wuhbreader = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cemu_assert_unimplemented();
|
||||
|
@ -469,6 +498,12 @@ void TitleInfo::Unmount(std::string_view virtualPath)
|
|||
if (m_mountpoints.empty())
|
||||
m_zarchive = nullptr;
|
||||
}
|
||||
if (m_wuhbreader)
|
||||
{
|
||||
cemu_assert_debug(m_titleFormat == TitleDataFormat::WUHB);
|
||||
delete m_wuhbreader;
|
||||
m_wuhbreader = nullptr;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -504,6 +539,20 @@ bool TitleInfo::ParseXmlInfo()
|
|||
auto xmlData = fsc_extractFile(fmt::format("{}meta/meta.xml", mountPath).c_str());
|
||||
if(xmlData)
|
||||
m_parsedMetaXml = ParsedMetaXml::Parse(xmlData->data(), xmlData->size());
|
||||
|
||||
if(!m_parsedMetaXml)
|
||||
{
|
||||
// meta/meta.ini (WUHB)
|
||||
auto iniData = fsc_extractFile(fmt::format("{}meta/meta.ini", mountPath).c_str());
|
||||
if (iniData)
|
||||
m_parsedMetaXml = ParseAromaIni(*iniData);
|
||||
if(m_parsedMetaXml)
|
||||
{
|
||||
m_parsedCosXml = new ParsedCosXml{.argstr = "root.rpx"};
|
||||
m_parsedAppXml = new ParsedAppXml{m_parsedMetaXml->m_title_id, 0, 0, 0, 0};
|
||||
}
|
||||
}
|
||||
|
||||
// code/app.xml
|
||||
xmlData = fsc_extractFile(fmt::format("{}code/app.xml", mountPath).c_str());
|
||||
if(xmlData)
|
||||
|
@ -541,6 +590,34 @@ bool TitleInfo::ParseXmlInfo()
|
|||
return true;
|
||||
}
|
||||
|
||||
ParsedMetaXml* TitleInfo::ParseAromaIni(std::span<unsigned char> content)
|
||||
{
|
||||
IniParser parser{content};
|
||||
while (parser.NextSection() && parser.GetCurrentSectionName() != "menu")
|
||||
continue;
|
||||
if (parser.GetCurrentSectionName() != "menu")
|
||||
return nullptr;
|
||||
|
||||
auto parsed = std::make_unique<ParsedMetaXml>();
|
||||
|
||||
const auto author = parser.FindOption("author");
|
||||
if (author)
|
||||
parsed->m_publisher[(size_t)CafeConsoleLanguage::EN] = *author;
|
||||
|
||||
const auto longName = parser.FindOption("longname");
|
||||
if (longName)
|
||||
parsed->m_long_name[(size_t)CafeConsoleLanguage::EN] = *longName;
|
||||
|
||||
const auto shortName = parser.FindOption("shortname");
|
||||
if (shortName)
|
||||
parsed->m_short_name[(size_t)CafeConsoleLanguage::EN] = *shortName;
|
||||
|
||||
auto checksumInput = std::string{*author}.append(*longName).append(*shortName);
|
||||
parsed->m_title_id = (0x0005000Full<<32) | crc32_calc(checksumInput.data(), checksumInput.length());
|
||||
|
||||
return parsed.release();
|
||||
}
|
||||
|
||||
bool TitleInfo::ParseAppXml(std::vector<uint8>& appXmlData)
|
||||
{
|
||||
pugi::xml_document app_doc;
|
||||
|
@ -565,7 +642,7 @@ bool TitleInfo::ParseAppXml(std::vector<uint8>& appXmlData)
|
|||
else if (name == "group_id")
|
||||
m_parsedAppXml->group_id = (uint32)std::stoull(child.text().as_string(), nullptr, 16);
|
||||
else if (name == "sdk_version")
|
||||
m_parsedAppXml->sdk_version = (uint32)std::stoull(child.text().as_string(), nullptr, 16);
|
||||
m_parsedAppXml->sdk_version = (uint32)std::stoull(child.text().as_string(), nullptr, 10);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -697,6 +774,9 @@ std::string TitleInfo::GetPrintPath() const
|
|||
case TitleDataFormat::WIIU_ARCHIVE:
|
||||
tmp.append(" [WUA]");
|
||||
break;
|
||||
case TitleDataFormat::WUHB:
|
||||
tmp.append(" [WUHB]");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -709,10 +789,41 @@ std::string TitleInfo::GetInstallPath() const
|
|||
{
|
||||
TitleId titleId = GetAppTitleId();
|
||||
TitleIdParser tip(titleId);
|
||||
std::string tmp;
|
||||
std::string tmp;
|
||||
if (tip.IsSystemTitle())
|
||||
tmp = fmt::format("sys/title/{:08x}/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
else
|
||||
tmp = fmt::format("usr/title/{:08x}/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
tmp = fmt::format("sys/title/{:08x}/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
else
|
||||
tmp = fmt::format("usr/title/{:08x}/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
ParsedCosXml* ParsedCosXml::Parse(uint8* xmlData, size_t xmlLen)
|
||||
{
|
||||
pugi::xml_document app_doc;
|
||||
if (!app_doc.load_buffer_inplace(xmlData, xmlLen))
|
||||
return nullptr;
|
||||
|
||||
const auto root = app_doc.child("app");
|
||||
if (!root)
|
||||
return nullptr;
|
||||
|
||||
ParsedCosXml* parsedCos = new ParsedCosXml();
|
||||
|
||||
auto node = root.child("argstr");
|
||||
if (node)
|
||||
parsedCos->argstr = node.text().as_string();
|
||||
|
||||
// parse permissions
|
||||
auto permissionsNode = root.child("permissions");
|
||||
for(uint32 permissionIndex = 0; permissionIndex < 19; ++permissionIndex)
|
||||
{
|
||||
std::string permissionName = fmt::format("p{}", permissionIndex);
|
||||
auto permissionNode = permissionsNode.child(permissionName.c_str());
|
||||
if (!permissionNode)
|
||||
break;
|
||||
parsedCos->permissions[permissionIndex].group = static_cast<CosCapabilityGroup>(ConvertString<uint32>(permissionNode.child("group").text().as_string(), 10));
|
||||
parsedCos->permissions[permissionIndex].mask = static_cast<CosCapabilityBits>(ConvertString<uint64>(permissionNode.child("mask").text().as_string(), 16));
|
||||
}
|
||||
|
||||
return parsedCos;
|
||||
}
|
|
@ -26,29 +26,95 @@ struct ParsedAppXml
|
|||
uint32 sdk_version;
|
||||
};
|
||||
|
||||
enum class CosCapabilityGroup : uint32
|
||||
{
|
||||
None = 0,
|
||||
BSP = 1,
|
||||
DK = 3,
|
||||
USB = 9,
|
||||
UHS = 12,
|
||||
FS = 11,
|
||||
MCP = 13,
|
||||
NIM = 14,
|
||||
ACT = 15,
|
||||
FPD = 16,
|
||||
BOSS = 17,
|
||||
ACP = 18,
|
||||
PDM = 19,
|
||||
AC = 20,
|
||||
NDM = 21,
|
||||
NSEC = 22
|
||||
};
|
||||
|
||||
enum class CosCapabilityBits : uint64
|
||||
{
|
||||
All = 0xFFFFFFFFFFFFFFFFull
|
||||
};
|
||||
|
||||
enum class CosCapabilityBitsFS : uint64
|
||||
{
|
||||
ODD_READ = (1llu << 0),
|
||||
ODD_WRITE = (1llu << 1),
|
||||
ODD_RAW_OPEN = (1llu << 2),
|
||||
ODD_MOUNT = (1llu << 3),
|
||||
SLCCMPT_READ = (1llu << 4),
|
||||
SLCCMPT_WRITE = (1llu << 5),
|
||||
SLCCMPT_RAW_OPEN = (1llu << 6),
|
||||
SLCCMPT_MOUNT = (1llu << 7),
|
||||
SLC_READ = (1llu << 8),
|
||||
SLC_WRITE = (1llu << 9),
|
||||
SLC_RAW_OPEN = (1llu << 10),
|
||||
SLC_MOUNT = (1llu << 11),
|
||||
MLC_READ = (1llu << 12),
|
||||
MLC_WRITE = (1llu << 13),
|
||||
MLC_RAW_OPEN = (1llu << 14),
|
||||
MLC_MOUNT = (1llu << 15),
|
||||
SDCARD_READ = (1llu << 16),
|
||||
SDCARD_WRITE = (1llu << 17),
|
||||
SDCARD_RAW_OPEN = (1llu << 18),
|
||||
SDCARD_MOUNT = (1llu << 19),
|
||||
HFIO_READ = (1llu << 20),
|
||||
HFIO_WRITE = (1llu << 21),
|
||||
HFIO_RAW_OPEN = (1llu << 22),
|
||||
HFIO_MOUNT = (1llu << 23),
|
||||
RAMDISK_READ = (1llu << 24),
|
||||
RAMDISK_WRITE = (1llu << 25),
|
||||
RAMDISK_RAW_OPEN = (1llu << 26),
|
||||
RAMDISK_MOUNT = (1llu << 27),
|
||||
USB_READ = (1llu << 28),
|
||||
USB_WRITE = (1llu << 29),
|
||||
USB_RAW_OPEN = (1llu << 30),
|
||||
USB_MOUNT = (1llu << 31),
|
||||
OTHER_READ = (1llu << 32),
|
||||
OTHER_WRITE = (1llu << 33),
|
||||
OTHER_RAW_OPEN = (1llu << 34),
|
||||
OTHER_MOUNT = (1llu << 35)
|
||||
};
|
||||
ENABLE_BITMASK_OPERATORS(CosCapabilityBitsFS);
|
||||
|
||||
struct ParsedCosXml
|
||||
{
|
||||
public:
|
||||
|
||||
std::string argstr;
|
||||
|
||||
static ParsedCosXml* Parse(uint8* xmlData, size_t xmlLen)
|
||||
struct Permission
|
||||
{
|
||||
pugi::xml_document app_doc;
|
||||
if (!app_doc.load_buffer_inplace(xmlData, xmlLen))
|
||||
return nullptr;
|
||||
CosCapabilityGroup group{CosCapabilityGroup::None};
|
||||
CosCapabilityBits mask{CosCapabilityBits::All};
|
||||
};
|
||||
Permission permissions[19]{};
|
||||
|
||||
const auto root = app_doc.child("app");
|
||||
if (!root)
|
||||
return nullptr;
|
||||
static ParsedCosXml* Parse(uint8* xmlData, size_t xmlLen);
|
||||
|
||||
ParsedCosXml* parsedCos = new ParsedCosXml();
|
||||
|
||||
for (const auto& child : root.children())
|
||||
CosCapabilityBits GetCapabilityBits(CosCapabilityGroup group) const
|
||||
{
|
||||
for (const auto& perm : permissions)
|
||||
{
|
||||
std::string_view name = child.name();
|
||||
if (name == "argstr")
|
||||
parsedCos->argstr = child.text().as_string();
|
||||
if (perm.group == group)
|
||||
return perm.mask;
|
||||
}
|
||||
return parsedCos;
|
||||
return CosCapabilityBits::All;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -61,6 +127,7 @@ public:
|
|||
WUD = 2, // WUD or WUX
|
||||
WIIU_ARCHIVE = 3, // Wii U compressed single-file archive (.wua)
|
||||
NUS = 4, // NUS format. Directory with .app files, title.tik and title.tmd
|
||||
WUHB = 5,
|
||||
// error
|
||||
INVALID_STRUCTURE = 0,
|
||||
};
|
||||
|
@ -151,7 +218,7 @@ public:
|
|||
// cos.xml
|
||||
std::string GetArgStr() const;
|
||||
|
||||
// meta.xml also contains a version which seems to match the one from app.xml
|
||||
// meta.xml also contains a version field which seems to match the one from app.xml
|
||||
// the titleId in meta.xml seems to be the title id of the base game for updates specifically. For AOC content it's the AOC's titleId
|
||||
|
||||
TitleIdParser::TITLE_TYPE GetTitleType();
|
||||
|
@ -160,6 +227,11 @@ public:
|
|||
return m_parsedMetaXml;
|
||||
}
|
||||
|
||||
ParsedCosXml* GetCosInfo()
|
||||
{
|
||||
return m_parsedCosXml;
|
||||
}
|
||||
|
||||
std::string GetPrintPath() const; // formatted path including type and WUA subpath. Intended for logging and user-facing information
|
||||
std::string GetInstallPath() const; // installation subpath, relative to storage base. E.g. "usr/title/.../..." or "sys/title/.../..."
|
||||
|
||||
|
@ -194,6 +266,7 @@ private:
|
|||
bool DetectFormat(const fs::path& path, fs::path& pathOut, TitleDataFormat& formatOut);
|
||||
void CalcUID();
|
||||
void SetInvalidReason(InvalidReason reason);
|
||||
ParsedMetaXml* ParseAromaIni(std::span<unsigned char> content);
|
||||
bool ParseAppXml(std::vector<uint8>& appXmlData);
|
||||
|
||||
bool m_isValid{ false };
|
||||
|
@ -206,6 +279,7 @@ private:
|
|||
std::vector<std::pair<sint32, std::string>> m_mountpoints;
|
||||
class FSTVolume* m_wudVolume{};
|
||||
class ZArchiveReader* m_zarchive{};
|
||||
class WUHBReader* m_wuhbreader{};
|
||||
// xml info
|
||||
bool m_hasParsedXmlFiles{ false };
|
||||
ParsedMetaXml* m_parsedMetaXml{};
|
||||
|
|
|
@ -342,7 +342,8 @@ bool _IsKnownFileNameOrExtension(const fs::path& path)
|
|||
fileExtension == ".wud" ||
|
||||
fileExtension == ".wux" ||
|
||||
fileExtension == ".iso" ||
|
||||
fileExtension == ".wua";
|
||||
fileExtension == ".wua" ||
|
||||
fileExtension == ".wuhb";
|
||||
// note: To detect extracted titles with RPX we rely on the presence of the content,code,meta directory structure
|
||||
}
|
||||
|
||||
|
|
|
@ -36,11 +36,14 @@ enum class LogType : sint32
|
|||
NN_NFP = 13,
|
||||
NN_FP = 24,
|
||||
NN_BOSS = 25,
|
||||
NN_SL = 26,
|
||||
|
||||
TextureReadback = 29,
|
||||
|
||||
ProcUi = 39,
|
||||
nlibcurl = 41,
|
||||
|
||||
PRUDP = 40,
|
||||
};
|
||||
|
||||
template <>
|
||||
|
|
|
@ -33,14 +33,7 @@ void DownloadManager::downloadTitleVersionList()
|
|||
{
|
||||
if (m_hasTitleVersionList)
|
||||
return;
|
||||
NAPI::AuthInfo authInfo;
|
||||
authInfo.accountId = m_authInfo.nnidAccountName;
|
||||
authInfo.passwordHash = m_authInfo.passwordHash;
|
||||
authInfo.deviceId = m_authInfo.deviceId;
|
||||
authInfo.serial = m_authInfo.serial;
|
||||
authInfo.country = m_authInfo.country;
|
||||
authInfo.region = m_authInfo.region;
|
||||
authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64;
|
||||
NAPI::AuthInfo authInfo = GetAuthInfo(false);
|
||||
auto versionListVersionResult = NAPI::TAG_GetVersionListVersion(authInfo);
|
||||
if (!versionListVersionResult.isValid)
|
||||
return;
|
||||
|
@ -195,15 +188,7 @@ public:
|
|||
|
||||
bool DownloadManager::_connect_refreshIASAccountIdAndDeviceToken()
|
||||
{
|
||||
NAPI::AuthInfo authInfo;
|
||||
authInfo.accountId = m_authInfo.nnidAccountName;
|
||||
authInfo.passwordHash = m_authInfo.passwordHash;
|
||||
authInfo.deviceId = m_authInfo.deviceId;
|
||||
authInfo.serial = m_authInfo.serial;
|
||||
authInfo.country = m_authInfo.country;
|
||||
authInfo.region = m_authInfo.region;
|
||||
authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64;
|
||||
|
||||
NAPI::AuthInfo authInfo = GetAuthInfo(false);
|
||||
// query IAS/ECS account id and device token (if not cached)
|
||||
auto rChallenge = NAPI::IAS_GetChallenge(authInfo);
|
||||
if (rChallenge.apiError != NAPI_RESULT::SUCCESS)
|
||||
|
@ -211,7 +196,6 @@ bool DownloadManager::_connect_refreshIASAccountIdAndDeviceToken()
|
|||
auto rRegistrationInfo = NAPI::IAS_GetRegistrationInfo_QueryInfo(authInfo, rChallenge.challenge);
|
||||
if (rRegistrationInfo.apiError != NAPI_RESULT::SUCCESS)
|
||||
return false;
|
||||
|
||||
m_iasToken.serviceAccountId = rRegistrationInfo.accountId;
|
||||
m_iasToken.deviceToken = rRegistrationInfo.deviceToken;
|
||||
// store to cache
|
||||
|
@ -221,24 +205,13 @@ bool DownloadManager::_connect_refreshIASAccountIdAndDeviceToken()
|
|||
std::vector<uint8> serializedData;
|
||||
if (!storedTokenInfo.serialize(serializedData))
|
||||
return false;
|
||||
s_nupFileCache->AddFileAsync({ fmt::format("{}/token_info", m_authInfo.nnidAccountName) }, serializedData.data(), serializedData.size());
|
||||
s_nupFileCache->AddFileAsync({ fmt::format("{}/token_info", m_authInfo.cachefileName) }, serializedData.data(), serializedData.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DownloadManager::_connect_queryAccountStatusAndServiceURLs()
|
||||
{
|
||||
NAPI::AuthInfo authInfo;
|
||||
authInfo.accountId = m_authInfo.nnidAccountName;
|
||||
authInfo.passwordHash = m_authInfo.passwordHash;
|
||||
authInfo.deviceId = m_authInfo.deviceId;
|
||||
authInfo.serial = m_authInfo.serial;
|
||||
authInfo.country = m_authInfo.country;
|
||||
authInfo.region = m_authInfo.region;
|
||||
authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64;
|
||||
|
||||
authInfo.IASToken.accountId = m_iasToken.serviceAccountId;
|
||||
authInfo.IASToken.deviceToken = m_iasToken.deviceToken;
|
||||
|
||||
NAPI::AuthInfo authInfo = GetAuthInfo(true);
|
||||
NAPI::NAPI_ECSGetAccountStatus_Result accountStatusResult = NAPI::ECS_GetAccountStatus(authInfo);
|
||||
if (accountStatusResult.apiError != NAPI_RESULT::SUCCESS)
|
||||
{
|
||||
|
@ -291,7 +264,7 @@ void DownloadManager::loadTicketCache()
|
|||
m_ticketCache.clear();
|
||||
cemu_assert_debug(m_ticketCache.empty());
|
||||
std::vector<uint8> ticketCacheBlob;
|
||||
if (!s_nupFileCache->GetFile({ fmt::format("{}/eticket_cache", m_authInfo.nnidAccountName) }, ticketCacheBlob))
|
||||
if (!s_nupFileCache->GetFile({ fmt::format("{}/eticket_cache", m_authInfo.cachefileName) }, ticketCacheBlob))
|
||||
return;
|
||||
MemStreamReader memReader(ticketCacheBlob.data(), ticketCacheBlob.size());
|
||||
uint8 version = memReader.readBE<uint8>();
|
||||
|
@ -343,23 +316,12 @@ void DownloadManager::storeTicketCache()
|
|||
memWriter.writePODVector(cert);
|
||||
}
|
||||
auto serializedBlob = memWriter.getResult();
|
||||
s_nupFileCache->AddFileAsync({ fmt::format("{}/eticket_cache", m_authInfo.nnidAccountName) }, serializedBlob.data(), serializedBlob.size());
|
||||
s_nupFileCache->AddFileAsync({ fmt::format("{}/eticket_cache", m_authInfo.cachefileName) }, serializedBlob.data(), serializedBlob.size());
|
||||
}
|
||||
|
||||
bool DownloadManager::syncAccountTickets()
|
||||
{
|
||||
NAPI::AuthInfo authInfo;
|
||||
authInfo.accountId = m_authInfo.nnidAccountName;
|
||||
authInfo.passwordHash = m_authInfo.passwordHash;
|
||||
authInfo.deviceId = m_authInfo.deviceId;
|
||||
authInfo.serial = m_authInfo.serial;
|
||||
authInfo.country = m_authInfo.country;
|
||||
authInfo.region = m_authInfo.region;
|
||||
authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64;
|
||||
|
||||
authInfo.IASToken.accountId = m_iasToken.serviceAccountId;
|
||||
authInfo.IASToken.deviceToken = m_iasToken.deviceToken;
|
||||
|
||||
NAPI::AuthInfo authInfo = GetAuthInfo(true);
|
||||
// query TIV list from server
|
||||
NAPI::NAPI_ECSAccountListETicketIds_Result resultTicketIds = NAPI::ECS_AccountListETicketIds(authInfo);
|
||||
if (!resultTicketIds.isValid())
|
||||
|
@ -425,19 +387,7 @@ bool DownloadManager::syncAccountTickets()
|
|||
bool DownloadManager::syncSystemTitleTickets()
|
||||
{
|
||||
setStatusMessage(_("Downloading system tickets...").utf8_string(), DLMGR_STATUS_CODE::CONNECTING);
|
||||
// todo - add GetAuth() function
|
||||
NAPI::AuthInfo authInfo;
|
||||
authInfo.accountId = m_authInfo.nnidAccountName;
|
||||
authInfo.passwordHash = m_authInfo.passwordHash;
|
||||
authInfo.deviceId = m_authInfo.deviceId;
|
||||
authInfo.serial = m_authInfo.serial;
|
||||
authInfo.country = m_authInfo.country;
|
||||
authInfo.region = m_authInfo.region;
|
||||
authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64;
|
||||
|
||||
authInfo.IASToken.accountId = m_iasToken.serviceAccountId;
|
||||
authInfo.IASToken.deviceToken = m_iasToken.deviceToken;
|
||||
|
||||
NAPI::AuthInfo authInfo = GetAuthInfo(true);
|
||||
auto querySystemTitleTicket = [&](uint64 titleId) -> void
|
||||
{
|
||||
// check if cached already
|
||||
|
@ -520,8 +470,7 @@ bool DownloadManager::syncUpdateTickets()
|
|||
if (findTicketByTitleIdAndVersion(itr.titleId, itr.availableTitleVersion))
|
||||
continue;
|
||||
|
||||
NAPI::AuthInfo dummyAuth;
|
||||
auto cetkResult = NAPI::CCS_GetCETK(dummyAuth, itr.titleId, itr.availableTitleVersion);
|
||||
auto cetkResult = NAPI::CCS_GetCETK(GetDownloadMgrNetworkService(), itr.titleId, itr.availableTitleVersion);
|
||||
if (!cetkResult.isValid)
|
||||
continue;
|
||||
NCrypto::ETicketParser ticketParser;
|
||||
|
@ -657,7 +606,7 @@ void DownloadManager::_handle_connect()
|
|||
if (s_nupFileCache)
|
||||
{
|
||||
std::vector<uint8> serializationBlob;
|
||||
if (s_nupFileCache->GetFile({ fmt::format("{}/token_info", m_authInfo.nnidAccountName) }, serializationBlob))
|
||||
if (s_nupFileCache->GetFile({ fmt::format("{}/token_info", m_authInfo.cachefileName) }, serializationBlob))
|
||||
{
|
||||
StoredTokenInfo storedTokenInfo;
|
||||
if (storedTokenInfo.deserialize(serializationBlob))
|
||||
|
@ -683,7 +632,7 @@ void DownloadManager::_handle_connect()
|
|||
if (!_connect_queryAccountStatusAndServiceURLs())
|
||||
{
|
||||
m_connectState.store(CONNECT_STATE::FAILED);
|
||||
setStatusMessage(_("Failed to query account status. Invalid account information?").utf8_string(), DLMGR_STATUS_CODE::FAILED);
|
||||
setStatusMessage(_("Failed to query account status").utf8_string(), DLMGR_STATUS_CODE::FAILED);
|
||||
return;
|
||||
}
|
||||
// load ticket cache and sync
|
||||
|
@ -692,7 +641,7 @@ void DownloadManager::_handle_connect()
|
|||
if (!syncTicketCache())
|
||||
{
|
||||
m_connectState.store(CONNECT_STATE::FAILED);
|
||||
setStatusMessage(_("Failed to request tickets (invalid NNID?)").utf8_string(), DLMGR_STATUS_CODE::FAILED);
|
||||
setStatusMessage(_("Failed to request tickets").utf8_string(), DLMGR_STATUS_CODE::FAILED);
|
||||
return;
|
||||
}
|
||||
searchForIncompleteDownloads();
|
||||
|
@ -713,22 +662,10 @@ void DownloadManager::connect(
|
|||
std::string_view serial,
|
||||
std::string_view deviceCertBase64)
|
||||
{
|
||||
if (nnidAccountName.empty())
|
||||
{
|
||||
m_connectState.store(CONNECT_STATE::FAILED);
|
||||
setStatusMessage(_("This account is not linked with an NNID").utf8_string(), DLMGR_STATUS_CODE::FAILED);
|
||||
return;
|
||||
}
|
||||
runManager();
|
||||
m_authInfo.nnidAccountName = nnidAccountName;
|
||||
m_authInfo.passwordHash = passwordHash;
|
||||
if (std::all_of(m_authInfo.passwordHash.begin(), m_authInfo.passwordHash.end(), [](uint8 v) { return v == 0; }))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "DLMgr: Invalid password hash");
|
||||
m_connectState.store(CONNECT_STATE::FAILED);
|
||||
setStatusMessage(_("Failed. Account does not have password set").utf8_string(), DLMGR_STATUS_CODE::FAILED);
|
||||
return;
|
||||
}
|
||||
m_authInfo.cachefileName = nnidAccountName.empty() ? "DefaultName" : nnidAccountName;
|
||||
m_authInfo.region = region;
|
||||
m_authInfo.country = country;
|
||||
m_authInfo.deviceCertBase64 = deviceCertBase64;
|
||||
|
@ -744,6 +681,31 @@ bool DownloadManager::IsConnected() const
|
|||
return m_connectState.load() != CONNECT_STATE::UNINITIALIZED;
|
||||
}
|
||||
|
||||
NetworkService DownloadManager::GetDownloadMgrNetworkService()
|
||||
{
|
||||
return NetworkService::Nintendo;
|
||||
}
|
||||
|
||||
NAPI::AuthInfo DownloadManager::GetAuthInfo(bool withIasToken)
|
||||
{
|
||||
NAPI::AuthInfo authInfo;
|
||||
authInfo.serviceOverwrite = GetDownloadMgrNetworkService();
|
||||
authInfo.accountId = m_authInfo.nnidAccountName;
|
||||
authInfo.passwordHash = m_authInfo.passwordHash;
|
||||
authInfo.deviceId = m_authInfo.deviceId;
|
||||
authInfo.serial = m_authInfo.serial;
|
||||
authInfo.country = m_authInfo.country;
|
||||
authInfo.region = m_authInfo.region;
|
||||
authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64;
|
||||
if(withIasToken)
|
||||
{
|
||||
cemu_assert_debug(!m_iasToken.serviceAccountId.empty());
|
||||
authInfo.IASToken.accountId = m_iasToken.serviceAccountId;
|
||||
authInfo.IASToken.deviceToken = m_iasToken.deviceToken;
|
||||
}
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
/* package / downloading */
|
||||
|
||||
// start/resume/retry download
|
||||
|
@ -1022,17 +984,7 @@ void DownloadManager::reportPackageProgress(Package* package, uint32 currentProg
|
|||
|
||||
void DownloadManager::asyncPackageDownloadTMD(Package* package)
|
||||
{
|
||||
NAPI::AuthInfo authInfo;
|
||||
authInfo.accountId = m_authInfo.nnidAccountName;
|
||||
authInfo.passwordHash = m_authInfo.passwordHash;
|
||||
authInfo.deviceId = m_authInfo.deviceId;
|
||||
authInfo.serial = m_authInfo.serial;
|
||||
authInfo.country = m_authInfo.country;
|
||||
authInfo.region = m_authInfo.region;
|
||||
authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64;
|
||||
authInfo.IASToken.accountId = m_iasToken.serviceAccountId;
|
||||
authInfo.IASToken.deviceToken = m_iasToken.deviceToken;
|
||||
|
||||
NAPI::AuthInfo authInfo = GetAuthInfo(true);
|
||||
TitleIdParser titleIdParser(package->titleId);
|
||||
NAPI::NAPI_CCSGetTMD_Result tmdResult;
|
||||
if (titleIdParser.GetType() == TitleIdParser::TITLE_TYPE::AOC)
|
||||
|
@ -1196,7 +1148,7 @@ void DownloadManager::asyncPackageDownloadContentFile(Package* package, uint16 i
|
|||
setPackageError(package, _("Cannot create file").utf8_string());
|
||||
return;
|
||||
}
|
||||
if (!NAPI::CCS_GetContentFile(titleId, contentId, CallbackInfo::writeCallback, &callbackInfoData))
|
||||
if (!NAPI::CCS_GetContentFile(GetDownloadMgrNetworkService(), titleId, contentId, CallbackInfo::writeCallback, &callbackInfoData))
|
||||
{
|
||||
setPackageError(package, _("Download failed").utf8_string());
|
||||
delete callbackInfoData.fileOutput;
|
||||
|
@ -1490,7 +1442,7 @@ void DownloadManager::prepareIDBE(uint64 titleId)
|
|||
if (s_nupFileCache->GetFile({ fmt::format("idbe/{0:016x}", titleId) }, idbeFile) && idbeFile.size() == sizeof(NAPI::IDBEIconDataV0))
|
||||
return addToCache(titleId, (NAPI::IDBEIconDataV0*)(idbeFile.data()));
|
||||
// not cached, query from server
|
||||
std::optional<NAPI::IDBEIconDataV0> iconData = NAPI::IDBE_Request(titleId);
|
||||
std::optional<NAPI::IDBEIconDataV0> iconData = NAPI::IDBE_Request(GetDownloadMgrNetworkService(), titleId);
|
||||
if (!iconData)
|
||||
return;
|
||||
s_nupFileCache->AddFileAsync({ fmt::format("idbe/{0:016x}", titleId) }, (uint8*)&(*iconData), sizeof(NAPI::IDBEIconDataV0));
|
||||
|
|
|
@ -2,17 +2,14 @@
|
|||
#include "util/helpers/Semaphore.h"
|
||||
#include "Cemu/ncrypto/ncrypto.h"
|
||||
#include "Cafe/TitleList/TitleId.h"
|
||||
|
||||
#include "util/helpers/ConcurrentQueue.h"
|
||||
#include "config/NetworkSettings.h"
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
#include <future>
|
||||
|
||||
// forward declarations
|
||||
namespace NAPI
|
||||
{
|
||||
struct IDBEIconDataV0;
|
||||
struct AuthInfo;
|
||||
}
|
||||
|
||||
namespace NCrypto
|
||||
|
@ -86,7 +83,6 @@ public:
|
|||
|
||||
bool IsConnected() const;
|
||||
|
||||
|
||||
private:
|
||||
/* connect / login */
|
||||
|
||||
|
@ -101,6 +97,7 @@ private:
|
|||
|
||||
struct
|
||||
{
|
||||
std::string cachefileName;
|
||||
std::string nnidAccountName;
|
||||
std::array<uint8, 32> passwordHash;
|
||||
std::string deviceCertBase64;
|
||||
|
@ -122,7 +119,10 @@ private:
|
|||
void _handle_connect();
|
||||
bool _connect_refreshIASAccountIdAndDeviceToken();
|
||||
bool _connect_queryAccountStatusAndServiceURLs();
|
||||
|
||||
|
||||
NetworkService GetDownloadMgrNetworkService();
|
||||
NAPI::AuthInfo GetAuthInfo(bool withIasToken);
|
||||
|
||||
/* idbe cache */
|
||||
public:
|
||||
void prepareIDBE(uint64 titleId);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <optional>
|
||||
#include "config/CemuConfig.h" // for ConsoleLanguage
|
||||
#include "config/NetworkSettings.h" // for NetworkService
|
||||
#include "config/ActiveSettings.h" // for GetNetworkService()
|
||||
|
||||
enum class NAPI_RESULT
|
||||
{
|
||||
|
@ -16,8 +17,6 @@ namespace NAPI
|
|||
// common auth info structure shared by ACT, ECS and IAS service
|
||||
struct AuthInfo
|
||||
{
|
||||
// todo - constructor for account name + raw password
|
||||
|
||||
// nnid
|
||||
std::string accountId;
|
||||
std::array<uint8, 32> passwordHash;
|
||||
|
@ -41,9 +40,13 @@ namespace NAPI
|
|||
std::string deviceToken;
|
||||
}IASToken;
|
||||
|
||||
// ACT token (for account.nintendo.net requests)
|
||||
|
||||
// service selection, if not set fall back to global setting
|
||||
std::optional<NetworkService> serviceOverwrite;
|
||||
|
||||
NetworkService GetService() const
|
||||
{
|
||||
return serviceOverwrite.value_or(ActiveSettings::GetNetworkService());
|
||||
}
|
||||
};
|
||||
|
||||
bool NAPI_MakeAuthInfoFromCurrentAccount(AuthInfo& authInfo); // helper function. Returns false if online credentials/dumped files are not available
|
||||
|
@ -232,9 +235,9 @@ namespace NAPI
|
|||
|
||||
NAPI_CCSGetTMD_Result CCS_GetTMD(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion);
|
||||
NAPI_CCSGetTMD_Result CCS_GetTMD(AuthInfo& authInfo, uint64 titleId);
|
||||
NAPI_CCSGetETicket_Result CCS_GetCETK(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion);
|
||||
bool CCS_GetContentFile(uint64 titleId, uint32 contentId, bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData);
|
||||
NAPI_CCSGetContentH3_Result CCS_GetContentH3File(uint64 titleId, uint32 contentId);
|
||||
NAPI_CCSGetETicket_Result CCS_GetCETK(NetworkService service, uint64 titleId, uint16 titleVersion);
|
||||
bool CCS_GetContentFile(NetworkService service, uint64 titleId, uint32 contentId, bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData);
|
||||
NAPI_CCSGetContentH3_Result CCS_GetContentH3File(NetworkService service, uint64 titleId, uint32 contentId);
|
||||
|
||||
/* IDBE */
|
||||
|
||||
|
@ -286,8 +289,8 @@ namespace NAPI
|
|||
|
||||
static_assert(sizeof(IDBEHeader) == 2+32);
|
||||
|
||||
std::optional<IDBEIconDataV0> IDBE_Request(uint64 titleId);
|
||||
std::vector<uint8> IDBE_RequestRawEncrypted(uint64 titleId); // same as IDBE_Request but doesn't strip the header and decrypt the IDBE
|
||||
std::optional<IDBEIconDataV0> IDBE_Request(NetworkService networkService, uint64 titleId);
|
||||
std::vector<uint8> IDBE_RequestRawEncrypted(NetworkService networkService, uint64 titleId); // same as IDBE_Request but doesn't strip the header and decrypt the IDBE
|
||||
|
||||
/* Version list */
|
||||
|
||||
|
|
|
@ -14,6 +14,21 @@
|
|||
|
||||
namespace NAPI
|
||||
{
|
||||
std::string _getACTUrl(NetworkService service)
|
||||
{
|
||||
switch (service)
|
||||
{
|
||||
case NetworkService::Nintendo:
|
||||
return NintendoURLs::ACTURL;
|
||||
case NetworkService::Pretendo:
|
||||
return PretendoURLs::ACTURL;
|
||||
case NetworkService::Custom:
|
||||
return GetNetworkConfig().urls.ACT.GetValue();
|
||||
default:
|
||||
return NintendoURLs::ACTURL;
|
||||
}
|
||||
}
|
||||
|
||||
struct ACTOauthToken : public _NAPI_CommonResultACT
|
||||
{
|
||||
std::string token;
|
||||
|
@ -91,7 +106,7 @@ namespace NAPI
|
|||
|
||||
struct OAuthTokenCacheEntry
|
||||
{
|
||||
OAuthTokenCacheEntry(std::string_view accountId, std::array<uint8, 32>& passwordHash, std::string_view token, std::string_view refreshToken, uint64 expiresIn) : accountId(accountId), passwordHash(passwordHash), token(token), refreshToken(refreshToken)
|
||||
OAuthTokenCacheEntry(std::string_view accountId, std::array<uint8, 32>& passwordHash, std::string_view token, std::string_view refreshToken, uint64 expiresIn, NetworkService service) : accountId(accountId), passwordHash(passwordHash), token(token), refreshToken(refreshToken), service(service)
|
||||
{
|
||||
expires = HighResolutionTimer::now().getTickInSeconds() + expiresIn;
|
||||
};
|
||||
|
@ -107,10 +122,10 @@ namespace NAPI
|
|||
}
|
||||
std::string accountId;
|
||||
std::array<uint8, 32> passwordHash;
|
||||
|
||||
std::string token;
|
||||
std::string refreshToken;
|
||||
uint64 expires;
|
||||
NetworkService service;
|
||||
};
|
||||
|
||||
std::vector<OAuthTokenCacheEntry> g_oauthTokenCache;
|
||||
|
@ -122,11 +137,12 @@ namespace NAPI
|
|||
ACTOauthToken result{};
|
||||
|
||||
// check cache first
|
||||
NetworkService service = authInfo.GetService();
|
||||
g_oauthTokenCacheMtx.lock();
|
||||
auto cacheItr = g_oauthTokenCache.begin();
|
||||
while (cacheItr != g_oauthTokenCache.end())
|
||||
{
|
||||
if (cacheItr->CheckIfSameAccount(authInfo))
|
||||
if (cacheItr->CheckIfSameAccount(authInfo) && cacheItr->service == service)
|
||||
{
|
||||
if (cacheItr->CheckIfExpired())
|
||||
{
|
||||
|
@ -145,7 +161,7 @@ namespace NAPI
|
|||
// token not cached, request from server via oauth2
|
||||
CurlRequestHelper req;
|
||||
|
||||
req.initate(fmt::format("{}/v1/api/oauth20/access_token/generate", LaunchSettings::GetActURLPrefix()), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);
|
||||
req.initate(authInfo.GetService(), fmt::format("{}/v1/api/oauth20/access_token/generate", _getACTUrl(authInfo.GetService())), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);
|
||||
_ACTSetCommonHeaderParameters(req, authInfo);
|
||||
_ACTSetDeviceParameters(req, authInfo);
|
||||
_ACTSetRegionAndCountryParameters(req, authInfo);
|
||||
|
@ -220,7 +236,7 @@ namespace NAPI
|
|||
if (expiration > 0)
|
||||
{
|
||||
g_oauthTokenCacheMtx.lock();
|
||||
g_oauthTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, result.token, result.refreshToken, expiration);
|
||||
g_oauthTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, result.token, result.refreshToken, expiration, service);
|
||||
g_oauthTokenCacheMtx.unlock();
|
||||
}
|
||||
return result;
|
||||
|
@ -230,14 +246,13 @@ namespace NAPI
|
|||
{
|
||||
CurlRequestHelper req;
|
||||
|
||||
req.initate(fmt::format("{}/v1/api/people/@me/profile", LaunchSettings::GetActURLPrefix()), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);
|
||||
req.initate(authInfo.GetService(), fmt::format("{}/v1/api/people/@me/profile", _getACTUrl(authInfo.GetService())), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);
|
||||
|
||||
_ACTSetCommonHeaderParameters(req, authInfo);
|
||||
_ACTSetDeviceParameters(req, authInfo);
|
||||
|
||||
// get oauth2 token
|
||||
ACTOauthToken oauthToken = ACT_GetOauthToken_WithCache(authInfo, 0x0005001010001C00, 0x0001C);
|
||||
|
||||
|
||||
cemu_assert_unimplemented();
|
||||
return true;
|
||||
|
@ -245,15 +260,16 @@ namespace NAPI
|
|||
|
||||
struct NexTokenCacheEntry
|
||||
{
|
||||
NexTokenCacheEntry(std::string_view accountId, std::array<uint8, 32>& passwordHash, uint32 gameServerId, ACTNexToken& nexToken) : accountId(accountId), passwordHash(passwordHash), nexToken(nexToken), gameServerId(gameServerId) {};
|
||||
NexTokenCacheEntry(std::string_view accountId, std::array<uint8, 32>& passwordHash, NetworkService networkService, uint32 gameServerId, ACTNexToken& nexToken) : accountId(accountId), passwordHash(passwordHash), networkService(networkService), nexToken(nexToken), gameServerId(gameServerId) {};
|
||||
|
||||
bool IsMatch(const AuthInfo& authInfo, const uint32 gameServerId) const
|
||||
{
|
||||
return authInfo.accountId == accountId && authInfo.passwordHash == passwordHash && this->gameServerId == gameServerId;
|
||||
return authInfo.accountId == accountId && authInfo.passwordHash == passwordHash && authInfo.GetService() == networkService && this->gameServerId == gameServerId;
|
||||
}
|
||||
|
||||
std::string accountId;
|
||||
std::array<uint8, 32> passwordHash;
|
||||
NetworkService networkService;
|
||||
uint32 gameServerId;
|
||||
|
||||
ACTNexToken nexToken;
|
||||
|
@ -297,7 +313,7 @@ namespace NAPI
|
|||
}
|
||||
// do request
|
||||
CurlRequestHelper req;
|
||||
req.initate(fmt::format("{}/v1/api/provider/nex_token/@me?game_server_id={:08X}", LaunchSettings::GetActURLPrefix(), serverId), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);
|
||||
req.initate(authInfo.GetService(), fmt::format("{}/v1/api/provider/nex_token/@me?game_server_id={:08X}", _getACTUrl(authInfo.GetService()), serverId), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);
|
||||
_ACTSetCommonHeaderParameters(req, authInfo);
|
||||
_ACTSetDeviceParameters(req, authInfo);
|
||||
_ACTSetRegionAndCountryParameters(req, authInfo);
|
||||
|
@ -374,21 +390,21 @@ namespace NAPI
|
|||
result.nexToken.port = (uint16)StringHelpers::ToInt(port);
|
||||
result.apiError = NAPI_RESULT::SUCCESS;
|
||||
g_nexTokenCacheMtx.lock();
|
||||
g_nexTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, serverId, result.nexToken);
|
||||
g_nexTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, authInfo.GetService(), serverId, result.nexToken);
|
||||
g_nexTokenCacheMtx.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
struct IndependentTokenCacheEntry
|
||||
{
|
||||
IndependentTokenCacheEntry(std::string_view accountId, std::array<uint8, 32>& passwordHash, std::string_view clientId, std::string_view independentToken, sint64 expiresIn) : accountId(accountId), passwordHash(passwordHash), clientId(clientId), independentToken(independentToken)
|
||||
IndependentTokenCacheEntry(std::string_view accountId, std::array<uint8, 32>& passwordHash, NetworkService networkService, std::string_view clientId, std::string_view independentToken, sint64 expiresIn) : accountId(accountId), passwordHash(passwordHash), networkService(networkService), clientId(clientId), independentToken(independentToken)
|
||||
{
|
||||
expires = HighResolutionTimer::now().getTickInSeconds() + expiresIn;
|
||||
};
|
||||
|
||||
bool IsMatch(const AuthInfo& authInfo, const std::string_view clientId) const
|
||||
{
|
||||
return authInfo.accountId == accountId && authInfo.passwordHash == passwordHash && this->clientId == clientId;
|
||||
return authInfo.accountId == accountId && authInfo.passwordHash == passwordHash && authInfo.GetService() == networkService && this->clientId == clientId;
|
||||
}
|
||||
|
||||
bool CheckIfExpired() const
|
||||
|
@ -398,6 +414,7 @@ namespace NAPI
|
|||
|
||||
std::string accountId;
|
||||
std::array<uint8, 32> passwordHash;
|
||||
NetworkService networkService;
|
||||
std::string clientId;
|
||||
sint64 expires;
|
||||
|
||||
|
@ -449,7 +466,7 @@ namespace NAPI
|
|||
}
|
||||
// do request
|
||||
CurlRequestHelper req;
|
||||
req.initate(fmt::format("{}/v1/api/provider/service_token/@me?client_id={}", LaunchSettings::GetActURLPrefix(), clientId), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);
|
||||
req.initate(authInfo.GetService(), fmt::format("{}/v1/api/provider/service_token/@me?client_id={}", _getACTUrl(authInfo.GetService()), clientId), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);
|
||||
_ACTSetCommonHeaderParameters(req, authInfo);
|
||||
_ACTSetDeviceParameters(req, authInfo);
|
||||
_ACTSetRegionAndCountryParameters(req, authInfo);
|
||||
|
@ -494,7 +511,7 @@ namespace NAPI
|
|||
result.apiError = NAPI_RESULT::SUCCESS;
|
||||
|
||||
g_IndependentTokenCacheMtx.lock();
|
||||
g_IndependentTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, clientId, result.token, 3600);
|
||||
g_IndependentTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, authInfo.GetService(), clientId, result.token, 3600);
|
||||
g_IndependentTokenCacheMtx.unlock();
|
||||
return result;
|
||||
}
|
||||
|
@ -520,7 +537,7 @@ namespace NAPI
|
|||
}
|
||||
// do request
|
||||
CurlRequestHelper req;
|
||||
req.initate(fmt::format("{}/v1/api/admin/mapped_ids?input_type=user_id&output_type=pid&input={}", LaunchSettings::GetActURLPrefix(), nnid), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);
|
||||
req.initate(authInfo.GetService(), fmt::format("{}/v1/api/admin/mapped_ids?input_type=user_id&output_type=pid&input={}", _getACTUrl(authInfo.GetService()), nnid), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);
|
||||
_ACTSetCommonHeaderParameters(req, authInfo);
|
||||
_ACTSetDeviceParameters(req, authInfo);
|
||||
_ACTSetRegionAndCountryParameters(req, authInfo);
|
||||
|
|
|
@ -16,103 +16,112 @@
|
|||
namespace NAPI
|
||||
{
|
||||
/* Service URL manager */
|
||||
std::string s_serviceURL_ContentPrefixURL;
|
||||
std::string s_serviceURL_UncachedContentPrefixURL;
|
||||
std::string s_serviceURL_EcsURL;
|
||||
std::string s_serviceURL_IasURL;
|
||||
std::string s_serviceURL_CasURL;
|
||||
std::string s_serviceURL_NusURL;
|
||||
|
||||
std::string _getNUSUrl()
|
||||
struct CachedServiceUrls
|
||||
{
|
||||
if (!s_serviceURL_NusURL.empty())
|
||||
return s_serviceURL_NusURL;
|
||||
switch (ActiveSettings::GetNetworkService())
|
||||
{
|
||||
case NetworkService::Nintendo:
|
||||
return NintendoURLs::NUSURL;
|
||||
break;
|
||||
case NetworkService::Pretendo:
|
||||
return PretendoURLs::NUSURL;
|
||||
break;
|
||||
case NetworkService::Custom:
|
||||
return GetNetworkConfig().urls.NUS;
|
||||
break;
|
||||
default:
|
||||
return NintendoURLs::NUSURL;
|
||||
break;
|
||||
}
|
||||
std::string s_serviceURL_ContentPrefixURL;
|
||||
std::string s_serviceURL_UncachedContentPrefixURL;
|
||||
std::string s_serviceURL_EcsURL;
|
||||
std::string s_serviceURL_IasURL;
|
||||
std::string s_serviceURL_CasURL;
|
||||
std::string s_serviceURL_NusURL;
|
||||
};
|
||||
|
||||
std::unordered_map<NetworkService, CachedServiceUrls> s_cachedServiceUrlsMap;
|
||||
|
||||
CachedServiceUrls& GetCachedServiceUrls(NetworkService service)
|
||||
{
|
||||
return s_cachedServiceUrlsMap[service];
|
||||
}
|
||||
|
||||
std::string _getIASUrl()
|
||||
std::string _getNUSUrl(NetworkService service)
|
||||
{
|
||||
if (!s_serviceURL_IasURL.empty())
|
||||
return s_serviceURL_IasURL;
|
||||
switch (ActiveSettings::GetNetworkService())
|
||||
{
|
||||
case NetworkService::Nintendo:
|
||||
return NintendoURLs::IASURL;
|
||||
break;
|
||||
case NetworkService::Pretendo:
|
||||
return PretendoURLs::IASURL;
|
||||
break;
|
||||
case NetworkService::Custom:
|
||||
return GetNetworkConfig().urls.IAS;
|
||||
break;
|
||||
default:
|
||||
return NintendoURLs::IASURL;
|
||||
break;
|
||||
}
|
||||
auto& cachedServiceUrls = GetCachedServiceUrls(service);
|
||||
if (!cachedServiceUrls.s_serviceURL_NusURL.empty())
|
||||
return cachedServiceUrls.s_serviceURL_NusURL;
|
||||
switch (service)
|
||||
{
|
||||
case NetworkService::Nintendo:
|
||||
return NintendoURLs::NUSURL;
|
||||
case NetworkService::Pretendo:
|
||||
return PretendoURLs::NUSURL;
|
||||
case NetworkService::Custom:
|
||||
return GetNetworkConfig().urls.NUS;
|
||||
default:
|
||||
return NintendoURLs::NUSURL;
|
||||
}
|
||||
}
|
||||
|
||||
std::string _getECSUrl()
|
||||
std::string _getIASUrl(NetworkService service)
|
||||
{
|
||||
auto& cachedServiceUrls = GetCachedServiceUrls(service);
|
||||
if (!cachedServiceUrls.s_serviceURL_IasURL.empty())
|
||||
return cachedServiceUrls.s_serviceURL_IasURL;
|
||||
switch (service)
|
||||
{
|
||||
case NetworkService::Nintendo:
|
||||
return NintendoURLs::IASURL;
|
||||
case NetworkService::Pretendo:
|
||||
return PretendoURLs::IASURL;
|
||||
case NetworkService::Custom:
|
||||
return GetNetworkConfig().urls.IAS;
|
||||
default:
|
||||
return NintendoURLs::IASURL;
|
||||
}
|
||||
}
|
||||
|
||||
std::string _getECSUrl(NetworkService service)
|
||||
{
|
||||
// this is the first url queried (GetAccountStatus). The others are dynamically set if provided by the server but will fallback to hardcoded defaults otherwise
|
||||
if (!s_serviceURL_EcsURL.empty())
|
||||
return s_serviceURL_EcsURL;
|
||||
return LaunchSettings::GetServiceURL_ecs(); // by default this is "https://ecs.wup.shop.nintendo.net/ecs/services/ECommerceSOAP"
|
||||
auto& cachedServiceUrls = GetCachedServiceUrls(service);
|
||||
if (!cachedServiceUrls.s_serviceURL_EcsURL.empty())
|
||||
return cachedServiceUrls.s_serviceURL_EcsURL;
|
||||
switch (service)
|
||||
{
|
||||
case NetworkService::Nintendo:
|
||||
return NintendoURLs::ECSURL;
|
||||
case NetworkService::Pretendo:
|
||||
return PretendoURLs::ECSURL;
|
||||
case NetworkService::Custom:
|
||||
return GetNetworkConfig().urls.ECS;
|
||||
default:
|
||||
return NintendoURLs::ECSURL;
|
||||
}
|
||||
}
|
||||
|
||||
std::string _getCCSUncachedUrl() // used for TMD requests
|
||||
std::string _getCCSUncachedUrl(NetworkService service) // used for TMD requests
|
||||
{
|
||||
if (!s_serviceURL_UncachedContentPrefixURL.empty())
|
||||
return s_serviceURL_UncachedContentPrefixURL;
|
||||
switch (ActiveSettings::GetNetworkService())
|
||||
{
|
||||
case NetworkService::Nintendo:
|
||||
return NintendoURLs::CCSUURL;
|
||||
break;
|
||||
case NetworkService::Pretendo:
|
||||
return PretendoURLs::CCSUURL;
|
||||
break;
|
||||
case NetworkService::Custom:
|
||||
return GetNetworkConfig().urls.CCSU;
|
||||
break;
|
||||
default:
|
||||
return NintendoURLs::CCSUURL;
|
||||
break;
|
||||
}
|
||||
auto& cachedServiceUrls = GetCachedServiceUrls(service);
|
||||
if (!cachedServiceUrls.s_serviceURL_UncachedContentPrefixURL.empty())
|
||||
return cachedServiceUrls.s_serviceURL_UncachedContentPrefixURL;
|
||||
switch (service)
|
||||
{
|
||||
case NetworkService::Nintendo:
|
||||
return NintendoURLs::CCSUURL;
|
||||
case NetworkService::Pretendo:
|
||||
return PretendoURLs::CCSUURL;
|
||||
case NetworkService::Custom:
|
||||
return GetNetworkConfig().urls.CCSU;
|
||||
default:
|
||||
return NintendoURLs::CCSUURL;
|
||||
}
|
||||
}
|
||||
|
||||
std::string _getCCSUrl() // used for game data downloads
|
||||
std::string _getCCSUrl(NetworkService service) // used for game data downloads
|
||||
{
|
||||
if (!s_serviceURL_ContentPrefixURL.empty())
|
||||
return s_serviceURL_ContentPrefixURL;
|
||||
switch (ActiveSettings::GetNetworkService())
|
||||
{
|
||||
case NetworkService::Nintendo:
|
||||
return NintendoURLs::CCSURL;
|
||||
break;
|
||||
case NetworkService::Pretendo:
|
||||
return PretendoURLs::CCSURL;
|
||||
break;
|
||||
case NetworkService::Custom:
|
||||
return GetNetworkConfig().urls.CCS;
|
||||
break;
|
||||
default:
|
||||
return NintendoURLs::CCSURL;
|
||||
break;
|
||||
}
|
||||
auto& cachedServiceUrls = GetCachedServiceUrls(service);
|
||||
if (!cachedServiceUrls.s_serviceURL_ContentPrefixURL.empty())
|
||||
return cachedServiceUrls.s_serviceURL_ContentPrefixURL;
|
||||
switch (service)
|
||||
{
|
||||
case NetworkService::Nintendo:
|
||||
return NintendoURLs::CCSURL;
|
||||
case NetworkService::Pretendo:
|
||||
return PretendoURLs::CCSURL;
|
||||
case NetworkService::Custom:
|
||||
return GetNetworkConfig().urls.CCS;
|
||||
default:
|
||||
return NintendoURLs::CCSURL;
|
||||
}
|
||||
}
|
||||
|
||||
/* NUS */
|
||||
|
@ -122,8 +131,8 @@ namespace NAPI
|
|||
{
|
||||
NAPI_NUSGetSystemCommonETicket_Result result{};
|
||||
|
||||
CurlSOAPHelper soapHelper;
|
||||
soapHelper.SOAP_initate("nus", _getNUSUrl(), "GetSystemCommonETicket", "1.0");
|
||||
CurlSOAPHelper soapHelper(authInfo.GetService());
|
||||
soapHelper.SOAP_initate("nus", _getNUSUrl(authInfo.GetService()), "GetSystemCommonETicket", "1.0");
|
||||
|
||||
soapHelper.SOAP_addRequestField("DeviceId", fmt::format("{}", authInfo.getDeviceIdWithPlatform()));
|
||||
soapHelper.SOAP_addRequestField("RegionId", NCrypto::GetRegionAsString(authInfo.region));
|
||||
|
@ -175,8 +184,8 @@ namespace NAPI
|
|||
{
|
||||
NAPI_IASGetChallenge_Result result{};
|
||||
|
||||
CurlSOAPHelper soapHelper;
|
||||
soapHelper.SOAP_initate("ias", _getIASUrl(), "GetChallenge", "2.0");
|
||||
CurlSOAPHelper soapHelper(authInfo.GetService());
|
||||
soapHelper.SOAP_initate("ias", _getIASUrl(authInfo.GetService()), "GetChallenge", "2.0");
|
||||
|
||||
soapHelper.SOAP_addRequestField("DeviceId", fmt::format("{}", authInfo.getDeviceIdWithPlatform())); // not validated but the generated Challenge is bound to this DeviceId
|
||||
soapHelper.SOAP_addRequestField("Region", NCrypto::GetRegionAsString(authInfo.region));
|
||||
|
@ -200,8 +209,8 @@ namespace NAPI
|
|||
NAPI_IASGetRegistrationInfo_Result IAS_GetRegistrationInfo_QueryInfo(AuthInfo& authInfo, std::string challenge)
|
||||
{
|
||||
NAPI_IASGetRegistrationInfo_Result result;
|
||||
CurlSOAPHelper soapHelper;
|
||||
soapHelper.SOAP_initate("ias", _getIASUrl(), "GetRegistrationInfo", "2.0");
|
||||
CurlSOAPHelper soapHelper(authInfo.GetService());
|
||||
soapHelper.SOAP_initate("ias", _getIASUrl(authInfo.GetService()), "GetRegistrationInfo", "2.0");
|
||||
|
||||
soapHelper.SOAP_addRequestField("DeviceId", fmt::format("{}", authInfo.getDeviceIdWithPlatform())); // this must match the DeviceId used to generate Challenge
|
||||
soapHelper.SOAP_addRequestField("Region", NCrypto::GetRegionAsString(authInfo.region));
|
||||
|
@ -301,8 +310,8 @@ namespace NAPI
|
|||
{
|
||||
NAPI_ECSGetAccountStatus_Result result{};
|
||||
|
||||
CurlSOAPHelper soapHelper;
|
||||
soapHelper.SOAP_initate("ecs", _getECSUrl(), "GetAccountStatus", "2.0");
|
||||
CurlSOAPHelper soapHelper(authInfo.GetService());
|
||||
soapHelper.SOAP_initate("ecs", _getECSUrl(authInfo.GetService()), "GetAccountStatus", "2.0");
|
||||
|
||||
soapHelper.SOAP_addRequestField("DeviceId", fmt::format("{}", authInfo.getDeviceIdWithPlatform()));
|
||||
soapHelper.SOAP_addRequestField("Region", NCrypto::GetRegionAsString(authInfo.region));
|
||||
|
@ -367,19 +376,19 @@ namespace NAPI
|
|||
}
|
||||
|
||||
// assign service URLs
|
||||
auto& cachedServiceUrls = GetCachedServiceUrls(authInfo.GetService());
|
||||
if (!result.serviceURLs.ContentPrefixURL.empty())
|
||||
s_serviceURL_ContentPrefixURL = result.serviceURLs.ContentPrefixURL;
|
||||
cachedServiceUrls.s_serviceURL_ContentPrefixURL = result.serviceURLs.ContentPrefixURL;
|
||||
if (!result.serviceURLs.UncachedContentPrefixURL.empty())
|
||||
s_serviceURL_UncachedContentPrefixURL = result.serviceURLs.UncachedContentPrefixURL;
|
||||
cachedServiceUrls.s_serviceURL_UncachedContentPrefixURL = result.serviceURLs.UncachedContentPrefixURL;
|
||||
if (!result.serviceURLs.IasURL.empty())
|
||||
s_serviceURL_IasURL = result.serviceURLs.IasURL;
|
||||
cachedServiceUrls.s_serviceURL_IasURL = result.serviceURLs.IasURL;
|
||||
if (!result.serviceURLs.CasURL.empty())
|
||||
s_serviceURL_CasURL = result.serviceURLs.CasURL;
|
||||
cachedServiceUrls.s_serviceURL_CasURL = result.serviceURLs.CasURL;
|
||||
if (!result.serviceURLs.NusURL.empty())
|
||||
s_serviceURL_NusURL = result.serviceURLs.NusURL;
|
||||
cachedServiceUrls.s_serviceURL_NusURL = result.serviceURLs.NusURL;
|
||||
if (!result.serviceURLs.EcsURL.empty())
|
||||
s_serviceURL_EcsURL = result.serviceURLs.EcsURL;
|
||||
|
||||
cachedServiceUrls.s_serviceURL_EcsURL = result.serviceURLs.EcsURL;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -387,8 +396,8 @@ namespace NAPI
|
|||
{
|
||||
NAPI_ECSAccountListETicketIds_Result result{};
|
||||
|
||||
CurlSOAPHelper soapHelper;
|
||||
soapHelper.SOAP_initate("ecs", _getECSUrl(), "AccountListETicketIds", "2.0");
|
||||
CurlSOAPHelper soapHelper(authInfo.GetService());
|
||||
soapHelper.SOAP_initate("ecs", _getECSUrl(authInfo.GetService()), "AccountListETicketIds", "2.0");
|
||||
|
||||
soapHelper.SOAP_addRequestField("DeviceId", fmt::format("{}", authInfo.getDeviceIdWithPlatform()));
|
||||
soapHelper.SOAP_addRequestField("Region", NCrypto::GetRegionAsString(authInfo.region));
|
||||
|
@ -446,8 +455,8 @@ namespace NAPI
|
|||
{
|
||||
NAPI_ECSAccountGetETickets_Result result{};
|
||||
|
||||
CurlSOAPHelper soapHelper;
|
||||
soapHelper.SOAP_initate("ecs", _getECSUrl(), "AccountGetETickets", "2.0");
|
||||
CurlSOAPHelper soapHelper(authInfo.GetService());
|
||||
soapHelper.SOAP_initate("ecs", _getECSUrl(authInfo.GetService()), "AccountGetETickets", "2.0");
|
||||
|
||||
soapHelper.SOAP_addRequestField("DeviceId", fmt::format("{}", authInfo.getDeviceIdWithPlatform()));
|
||||
soapHelper.SOAP_addRequestField("Region", NCrypto::GetRegionAsString(authInfo.region));
|
||||
|
@ -512,7 +521,7 @@ namespace NAPI
|
|||
{
|
||||
NAPI_CCSGetTMD_Result result{};
|
||||
CurlRequestHelper req;
|
||||
req.initate(fmt::format("{}/{:016x}/tmd.{}?deviceId={}&accountId={}", _getCCSUncachedUrl(), titleId, titleVersion, authInfo.getDeviceIdWithPlatform(), authInfo.IASToken.accountId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);
|
||||
req.initate(authInfo.GetService(), fmt::format("{}/{:016x}/tmd.{}?deviceId={}&accountId={}", _getCCSUncachedUrl(authInfo.GetService()), titleId, titleVersion, authInfo.getDeviceIdWithPlatform(), authInfo.IASToken.accountId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);
|
||||
req.setTimeout(180);
|
||||
if (!req.submitRequest(false))
|
||||
{
|
||||
|
@ -528,7 +537,7 @@ namespace NAPI
|
|||
{
|
||||
NAPI_CCSGetTMD_Result result{};
|
||||
CurlRequestHelper req;
|
||||
req.initate(fmt::format("{}/{:016x}/tmd?deviceId={}&accountId={}", _getCCSUncachedUrl(), titleId, authInfo.getDeviceIdWithPlatform(), authInfo.IASToken.accountId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);
|
||||
req.initate(authInfo.GetService(), fmt::format("{}/{:016x}/tmd?deviceId={}&accountId={}", _getCCSUncachedUrl(authInfo.GetService()), titleId, authInfo.getDeviceIdWithPlatform(), authInfo.IASToken.accountId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);
|
||||
req.setTimeout(180);
|
||||
if (!req.submitRequest(false))
|
||||
{
|
||||
|
@ -540,11 +549,11 @@ namespace NAPI
|
|||
return result;
|
||||
}
|
||||
|
||||
NAPI_CCSGetETicket_Result CCS_GetCETK(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion)
|
||||
NAPI_CCSGetETicket_Result CCS_GetCETK(NetworkService service, uint64 titleId, uint16 titleVersion)
|
||||
{
|
||||
NAPI_CCSGetETicket_Result result{};
|
||||
CurlRequestHelper req;
|
||||
req.initate(fmt::format("{}/{:016x}/cetk", _getCCSUncachedUrl(), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);
|
||||
req.initate(service, fmt::format("{}/{:016x}/cetk", _getCCSUncachedUrl(service), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);
|
||||
req.setTimeout(180);
|
||||
if (!req.submitRequest(false))
|
||||
{
|
||||
|
@ -556,10 +565,10 @@ namespace NAPI
|
|||
return result;
|
||||
}
|
||||
|
||||
bool CCS_GetContentFile(uint64 titleId, uint32 contentId, bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData)
|
||||
bool CCS_GetContentFile(NetworkService service, uint64 titleId, uint32 contentId, bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData)
|
||||
{
|
||||
CurlRequestHelper req;
|
||||
req.initate(fmt::format("{}/{:016x}/{:08x}", _getCCSUrl(), titleId, contentId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);
|
||||
req.initate(service, fmt::format("{}/{:016x}/{:08x}", _getCCSUrl(service), titleId, contentId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);
|
||||
req.setWriteCallback(cbWriteCallback, userData);
|
||||
req.setTimeout(0);
|
||||
if (!req.submitRequest(false))
|
||||
|
@ -570,11 +579,11 @@ namespace NAPI
|
|||
return true;
|
||||
}
|
||||
|
||||
NAPI_CCSGetContentH3_Result CCS_GetContentH3File(uint64 titleId, uint32 contentId)
|
||||
NAPI_CCSGetContentH3_Result CCS_GetContentH3File(NetworkService service, uint64 titleId, uint32 contentId)
|
||||
{
|
||||
NAPI_CCSGetContentH3_Result result{};
|
||||
CurlRequestHelper req;
|
||||
req.initate(fmt::format("{}/{:016x}/{:08x}.h3", _getCCSUrl(), titleId, contentId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);
|
||||
req.initate(service, fmt::format("{}/{:016x}/{:08x}.h3", _getCCSUrl(service), titleId, contentId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);
|
||||
if (!req.submitRequest(false))
|
||||
{
|
||||
cemuLog_log(LogType::Force, fmt::format("Failed to request content hash file {:08x}.h3 for title {:016X}", contentId, titleId));
|
||||
|
|
|
@ -119,7 +119,7 @@ CurlRequestHelper::~CurlRequestHelper()
|
|||
curl_easy_cleanup(m_curl);
|
||||
}
|
||||
|
||||
void CurlRequestHelper::initate(std::string url, SERVER_SSL_CONTEXT sslContext)
|
||||
void CurlRequestHelper::initate(NetworkService service, std::string url, SERVER_SSL_CONTEXT sslContext)
|
||||
{
|
||||
// reset parameters
|
||||
m_headerExtraFields.clear();
|
||||
|
@ -131,8 +131,10 @@ void CurlRequestHelper::initate(std::string url, SERVER_SSL_CONTEXT sslContext)
|
|||
curl_easy_setopt(m_curl, CURLOPT_TIMEOUT, 60);
|
||||
|
||||
// SSL
|
||||
if (GetNetworkConfig().disablesslver.GetValue() && ActiveSettings::GetNetworkService() == NetworkService::Custom || ActiveSettings::GetNetworkService() == NetworkService::Pretendo){ //Remove once Pretendo has SSL
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||
if (IsNetworkServiceSSLDisabled(service))
|
||||
{
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
}
|
||||
else if (sslContext == SERVER_SSL_CONTEXT::ACT || sslContext == SERVER_SSL_CONTEXT::TAGAYA)
|
||||
{
|
||||
|
@ -256,18 +258,24 @@ bool CurlRequestHelper::submitRequest(bool isPost)
|
|||
return true;
|
||||
}
|
||||
|
||||
CurlSOAPHelper::CurlSOAPHelper()
|
||||
CurlSOAPHelper::CurlSOAPHelper(NetworkService service)
|
||||
{
|
||||
m_curl = curl_easy_init();
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, __curlWriteCallback);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, this);
|
||||
|
||||
// SSL
|
||||
if (!GetNetworkConfig().disablesslver.GetValue() && ActiveSettings::GetNetworkService() != NetworkService::Pretendo && ActiveSettings::GetNetworkService() != NetworkService::Custom) { //Remove once Pretendo has SSL
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_SOAP);
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL);
|
||||
if (!IsNetworkServiceSSLDisabled(service))
|
||||
{
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_SOAP);
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL);
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||
}
|
||||
if(GetConfig().proxy_server.GetValue() != "")
|
||||
else
|
||||
{
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
}
|
||||
if (GetConfig().proxy_server.GetValue() != "")
|
||||
{
|
||||
curl_easy_setopt(m_curl, CURLOPT_PROXY, GetConfig().proxy_server.GetValue().c_str());
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue