Merge branch 'refs/heads/main' into loadaudio

# Conflicts:
#	src/config/CemuConfig.h
This commit is contained in:
goeiecool9999 2024-05-14 14:22:48 +02:00
commit da3144a801
148 changed files with 5509 additions and 2279 deletions

View file

@ -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

View file

@ -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

View file

@ -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
View file

@ -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

@ -1 +1 @@
Subproject commit 53bef8994c541b6561884a8395ea35715ece75db
Subproject commit cbf4a6641528cee6f172328984576f51698de726

View 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})

View 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")

View 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

View 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)

View 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"
]
}
}
}

View 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})

View 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")

View 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

View 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)

View 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"
]
}
}
}

View file

@ -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
View 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>

View file

@ -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()

View file

@ -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

View file

@ -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)
{

View file

@ -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();

View 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

View 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;
}

View 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;
};

View file

@ -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);

View 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;
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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{};

View file

@ -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)

View file

@ -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();

View file

@ -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

View file

@ -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);
}
}

View file

@ -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)
{

View file

@ -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();

View file

@ -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);
}

View file

@ -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);

View file

@ -2,7 +2,6 @@
void iosuCrypto_init();
bool iosuCrypto_hasAllDataForLogin();
bool iosuCrypto_getDeviceId(uint32* deviceId);
void iosuCrypto_getDeviceSerialString(char* serialString);

View file

@ -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;

View file

@ -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();
}
}
}

View file

@ -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));

View file

@ -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;
}
};

View file

@ -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:

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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();

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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();

View file

@ -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;

View file

@ -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);

View file

@ -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 &currentThread->context.error;
return &currentThread->context.ghs_errno;
}
void* __get_eh_store_globals()

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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

View file

@ -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()

View file

@ -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();
}

View file

@ -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;
}

View file

@ -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();
};

View file

@ -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);
}
};

View file

@ -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();
};

View file

@ -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);

View file

@ -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();

View file

@ -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);

View file

@ -45,7 +45,8 @@ namespace coreinit
};
void OSTicksToCalendarTime(uint64 ticks, OSCalendarTime_t* calenderStruct);
uint64 OSGetTime();
uint64 coreinit_getOSTime();
uint64 coreinit_getTimerTick();

View file

@ -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

View file

@ -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;

View file

@ -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();
};

View file

@ -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);
}

View file

@ -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);

View file

@ -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();
}

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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 = &param;
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 = &param;
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 = &param;
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 = &param;
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 = &param;
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 = &param;
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 = &param;
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 = &param;
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 = &param;
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);

View 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);
}

View file

@ -0,0 +1 @@
void nnSL_load();

View file

@ -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);

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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());
}

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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{};

View file

@ -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
}

View file

@ -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 <>

View file

@ -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));

View file

@ -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);

View file

@ -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 */

View file

@ -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);

View file

@ -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));

View file

@ -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