Compare commits
60 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
914ead075e | ||
|
|
53fb4a78a3 | ||
|
|
1a85c18600 | ||
|
|
381381c7e0 | ||
|
|
2fed6dd7e1 | ||
|
|
9627c550a0 | ||
|
|
adc617ccc4 | ||
|
|
802bbb2263 | ||
|
|
6c72b7f011 | ||
|
|
25e47738f7 | ||
|
|
b23c6b456c | ||
|
|
240650f6a6 | ||
|
|
c765d5be0b | ||
|
|
1611c53c12 | ||
|
|
313f047f97 | ||
|
|
7e75593c20 | ||
|
|
d244677df9 | ||
|
|
ec4cba9de8 | ||
|
|
caef92a584 | ||
|
|
4fa625c4fa | ||
|
|
cbef6b1fca | ||
|
|
aec129c1ab | ||
|
|
770611fdf3 | ||
|
|
07e3c56f0d | ||
|
|
eb4ce48b65 | ||
|
|
1524ff87d2 | ||
|
|
312e5eda66 | ||
|
|
161d696013 | ||
|
|
9981ce8d98 | ||
|
|
40493231ed | ||
|
|
43a1948d58 | ||
|
|
a1815b617c | ||
|
|
908c79881b | ||
|
|
a5bc0bcc66 | ||
|
|
d3cb9201f1 | ||
|
|
ed0319cfed | ||
|
|
3f3c2dc20f | ||
|
|
78ce053b4d | ||
|
|
8509460d2c | ||
|
|
2c1e2c63c3 | ||
|
|
7b0affb6e0 | ||
|
|
ca36722a54 | ||
|
|
603952bc27 | ||
|
|
4ef66ec8fb | ||
|
|
d41ffb592c | ||
|
|
5e7e55b98a | ||
|
|
36148fe7f6 | ||
|
|
01bc0c84f0 | ||
|
|
c34a95fa25 | ||
|
|
b5d6194f6d | ||
|
|
a5e419535f | ||
|
|
9775fae4eb | ||
|
|
a262dc02b5 | ||
|
|
fca5752690 | ||
|
|
7b48e7b363 | ||
|
|
a7d9be1384 | ||
|
|
075155022e | ||
|
|
8f8c0b69dc | ||
|
|
31c6ba7ecd | ||
|
|
1fd194141a |
@@ -3,14 +3,12 @@
|
||||
# Exit on error, rather than continuing with the rest of the script.
|
||||
set -e
|
||||
|
||||
cd /yuzu
|
||||
|
||||
ccache -s
|
||||
|
||||
mkdir build || true && cd build
|
||||
cmake .. -DDISPLAY_VERSION=$1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/clang -DCMAKE_CXX_COMPILER=/usr/lib/ccache/clang++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DCMAKE_INSTALL_PREFIX="/usr"
|
||||
cmake .. -GNinja -DDISPLAY_VERSION=$1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/clang -DCMAKE_CXX_COMPILER=/usr/lib/ccache/clang++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DCMAKE_INSTALL_PREFIX="/usr"
|
||||
|
||||
make -j$(nproc)
|
||||
ninja
|
||||
|
||||
ccache -s
|
||||
|
||||
|
||||
@@ -4,5 +4,5 @@ mkdir -p "ccache" || true
|
||||
chmod a+x ./.ci/scripts/clang/docker.sh
|
||||
# the UID for the container yuzu user is 1027
|
||||
sudo chown -R 1027 ./
|
||||
docker run -e ENABLE_COMPATIBILITY_REPORTING -e CCACHE_DIR=/yuzu/ccache -v $(pwd):/yuzu yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.ci/scripts/clang/docker.sh $1
|
||||
docker run -e ENABLE_COMPATIBILITY_REPORTING -e CCACHE_DIR=/yuzu/ccache -v "$(pwd):/yuzu" -w /yuzu yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.ci/scripts/clang/docker.sh "$1"
|
||||
sudo chown -R $UID ./
|
||||
|
||||
0
.ci/scripts/clang/upload.sh
Normal file → Executable file
0
.ci/scripts/clang/upload.sh
Normal file → Executable file
@@ -4,8 +4,10 @@
|
||||
cp license.txt "$DIR_NAME"
|
||||
cp README.md "$DIR_NAME"
|
||||
|
||||
tar -cJvf "${REV_NAME}-source.tar.xz" src externals CMakeLists.txt README.md license.txt
|
||||
cp "${REV_NAME}-source.tar.xz" "$DIR_NAME"
|
||||
if [[ -z "${NO_SOURCE_PACK}" ]]; then
|
||||
tar -cJvf "${REV_NAME}-source.tar.xz" src externals CMakeLists.txt README.md license.txt
|
||||
cp -v "${REV_NAME}-source.tar.xz" "$DIR_NAME"
|
||||
fi
|
||||
|
||||
tar $COMPRESSION_FLAGS "$ARCHIVE_NAME" "$DIR_NAME"
|
||||
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
chmod a+x ./.ci/scripts/format/docker.sh
|
||||
# the UID for the container yuzu user is 1027
|
||||
sudo chown -R 1027 ./
|
||||
docker run -v $(pwd):/yuzu yuzuemu/build-environments:linux-clang-format /bin/bash -ex /yuzu/.ci/scripts/format/docker.sh
|
||||
docker run -v "$(pwd):/yuzu" -w /yuzu yuzuemu/build-environments:linux-clang-format /bin/bash -ex /yuzu/.ci/scripts/format/docker.sh
|
||||
sudo chown -R $UID ./
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
# Exit on error, rather than continuing with the rest of the script.
|
||||
set -e
|
||||
|
||||
cd /yuzu
|
||||
|
||||
ccache -s
|
||||
|
||||
mkdir build || true && cd build
|
||||
@@ -19,15 +17,16 @@ cmake .. \
|
||||
-DENABLE_QT_TRANSLATION=ON \
|
||||
-DUSE_DISCORD_PRESENCE=ON \
|
||||
-DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \
|
||||
-DYUZU_USE_BUNDLED_FFMPEG=ON
|
||||
-DYUZU_USE_BUNDLED_FFMPEG=ON \
|
||||
-GNinja
|
||||
|
||||
make -j$(nproc)
|
||||
ninja
|
||||
|
||||
ccache -s
|
||||
|
||||
ctest -VV -C Release
|
||||
|
||||
make install DESTDIR=AppDir
|
||||
DESTDIR="$PWD/AppDir" ninja install
|
||||
rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester
|
||||
|
||||
# Download tools needed to build an AppImage
|
||||
|
||||
@@ -4,5 +4,5 @@ mkdir -p "ccache" || true
|
||||
chmod a+x ./.ci/scripts/linux/docker.sh
|
||||
# the UID for the container yuzu user is 1027
|
||||
sudo chown -R 1027 ./
|
||||
docker run -e ENABLE_COMPATIBILITY_REPORTING -e CCACHE_DIR=/yuzu/ccache -v $(pwd):/yuzu yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.ci/scripts/linux/docker.sh $1
|
||||
docker run -e ENABLE_COMPATIBILITY_REPORTING -e CCACHE_DIR=/yuzu/ccache -v "$(pwd):/yuzu" -w /yuzu yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.ci/scripts/linux/docker.sh "$1"
|
||||
sudo chown -R $UID ./
|
||||
|
||||
5
.ci/scripts/linux/upload.sh
Normal file → Executable file
5
.ci/scripts/linux/upload.sh
Normal file → Executable file
@@ -24,6 +24,11 @@ cd build
|
||||
wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/appimagetool-x86_64.AppImage
|
||||
chmod 755 appimagetool-x86_64.AppImage
|
||||
|
||||
# if FUSE is not available, then fallback to extract and run
|
||||
if ! ./appimagetool-x86_64.AppImage --version; then
|
||||
export APPIMAGE_EXTRACT_AND_RUN=1
|
||||
fi
|
||||
|
||||
if [ "${RELEASE_NAME}" = "mainline" ]; then
|
||||
# Generate update information if releasing to mainline
|
||||
./appimagetool-x86_64.AppImage -u "gh-releases-zsync|yuzu-emu|yuzu-${RELEASE_NAME}|latest|yuzu-*.AppImage.zsync" AppDir "${APPIMAGE_NAME}"
|
||||
|
||||
@@ -2,19 +2,23 @@
|
||||
|
||||
set -e
|
||||
|
||||
cd /yuzu
|
||||
#cd /yuzu
|
||||
|
||||
ccache -s
|
||||
ccache -sv
|
||||
|
||||
mkdir build || true && cd build
|
||||
LDFLAGS="-fuse-ld=lld"
|
||||
mkdir -p "$HOME/.conan/profiles"
|
||||
wget -c "https://github.com/yuzu-emu/build-environments/raw/master/linux-mingw/default" -O "$HOME/.conan/profiles/default"
|
||||
wget -c "https://github.com/yuzu-emu/build-environments/raw/master/linux-mingw/settings.yml" -O "$HOME/.conan/settings.yml"
|
||||
|
||||
mkdir -p build && cd build
|
||||
export LDFLAGS="-fuse-ld=lld"
|
||||
# -femulated-tls required due to an incompatibility between GCC and Clang
|
||||
# TODO(lat9nq): If this is widespread, we probably need to add this to CMakeLists where appropriate
|
||||
export CXXFLAGS="-femulated-tls"
|
||||
cmake .. \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_CXX_FLAGS="-femulated-tls" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWClangCross.cmake" \
|
||||
-DDISPLAY_VERSION=$1 \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${PWD}/../CMakeModules/MinGWClangCross.cmake" \
|
||||
-DDISPLAY_VERSION="$1" \
|
||||
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
|
||||
-DENABLE_QT_TRANSLATION=ON \
|
||||
-DUSE_CCACHE=ON \
|
||||
@@ -23,7 +27,7 @@ cmake .. \
|
||||
-GNinja
|
||||
ninja yuzu yuzu-cmd
|
||||
|
||||
ccache -s
|
||||
ccache -sv
|
||||
|
||||
echo "Tests skipped"
|
||||
#ctest -VV -C Release
|
||||
@@ -61,7 +65,7 @@ python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll
|
||||
# copy FFmpeg libraries
|
||||
EXTERNALS_PATH="$(pwd)/build/externals"
|
||||
FFMPEG_DLL_PATH="$(find "${EXTERNALS_PATH}" -maxdepth 1 -type d | grep 'ffmpeg-')/bin"
|
||||
find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';'
|
||||
find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -nv {} package/ ';'
|
||||
|
||||
# copy libraries from yuzu.exe path
|
||||
find "$(pwd)/build/bin/" -type f -regex ".*\.dll" -exec cp -v {} package/ ';'
|
||||
|
||||
@@ -4,5 +4,5 @@ mkdir -p "ccache" || true
|
||||
chmod a+x ./.ci/scripts/windows/docker.sh
|
||||
# the UID for the container yuzu user is 1027
|
||||
sudo chown -R 1027 ./
|
||||
docker run -e CCACHE_DIR=/yuzu/ccache -v $(pwd):/yuzu yuzuemu/build-environments:linux-mingw /bin/bash -ex /yuzu/.ci/scripts/windows/docker.sh $1
|
||||
docker run -e CCACHE_DIR=/yuzu/ccache -v "$(pwd):/yuzu" -w /yuzu yuzuemu/build-environments:linux-mingw /bin/bash -ex /yuzu/.ci/scripts/windows/docker.sh "$1"
|
||||
sudo chown -R $UID ./
|
||||
|
||||
0
.ci/scripts/windows/upload.sh
Normal file → Executable file
0
.ci/scripts/windows/upload.sh
Normal file → Executable file
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
container: yuzuemu/build-environments:linux-transifex
|
||||
if: ${{ github.repository == 'yuzu-emu/yuzu' && !github.head_ref }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
115
.github/workflows/verify.yml
vendored
Normal file
115
.github/workflows/verify.yml
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
name: 'yuzu verify'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
format:
|
||||
name: 'verify format'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: yuzuemu/build-environments:linux-clang-format
|
||||
options: -u 1001
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: false
|
||||
- name: 'Verify Formatting'
|
||||
run: bash -ex ./.ci/scripts/format/script.sh
|
||||
build:
|
||||
name: 'test build'
|
||||
needs: format
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- type: clang
|
||||
image: linux-fresh
|
||||
- type: linux
|
||||
image: linux-fresh
|
||||
- type: windows
|
||||
image: linux-mingw
|
||||
container:
|
||||
image: yuzuemu/build-environments:${{ matrix.image }}
|
||||
options: -u 1001
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
- name: Set up cache
|
||||
uses: actions/cache@v3
|
||||
id: ccache-restore
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ${{ runner.os }}-${{ matrix.type }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ matrix.type }}-
|
||||
- name: Create ccache directory
|
||||
if: steps.ccache-restore.outputs.cache-hit != 'true'
|
||||
run: mkdir -p ~/.ccache
|
||||
- name: Build
|
||||
run: ./.ci/scripts/${{ matrix.type }}/docker.sh
|
||||
env:
|
||||
ENABLE_COMPATIBILITY_REPORTING: "ON"
|
||||
- name: Pack
|
||||
run: ./.ci/scripts/${{ matrix.type }}/upload.sh
|
||||
env:
|
||||
NO_SOURCE_PACK: "YES"
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.type }}
|
||||
path: artifacts/
|
||||
build-msvc:
|
||||
name: 'test build (windows, msvc)'
|
||||
needs: format
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- name: Set up cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.buildcache
|
||||
key: ${{ runner.os }}-msvc-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-msvc-
|
||||
- name: Install dependencies
|
||||
# due to how chocolatey works, only cmd.exe is supported here
|
||||
shell: cmd
|
||||
run: |
|
||||
choco install vulkan-sdk wget
|
||||
python -m pip install --upgrade pip conan
|
||||
call refreshenv
|
||||
wget https://github.com/mbitsnbites/buildcache/releases/download/v0.27.6/buildcache-windows.zip
|
||||
7z x buildcache-windows.zip
|
||||
copy buildcache\bin\buildcache.exe C:\ProgramData\chocolatey\bin
|
||||
rmdir buildcache
|
||||
echo %PATH% >> %GITHUB_PATH%
|
||||
- name: Set up MSVC
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
- name: Configure
|
||||
env:
|
||||
CC: cl.exe
|
||||
CXX: cl.exe
|
||||
run: |
|
||||
glslangValidator --version
|
||||
mkdir build
|
||||
cmake . -B build -GNinja -DCMAKE_TOOLCHAIN_FILE="CMakeModules/MSVCCache.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DCMAKE_BUILD_TYPE=Release
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
- name: Cache Summary
|
||||
run: buildcache -s
|
||||
- name: Pack
|
||||
shell: pwsh
|
||||
run: .\.ci\scripts\windows\upload.ps1
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: msvc
|
||||
path: artifacts/
|
||||
@@ -627,6 +627,14 @@ add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY
|
||||
-DBOOST_DATE_TIME_NO_LIB
|
||||
-DBOOST_REGEX_NO_LIB
|
||||
)
|
||||
# Adjustments for MSVC + Ninja
|
||||
if (MSVC AND CMAKE_GENERATOR STREQUAL "Ninja")
|
||||
add_compile_options(
|
||||
/wd4711 # function 'function' selected for automatic inline expansion
|
||||
/wd4464 # relative include path contains '..'
|
||||
/wd4820 # 'identifier1': '4' bytes padding added after data member 'identifier2'
|
||||
)
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(externals)
|
||||
|
||||
@@ -2,5 +2,6 @@ function(copy_yuzu_FFmpeg_deps target_dir)
|
||||
include(WindowsCopyFiles)
|
||||
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
|
||||
file(READ "${FFmpeg_PATH}/requirements.txt" FFmpeg_REQUIRED_DLLS)
|
||||
string(STRIP "${FFmpeg_REQUIRED_DLLS}" FFmpeg_REQUIRED_DLLS)
|
||||
windows_copy_files(${target_dir} ${FFmpeg_DLL_DIR} ${DLL_DEST} ${FFmpeg_REQUIRED_DLLS})
|
||||
endfunction(copy_yuzu_FFmpeg_deps)
|
||||
|
||||
12
CMakeModules/MSVCCache.cmake
Normal file
12
CMakeModules/MSVCCache.cmake
Normal file
@@ -0,0 +1,12 @@
|
||||
# buildcache wrapper
|
||||
OPTION(USE_CCACHE "Use buildcache for compilation" OFF)
|
||||
IF(USE_CCACHE)
|
||||
FIND_PROGRAM(CCACHE buildcache)
|
||||
IF (CCACHE)
|
||||
MESSAGE(STATUS "Using buildcache found in PATH")
|
||||
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
|
||||
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
|
||||
ELSE(CCACHE)
|
||||
MESSAGE(WARNING "USE_CCACHE enabled, but no buildcache executable found")
|
||||
ENDIF(CCACHE)
|
||||
ENDIF(USE_CCACHE)
|
||||
864
dist/languages/ca.ts
vendored
864
dist/languages/ca.ts
vendored
File diff suppressed because it is too large
Load Diff
925
dist/languages/cs.ts
vendored
925
dist/languages/cs.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/da.ts
vendored
864
dist/languages/da.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/de.ts
vendored
864
dist/languages/de.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/el.ts
vendored
864
dist/languages/el.ts
vendored
File diff suppressed because it is too large
Load Diff
868
dist/languages/es.ts
vendored
868
dist/languages/es.ts
vendored
File diff suppressed because it is too large
Load Diff
868
dist/languages/fr.ts
vendored
868
dist/languages/fr.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/id.ts
vendored
864
dist/languages/id.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/it.ts
vendored
864
dist/languages/it.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/ja_JP.ts
vendored
864
dist/languages/ja_JP.ts
vendored
File diff suppressed because it is too large
Load Diff
876
dist/languages/ko_KR.ts
vendored
876
dist/languages/ko_KR.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/nb.ts
vendored
864
dist/languages/nb.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/nl.ts
vendored
864
dist/languages/nl.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/pl.ts
vendored
864
dist/languages/pl.ts
vendored
File diff suppressed because it is too large
Load Diff
872
dist/languages/pt_BR.ts
vendored
872
dist/languages/pt_BR.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/pt_PT.ts
vendored
864
dist/languages/pt_PT.ts
vendored
File diff suppressed because it is too large
Load Diff
886
dist/languages/ru_RU.ts
vendored
886
dist/languages/ru_RU.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/sv.ts
vendored
864
dist/languages/sv.ts
vendored
File diff suppressed because it is too large
Load Diff
890
dist/languages/tr_TR.ts
vendored
890
dist/languages/tr_TR.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/vi.ts
vendored
864
dist/languages/vi.ts
vendored
File diff suppressed because it is too large
Load Diff
864
dist/languages/vi_VN.ts
vendored
864
dist/languages/vi_VN.ts
vendored
File diff suppressed because it is too large
Load Diff
866
dist/languages/zh_CN.ts
vendored
866
dist/languages/zh_CN.ts
vendored
File diff suppressed because it is too large
Load Diff
868
dist/languages/zh_TW.ts
vendored
868
dist/languages/zh_TW.ts
vendored
File diff suppressed because it is too large
Load Diff
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: 5ad1d02351...9ebf6a8384
@@ -36,7 +36,6 @@ if (MSVC)
|
||||
# /GT - Supports fiber safety for data allocated using static thread-local storage
|
||||
add_compile_options(
|
||||
/MP
|
||||
/Zi
|
||||
/Zm200
|
||||
/Zo
|
||||
/permissive-
|
||||
@@ -79,6 +78,13 @@ if (MSVC)
|
||||
/we5245 # 'function': unreferenced function with internal linkage has been removed
|
||||
)
|
||||
|
||||
if (USE_CCACHE)
|
||||
# when caching, we need to use /Z7 to downgrade debug info to use an older but more cachable format
|
||||
add_compile_options(/Z7)
|
||||
else()
|
||||
add_compile_options(/Zi)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64)
|
||||
add_compile_options(/QIntel-jcc-erratum)
|
||||
endif()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "audio_core/audio_out.h"
|
||||
@@ -88,9 +89,12 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memor
|
||||
stream = audio_out->OpenStream(
|
||||
core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
|
||||
fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback));
|
||||
process_event = Core::Timing::CreateEvent(
|
||||
fmt::format("AudioRenderer-Instance{}-Process", instance_number),
|
||||
[this](std::uintptr_t, std::chrono::nanoseconds) { ReleaseAndQueueBuffers(); });
|
||||
process_event =
|
||||
Core::Timing::CreateEvent(fmt::format("AudioRenderer-Instance{}-Process", instance_number),
|
||||
[this](std::uintptr_t, s64, std::chrono::nanoseconds) {
|
||||
ReleaseAndQueueBuffers();
|
||||
return std::nullopt;
|
||||
});
|
||||
for (s32 i = 0; i < NUM_BUFFERS; ++i) {
|
||||
QueueMixedBuffer(i);
|
||||
}
|
||||
@@ -98,13 +102,13 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memor
|
||||
|
||||
AudioRenderer::~AudioRenderer() = default;
|
||||
|
||||
ResultCode AudioRenderer::Start() {
|
||||
Result AudioRenderer::Start() {
|
||||
audio_out->StartStream(stream);
|
||||
ReleaseAndQueueBuffers();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode AudioRenderer::Stop() {
|
||||
Result AudioRenderer::Stop() {
|
||||
audio_out->StopStream(stream);
|
||||
return ResultSuccess;
|
||||
}
|
||||
@@ -125,8 +129,8 @@ Stream::State AudioRenderer::GetStreamState() const {
|
||||
return stream->GetState();
|
||||
}
|
||||
|
||||
ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
|
||||
std::vector<u8>& output_params) {
|
||||
Result AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
|
||||
std::vector<u8>& output_params) {
|
||||
std::scoped_lock lock{mutex};
|
||||
InfoUpdater info_updater{input_params, output_params, behavior_info};
|
||||
|
||||
|
||||
@@ -43,10 +43,10 @@ public:
|
||||
Stream::ReleaseCallback&& release_callback, std::size_t instance_number);
|
||||
~AudioRenderer();
|
||||
|
||||
[[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
|
||||
std::vector<u8>& output_params);
|
||||
[[nodiscard]] ResultCode Start();
|
||||
[[nodiscard]] ResultCode Stop();
|
||||
[[nodiscard]] Result UpdateAudioRenderer(const std::vector<u8>& input_params,
|
||||
std::vector<u8>& output_params);
|
||||
[[nodiscard]] Result Start();
|
||||
[[nodiscard]] Result Stop();
|
||||
void QueueMixedBuffer(Buffer::Tag tag);
|
||||
void ReleaseAndQueueBuffers();
|
||||
[[nodiscard]] u32 GetSampleRate() const;
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
|
||||
namespace AudioCommon {
|
||||
namespace Audren {
|
||||
constexpr ResultCode ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41};
|
||||
constexpr ResultCode ERR_SPLITTER_SORT_FAILED{ErrorModule::Audio, 43};
|
||||
constexpr Result ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41};
|
||||
constexpr Result ERR_SPLITTER_SORT_FAILED{ErrorModule::Audio, 43};
|
||||
} // namespace Audren
|
||||
|
||||
constexpr u8 BASE_REVISION = '0';
|
||||
|
||||
@@ -285,9 +285,8 @@ bool InfoUpdater::UpdateSplitterInfo(SplitterContext& splitter_context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ResultCode InfoUpdater::UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
|
||||
SplitterContext& splitter_context,
|
||||
EffectContext& effect_context) {
|
||||
Result InfoUpdater::UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
|
||||
SplitterContext& splitter_context, EffectContext& effect_context) {
|
||||
std::vector<MixInfo::InParams> mix_in_params;
|
||||
|
||||
if (!behavior_info.IsMixInParameterDirtyOnlyUpdateSupported()) {
|
||||
|
||||
@@ -32,8 +32,8 @@ public:
|
||||
VAddr audio_codec_dsp_addr);
|
||||
bool UpdateEffects(EffectContext& effect_context, bool is_active);
|
||||
bool UpdateSplitterInfo(SplitterContext& splitter_context);
|
||||
ResultCode UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
|
||||
SplitterContext& splitter_context, EffectContext& effect_context);
|
||||
Result UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
|
||||
SplitterContext& splitter_context, EffectContext& effect_context);
|
||||
bool UpdateSinks(SinkContext& sink_context);
|
||||
bool UpdatePerformanceBuffer();
|
||||
bool UpdateErrorInfo(BehaviorInfo& in_behavior_info);
|
||||
|
||||
@@ -34,9 +34,10 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format
|
||||
ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_)
|
||||
: sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)},
|
||||
sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} {
|
||||
release_event =
|
||||
Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
|
||||
release_event = Core::Timing::CreateEvent(
|
||||
name, [this](std::uintptr_t, s64 time, std::chrono::nanoseconds ns_late) {
|
||||
ReleaseActiveBuffer(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,14 +18,16 @@
|
||||
/// Helper macros to insert unused bytes or words to properly align structs. These values will be
|
||||
/// zero-initialized.
|
||||
#define INSERT_PADDING_BYTES(num_bytes) \
|
||||
std::array<u8, num_bytes> CONCAT2(pad, __LINE__) {}
|
||||
[[maybe_unused]] std::array<u8, num_bytes> CONCAT2(pad, __LINE__) {}
|
||||
#define INSERT_PADDING_WORDS(num_words) \
|
||||
std::array<u32, num_words> CONCAT2(pad, __LINE__) {}
|
||||
[[maybe_unused]] std::array<u32, num_words> CONCAT2(pad, __LINE__) {}
|
||||
|
||||
/// These are similar to the INSERT_PADDING_* macros but do not zero-initialize the contents.
|
||||
/// This keeps the structure trivial to construct.
|
||||
#define INSERT_PADDING_BYTES_NOINIT(num_bytes) std::array<u8, num_bytes> CONCAT2(pad, __LINE__)
|
||||
#define INSERT_PADDING_WORDS_NOINIT(num_words) std::array<u32, num_words> CONCAT2(pad, __LINE__)
|
||||
#define INSERT_PADDING_BYTES_NOINIT(num_bytes) \
|
||||
[[maybe_unused]] std::array<u8, num_bytes> CONCAT2(pad, __LINE__)
|
||||
#define INSERT_PADDING_WORDS_NOINIT(num_words) \
|
||||
[[maybe_unused]] std::array<u32, num_words> CONCAT2(pad, __LINE__)
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
||||
|
||||
@@ -20,10 +20,8 @@ struct Fiber::FiberImpl {
|
||||
VirtualBuffer<u8> rewind_stack;
|
||||
|
||||
std::mutex guard;
|
||||
std::function<void(void*)> entry_point;
|
||||
std::function<void(void*)> rewind_point;
|
||||
void* rewind_parameter{};
|
||||
void* start_parameter{};
|
||||
std::function<void()> entry_point;
|
||||
std::function<void()> rewind_point;
|
||||
std::shared_ptr<Fiber> previous_fiber;
|
||||
bool is_thread_fiber{};
|
||||
bool released{};
|
||||
@@ -34,13 +32,8 @@ struct Fiber::FiberImpl {
|
||||
boost::context::detail::fcontext_t rewind_context{};
|
||||
};
|
||||
|
||||
void Fiber::SetStartParameter(void* new_parameter) {
|
||||
impl->start_parameter = new_parameter;
|
||||
}
|
||||
|
||||
void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) {
|
||||
void Fiber::SetRewindPoint(std::function<void()>&& rewind_func) {
|
||||
impl->rewind_point = std::move(rewind_func);
|
||||
impl->rewind_parameter = rewind_param;
|
||||
}
|
||||
|
||||
void Fiber::Start(boost::context::detail::transfer_t& transfer) {
|
||||
@@ -48,7 +41,7 @@ void Fiber::Start(boost::context::detail::transfer_t& transfer) {
|
||||
impl->previous_fiber->impl->context = transfer.fctx;
|
||||
impl->previous_fiber->impl->guard.unlock();
|
||||
impl->previous_fiber.reset();
|
||||
impl->entry_point(impl->start_parameter);
|
||||
impl->entry_point();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
@@ -59,7 +52,7 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf
|
||||
u8* tmp = impl->stack_limit;
|
||||
impl->stack_limit = impl->rewind_stack_limit;
|
||||
impl->rewind_stack_limit = tmp;
|
||||
impl->rewind_point(impl->rewind_parameter);
|
||||
impl->rewind_point();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
@@ -73,10 +66,8 @@ void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) {
|
||||
fiber->OnRewind(transfer);
|
||||
}
|
||||
|
||||
Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
|
||||
: impl{std::make_unique<FiberImpl>()} {
|
||||
Fiber::Fiber(std::function<void()>&& entry_point_func) : impl{std::make_unique<FiberImpl>()} {
|
||||
impl->entry_point = std::move(entry_point_func);
|
||||
impl->start_parameter = start_parameter;
|
||||
impl->stack_limit = impl->stack.data();
|
||||
impl->rewind_stack_limit = impl->rewind_stack.data();
|
||||
u8* stack_base = impl->stack_limit + default_stack_size;
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Common {
|
||||
*/
|
||||
class Fiber {
|
||||
public:
|
||||
Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter);
|
||||
Fiber(std::function<void()>&& entry_point_func);
|
||||
~Fiber();
|
||||
|
||||
Fiber(const Fiber&) = delete;
|
||||
@@ -43,16 +43,13 @@ public:
|
||||
static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to);
|
||||
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
|
||||
|
||||
void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param);
|
||||
void SetRewindPoint(std::function<void()>&& rewind_func);
|
||||
|
||||
void Rewind();
|
||||
|
||||
/// Only call from main thread's fiber
|
||||
void Exit();
|
||||
|
||||
/// Changes the start parameter of the fiber. Has no effect if the fiber already started
|
||||
void SetStartParameter(void* new_parameter);
|
||||
|
||||
private:
|
||||
Fiber();
|
||||
|
||||
|
||||
@@ -101,15 +101,15 @@ struct ResolutionScalingInfo {
|
||||
}
|
||||
};
|
||||
|
||||
/** The BasicSetting class is a simple resource manager. It defines a label and default value
|
||||
* alongside the actual value of the setting for simpler and less-error prone use with frontend
|
||||
* configurations. Setting a default value and label is required, though subclasses may deviate from
|
||||
* this requirement.
|
||||
/** The Setting class is a simple resource manager. It defines a label and default value alongside
|
||||
* the actual value of the setting for simpler and less-error prone use with frontend
|
||||
* configurations. Specifying a default value and label is required. A minimum and maximum range can
|
||||
* be specified for sanitization.
|
||||
*/
|
||||
template <typename Type>
|
||||
class BasicSetting {
|
||||
class Setting {
|
||||
protected:
|
||||
BasicSetting() = default;
|
||||
Setting() = default;
|
||||
|
||||
/**
|
||||
* Only sets the setting to the given initializer, leaving the other members to their default
|
||||
@@ -117,7 +117,7 @@ protected:
|
||||
*
|
||||
* @param global_val Initial value of the setting
|
||||
*/
|
||||
explicit BasicSetting(const Type& global_val) : global{global_val} {}
|
||||
explicit Setting(const Type& val) : value{val} {}
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -126,9 +126,22 @@ public:
|
||||
* @param default_val Intial value of the setting, and default value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit BasicSetting(const Type& default_val, const std::string& name)
|
||||
: default_value{default_val}, global{default_val}, label{name} {}
|
||||
virtual ~BasicSetting() = default;
|
||||
explicit Setting(const Type& default_val, const std::string& name)
|
||||
: value{default_val}, default_value{default_val}, ranged{false}, label{name} {}
|
||||
virtual ~Setting() = default;
|
||||
|
||||
/**
|
||||
* Sets a default value, minimum value, maximum value, and label.
|
||||
*
|
||||
* @param default_val Intial value of the setting, and default value of the setting
|
||||
* @param min_val Sets the minimum allowed value of the setting
|
||||
* @param max_val Sets the maximum allowed value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
|
||||
const std::string& name)
|
||||
: value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val},
|
||||
ranged{true}, label{name} {}
|
||||
|
||||
/**
|
||||
* Returns a reference to the setting's value.
|
||||
@@ -136,17 +149,17 @@ public:
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
[[nodiscard]] virtual const Type& GetValue() const {
|
||||
return global;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the setting to the given value.
|
||||
*
|
||||
* @param value The desired value
|
||||
* @param val The desired value
|
||||
*/
|
||||
virtual void SetValue(const Type& value) {
|
||||
Type temp{value};
|
||||
std::swap(global, temp);
|
||||
virtual void SetValue(const Type& val) {
|
||||
Type temp{(ranged) ? std::clamp(val, minimum, maximum) : val};
|
||||
std::swap(value, temp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,14 +183,14 @@ public:
|
||||
/**
|
||||
* Assigns a value to the setting.
|
||||
*
|
||||
* @param value The desired setting value
|
||||
* @param val The desired setting value
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
virtual const Type& operator=(const Type& value) {
|
||||
Type temp{value};
|
||||
std::swap(global, temp);
|
||||
return global;
|
||||
virtual const Type& operator=(const Type& val) {
|
||||
Type temp{(ranged) ? std::clamp(val, minimum, maximum) : val};
|
||||
std::swap(value, temp);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,23 +199,39 @@ public:
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
explicit virtual operator const Type&() const {
|
||||
return global;
|
||||
return value;
|
||||
}
|
||||
|
||||
protected:
|
||||
Type value{}; ///< The setting
|
||||
const Type default_value{}; ///< The default value
|
||||
Type global{}; ///< The setting
|
||||
const Type maximum{}; ///< Maximum allowed value of the setting
|
||||
const Type minimum{}; ///< Minimum allowed value of the setting
|
||||
const bool ranged; ///< The setting has sanitization ranges
|
||||
const std::string label{}; ///< The setting's label
|
||||
};
|
||||
|
||||
/**
|
||||
* BasicRangedSetting class is intended for use with quantifiable settings that need a more
|
||||
* restrictive range than implicitly defined by its type. Implements a minimum and maximum that is
|
||||
* simply used to sanitize SetValue and the assignment overload.
|
||||
* The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
|
||||
* custom setting to switch to when a guest application specifically requires it. The effect is that
|
||||
* other components of the emulator can access the setting's intended value without any need for the
|
||||
* component to ask whether the custom or global setting is needed at the moment.
|
||||
*
|
||||
* By default, the global setting is used.
|
||||
*/
|
||||
template <typename Type>
|
||||
class BasicRangedSetting : virtual public BasicSetting<Type> {
|
||||
class SwitchableSetting : virtual public Setting<Type> {
|
||||
public:
|
||||
/**
|
||||
* Sets a default value, label, and setting value.
|
||||
*
|
||||
* @param default_val Intial value of the setting, and default value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit SwitchableSetting(const Type& default_val, const std::string& name)
|
||||
: Setting<Type>{default_val, name} {}
|
||||
virtual ~SwitchableSetting() = default;
|
||||
|
||||
/**
|
||||
* Sets a default value, minimum value, maximum value, and label.
|
||||
*
|
||||
@@ -211,57 +240,9 @@ public:
|
||||
* @param max_val Sets the maximum allowed value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit BasicRangedSetting(const Type& default_val, const Type& min_val, const Type& max_val,
|
||||
const std::string& name)
|
||||
: BasicSetting<Type>{default_val, name}, minimum{min_val}, maximum{max_val} {}
|
||||
virtual ~BasicRangedSetting() = default;
|
||||
|
||||
/**
|
||||
* Like BasicSetting's SetValue, except value is clamped to the range of the setting.
|
||||
*
|
||||
* @param value The desired value
|
||||
*/
|
||||
void SetValue(const Type& value) override {
|
||||
this->global = std::clamp(value, minimum, maximum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like BasicSetting's assignment overload, except value is clamped to the range of the setting.
|
||||
*
|
||||
* @param value The desired value
|
||||
* @returns A reference to the setting's value
|
||||
*/
|
||||
const Type& operator=(const Type& value) override {
|
||||
this->global = std::clamp(value, minimum, maximum);
|
||||
return this->global;
|
||||
}
|
||||
|
||||
const Type minimum; ///< Minimum allowed value of the setting
|
||||
const Type maximum; ///< Maximum allowed value of the setting
|
||||
};
|
||||
|
||||
/**
|
||||
* The Setting class is a slightly more complex version of the BasicSetting class. This adds a
|
||||
* custom setting to switch to when a guest application specifically requires it. The effect is that
|
||||
* other components of the emulator can access the setting's intended value without any need for the
|
||||
* component to ask whether the custom or global setting is needed at the moment.
|
||||
*
|
||||
* By default, the global setting is used.
|
||||
*
|
||||
* Like the BasicSetting, this requires setting a default value and label to use.
|
||||
*/
|
||||
template <typename Type>
|
||||
class Setting : virtual public BasicSetting<Type> {
|
||||
public:
|
||||
/**
|
||||
* Sets a default value, label, and setting value.
|
||||
*
|
||||
* @param default_val Intial value of the setting, and default value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit Setting(const Type& default_val, const std::string& name)
|
||||
: BasicSetting<Type>(default_val, name) {}
|
||||
virtual ~Setting() = default;
|
||||
explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
|
||||
const std::string& name)
|
||||
: Setting<Type>{default_val, min_val, max_val, name} {}
|
||||
|
||||
/**
|
||||
* Tells this setting to represent either the global or custom setting when other member
|
||||
@@ -292,13 +273,13 @@ public:
|
||||
*/
|
||||
[[nodiscard]] virtual const Type& GetValue() const override {
|
||||
if (use_global) {
|
||||
return this->global;
|
||||
return this->value;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
[[nodiscard]] virtual const Type& GetValue(bool need_global) const {
|
||||
if (use_global || need_global) {
|
||||
return this->global;
|
||||
return this->value;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
@@ -306,12 +287,12 @@ public:
|
||||
/**
|
||||
* Sets the current setting value depending on the global state.
|
||||
*
|
||||
* @param value The new value
|
||||
* @param val The new value
|
||||
*/
|
||||
void SetValue(const Type& value) override {
|
||||
Type temp{value};
|
||||
void SetValue(const Type& val) override {
|
||||
Type temp{(this->ranged) ? std::clamp(val, this->minimum, this->maximum) : val};
|
||||
if (use_global) {
|
||||
std::swap(this->global, temp);
|
||||
std::swap(this->value, temp);
|
||||
} else {
|
||||
std::swap(custom, temp);
|
||||
}
|
||||
@@ -320,15 +301,15 @@ public:
|
||||
/**
|
||||
* Assigns the current setting value depending on the global state.
|
||||
*
|
||||
* @param value The new value
|
||||
* @param val The new value
|
||||
*
|
||||
* @returns A reference to the current setting value
|
||||
*/
|
||||
const Type& operator=(const Type& value) override {
|
||||
Type temp{value};
|
||||
const Type& operator=(const Type& val) override {
|
||||
Type temp{(this->ranged) ? std::clamp(val, this->minimum, this->maximum) : val};
|
||||
if (use_global) {
|
||||
std::swap(this->global, temp);
|
||||
return this->global;
|
||||
std::swap(this->value, temp);
|
||||
return this->value;
|
||||
}
|
||||
std::swap(custom, temp);
|
||||
return custom;
|
||||
@@ -341,7 +322,7 @@ public:
|
||||
*/
|
||||
virtual explicit operator const Type&() const override {
|
||||
if (use_global) {
|
||||
return this->global;
|
||||
return this->value;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
@@ -351,75 +332,6 @@ protected:
|
||||
Type custom{}; ///< The custom value of the setting
|
||||
};
|
||||
|
||||
/**
|
||||
* RangedSetting is a Setting that implements a maximum and minimum value for its setting. Intended
|
||||
* for use with quantifiable settings.
|
||||
*/
|
||||
template <typename Type>
|
||||
class RangedSetting final : public BasicRangedSetting<Type>, public Setting<Type> {
|
||||
public:
|
||||
/**
|
||||
* Sets a default value, minimum value, maximum value, and label.
|
||||
*
|
||||
* @param default_val Intial value of the setting, and default value of the setting
|
||||
* @param min_val Sets the minimum allowed value of the setting
|
||||
* @param max_val Sets the maximum allowed value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit RangedSetting(const Type& default_val, const Type& min_val, const Type& max_val,
|
||||
const std::string& name)
|
||||
: BasicSetting<Type>{default_val, name},
|
||||
BasicRangedSetting<Type>{default_val, min_val, max_val, name}, Setting<Type>{default_val,
|
||||
name} {}
|
||||
virtual ~RangedSetting() = default;
|
||||
|
||||
// The following are needed to avoid a MSVC bug
|
||||
// (source: https://stackoverflow.com/questions/469508)
|
||||
[[nodiscard]] const Type& GetValue() const override {
|
||||
return Setting<Type>::GetValue();
|
||||
}
|
||||
[[nodiscard]] const Type& GetValue(bool need_global) const override {
|
||||
return Setting<Type>::GetValue(need_global);
|
||||
}
|
||||
explicit operator const Type&() const override {
|
||||
if (this->use_global) {
|
||||
return this->global;
|
||||
}
|
||||
return this->custom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like BasicSetting's SetValue, except value is clamped to the range of the setting. Sets the
|
||||
* appropriate value depending on the global state.
|
||||
*
|
||||
* @param value The desired value
|
||||
*/
|
||||
void SetValue(const Type& value) override {
|
||||
const Type temp = std::clamp(value, this->minimum, this->maximum);
|
||||
if (this->use_global) {
|
||||
this->global = temp;
|
||||
}
|
||||
this->custom = temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like BasicSetting's assignment overload, except value is clamped to the range of the setting.
|
||||
* Uses the appropriate value depending on the global state.
|
||||
*
|
||||
* @param value The desired value
|
||||
* @returns A reference to the setting's value
|
||||
*/
|
||||
const Type& operator=(const Type& value) override {
|
||||
const Type temp = std::clamp(value, this->minimum, this->maximum);
|
||||
if (this->use_global) {
|
||||
this->global = temp;
|
||||
return this->global;
|
||||
}
|
||||
this->custom = temp;
|
||||
return this->custom;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The InputSetting class allows for getting a reference to either the global or custom members.
|
||||
* This is required as we cannot easily modify the values of user-defined types within containers
|
||||
@@ -431,7 +343,7 @@ template <typename Type>
|
||||
class InputSetting final {
|
||||
public:
|
||||
InputSetting() = default;
|
||||
explicit InputSetting(Type val) : BasicSetting<Type>(val) {}
|
||||
explicit InputSetting(Type val) : Setting<Type>(val) {}
|
||||
~InputSetting() = default;
|
||||
void SetGlobal(bool to_global) {
|
||||
use_global = to_global;
|
||||
@@ -459,175 +371,175 @@ struct TouchFromButtonMap {
|
||||
|
||||
struct Values {
|
||||
// Audio
|
||||
BasicSetting<std::string> audio_device_id{"auto", "output_device"};
|
||||
BasicSetting<std::string> sink_id{"auto", "output_engine"};
|
||||
BasicSetting<bool> audio_muted{false, "audio_muted"};
|
||||
RangedSetting<u8> volume{100, 0, 100, "volume"};
|
||||
Setting<std::string> audio_device_id{"auto", "output_device"};
|
||||
Setting<std::string> sink_id{"auto", "output_engine"};
|
||||
Setting<bool> audio_muted{false, "audio_muted"};
|
||||
SwitchableSetting<u8> volume{100, 0, 100, "volume"};
|
||||
|
||||
// Core
|
||||
Setting<bool> use_multi_core{true, "use_multi_core"};
|
||||
Setting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"};
|
||||
SwitchableSetting<bool> use_multi_core{true, "use_multi_core"};
|
||||
SwitchableSetting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"};
|
||||
|
||||
// Cpu
|
||||
RangedSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
|
||||
CPUAccuracy::Paranoid, "cpu_accuracy"};
|
||||
SwitchableSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
|
||||
CPUAccuracy::Paranoid, "cpu_accuracy"};
|
||||
// TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
|
||||
BasicSetting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
|
||||
BasicSetting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
|
||||
Setting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
|
||||
Setting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
|
||||
|
||||
BasicSetting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
|
||||
BasicSetting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
|
||||
BasicSetting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"};
|
||||
BasicSetting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"};
|
||||
BasicSetting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"};
|
||||
BasicSetting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"};
|
||||
BasicSetting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
|
||||
BasicSetting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
|
||||
BasicSetting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
|
||||
BasicSetting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"};
|
||||
BasicSetting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"};
|
||||
Setting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
|
||||
Setting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
|
||||
Setting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"};
|
||||
Setting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"};
|
||||
Setting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"};
|
||||
Setting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"};
|
||||
Setting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
|
||||
Setting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
|
||||
Setting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
|
||||
Setting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"};
|
||||
Setting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"};
|
||||
|
||||
Setting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
|
||||
Setting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
|
||||
Setting<bool> cpuopt_unsafe_ignore_standard_fpcr{true, "cpuopt_unsafe_ignore_standard_fpcr"};
|
||||
Setting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
|
||||
Setting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
|
||||
Setting<bool> cpuopt_unsafe_ignore_global_monitor{true, "cpuopt_unsafe_ignore_global_monitor"};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_ignore_standard_fpcr{
|
||||
true, "cpuopt_unsafe_ignore_standard_fpcr"};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_ignore_global_monitor{
|
||||
true, "cpuopt_unsafe_ignore_global_monitor"};
|
||||
|
||||
// Renderer
|
||||
RangedSetting<RendererBackend> renderer_backend{
|
||||
SwitchableSetting<RendererBackend> renderer_backend{
|
||||
RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"};
|
||||
BasicSetting<bool> renderer_debug{false, "debug"};
|
||||
BasicSetting<bool> renderer_shader_feedback{false, "shader_feedback"};
|
||||
BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
|
||||
BasicSetting<bool> disable_shader_loop_safety_checks{false,
|
||||
"disable_shader_loop_safety_checks"};
|
||||
Setting<int> vulkan_device{0, "vulkan_device"};
|
||||
Setting<bool> renderer_debug{false, "debug"};
|
||||
Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
|
||||
Setting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
|
||||
Setting<bool> disable_shader_loop_safety_checks{false, "disable_shader_loop_safety_checks"};
|
||||
SwitchableSetting<int> vulkan_device{0, "vulkan_device"};
|
||||
|
||||
ResolutionScalingInfo resolution_info{};
|
||||
Setting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"};
|
||||
Setting<ScalingFilter> scaling_filter{ScalingFilter::Bilinear, "scaling_filter"};
|
||||
Setting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"};
|
||||
SwitchableSetting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"};
|
||||
SwitchableSetting<ScalingFilter> scaling_filter{ScalingFilter::Bilinear, "scaling_filter"};
|
||||
SwitchableSetting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"};
|
||||
// *nix platforms may have issues with the borderless windowed fullscreen mode.
|
||||
// Default to exclusive fullscreen on these platforms for now.
|
||||
RangedSetting<FullscreenMode> fullscreen_mode{
|
||||
SwitchableSetting<FullscreenMode> fullscreen_mode{
|
||||
#ifdef _WIN32
|
||||
FullscreenMode::Borderless,
|
||||
#else
|
||||
FullscreenMode::Exclusive,
|
||||
#endif
|
||||
FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"};
|
||||
RangedSetting<int> aspect_ratio{0, 0, 3, "aspect_ratio"};
|
||||
RangedSetting<int> max_anisotropy{0, 0, 5, "max_anisotropy"};
|
||||
Setting<bool> use_speed_limit{true, "use_speed_limit"};
|
||||
RangedSetting<u16> speed_limit{100, 0, 9999, "speed_limit"};
|
||||
Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
|
||||
RangedSetting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
|
||||
GPUAccuracy::Extreme, "gpu_accuracy"};
|
||||
Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
|
||||
Setting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
|
||||
Setting<bool> accelerate_astc{true, "accelerate_astc"};
|
||||
Setting<bool> use_vsync{true, "use_vsync"};
|
||||
RangedSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"};
|
||||
BasicSetting<bool> disable_fps_limit{false, "disable_fps_limit"};
|
||||
RangedSetting<ShaderBackend> shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL,
|
||||
ShaderBackend::SPIRV, "shader_backend"};
|
||||
Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
|
||||
Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
|
||||
SwitchableSetting<int> aspect_ratio{0, 0, 3, "aspect_ratio"};
|
||||
SwitchableSetting<int> max_anisotropy{0, 0, 5, "max_anisotropy"};
|
||||
SwitchableSetting<bool> use_speed_limit{true, "use_speed_limit"};
|
||||
SwitchableSetting<u16> speed_limit{100, 0, 9999, "speed_limit"};
|
||||
SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
|
||||
SwitchableSetting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
|
||||
GPUAccuracy::Extreme, "gpu_accuracy"};
|
||||
SwitchableSetting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
|
||||
SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
|
||||
SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"};
|
||||
SwitchableSetting<bool> use_vsync{true, "use_vsync"};
|
||||
SwitchableSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"};
|
||||
Setting<bool> disable_fps_limit{false, "disable_fps_limit"};
|
||||
SwitchableSetting<ShaderBackend> shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL,
|
||||
ShaderBackend::SPIRV, "shader_backend"};
|
||||
SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
|
||||
SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
|
||||
|
||||
Setting<u8> bg_red{0, "bg_red"};
|
||||
Setting<u8> bg_green{0, "bg_green"};
|
||||
Setting<u8> bg_blue{0, "bg_blue"};
|
||||
SwitchableSetting<u8> bg_red{0, "bg_red"};
|
||||
SwitchableSetting<u8> bg_green{0, "bg_green"};
|
||||
SwitchableSetting<u8> bg_blue{0, "bg_blue"};
|
||||
|
||||
// System
|
||||
Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
|
||||
SwitchableSetting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
|
||||
// Measured in seconds since epoch
|
||||
std::optional<s64> custom_rtc;
|
||||
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
|
||||
s64 custom_rtc_differential;
|
||||
|
||||
BasicSetting<s32> current_user{0, "current_user"};
|
||||
RangedSetting<s32> language_index{1, 0, 17, "language_index"};
|
||||
RangedSetting<s32> region_index{1, 0, 6, "region_index"};
|
||||
RangedSetting<s32> time_zone_index{0, 0, 45, "time_zone_index"};
|
||||
RangedSetting<s32> sound_index{1, 0, 2, "sound_index"};
|
||||
Setting<s32> current_user{0, "current_user"};
|
||||
SwitchableSetting<s32> language_index{1, 0, 17, "language_index"};
|
||||
SwitchableSetting<s32> region_index{1, 0, 6, "region_index"};
|
||||
SwitchableSetting<s32> time_zone_index{0, 0, 45, "time_zone_index"};
|
||||
SwitchableSetting<s32> sound_index{1, 0, 2, "sound_index"};
|
||||
|
||||
// Controls
|
||||
InputSetting<std::array<PlayerInput, 10>> players;
|
||||
|
||||
Setting<bool> use_docked_mode{true, "use_docked_mode"};
|
||||
SwitchableSetting<bool> use_docked_mode{true, "use_docked_mode"};
|
||||
|
||||
BasicSetting<bool> enable_raw_input{false, "enable_raw_input"};
|
||||
BasicSetting<bool> controller_navigation{true, "controller_navigation"};
|
||||
Setting<bool> enable_raw_input{false, "enable_raw_input"};
|
||||
Setting<bool> controller_navigation{true, "controller_navigation"};
|
||||
|
||||
Setting<bool> vibration_enabled{true, "vibration_enabled"};
|
||||
Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
|
||||
SwitchableSetting<bool> vibration_enabled{true, "vibration_enabled"};
|
||||
SwitchableSetting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
|
||||
|
||||
Setting<bool> motion_enabled{true, "motion_enabled"};
|
||||
BasicSetting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"};
|
||||
BasicSetting<bool> enable_udp_controller{false, "enable_udp_controller"};
|
||||
SwitchableSetting<bool> motion_enabled{true, "motion_enabled"};
|
||||
Setting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"};
|
||||
Setting<bool> enable_udp_controller{false, "enable_udp_controller"};
|
||||
|
||||
BasicSetting<bool> pause_tas_on_load{true, "pause_tas_on_load"};
|
||||
BasicSetting<bool> tas_enable{false, "tas_enable"};
|
||||
BasicSetting<bool> tas_loop{false, "tas_loop"};
|
||||
Setting<bool> pause_tas_on_load{true, "pause_tas_on_load"};
|
||||
Setting<bool> tas_enable{false, "tas_enable"};
|
||||
Setting<bool> tas_loop{false, "tas_loop"};
|
||||
|
||||
BasicSetting<bool> mouse_panning{false, "mouse_panning"};
|
||||
BasicRangedSetting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"};
|
||||
BasicSetting<bool> mouse_enabled{false, "mouse_enabled"};
|
||||
Setting<bool> mouse_panning{false, "mouse_panning"};
|
||||
Setting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"};
|
||||
Setting<bool> mouse_enabled{false, "mouse_enabled"};
|
||||
|
||||
BasicSetting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
|
||||
BasicSetting<bool> keyboard_enabled{false, "keyboard_enabled"};
|
||||
Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
|
||||
Setting<bool> keyboard_enabled{false, "keyboard_enabled"};
|
||||
|
||||
BasicSetting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
|
||||
Setting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
|
||||
ButtonsRaw debug_pad_buttons;
|
||||
AnalogsRaw debug_pad_analogs;
|
||||
|
||||
TouchscreenInput touchscreen;
|
||||
|
||||
BasicSetting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850",
|
||||
"touch_device"};
|
||||
BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"};
|
||||
Setting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850", "touch_device"};
|
||||
Setting<int> touch_from_button_map_index{0, "touch_from_button_map"};
|
||||
std::vector<TouchFromButtonMap> touch_from_button_maps;
|
||||
|
||||
BasicSetting<bool> enable_ring_controller{true, "enable_ring_controller"};
|
||||
Setting<bool> enable_ring_controller{true, "enable_ring_controller"};
|
||||
RingconRaw ringcon_analogs;
|
||||
|
||||
// Data Storage
|
||||
BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"};
|
||||
BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"};
|
||||
BasicSetting<bool> gamecard_current_game{false, "gamecard_current_game"};
|
||||
BasicSetting<std::string> gamecard_path{std::string(), "gamecard_path"};
|
||||
Setting<bool> use_virtual_sd{true, "use_virtual_sd"};
|
||||
Setting<bool> gamecard_inserted{false, "gamecard_inserted"};
|
||||
Setting<bool> gamecard_current_game{false, "gamecard_current_game"};
|
||||
Setting<std::string> gamecard_path{std::string(), "gamecard_path"};
|
||||
|
||||
// Debugging
|
||||
bool record_frame_times;
|
||||
BasicSetting<bool> use_gdbstub{false, "use_gdbstub"};
|
||||
BasicSetting<u16> gdbstub_port{6543, "gdbstub_port"};
|
||||
BasicSetting<std::string> program_args{std::string(), "program_args"};
|
||||
BasicSetting<bool> dump_exefs{false, "dump_exefs"};
|
||||
BasicSetting<bool> dump_nso{false, "dump_nso"};
|
||||
BasicSetting<bool> dump_shaders{false, "dump_shaders"};
|
||||
BasicSetting<bool> dump_macros{false, "dump_macros"};
|
||||
BasicSetting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
|
||||
BasicSetting<bool> reporting_services{false, "reporting_services"};
|
||||
BasicSetting<bool> quest_flag{false, "quest_flag"};
|
||||
BasicSetting<bool> disable_macro_jit{false, "disable_macro_jit"};
|
||||
BasicSetting<bool> extended_logging{false, "extended_logging"};
|
||||
BasicSetting<bool> use_debug_asserts{false, "use_debug_asserts"};
|
||||
BasicSetting<bool> use_auto_stub{false, "use_auto_stub"};
|
||||
BasicSetting<bool> enable_all_controllers{false, "enable_all_controllers"};
|
||||
Setting<bool> use_gdbstub{false, "use_gdbstub"};
|
||||
Setting<u16> gdbstub_port{6543, "gdbstub_port"};
|
||||
Setting<std::string> program_args{std::string(), "program_args"};
|
||||
Setting<bool> dump_exefs{false, "dump_exefs"};
|
||||
Setting<bool> dump_nso{false, "dump_nso"};
|
||||
Setting<bool> dump_shaders{false, "dump_shaders"};
|
||||
Setting<bool> dump_macros{false, "dump_macros"};
|
||||
Setting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
|
||||
Setting<bool> reporting_services{false, "reporting_services"};
|
||||
Setting<bool> quest_flag{false, "quest_flag"};
|
||||
Setting<bool> disable_macro_jit{false, "disable_macro_jit"};
|
||||
Setting<bool> extended_logging{false, "extended_logging"};
|
||||
Setting<bool> use_debug_asserts{false, "use_debug_asserts"};
|
||||
Setting<bool> use_auto_stub{false, "use_auto_stub"};
|
||||
Setting<bool> enable_all_controllers{false, "enable_all_controllers"};
|
||||
|
||||
// Miscellaneous
|
||||
BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
|
||||
BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
|
||||
Setting<std::string> log_filter{"*:Info", "log_filter"};
|
||||
Setting<bool> use_dev_keys{false, "use_dev_keys"};
|
||||
|
||||
// Network
|
||||
BasicSetting<std::string> network_interface{std::string(), "network_interface"};
|
||||
Setting<std::string> network_interface{std::string(), "network_interface"};
|
||||
|
||||
// WebService
|
||||
BasicSetting<bool> enable_telemetry{true, "enable_telemetry"};
|
||||
BasicSetting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"};
|
||||
BasicSetting<std::string> yuzu_username{std::string(), "yuzu_username"};
|
||||
BasicSetting<std::string> yuzu_token{std::string(), "yuzu_token"};
|
||||
Setting<bool> enable_telemetry{true, "enable_telemetry"};
|
||||
Setting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"};
|
||||
Setting<std::string> yuzu_username{std::string(), "yuzu_username"};
|
||||
Setting<std::string> yuzu_token{std::string(), "yuzu_token"};
|
||||
|
||||
// Add-Ons
|
||||
std::map<u64, std::vector<std::string>> disabled_addons;
|
||||
|
||||
@@ -222,7 +222,7 @@ add_library(core STATIC
|
||||
hle/kernel/k_page_buffer.h
|
||||
hle/kernel/k_page_heap.cpp
|
||||
hle/kernel/k_page_heap.h
|
||||
hle/kernel/k_page_linked_list.h
|
||||
hle/kernel/k_page_group.h
|
||||
hle/kernel/k_page_table.cpp
|
||||
hle/kernel/k_page_table.h
|
||||
hle/kernel/k_port.cpp
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include "common/bit_field.h"
|
||||
@@ -68,8 +72,19 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt
|
||||
if (symbol_set != symbols.end()) {
|
||||
const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset);
|
||||
if (symbol.has_value()) {
|
||||
#ifdef _MSC_VER
|
||||
// TODO(DarkLordZach): Add demangling of symbol names.
|
||||
entry.name = *symbol;
|
||||
#else
|
||||
int status{-1};
|
||||
char* demangled{abi::__cxa_demangle(symbol->c_str(), nullptr, nullptr, &status)};
|
||||
if (status == 0 && demangled != nullptr) {
|
||||
entry.name = demangled;
|
||||
std::free(demangled);
|
||||
} else {
|
||||
entry.name = *symbol;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,16 +134,23 @@ void ARM_Interface::Run() {
|
||||
}
|
||||
system.ExitDynarmicProfile();
|
||||
|
||||
// Notify the debugger and go to sleep if a breakpoint was hit.
|
||||
if (Has(hr, breakpoint)) {
|
||||
// Notify the debugger and go to sleep if a breakpoint was hit,
|
||||
// or if the thread is unable to continue for any reason.
|
||||
if (Has(hr, breakpoint) || Has(hr, no_execute)) {
|
||||
RewindBreakpointInstruction();
|
||||
system.GetDebugger().NotifyThreadStopped(current_thread);
|
||||
current_thread->RequestSuspend(SuspendType::Debug);
|
||||
if (system.DebuggerEnabled()) {
|
||||
system.GetDebugger().NotifyThreadStopped(current_thread);
|
||||
}
|
||||
current_thread->RequestSuspend(Kernel::SuspendType::Debug);
|
||||
break;
|
||||
}
|
||||
|
||||
// Notify the debugger and go to sleep if a watchpoint was hit.
|
||||
if (Has(hr, watchpoint)) {
|
||||
RewindBreakpointInstruction();
|
||||
system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint());
|
||||
if (system.DebuggerEnabled()) {
|
||||
system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint());
|
||||
}
|
||||
current_thread->RequestSuspend(SuspendType::Debug);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -204,6 +204,7 @@ public:
|
||||
static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
|
||||
static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4;
|
||||
static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::UserDefined5;
|
||||
static constexpr Dynarmic::HaltReason no_execute = Dynarmic::HaltReason::UserDefined6;
|
||||
|
||||
protected:
|
||||
/// System context that this ARM interface is running under.
|
||||
|
||||
@@ -48,6 +48,12 @@ public:
|
||||
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
|
||||
return memory.Read64(vaddr);
|
||||
}
|
||||
std::optional<u32> MemoryReadCode(u32 vaddr) override {
|
||||
if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return MemoryRead32(vaddr);
|
||||
}
|
||||
|
||||
void MemoryWrite8(u32 vaddr, u8 value) override {
|
||||
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
|
||||
@@ -89,21 +95,28 @@ public:
|
||||
|
||||
void InterpreterFallback(u32 pc, std::size_t num_instructions) override {
|
||||
parent.LogBacktrace();
|
||||
UNIMPLEMENTED_MSG("This should never happen, pc = {:08X}, code = {:08X}", pc,
|
||||
MemoryReadCode(pc));
|
||||
LOG_ERROR(Core_ARM,
|
||||
"Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
|
||||
num_instructions, MemoryRead32(pc));
|
||||
}
|
||||
|
||||
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
|
||||
if (debugger_enabled) {
|
||||
parent.SaveContext(parent.breakpoint_context);
|
||||
parent.jit.load()->HaltExecution(ARM_Interface::breakpoint);
|
||||
switch (exception) {
|
||||
case Dynarmic::A32::Exception::NoExecuteFault:
|
||||
LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#08x}", pc);
|
||||
ReturnException(pc, ARM_Interface::no_execute);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
if (debugger_enabled) {
|
||||
ReturnException(pc, ARM_Interface::breakpoint);
|
||||
return;
|
||||
}
|
||||
|
||||
parent.LogBacktrace();
|
||||
LOG_CRITICAL(Core_ARM,
|
||||
"ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
|
||||
exception, pc, MemoryReadCode(pc), parent.IsInThumbMode());
|
||||
parent.LogBacktrace();
|
||||
LOG_CRITICAL(Core_ARM,
|
||||
"ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
|
||||
exception, pc, MemoryRead32(pc), parent.IsInThumbMode());
|
||||
}
|
||||
}
|
||||
|
||||
void CallSVC(u32 swi) override {
|
||||
@@ -141,15 +154,20 @@ public:
|
||||
|
||||
const auto match{parent.MatchingWatchpoint(addr, size, type)};
|
||||
if (match) {
|
||||
parent.SaveContext(parent.breakpoint_context);
|
||||
parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
|
||||
parent.halted_watchpoint = match;
|
||||
ReturnException(parent.jit.load()->Regs()[15], ARM_Interface::watchpoint);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReturnException(u32 pc, Dynarmic::HaltReason hr) {
|
||||
parent.SaveContext(parent.breakpoint_context);
|
||||
parent.breakpoint_context.cpu_registers[15] = pc;
|
||||
parent.jit.load()->HaltExecution(hr);
|
||||
}
|
||||
|
||||
ARM_Dynarmic_32& parent;
|
||||
Core::Memory::Memory& memory;
|
||||
std::size_t num_interpreted_instructions{};
|
||||
@@ -409,18 +427,38 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
|
||||
}
|
||||
|
||||
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system,
|
||||
u64 sp, u64 lr) {
|
||||
// No way to get accurate stack traces in A32 yet
|
||||
return {};
|
||||
u64 fp, u64 lr, u64 pc) {
|
||||
std::vector<BacktraceEntry> out;
|
||||
auto& memory = system.Memory();
|
||||
|
||||
out.push_back({"", 0, pc, 0, ""});
|
||||
|
||||
// fp (= r11) points to the last frame record.
|
||||
// Frame records are two words long:
|
||||
// fp+0 : pointer to previous frame record
|
||||
// fp+4 : value of lr for frame
|
||||
while (true) {
|
||||
out.push_back({"", 0, lr, 0, ""});
|
||||
if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
|
||||
break;
|
||||
}
|
||||
lr = memory.Read32(fp + 4);
|
||||
fp = memory.Read32(fp);
|
||||
}
|
||||
|
||||
SymbolicateBacktrace(system, out);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktraceFromContext(
|
||||
System& system, const ThreadContext32& ctx) {
|
||||
return GetBacktrace(system, ctx.cpu_registers[13], ctx.cpu_registers[14]);
|
||||
const auto& reg = ctx.cpu_registers;
|
||||
return GetBacktrace(system, reg[11], reg[14], reg[15]);
|
||||
}
|
||||
|
||||
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace() const {
|
||||
return GetBacktrace(system, GetReg(13), GetReg(14));
|
||||
return GetBacktrace(system, GetReg(11), GetReg(14), GetReg(15));
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -78,7 +78,7 @@ protected:
|
||||
private:
|
||||
std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const;
|
||||
|
||||
static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 sp, u64 lr);
|
||||
static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc);
|
||||
|
||||
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
|
||||
using JitCacheType =
|
||||
|
||||
@@ -52,6 +52,12 @@ public:
|
||||
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
|
||||
return {memory.Read64(vaddr), memory.Read64(vaddr + 8)};
|
||||
}
|
||||
std::optional<u32> MemoryReadCode(u64 vaddr) override {
|
||||
if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return MemoryRead32(vaddr);
|
||||
}
|
||||
|
||||
void MemoryWrite8(u64 vaddr, u8 value) override {
|
||||
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
|
||||
@@ -105,7 +111,7 @@ public:
|
||||
parent.LogBacktrace();
|
||||
LOG_ERROR(Core_ARM,
|
||||
"Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
|
||||
num_instructions, MemoryReadCode(pc));
|
||||
num_instructions, MemoryRead32(pc));
|
||||
}
|
||||
|
||||
void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op,
|
||||
@@ -138,16 +144,19 @@ public:
|
||||
case Dynarmic::A64::Exception::SendEventLocal:
|
||||
case Dynarmic::A64::Exception::Yield:
|
||||
return;
|
||||
case Dynarmic::A64::Exception::NoExecuteFault:
|
||||
LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#016x}", pc);
|
||||
ReturnException(pc, ARM_Interface::no_execute);
|
||||
return;
|
||||
default:
|
||||
if (debugger_enabled) {
|
||||
parent.SaveContext(parent.breakpoint_context);
|
||||
parent.jit.load()->HaltExecution(ARM_Interface::breakpoint);
|
||||
ReturnException(pc, ARM_Interface::breakpoint);
|
||||
return;
|
||||
}
|
||||
|
||||
parent.LogBacktrace();
|
||||
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
|
||||
static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
|
||||
LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
|
||||
static_cast<std::size_t>(exception), pc, MemoryRead32(pc));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,15 +197,20 @@ public:
|
||||
|
||||
const auto match{parent.MatchingWatchpoint(addr, size, type)};
|
||||
if (match) {
|
||||
parent.SaveContext(parent.breakpoint_context);
|
||||
parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
|
||||
parent.halted_watchpoint = match;
|
||||
ReturnException(parent.jit.load()->GetPC(), ARM_Interface::watchpoint);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReturnException(u64 pc, Dynarmic::HaltReason hr) {
|
||||
parent.SaveContext(parent.breakpoint_context);
|
||||
parent.breakpoint_context.pc = pc;
|
||||
parent.jit.load()->HaltExecution(hr);
|
||||
}
|
||||
|
||||
ARM_Dynarmic_64& parent;
|
||||
Core::Memory::Memory& memory;
|
||||
u64 tpidrro_el0 = 0;
|
||||
@@ -480,22 +494,22 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
|
||||
}
|
||||
|
||||
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system,
|
||||
u64 fp, u64 lr) {
|
||||
u64 fp, u64 lr, u64 pc) {
|
||||
std::vector<BacktraceEntry> out;
|
||||
auto& memory = system.Memory();
|
||||
|
||||
// fp (= r29) points to the last frame record.
|
||||
// Note that this is the frame record for the *previous* frame, not the current one.
|
||||
// Note we need to subtract 4 from our last read to get the proper address
|
||||
out.push_back({"", 0, pc, 0, ""});
|
||||
|
||||
// fp (= x29) points to the previous frame record.
|
||||
// Frame records are two words long:
|
||||
// fp+0 : pointer to previous frame record
|
||||
// fp+8 : value of lr for frame
|
||||
while (true) {
|
||||
out.push_back({"", 0, lr, 0, ""});
|
||||
if (!fp) {
|
||||
if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
|
||||
break;
|
||||
}
|
||||
lr = memory.Read64(fp + 8) - 4;
|
||||
lr = memory.Read64(fp + 8);
|
||||
fp = memory.Read64(fp);
|
||||
}
|
||||
|
||||
@@ -506,11 +520,12 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::S
|
||||
|
||||
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktraceFromContext(
|
||||
System& system, const ThreadContext64& ctx) {
|
||||
return GetBacktrace(system, ctx.cpu_registers[29], ctx.cpu_registers[30]);
|
||||
const auto& reg = ctx.cpu_registers;
|
||||
return GetBacktrace(system, reg[29], reg[30], ctx.pc);
|
||||
}
|
||||
|
||||
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace() const {
|
||||
return GetBacktrace(system, GetReg(29), GetReg(30));
|
||||
return GetBacktrace(system, GetReg(29), GetReg(30), GetPC());
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -73,7 +73,7 @@ private:
|
||||
std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
|
||||
std::size_t address_space_bits) const;
|
||||
|
||||
static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr);
|
||||
static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc);
|
||||
|
||||
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
|
||||
using JitCacheType =
|
||||
|
||||
@@ -22,10 +22,11 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac
|
||||
}
|
||||
|
||||
struct CoreTiming::Event {
|
||||
u64 time;
|
||||
s64 time;
|
||||
u64 fifo_order;
|
||||
std::uintptr_t user_data;
|
||||
std::weak_ptr<EventType> type;
|
||||
s64 reschedule_time;
|
||||
|
||||
// Sort by time, unless the times are the same, in which case sort by
|
||||
// the order added to the queue
|
||||
@@ -58,15 +59,11 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
|
||||
event_fifo_id = 0;
|
||||
shutting_down = false;
|
||||
ticks = 0;
|
||||
const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {};
|
||||
const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
|
||||
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
|
||||
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
|
||||
if (is_multicore) {
|
||||
const auto hardware_concurrency = std::thread::hardware_concurrency();
|
||||
size_t id = 0;
|
||||
worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
|
||||
if (hardware_concurrency > 8) {
|
||||
worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
|
||||
}
|
||||
worker_threads.emplace_back(ThreadEntry, std::ref(*this), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +78,7 @@ void CoreTiming::Shutdown() {
|
||||
thread.join();
|
||||
}
|
||||
worker_threads.clear();
|
||||
pause_callbacks.clear();
|
||||
ClearPendingEvents();
|
||||
has_started = false;
|
||||
}
|
||||
@@ -98,6 +96,14 @@ void CoreTiming::Pause(bool is_paused_) {
|
||||
}
|
||||
}
|
||||
paused_state.store(is_paused_, std::memory_order_relaxed);
|
||||
|
||||
if (!is_paused_) {
|
||||
pause_end_time = GetGlobalTimeNs().count();
|
||||
}
|
||||
|
||||
for (auto& cb : pause_callbacks) {
|
||||
cb(is_paused_);
|
||||
}
|
||||
}
|
||||
|
||||
void CoreTiming::SyncPause(bool is_paused_) {
|
||||
@@ -121,6 +127,14 @@ void CoreTiming::SyncPause(bool is_paused_) {
|
||||
wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; });
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_paused_) {
|
||||
pause_end_time = GetGlobalTimeNs().count();
|
||||
}
|
||||
|
||||
for (auto& cb : pause_callbacks) {
|
||||
cb(is_paused_);
|
||||
}
|
||||
}
|
||||
|
||||
bool CoreTiming::IsRunning() const {
|
||||
@@ -134,12 +148,30 @@ bool CoreTiming::HasPendingEvents() const {
|
||||
|
||||
void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
||||
const std::shared_ptr<EventType>& event_type,
|
||||
std::uintptr_t user_data) {
|
||||
std::uintptr_t user_data, bool absolute_time) {
|
||||
|
||||
std::unique_lock main_lock(event_mutex);
|
||||
const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count());
|
||||
const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
|
||||
|
||||
event_queue.emplace_back(Event{timeout, event_fifo_id++, user_data, event_type});
|
||||
event_queue.emplace_back(Event{next_time.count(), event_fifo_id++, user_data, event_type, 0});
|
||||
pending_events.fetch_add(1, std::memory_order_relaxed);
|
||||
|
||||
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
|
||||
|
||||
if (is_multicore) {
|
||||
event_cv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
||||
std::chrono::nanoseconds resched_time,
|
||||
const std::shared_ptr<EventType>& event_type,
|
||||
std::uintptr_t user_data, bool absolute_time) {
|
||||
std::unique_lock main_lock(event_mutex);
|
||||
const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time};
|
||||
|
||||
event_queue.emplace_back(
|
||||
Event{next_time.count(), event_fifo_id++, user_data, event_type, resched_time.count()});
|
||||
pending_events.fetch_add(1, std::memory_order_relaxed);
|
||||
|
||||
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
|
||||
@@ -218,6 +250,11 @@ void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
|
||||
}
|
||||
}
|
||||
|
||||
void CoreTiming::RegisterPauseCallback(PauseCallback&& callback) {
|
||||
std::unique_lock main_lock(event_mutex);
|
||||
pause_callbacks.emplace_back(std::move(callback));
|
||||
}
|
||||
|
||||
std::optional<s64> CoreTiming::Advance() {
|
||||
global_timer = GetGlobalTimeNs().count();
|
||||
|
||||
@@ -228,17 +265,31 @@ std::optional<s64> CoreTiming::Advance() {
|
||||
event_queue.pop_back();
|
||||
|
||||
if (const auto event_type{evt.type.lock()}) {
|
||||
sequence_mutex.lock();
|
||||
event_mutex.unlock();
|
||||
|
||||
event_type->guard.lock();
|
||||
sequence_mutex.unlock();
|
||||
const s64 delay = static_cast<s64>(GetGlobalTimeNs().count() - evt.time);
|
||||
event_type->callback(evt.user_data, std::chrono::nanoseconds{delay});
|
||||
event_type->guard.unlock();
|
||||
const auto new_schedule_time{event_type->callback(
|
||||
evt.user_data, evt.time,
|
||||
std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})};
|
||||
|
||||
event_mutex.lock();
|
||||
pending_events.fetch_sub(1, std::memory_order_relaxed);
|
||||
|
||||
if (evt.reschedule_time != 0) {
|
||||
// If this event was scheduled into a pause, its time now is going to be way behind.
|
||||
// Re-set this event to continue from the end of the pause.
|
||||
auto next_time{evt.time + evt.reschedule_time};
|
||||
if (evt.time < pause_end_time) {
|
||||
next_time = pause_end_time + evt.reschedule_time;
|
||||
}
|
||||
|
||||
const auto next_schedule_time{new_schedule_time.has_value()
|
||||
? new_schedule_time.value().count()
|
||||
: evt.reschedule_time};
|
||||
event_queue.emplace_back(
|
||||
Event{next_time, event_fifo_id++, evt.user_data, evt.type, next_schedule_time});
|
||||
pending_events.fetch_add(1, std::memory_order_relaxed);
|
||||
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
|
||||
}
|
||||
}
|
||||
|
||||
global_timer = GetGlobalTimeNs().count();
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
namespace Core::Timing {
|
||||
|
||||
/// A callback that may be scheduled for a particular core timing event.
|
||||
using TimedCallback =
|
||||
std::function<void(std::uintptr_t user_data, std::chrono::nanoseconds ns_late)>;
|
||||
using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
|
||||
std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
|
||||
using PauseCallback = std::function<void(bool paused)>;
|
||||
|
||||
/// Contains the characteristics of a particular event.
|
||||
struct EventType {
|
||||
@@ -32,7 +33,6 @@ struct EventType {
|
||||
TimedCallback callback;
|
||||
/// A pointer to the name of the event.
|
||||
const std::string name;
|
||||
mutable std::mutex guard;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -94,7 +94,15 @@ public:
|
||||
|
||||
/// Schedules an event in core timing
|
||||
void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
||||
const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0);
|
||||
const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0,
|
||||
bool absolute_time = false);
|
||||
|
||||
/// Schedules an event which will automatically re-schedule itself with the given time, until
|
||||
/// unscheduled
|
||||
void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
||||
std::chrono::nanoseconds resched_time,
|
||||
const std::shared_ptr<EventType>& event_type,
|
||||
std::uintptr_t user_data = 0, bool absolute_time = false);
|
||||
|
||||
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data);
|
||||
|
||||
@@ -126,6 +134,9 @@ public:
|
||||
/// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
|
||||
std::optional<s64> Advance();
|
||||
|
||||
/// Register a callback function to be called when coretiming pauses.
|
||||
void RegisterPauseCallback(PauseCallback&& callback);
|
||||
|
||||
private:
|
||||
struct Event;
|
||||
|
||||
@@ -137,7 +148,7 @@ private:
|
||||
|
||||
std::unique_ptr<Common::WallClock> clock;
|
||||
|
||||
u64 global_timer = 0;
|
||||
s64 global_timer = 0;
|
||||
|
||||
// The queue is a min-heap using std::make_heap/push_heap/pop_heap.
|
||||
// We don't use std::priority_queue because we need to be able to serialize, unserialize and
|
||||
@@ -157,17 +168,19 @@ private:
|
||||
std::condition_variable wait_pause_cv;
|
||||
std::condition_variable wait_signal_cv;
|
||||
mutable std::mutex event_mutex;
|
||||
mutable std::mutex sequence_mutex;
|
||||
|
||||
std::atomic<bool> paused_state{};
|
||||
bool is_paused{};
|
||||
bool shutting_down{};
|
||||
bool is_multicore{};
|
||||
size_t pause_count{};
|
||||
s64 pause_end_time{};
|
||||
|
||||
/// Cycle timing
|
||||
u64 ticks{};
|
||||
s64 downcount{};
|
||||
|
||||
std::vector<PauseCallback> pause_callbacks{};
|
||||
};
|
||||
|
||||
/// Creates a core timing event with the given name and callback.
|
||||
|
||||
@@ -41,51 +41,32 @@ void CpuManager::Shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
|
||||
return GuestThreadFunction;
|
||||
}
|
||||
|
||||
std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
|
||||
return IdleThreadFunction;
|
||||
}
|
||||
|
||||
std::function<void(void*)> CpuManager::GetShutdownThreadStartFunc() {
|
||||
return ShutdownThreadFunction;
|
||||
}
|
||||
|
||||
void CpuManager::GuestThreadFunction(void* cpu_manager_) {
|
||||
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
|
||||
if (cpu_manager->is_multicore) {
|
||||
cpu_manager->MultiCoreRunGuestThread();
|
||||
void CpuManager::GuestThreadFunction() {
|
||||
if (is_multicore) {
|
||||
MultiCoreRunGuestThread();
|
||||
} else {
|
||||
cpu_manager->SingleCoreRunGuestThread();
|
||||
SingleCoreRunGuestThread();
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::GuestRewindFunction(void* cpu_manager_) {
|
||||
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
|
||||
if (cpu_manager->is_multicore) {
|
||||
cpu_manager->MultiCoreRunGuestLoop();
|
||||
void CpuManager::GuestRewindFunction() {
|
||||
if (is_multicore) {
|
||||
MultiCoreRunGuestLoop();
|
||||
} else {
|
||||
cpu_manager->SingleCoreRunGuestLoop();
|
||||
SingleCoreRunGuestLoop();
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::IdleThreadFunction(void* cpu_manager_) {
|
||||
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
|
||||
if (cpu_manager->is_multicore) {
|
||||
cpu_manager->MultiCoreRunIdleThread();
|
||||
void CpuManager::IdleThreadFunction() {
|
||||
if (is_multicore) {
|
||||
MultiCoreRunIdleThread();
|
||||
} else {
|
||||
cpu_manager->SingleCoreRunIdleThread();
|
||||
SingleCoreRunIdleThread();
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::ShutdownThreadFunction(void* cpu_manager) {
|
||||
static_cast<CpuManager*>(cpu_manager)->ShutdownThread();
|
||||
}
|
||||
|
||||
void* CpuManager::GetStartFuncParameter() {
|
||||
return this;
|
||||
void CpuManager::ShutdownThreadFunction() {
|
||||
ShutdownThread();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -97,7 +78,7 @@ void CpuManager::MultiCoreRunGuestThread() {
|
||||
kernel.CurrentScheduler()->OnThreadStart();
|
||||
auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
|
||||
auto& host_context = thread->GetHostContext();
|
||||
host_context->SetRewindPoint(GuestRewindFunction, this);
|
||||
host_context->SetRewindPoint([this] { GuestRewindFunction(); });
|
||||
MultiCoreRunGuestLoop();
|
||||
}
|
||||
|
||||
@@ -134,7 +115,7 @@ void CpuManager::SingleCoreRunGuestThread() {
|
||||
kernel.CurrentScheduler()->OnThreadStart();
|
||||
auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
|
||||
auto& host_context = thread->GetHostContext();
|
||||
host_context->SetRewindPoint(GuestRewindFunction, this);
|
||||
host_context->SetRewindPoint([this] { GuestRewindFunction(); });
|
||||
SingleCoreRunGuestLoop();
|
||||
}
|
||||
|
||||
@@ -194,7 +175,9 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
|
||||
{
|
||||
auto& scheduler = system.Kernel().Scheduler(current_core);
|
||||
scheduler.Reload(scheduler.GetSchedulerCurrentThread());
|
||||
idle_count = 0;
|
||||
if (!scheduler.IsIdle()) {
|
||||
idle_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,10 +50,15 @@ public:
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
static std::function<void(void*)> GetGuestThreadStartFunc();
|
||||
static std::function<void(void*)> GetIdleThreadStartFunc();
|
||||
static std::function<void(void*)> GetShutdownThreadStartFunc();
|
||||
void* GetStartFuncParameter();
|
||||
std::function<void()> GetGuestThreadStartFunc() {
|
||||
return [this] { GuestThreadFunction(); };
|
||||
}
|
||||
std::function<void()> GetIdleThreadStartFunc() {
|
||||
return [this] { IdleThreadFunction(); };
|
||||
}
|
||||
std::function<void()> GetShutdownThreadStartFunc() {
|
||||
return [this] { ShutdownThreadFunction(); };
|
||||
}
|
||||
|
||||
void PreemptSingleCore(bool from_running_enviroment = true);
|
||||
|
||||
@@ -62,10 +67,10 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static void GuestThreadFunction(void* cpu_manager);
|
||||
static void GuestRewindFunction(void* cpu_manager);
|
||||
static void IdleThreadFunction(void* cpu_manager);
|
||||
static void ShutdownThreadFunction(void* cpu_manager);
|
||||
void GuestThreadFunction();
|
||||
void GuestRewindFunction();
|
||||
void IdleThreadFunction();
|
||||
void ShutdownThreadFunction();
|
||||
|
||||
void MultiCoreRunGuestThread();
|
||||
void MultiCoreRunGuestLoop();
|
||||
|
||||
@@ -191,8 +191,10 @@ std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const
|
||||
const auto& gprs{context.cpu_registers};
|
||||
const auto& fprs{context.vector_registers};
|
||||
|
||||
if (id <= SP_REGISTER) {
|
||||
if (id < SP_REGISTER) {
|
||||
return ValueToHex(gprs[id]);
|
||||
} else if (id == SP_REGISTER) {
|
||||
return ValueToHex(context.sp);
|
||||
} else if (id == PC_REGISTER) {
|
||||
return ValueToHex(context.pc);
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
@@ -215,8 +217,10 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
|
||||
|
||||
auto& context{thread->GetContext64()};
|
||||
|
||||
if (id <= SP_REGISTER) {
|
||||
if (id < SP_REGISTER) {
|
||||
context.cpu_registers[id] = HexToValue<u64>(value);
|
||||
} else if (id == SP_REGISTER) {
|
||||
context.sp = HexToValue<u64>(value);
|
||||
} else if (id == PC_REGISTER) {
|
||||
context.pc = HexToValue<u64>(value);
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
constexpr ResultCode ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1};
|
||||
constexpr ResultCode ERROR_PATH_ALREADY_EXISTS{ErrorModule::FS, 2};
|
||||
constexpr ResultCode ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002};
|
||||
constexpr ResultCode ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001};
|
||||
constexpr ResultCode ERROR_OUT_OF_BOUNDS{ErrorModule::FS, 3005};
|
||||
constexpr ResultCode ERROR_FAILED_MOUNT_ARCHIVE{ErrorModule::FS, 3223};
|
||||
constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::FS, 6001};
|
||||
constexpr ResultCode ERROR_INVALID_OFFSET{ErrorModule::FS, 6061};
|
||||
constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::FS, 6062};
|
||||
constexpr Result ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1};
|
||||
constexpr Result ERROR_PATH_ALREADY_EXISTS{ErrorModule::FS, 2};
|
||||
constexpr Result ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002};
|
||||
constexpr Result ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001};
|
||||
constexpr Result ERROR_OUT_OF_BOUNDS{ErrorModule::FS, 3005};
|
||||
constexpr Result ERROR_FAILED_MOUNT_ARCHIVE{ErrorModule::FS, 3223};
|
||||
constexpr Result ERROR_INVALID_ARGUMENT{ErrorModule::FS, 6001};
|
||||
constexpr Result ERROR_INVALID_OFFSET{ErrorModule::FS, 6061};
|
||||
constexpr Result ERROR_INVALID_SIZE{ErrorModule::FS, 6062};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
@@ -8,12 +8,12 @@ namespace Core::Frontend {
|
||||
|
||||
ErrorApplet::~ErrorApplet() = default;
|
||||
|
||||
void DefaultErrorApplet::ShowError(ResultCode error, std::function<void()> finished) const {
|
||||
void DefaultErrorApplet::ShowError(Result error, std::function<void()> finished) const {
|
||||
LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})",
|
||||
error.module.Value(), error.description.Value(), error.raw);
|
||||
}
|
||||
|
||||
void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
|
||||
void DefaultErrorApplet::ShowErrorWithTimestamp(Result error, std::chrono::seconds time,
|
||||
std::function<void()> finished) const {
|
||||
LOG_CRITICAL(
|
||||
Service_Fatal,
|
||||
@@ -21,7 +21,7 @@ void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::s
|
||||
error.module.Value(), error.description.Value(), error.raw, time.count());
|
||||
}
|
||||
|
||||
void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_text,
|
||||
void DefaultErrorApplet::ShowCustomErrorText(Result error, std::string main_text,
|
||||
std::string detail_text,
|
||||
std::function<void()> finished) const {
|
||||
LOG_CRITICAL(Service_Fatal,
|
||||
|
||||
@@ -14,22 +14,22 @@ class ErrorApplet {
|
||||
public:
|
||||
virtual ~ErrorApplet();
|
||||
|
||||
virtual void ShowError(ResultCode error, std::function<void()> finished) const = 0;
|
||||
virtual void ShowError(Result error, std::function<void()> finished) const = 0;
|
||||
|
||||
virtual void ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
|
||||
virtual void ShowErrorWithTimestamp(Result error, std::chrono::seconds time,
|
||||
std::function<void()> finished) const = 0;
|
||||
|
||||
virtual void ShowCustomErrorText(ResultCode error, std::string dialog_text,
|
||||
virtual void ShowCustomErrorText(Result error, std::string dialog_text,
|
||||
std::string fullscreen_text,
|
||||
std::function<void()> finished) const = 0;
|
||||
};
|
||||
|
||||
class DefaultErrorApplet final : public ErrorApplet {
|
||||
public:
|
||||
void ShowError(ResultCode error, std::function<void()> finished) const override;
|
||||
void ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
|
||||
void ShowError(Result error, std::function<void()> finished) const override;
|
||||
void ShowErrorWithTimestamp(Result error, std::chrono::seconds time,
|
||||
std::function<void()> finished) const override;
|
||||
void ShowCustomErrorText(ResultCode error, std::string main_text, std::string detail_text,
|
||||
void ShowCustomErrorText(Result error, std::string main_text, std::string detail_text,
|
||||
std::function<void()> finished) const override;
|
||||
};
|
||||
|
||||
|
||||
@@ -11,11 +11,14 @@ namespace Core::Hardware {
|
||||
|
||||
InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) {
|
||||
gpu_interrupt_event = Core::Timing::CreateEvent(
|
||||
"GPUInterrupt", [this](std::uintptr_t message, std::chrono::nanoseconds) {
|
||||
"GPUInterrupt",
|
||||
[this](std::uintptr_t message, u64 time,
|
||||
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
|
||||
auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv");
|
||||
const u32 syncpt = static_cast<u32>(message >> 32);
|
||||
const u32 value = static_cast<u32>(message);
|
||||
nvdrv->SignalGPUInterruptSyncpt(syncpt, value);
|
||||
return std::nullopt;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -272,6 +272,7 @@ enum class VibrationDeviceType : u32 {
|
||||
Unknown = 0,
|
||||
LinearResonantActuator = 1,
|
||||
GcErm = 2,
|
||||
N64 = 3,
|
||||
};
|
||||
|
||||
// This is nn::hid::VibrationGcErmCommand
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
namespace IPC {
|
||||
|
||||
constexpr ResultCode ERR_REMOTE_PROCESS_DEAD{ErrorModule::HIPC, 301};
|
||||
constexpr Result ERR_REMOTE_PROCESS_DEAD{ErrorModule::HIPC, 301};
|
||||
|
||||
class RequestHelperBase {
|
||||
protected:
|
||||
@@ -176,7 +176,7 @@ public:
|
||||
void PushImpl(float value);
|
||||
void PushImpl(double value);
|
||||
void PushImpl(bool value);
|
||||
void PushImpl(ResultCode value);
|
||||
void PushImpl(Result value);
|
||||
|
||||
template <typename T>
|
||||
void Push(T value) {
|
||||
@@ -251,7 +251,7 @@ void ResponseBuilder::PushRaw(const T& value) {
|
||||
index += (sizeof(T) + 3) / 4; // round up to word length
|
||||
}
|
||||
|
||||
inline void ResponseBuilder::PushImpl(ResultCode value) {
|
||||
inline void ResponseBuilder::PushImpl(Result value) {
|
||||
// Result codes are actually 64-bit in the IPC buffer, but only the high part is discarded.
|
||||
Push(value.raw);
|
||||
Push<u32>(0);
|
||||
@@ -481,8 +481,8 @@ inline bool RequestParser::Pop() {
|
||||
}
|
||||
|
||||
template <>
|
||||
inline ResultCode RequestParser::Pop() {
|
||||
return ResultCode{Pop<u32>()};
|
||||
inline Result RequestParser::Pop() {
|
||||
return Result{Pop<u32>()};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -188,8 +188,8 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
|
||||
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
|
||||
}
|
||||
|
||||
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
|
||||
u32_le* src_cmdbuf) {
|
||||
Result HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
|
||||
u32_le* src_cmdbuf) {
|
||||
ParseCommandBuffer(handle_table, src_cmdbuf, true);
|
||||
|
||||
if (command_header->IsCloseCommand()) {
|
||||
@@ -202,7 +202,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTab
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) {
|
||||
Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) {
|
||||
auto current_offset = handles_offset;
|
||||
auto& owner_process = *requesting_thread.GetOwnerProcess();
|
||||
auto& handle_table = owner_process.GetHandleTable();
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/svc_common.h"
|
||||
|
||||
union ResultCode;
|
||||
union Result;
|
||||
|
||||
namespace Core::Memory {
|
||||
class Memory;
|
||||
@@ -71,10 +71,10 @@ public:
|
||||
* it should be used to differentiate which client (As in ClientSession) we're answering to.
|
||||
* TODO(Subv): Use a wrapper structure to hold all the information relevant to
|
||||
* this request (ServerSession, Originator thread, Translated command buffer, etc).
|
||||
* @returns ResultCode the result code of the translate operation.
|
||||
* @returns Result the result code of the translate operation.
|
||||
*/
|
||||
virtual ResultCode HandleSyncRequest(Kernel::KServerSession& session,
|
||||
Kernel::HLERequestContext& context) = 0;
|
||||
virtual Result HandleSyncRequest(Kernel::KServerSession& session,
|
||||
Kernel::HLERequestContext& context) = 0;
|
||||
|
||||
/**
|
||||
* Signals that a client has just connected to this HLE handler and keeps the
|
||||
@@ -212,11 +212,10 @@ public:
|
||||
}
|
||||
|
||||
/// Populates this context with data from the requesting process/thread.
|
||||
ResultCode PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
|
||||
u32_le* src_cmdbuf);
|
||||
Result PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf);
|
||||
|
||||
/// Writes data from this context back to the requesting process/thread.
|
||||
ResultCode WriteToOutgoingCommandBuffer(KThread& requesting_thread);
|
||||
Result WriteToOutgoingCommandBuffer(KThread& requesting_thread);
|
||||
|
||||
u32_le GetHipcCommand() const {
|
||||
return command;
|
||||
|
||||
@@ -90,8 +90,7 @@ public:
|
||||
explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel_, KAddressArbiter::ThreadTree* t)
|
||||
: KThreadQueue(kernel_), m_tree(t) {}
|
||||
|
||||
void CancelWait(KThread* waiting_thread, ResultCode wait_result,
|
||||
bool cancel_timer_task) override {
|
||||
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
|
||||
// If the thread is waiting on an address arbiter, remove it from the tree.
|
||||
if (waiting_thread->IsWaitingForAddressArbiter()) {
|
||||
m_tree->erase(m_tree->iterator_to(*waiting_thread));
|
||||
@@ -108,7 +107,7 @@ private:
|
||||
|
||||
} // namespace
|
||||
|
||||
ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) {
|
||||
Result KAddressArbiter::Signal(VAddr addr, s32 count) {
|
||||
// Perform signaling.
|
||||
s32 num_waiters{};
|
||||
{
|
||||
@@ -131,7 +130,7 @@ ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 count) {
|
||||
Result KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 count) {
|
||||
// Perform signaling.
|
||||
s32 num_waiters{};
|
||||
{
|
||||
@@ -164,7 +163,7 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 value, s32 count) {
|
||||
Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 value, s32 count) {
|
||||
// Perform signaling.
|
||||
s32 num_waiters{};
|
||||
{
|
||||
@@ -232,7 +231,7 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) {
|
||||
Result KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) {
|
||||
// Prepare to wait.
|
||||
KThread* cur_thread = GetCurrentThreadPointer(kernel);
|
||||
ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree));
|
||||
@@ -285,7 +284,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
|
||||
return cur_thread->GetWaitResult();
|
||||
}
|
||||
|
||||
ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
|
||||
Result KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
|
||||
// Prepare to wait.
|
||||
KThread* cur_thread = GetCurrentThreadPointer(kernel);
|
||||
ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree));
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "core/hle/kernel/k_condition_variable.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
|
||||
union ResultCode;
|
||||
union Result;
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
@@ -25,8 +25,7 @@ public:
|
||||
explicit KAddressArbiter(Core::System& system_);
|
||||
~KAddressArbiter();
|
||||
|
||||
[[nodiscard]] ResultCode SignalToAddress(VAddr addr, Svc::SignalType type, s32 value,
|
||||
s32 count) {
|
||||
[[nodiscard]] Result SignalToAddress(VAddr addr, Svc::SignalType type, s32 value, s32 count) {
|
||||
switch (type) {
|
||||
case Svc::SignalType::Signal:
|
||||
return Signal(addr, count);
|
||||
@@ -39,8 +38,8 @@ public:
|
||||
return ResultUnknown;
|
||||
}
|
||||
|
||||
[[nodiscard]] ResultCode WaitForAddress(VAddr addr, Svc::ArbitrationType type, s32 value,
|
||||
s64 timeout) {
|
||||
[[nodiscard]] Result WaitForAddress(VAddr addr, Svc::ArbitrationType type, s32 value,
|
||||
s64 timeout) {
|
||||
switch (type) {
|
||||
case Svc::ArbitrationType::WaitIfLessThan:
|
||||
return WaitIfLessThan(addr, value, false, timeout);
|
||||
@@ -54,11 +53,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] ResultCode Signal(VAddr addr, s32 count);
|
||||
[[nodiscard]] ResultCode SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 count);
|
||||
[[nodiscard]] ResultCode SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 value, s32 count);
|
||||
[[nodiscard]] ResultCode WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout);
|
||||
[[nodiscard]] ResultCode WaitIfEqual(VAddr addr, s32 value, s64 timeout);
|
||||
[[nodiscard]] Result Signal(VAddr addr, s32 count);
|
||||
[[nodiscard]] Result SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 count);
|
||||
[[nodiscard]] Result SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 value, s32 count);
|
||||
[[nodiscard]] Result WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout);
|
||||
[[nodiscard]] Result WaitIfEqual(VAddr addr, s32 value, s64 timeout);
|
||||
|
||||
ThreadTree thread_tree;
|
||||
|
||||
|
||||
@@ -59,8 +59,8 @@ bool KClientPort::IsSignaled() const {
|
||||
return num_sessions < max_sessions;
|
||||
}
|
||||
|
||||
ResultCode KClientPort::CreateSession(KClientSession** out,
|
||||
std::shared_ptr<SessionRequestManager> session_manager) {
|
||||
Result KClientPort::CreateSession(KClientSession** out,
|
||||
std::shared_ptr<SessionRequestManager> session_manager) {
|
||||
// Reserve a new session from the resource limit.
|
||||
KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
|
||||
LimitableResource::Sessions);
|
||||
|
||||
@@ -53,8 +53,8 @@ public:
|
||||
void Destroy() override;
|
||||
bool IsSignaled() const override;
|
||||
|
||||
ResultCode CreateSession(KClientSession** out,
|
||||
std::shared_ptr<SessionRequestManager> session_manager = nullptr);
|
||||
Result CreateSession(KClientSession** out,
|
||||
std::shared_ptr<SessionRequestManager> session_manager = nullptr);
|
||||
|
||||
private:
|
||||
std::atomic<s32> num_sessions{};
|
||||
|
||||
@@ -21,8 +21,8 @@ void KClientSession::Destroy() {
|
||||
|
||||
void KClientSession::OnServerClosed() {}
|
||||
|
||||
ResultCode KClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
|
||||
Core::Timing::CoreTiming& core_timing) {
|
||||
Result KClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
|
||||
Core::Timing::CoreTiming& core_timing) {
|
||||
// Signal the server session that new data is available
|
||||
return parent->GetServerSession().HandleSyncRequest(thread, memory, core_timing);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
union ResultCode;
|
||||
union Result;
|
||||
|
||||
namespace Core::Memory {
|
||||
class Memory;
|
||||
@@ -46,8 +46,8 @@ public:
|
||||
return parent;
|
||||
}
|
||||
|
||||
ResultCode SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
|
||||
Core::Timing::CoreTiming& core_timing);
|
||||
Result SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
|
||||
Core::Timing::CoreTiming& core_timing);
|
||||
|
||||
void OnServerClosed();
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "core/hle/kernel/k_code_memory.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_memory_block.h"
|
||||
#include "core/hle/kernel/k_page_linked_list.h"
|
||||
#include "core/hle/kernel/k_page_group.h"
|
||||
#include "core/hle/kernel/k_page_table.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
@@ -19,7 +19,7 @@ namespace Kernel {
|
||||
KCodeMemory::KCodeMemory(KernelCore& kernel_)
|
||||
: KAutoObjectWithSlabHeapAndContainer{kernel_}, m_lock(kernel_) {}
|
||||
|
||||
ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, size_t size) {
|
||||
Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, size_t size) {
|
||||
// Set members.
|
||||
m_owner = kernel.CurrentProcess();
|
||||
|
||||
@@ -62,7 +62,7 @@ void KCodeMemory::Finalize() {
|
||||
m_owner->Close();
|
||||
}
|
||||
|
||||
ResultCode KCodeMemory::Map(VAddr address, size_t size) {
|
||||
Result KCodeMemory::Map(VAddr address, size_t size) {
|
||||
// Validate the size.
|
||||
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
|
||||
|
||||
@@ -82,7 +82,7 @@ ResultCode KCodeMemory::Map(VAddr address, size_t size) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KCodeMemory::Unmap(VAddr address, size_t size) {
|
||||
Result KCodeMemory::Unmap(VAddr address, size_t size) {
|
||||
// Validate the size.
|
||||
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
|
||||
|
||||
@@ -99,7 +99,7 @@ ResultCode KCodeMemory::Unmap(VAddr address, size_t size) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) {
|
||||
Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) {
|
||||
// Validate the size.
|
||||
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
|
||||
|
||||
@@ -133,7 +133,7 @@ ResultCode KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermis
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
|
||||
Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
|
||||
// Validate the size.
|
||||
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "core/device_memory.h"
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_page_linked_list.h"
|
||||
#include "core/hle/kernel/k_page_group.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
@@ -29,13 +29,13 @@ class KCodeMemory final
|
||||
public:
|
||||
explicit KCodeMemory(KernelCore& kernel_);
|
||||
|
||||
ResultCode Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size);
|
||||
Result Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size);
|
||||
void Finalize();
|
||||
|
||||
ResultCode Map(VAddr address, size_t size);
|
||||
ResultCode Unmap(VAddr address, size_t size);
|
||||
ResultCode MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm);
|
||||
ResultCode UnmapFromOwner(VAddr address, size_t size);
|
||||
Result Map(VAddr address, size_t size);
|
||||
Result Unmap(VAddr address, size_t size);
|
||||
Result MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm);
|
||||
Result UnmapFromOwner(VAddr address, size_t size);
|
||||
|
||||
bool IsInitialized() const {
|
||||
return m_is_initialized;
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
KPageLinkedList m_page_group{};
|
||||
KPageGroup m_page_group{};
|
||||
KProcess* m_owner{};
|
||||
VAddr m_address{};
|
||||
KLightLock m_lock;
|
||||
|
||||
@@ -61,8 +61,7 @@ public:
|
||||
explicit ThreadQueueImplForKConditionVariableWaitForAddress(KernelCore& kernel_)
|
||||
: KThreadQueue(kernel_) {}
|
||||
|
||||
void CancelWait(KThread* waiting_thread, ResultCode wait_result,
|
||||
bool cancel_timer_task) override {
|
||||
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
|
||||
// Remove the thread as a waiter from its owner.
|
||||
waiting_thread->GetLockOwner()->RemoveWaiter(waiting_thread);
|
||||
|
||||
@@ -80,8 +79,7 @@ public:
|
||||
KernelCore& kernel_, KConditionVariable::ThreadTree* t)
|
||||
: KThreadQueue(kernel_), m_tree(t) {}
|
||||
|
||||
void CancelWait(KThread* waiting_thread, ResultCode wait_result,
|
||||
bool cancel_timer_task) override {
|
||||
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
|
||||
// Remove the thread as a waiter from its owner.
|
||||
if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) {
|
||||
owner->RemoveWaiter(waiting_thread);
|
||||
@@ -105,7 +103,7 @@ KConditionVariable::KConditionVariable(Core::System& system_)
|
||||
|
||||
KConditionVariable::~KConditionVariable() = default;
|
||||
|
||||
ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
|
||||
Result KConditionVariable::SignalToAddress(VAddr addr) {
|
||||
KThread* owner_thread = GetCurrentThreadPointer(kernel);
|
||||
|
||||
// Signal the address.
|
||||
@@ -126,7 +124,7 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
|
||||
}
|
||||
|
||||
// Write the value to userspace.
|
||||
ResultCode result{ResultSuccess};
|
||||
Result result{ResultSuccess};
|
||||
if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] {
|
||||
result = ResultSuccess;
|
||||
} else {
|
||||
@@ -146,7 +144,7 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
|
||||
}
|
||||
}
|
||||
|
||||
ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) {
|
||||
Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) {
|
||||
KThread* cur_thread = GetCurrentThreadPointer(kernel);
|
||||
ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(kernel);
|
||||
|
||||
@@ -261,7 +259,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
|
||||
}
|
||||
}
|
||||
|
||||
ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
|
||||
Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
|
||||
// Prepare to wait.
|
||||
KThread* cur_thread = GetCurrentThreadPointer(kernel);
|
||||
ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue(
|
||||
|
||||
@@ -25,12 +25,12 @@ public:
|
||||
~KConditionVariable();
|
||||
|
||||
// Arbitration
|
||||
[[nodiscard]] ResultCode SignalToAddress(VAddr addr);
|
||||
[[nodiscard]] ResultCode WaitForAddress(Handle handle, VAddr addr, u32 value);
|
||||
[[nodiscard]] Result SignalToAddress(VAddr addr);
|
||||
[[nodiscard]] Result WaitForAddress(Handle handle, VAddr addr, u32 value);
|
||||
|
||||
// Condition variable
|
||||
void Signal(u64 cv_key, s32 count);
|
||||
[[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout);
|
||||
[[nodiscard]] Result Wait(VAddr addr, u64 key, u32 value, s64 timeout);
|
||||
|
||||
private:
|
||||
void SignalImpl(KThread* thread);
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Kernel {
|
||||
KHandleTable::KHandleTable(KernelCore& kernel_) : kernel{kernel_} {}
|
||||
KHandleTable::~KHandleTable() = default;
|
||||
|
||||
ResultCode KHandleTable::Finalize() {
|
||||
Result KHandleTable::Finalize() {
|
||||
// Get the table and clear our record of it.
|
||||
u16 saved_table_size = 0;
|
||||
{
|
||||
@@ -62,7 +62,7 @@ bool KHandleTable::Remove(Handle handle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj) {
|
||||
Result KHandleTable::Add(Handle* out_handle, KAutoObject* obj) {
|
||||
KScopedDisableDispatch dd(kernel);
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
@@ -85,7 +85,7 @@ ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KHandleTable::Reserve(Handle* out_handle) {
|
||||
Result KHandleTable::Reserve(Handle* out_handle) {
|
||||
KScopedDisableDispatch dd(kernel);
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
explicit KHandleTable(KernelCore& kernel_);
|
||||
~KHandleTable();
|
||||
|
||||
ResultCode Initialize(s32 size) {
|
||||
Result Initialize(s32 size) {
|
||||
R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
|
||||
|
||||
// Initialize all fields.
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
return m_max_count;
|
||||
}
|
||||
|
||||
ResultCode Finalize();
|
||||
Result Finalize();
|
||||
bool Remove(Handle handle);
|
||||
|
||||
template <typename T = KAutoObject>
|
||||
@@ -100,10 +100,10 @@ public:
|
||||
return this->template GetObjectWithoutPseudoHandle<T>(handle);
|
||||
}
|
||||
|
||||
ResultCode Reserve(Handle* out_handle);
|
||||
Result Reserve(Handle* out_handle);
|
||||
void Unreserve(Handle handle);
|
||||
|
||||
ResultCode Add(Handle* out_handle, KAutoObject* obj);
|
||||
Result Add(Handle* out_handle, KAutoObject* obj);
|
||||
void Register(Handle handle, KAutoObject* obj);
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -17,8 +17,7 @@ public:
|
||||
bool term)
|
||||
: KThreadQueue(kernel_), m_wait_list(wl), m_allow_terminating_thread(term) {}
|
||||
|
||||
void CancelWait(KThread* waiting_thread, ResultCode wait_result,
|
||||
bool cancel_timer_task) override {
|
||||
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
|
||||
// Only process waits if we're allowed to.
|
||||
if (ResultTerminationRequested == wait_result && m_allow_terminating_thread) {
|
||||
return;
|
||||
|
||||
@@ -15,8 +15,7 @@ class ThreadQueueImplForKLightLock final : public KThreadQueue {
|
||||
public:
|
||||
explicit ThreadQueueImplForKLightLock(KernelCore& kernel_) : KThreadQueue(kernel_) {}
|
||||
|
||||
void CancelWait(KThread* waiting_thread, ResultCode wait_result,
|
||||
bool cancel_timer_task) override {
|
||||
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
|
||||
// Remove the thread as a waiter from its owner.
|
||||
if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) {
|
||||
owner->RemoveWaiter(waiting_thread);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "core/device_memory.h"
|
||||
#include "core/hle/kernel/initial_process.h"
|
||||
#include "core/hle/kernel/k_memory_manager.h"
|
||||
#include "core/hle/kernel/k_page_linked_list.h"
|
||||
#include "core/hle/kernel/k_page_group.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
|
||||
@@ -208,8 +208,8 @@ PAddr KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_p
|
||||
return allocated_block;
|
||||
}
|
||||
|
||||
ResultCode KMemoryManager::AllocatePageGroupImpl(KPageLinkedList* out, size_t num_pages, Pool pool,
|
||||
Direction dir, bool random) {
|
||||
Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, Pool pool,
|
||||
Direction dir, bool random) {
|
||||
// Choose a heap based on our page size request.
|
||||
const s32 heap_index = KPageHeap::GetBlockIndex(num_pages);
|
||||
R_UNLESS(0 <= heap_index, ResultOutOfMemory);
|
||||
@@ -257,7 +257,7 @@ ResultCode KMemoryManager::AllocatePageGroupImpl(KPageLinkedList* out, size_t nu
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KMemoryManager::AllocateAndOpen(KPageLinkedList* out, size_t num_pages, u32 option) {
|
||||
Result KMemoryManager::AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 option) {
|
||||
ASSERT(out != nullptr);
|
||||
ASSERT(out->GetNumPages() == 0);
|
||||
|
||||
@@ -293,8 +293,8 @@ ResultCode KMemoryManager::AllocateAndOpen(KPageLinkedList* out, size_t num_page
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KMemoryManager::AllocateAndOpenForProcess(KPageLinkedList* out, size_t num_pages,
|
||||
u32 option, u64 process_id, u8 fill_pattern) {
|
||||
Result KMemoryManager::AllocateAndOpenForProcess(KPageGroup* out, size_t num_pages, u32 option,
|
||||
u64 process_id, u8 fill_pattern) {
|
||||
ASSERT(out != nullptr);
|
||||
ASSERT(out->GetNumPages() == 0);
|
||||
|
||||
@@ -370,12 +370,12 @@ void KMemoryManager::Close(PAddr address, size_t num_pages) {
|
||||
}
|
||||
}
|
||||
|
||||
void KMemoryManager::Close(const KPageLinkedList& pg) {
|
||||
void KMemoryManager::Close(const KPageGroup& pg) {
|
||||
for (const auto& node : pg.Nodes()) {
|
||||
Close(node.GetAddress(), node.GetNumPages());
|
||||
}
|
||||
}
|
||||
void KMemoryManager::Open(const KPageLinkedList& pg) {
|
||||
void KMemoryManager::Open(const KPageGroup& pg) {
|
||||
for (const auto& node : pg.Nodes()) {
|
||||
Open(node.GetAddress(), node.GetNumPages());
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class System;
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KPageLinkedList;
|
||||
class KPageGroup;
|
||||
|
||||
class KMemoryManager final {
|
||||
public:
|
||||
@@ -65,17 +65,17 @@ public:
|
||||
}
|
||||
|
||||
PAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
|
||||
ResultCode AllocateAndOpen(KPageLinkedList* out, size_t num_pages, u32 option);
|
||||
ResultCode AllocateAndOpenForProcess(KPageLinkedList* out, size_t num_pages, u32 option,
|
||||
u64 process_id, u8 fill_pattern);
|
||||
Result AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 option);
|
||||
Result AllocateAndOpenForProcess(KPageGroup* out, size_t num_pages, u32 option, u64 process_id,
|
||||
u8 fill_pattern);
|
||||
|
||||
static constexpr size_t MaxManagerCount = 10;
|
||||
|
||||
void Close(PAddr address, size_t num_pages);
|
||||
void Close(const KPageLinkedList& pg);
|
||||
void Close(const KPageGroup& pg);
|
||||
|
||||
void Open(PAddr address, size_t num_pages);
|
||||
void Open(const KPageLinkedList& pg);
|
||||
void Open(const KPageGroup& pg);
|
||||
|
||||
public:
|
||||
static size_t CalculateManagementOverheadSize(size_t region_size) {
|
||||
@@ -262,8 +262,8 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
ResultCode AllocatePageGroupImpl(KPageLinkedList* out, size_t num_pages, Pool pool,
|
||||
Direction dir, bool random);
|
||||
Result AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, Pool pool, Direction dir,
|
||||
bool random);
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KPageLinkedList final {
|
||||
class KPageGroup final {
|
||||
public:
|
||||
class Node final {
|
||||
public:
|
||||
@@ -36,8 +36,8 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
KPageLinkedList() = default;
|
||||
KPageLinkedList(u64 address, u64 num_pages) {
|
||||
KPageGroup() = default;
|
||||
KPageGroup(u64 address, u64 num_pages) {
|
||||
ASSERT(AddBlock(address, num_pages).IsSuccess());
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
return num_pages;
|
||||
}
|
||||
|
||||
bool IsEqual(KPageLinkedList& other) const {
|
||||
bool IsEqual(KPageGroup& other) const {
|
||||
auto this_node = nodes.begin();
|
||||
auto other_node = other.nodes.begin();
|
||||
while (this_node != nodes.end() && other_node != other.nodes.end()) {
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
return this_node == nodes.end() && other_node == other.nodes.end();
|
||||
}
|
||||
|
||||
ResultCode AddBlock(u64 address, u64 num_pages) {
|
||||
Result AddBlock(u64 address, u64 num_pages) {
|
||||
if (!num_pages) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "core/hle/kernel/k_address_space_info.h"
|
||||
#include "core/hle/kernel/k_memory_block.h"
|
||||
#include "core/hle/kernel/k_memory_block_manager.h"
|
||||
#include "core/hle/kernel/k_page_linked_list.h"
|
||||
#include "core/hle/kernel/k_page_group.h"
|
||||
#include "core/hle/kernel/k_page_table.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
@@ -47,9 +47,9 @@ KPageTable::KPageTable(Core::System& system_)
|
||||
|
||||
KPageTable::~KPageTable() = default;
|
||||
|
||||
ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type,
|
||||
bool enable_aslr, VAddr code_addr,
|
||||
std::size_t code_size, KMemoryManager::Pool pool) {
|
||||
Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
|
||||
VAddr code_addr, std::size_t code_size,
|
||||
KMemoryManager::Pool pool) {
|
||||
|
||||
const auto GetSpaceStart = [this](KAddressSpaceInfo::Type type) {
|
||||
return KAddressSpaceInfo::GetAddressSpaceStart(address_space_width, type);
|
||||
@@ -257,8 +257,8 @@ ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_
|
||||
return InitializeMemoryLayout(start, end);
|
||||
}
|
||||
|
||||
ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemoryState state,
|
||||
KMemoryPermission perm) {
|
||||
Result KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemoryState state,
|
||||
KMemoryPermission perm) {
|
||||
const u64 size{num_pages * PageSize};
|
||||
|
||||
// Validate the mapping request.
|
||||
@@ -271,7 +271,7 @@ ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemory
|
||||
R_TRY(this->CheckMemoryState(addr, size, KMemoryState::All, KMemoryState::Free,
|
||||
KMemoryPermission::None, KMemoryPermission::None,
|
||||
KMemoryAttribute::None, KMemoryAttribute::None));
|
||||
KPageLinkedList pg;
|
||||
KPageGroup pg;
|
||||
R_TRY(system.Kernel().MemoryManager().AllocateAndOpen(
|
||||
&pg, num_pages,
|
||||
KMemoryManager::EncodeOption(KMemoryManager::Pool::Application, allocation_option)));
|
||||
@@ -283,7 +283,7 @@ ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemory
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size) {
|
||||
Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size) {
|
||||
// Validate the mapping request.
|
||||
R_UNLESS(this->CanContain(dst_address, size, KMemoryState::AliasCode),
|
||||
ResultInvalidMemoryRegion);
|
||||
@@ -313,7 +313,7 @@ ResultCode KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, std::
|
||||
const std::size_t num_pages = size / PageSize;
|
||||
|
||||
// Create page groups for the memory being mapped.
|
||||
KPageLinkedList pg;
|
||||
KPageGroup pg;
|
||||
AddRegionToPages(src_address, num_pages, pg);
|
||||
|
||||
// Reprotect the source as kernel-read/not mapped.
|
||||
@@ -344,8 +344,8 @@ ResultCode KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, std::
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size,
|
||||
ICacheInvalidationStrategy icache_invalidation_strategy) {
|
||||
Result KPageTable::UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size,
|
||||
ICacheInvalidationStrategy icache_invalidation_strategy) {
|
||||
// Validate the mapping request.
|
||||
R_UNLESS(this->CanContain(dst_address, size, KMemoryState::AliasCode),
|
||||
ResultInvalidMemoryRegion);
|
||||
@@ -489,7 +489,7 @@ VAddr KPageTable::FindFreeArea(VAddr region_start, std::size_t region_num_pages,
|
||||
return address;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages) {
|
||||
Result KPageTable::MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages) {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
const size_t size = num_pages * PageSize;
|
||||
@@ -541,7 +541,7 @@ ResultCode KPageTable::MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
bool KPageTable::IsValidPageGroup(const KPageLinkedList& pg_ll, VAddr addr, size_t num_pages) {
|
||||
bool KPageTable::IsValidPageGroup(const KPageGroup& pg_ll, VAddr addr, size_t num_pages) {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
const size_t size = num_pages * PageSize;
|
||||
@@ -630,8 +630,8 @@ bool KPageTable::IsValidPageGroup(const KPageLinkedList& pg_ll, VAddr addr, size
|
||||
return cur_block_address == cur_addr && cur_block_pages == (cur_size / PageSize);
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
|
||||
KPageTable& src_page_table, VAddr src_addr) {
|
||||
Result KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table,
|
||||
VAddr src_addr) {
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
const std::size_t num_pages{size / PageSize};
|
||||
@@ -660,7 +660,7 @@ ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::MapPhysicalMemory(VAddr address, std::size_t size) {
|
||||
Result KPageTable::MapPhysicalMemory(VAddr address, std::size_t size) {
|
||||
// Lock the physical memory lock.
|
||||
KScopedLightLock map_phys_mem_lk(map_physical_memory_lock);
|
||||
|
||||
@@ -721,7 +721,7 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr address, std::size_t size) {
|
||||
R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
|
||||
|
||||
// Allocate pages for the new memory.
|
||||
KPageLinkedList pg;
|
||||
KPageGroup pg;
|
||||
R_TRY(system.Kernel().MemoryManager().AllocateAndOpenForProcess(
|
||||
&pg, (size - mapped_size) / PageSize,
|
||||
KMemoryManager::EncodeOption(memory_pool, allocation_option), 0, 0));
|
||||
@@ -903,7 +903,7 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr address, std::size_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapPhysicalMemory(VAddr address, std::size_t size) {
|
||||
Result KPageTable::UnmapPhysicalMemory(VAddr address, std::size_t size) {
|
||||
// Lock the physical memory lock.
|
||||
KScopedLightLock map_phys_mem_lk(map_physical_memory_lock);
|
||||
|
||||
@@ -972,7 +972,7 @@ ResultCode KPageTable::UnmapPhysicalMemory(VAddr address, std::size_t size) {
|
||||
}
|
||||
|
||||
// Make a page group for the unmap region.
|
||||
KPageLinkedList pg;
|
||||
KPageGroup pg;
|
||||
{
|
||||
auto& impl = this->PageTableImpl();
|
||||
|
||||
@@ -1134,7 +1134,7 @@ ResultCode KPageTable::UnmapPhysicalMemory(VAddr address, std::size_t size) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||
Result KPageTable::MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryState src_state{};
|
||||
@@ -1147,7 +1147,7 @@ ResultCode KPageTable::MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t siz
|
||||
return ResultInvalidCurrentMemory;
|
||||
}
|
||||
|
||||
KPageLinkedList page_linked_list;
|
||||
KPageGroup page_linked_list;
|
||||
const std::size_t num_pages{size / PageSize};
|
||||
|
||||
AddRegionToPages(src_addr, num_pages, page_linked_list);
|
||||
@@ -1173,7 +1173,7 @@ ResultCode KPageTable::MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t siz
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||
Result KPageTable::UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryState src_state{};
|
||||
@@ -1188,8 +1188,8 @@ ResultCode KPageTable::UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t s
|
||||
KMemoryPermission::None, KMemoryAttribute::Mask,
|
||||
KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
|
||||
|
||||
KPageLinkedList src_pages;
|
||||
KPageLinkedList dst_pages;
|
||||
KPageGroup src_pages;
|
||||
KPageGroup dst_pages;
|
||||
const std::size_t num_pages{size / PageSize};
|
||||
|
||||
AddRegionToPages(src_addr, num_pages, src_pages);
|
||||
@@ -1215,8 +1215,8 @@ ResultCode KPageTable::UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t s
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::MapPages(VAddr addr, const KPageLinkedList& page_linked_list,
|
||||
KMemoryPermission perm) {
|
||||
Result KPageTable::MapPages(VAddr addr, const KPageGroup& page_linked_list,
|
||||
KMemoryPermission perm) {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
VAddr cur_addr{addr};
|
||||
@@ -1239,8 +1239,8 @@ ResultCode KPageTable::MapPages(VAddr addr, const KPageLinkedList& page_linked_l
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::MapPages(VAddr address, KPageLinkedList& page_linked_list,
|
||||
KMemoryState state, KMemoryPermission perm) {
|
||||
Result KPageTable::MapPages(VAddr address, KPageGroup& page_linked_list, KMemoryState state,
|
||||
KMemoryPermission perm) {
|
||||
// Check that the map is in range.
|
||||
const std::size_t num_pages{page_linked_list.GetNumPages()};
|
||||
const std::size_t size{num_pages * PageSize};
|
||||
@@ -1263,10 +1263,10 @@ ResultCode KPageTable::MapPages(VAddr address, KPageLinkedList& page_linked_list
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::MapPages(VAddr* out_addr, std::size_t num_pages, std::size_t alignment,
|
||||
PAddr phys_addr, bool is_pa_valid, VAddr region_start,
|
||||
std::size_t region_num_pages, KMemoryState state,
|
||||
KMemoryPermission perm) {
|
||||
Result KPageTable::MapPages(VAddr* out_addr, std::size_t num_pages, std::size_t alignment,
|
||||
PAddr phys_addr, bool is_pa_valid, VAddr region_start,
|
||||
std::size_t region_num_pages, KMemoryState state,
|
||||
KMemoryPermission perm) {
|
||||
ASSERT(Common::IsAligned(alignment, PageSize) && alignment >= PageSize);
|
||||
|
||||
// Ensure this is a valid map request.
|
||||
@@ -1303,7 +1303,7 @@ ResultCode KPageTable::MapPages(VAddr* out_addr, std::size_t num_pages, std::siz
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list) {
|
||||
Result KPageTable::UnmapPages(VAddr addr, const KPageGroup& page_linked_list) {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
VAddr cur_addr{addr};
|
||||
@@ -1321,8 +1321,7 @@ ResultCode KPageTable::UnmapPages(VAddr addr, const KPageLinkedList& page_linked
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list,
|
||||
KMemoryState state) {
|
||||
Result KPageTable::UnmapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state) {
|
||||
// Check that the unmap is in range.
|
||||
const std::size_t num_pages{page_linked_list.GetNumPages()};
|
||||
const std::size_t size{num_pages * PageSize};
|
||||
@@ -1345,7 +1344,7 @@ ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list,
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapPages(VAddr address, std::size_t num_pages, KMemoryState state) {
|
||||
Result KPageTable::UnmapPages(VAddr address, std::size_t num_pages, KMemoryState state) {
|
||||
// Check that the unmap is in range.
|
||||
const std::size_t size = num_pages * PageSize;
|
||||
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
|
||||
@@ -1369,10 +1368,10 @@ ResultCode KPageTable::UnmapPages(VAddr address, std::size_t num_pages, KMemoryS
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr) {
|
||||
Result KPageTable::MakeAndOpenPageGroup(KPageGroup* out, VAddr address, size_t num_pages,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr) {
|
||||
// Ensure that the page group isn't null.
|
||||
ASSERT(out != nullptr);
|
||||
|
||||
@@ -1394,8 +1393,8 @@ ResultCode KPageTable::MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address,
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
|
||||
Svc::MemoryPermission svc_perm) {
|
||||
Result KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
|
||||
Svc::MemoryPermission svc_perm) {
|
||||
const size_t num_pages = size / PageSize;
|
||||
|
||||
// Lock the table.
|
||||
@@ -1467,7 +1466,7 @@ KMemoryInfo KPageTable::QueryInfo(VAddr addr) {
|
||||
return QueryInfoImpl(addr);
|
||||
}
|
||||
|
||||
ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm) {
|
||||
Result KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm) {
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryState state{};
|
||||
@@ -1485,7 +1484,7 @@ ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemo
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
|
||||
Result KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryState state{};
|
||||
@@ -1500,8 +1499,8 @@ ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size,
|
||||
Svc::MemoryPermission svc_perm) {
|
||||
Result KPageTable::SetMemoryPermission(VAddr addr, std::size_t size,
|
||||
Svc::MemoryPermission svc_perm) {
|
||||
const size_t num_pages = size / PageSize;
|
||||
|
||||
// Lock the table.
|
||||
@@ -1528,7 +1527,7 @@ ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size,
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask, u32 attr) {
|
||||
Result KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask, u32 attr) {
|
||||
const size_t num_pages = size / PageSize;
|
||||
ASSERT((static_cast<KMemoryAttribute>(mask) | KMemoryAttribute::SetMask) ==
|
||||
KMemoryAttribute::SetMask);
|
||||
@@ -1563,7 +1562,7 @@ ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::SetMaxHeapSize(std::size_t size) {
|
||||
Result KPageTable::SetMaxHeapSize(std::size_t size) {
|
||||
// Lock the table.
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
@@ -1575,7 +1574,7 @@ ResultCode KPageTable::SetMaxHeapSize(std::size_t size) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
|
||||
Result KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
|
||||
// Lock the physical memory mutex.
|
||||
KScopedLightLock map_phys_mem_lk(map_physical_memory_lock);
|
||||
|
||||
@@ -1642,7 +1641,7 @@ ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
|
||||
R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
|
||||
|
||||
// Allocate pages for the heap extension.
|
||||
KPageLinkedList pg;
|
||||
KPageGroup pg;
|
||||
R_TRY(system.Kernel().MemoryManager().AllocateAndOpen(
|
||||
&pg, allocation_size / PageSize,
|
||||
KMemoryManager::EncodeOption(memory_pool, allocation_option)));
|
||||
@@ -1717,7 +1716,7 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages,
|
||||
if (is_map_only) {
|
||||
R_TRY(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr));
|
||||
} else {
|
||||
KPageLinkedList page_group;
|
||||
KPageGroup page_group;
|
||||
R_TRY(system.Kernel().MemoryManager().AllocateAndOpenForProcess(
|
||||
&page_group, needed_num_pages,
|
||||
KMemoryManager::EncodeOption(memory_pool, allocation_option), 0, 0));
|
||||
@@ -1729,11 +1728,11 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages,
|
||||
return addr;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||
Result KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryPermission perm{};
|
||||
if (const ResultCode result{CheckMemoryState(
|
||||
if (const Result result{CheckMemoryState(
|
||||
nullptr, &perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute,
|
||||
KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
|
||||
KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
|
||||
@@ -1752,11 +1751,11 @@ ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||
Result KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryPermission perm{};
|
||||
if (const ResultCode result{CheckMemoryState(
|
||||
if (const Result result{CheckMemoryState(
|
||||
nullptr, &perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute,
|
||||
KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
|
||||
KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
|
||||
@@ -1775,7 +1774,7 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::LockForCodeMemory(KPageLinkedList* out, VAddr addr, std::size_t size) {
|
||||
Result KPageTable::LockForCodeMemory(KPageGroup* out, VAddr addr, std::size_t size) {
|
||||
return this->LockMemoryAndOpen(
|
||||
out, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
|
||||
KMemoryPermission::All, KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
|
||||
@@ -1785,15 +1784,14 @@ ResultCode KPageTable::LockForCodeMemory(KPageLinkedList* out, VAddr addr, std::
|
||||
KMemoryAttribute::Locked);
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size,
|
||||
const KPageLinkedList& pg) {
|
||||
Result KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size, const KPageGroup& pg) {
|
||||
return this->UnlockMemory(
|
||||
addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
|
||||
KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::All,
|
||||
KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite, KMemoryAttribute::Locked, &pg);
|
||||
}
|
||||
|
||||
ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) {
|
||||
Result KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) {
|
||||
block_manager = std::make_unique<KMemoryBlockManager>(start, end);
|
||||
|
||||
return ResultSuccess;
|
||||
@@ -1818,7 +1816,7 @@ bool KPageTable::IsRegionContiguous(VAddr addr, u64 size) const {
|
||||
}
|
||||
|
||||
void KPageTable::AddRegionToPages(VAddr start, std::size_t num_pages,
|
||||
KPageLinkedList& page_linked_list) {
|
||||
KPageGroup& page_linked_list) {
|
||||
VAddr addr{start};
|
||||
while (addr < start + (num_pages * PageSize)) {
|
||||
const PAddr paddr{GetPhysicalAddr(addr)};
|
||||
@@ -1837,8 +1835,8 @@ VAddr KPageTable::AllocateVirtualMemory(VAddr start, std::size_t region_num_page
|
||||
IsKernel() ? 1 : 4);
|
||||
}
|
||||
|
||||
ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group,
|
||||
OperationType operation) {
|
||||
Result KPageTable::Operate(VAddr addr, std::size_t num_pages, const KPageGroup& page_group,
|
||||
OperationType operation) {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
ASSERT(Common::IsAligned(addr, PageSize));
|
||||
@@ -1862,8 +1860,8 @@ ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, const KPageLin
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm,
|
||||
OperationType operation, PAddr map_addr) {
|
||||
Result KPageTable::Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm,
|
||||
OperationType operation, PAddr map_addr) {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
ASSERT(num_pages > 0);
|
||||
@@ -2005,10 +2003,10 @@ bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) co
|
||||
}
|
||||
}
|
||||
|
||||
ResultCode KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr) const {
|
||||
Result KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr) const {
|
||||
// Validate the states match expectation.
|
||||
R_UNLESS((info.state & state_mask) == state, ResultInvalidCurrentMemory);
|
||||
R_UNLESS((info.perm & perm_mask) == perm, ResultInvalidCurrentMemory);
|
||||
@@ -2017,12 +2015,11 @@ ResultCode KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState st
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::CheckMemoryStateContiguous(std::size_t* out_blocks_needed, VAddr addr,
|
||||
std::size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr) const {
|
||||
Result KPageTable::CheckMemoryStateContiguous(std::size_t* out_blocks_needed, VAddr addr,
|
||||
std::size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr) const {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
// Get information about the first block.
|
||||
@@ -2060,12 +2057,12 @@ ResultCode KPageTable::CheckMemoryStateContiguous(std::size_t* out_blocks_needed
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
|
||||
KMemoryAttribute* out_attr, std::size_t* out_blocks_needed,
|
||||
VAddr addr, std::size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr, KMemoryAttribute ignore_attr) const {
|
||||
Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
|
||||
KMemoryAttribute* out_attr, std::size_t* out_blocks_needed,
|
||||
VAddr addr, std::size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr, KMemoryAttribute ignore_attr) const {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
// Get information about the first block.
|
||||
@@ -2122,11 +2119,11 @@ ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermissi
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::LockMemoryAndOpen(KPageLinkedList* out_pg, PAddr* out_paddr, VAddr addr,
|
||||
size_t size, KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
||||
KMemoryPermission new_perm, KMemoryAttribute lock_attr) {
|
||||
Result KPageTable::LockMemoryAndOpen(KPageGroup* out_pg, PAddr* out_paddr, VAddr addr, size_t size,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
||||
KMemoryPermission new_perm, KMemoryAttribute lock_attr) {
|
||||
// Validate basic preconditions.
|
||||
ASSERT((lock_attr & attr) == KMemoryAttribute::None);
|
||||
ASSERT((lock_attr & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)) ==
|
||||
@@ -2180,11 +2177,11 @@ ResultCode KPageTable::LockMemoryAndOpen(KPageLinkedList* out_pg, PAddr* out_pad
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr, KMemoryPermission new_perm,
|
||||
KMemoryAttribute lock_attr, const KPageLinkedList* pg) {
|
||||
Result KPageTable::UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr, KMemoryPermission new_perm,
|
||||
KMemoryAttribute lock_attr, const KPageGroup* pg) {
|
||||
// Validate basic preconditions.
|
||||
ASSERT((attr_mask & lock_attr) == lock_attr);
|
||||
ASSERT((attr & lock_attr) == lock_attr);
|
||||
|
||||
@@ -33,51 +33,49 @@ public:
|
||||
explicit KPageTable(Core::System& system_);
|
||||
~KPageTable();
|
||||
|
||||
ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
|
||||
VAddr code_addr, std::size_t code_size,
|
||||
KMemoryManager::Pool pool);
|
||||
ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state,
|
||||
KMemoryPermission perm);
|
||||
ResultCode MapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size);
|
||||
ResultCode UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size,
|
||||
ICacheInvalidationStrategy icache_invalidation_strategy);
|
||||
ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table,
|
||||
VAddr src_addr);
|
||||
ResultCode MapPhysicalMemory(VAddr addr, std::size_t size);
|
||||
ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size);
|
||||
ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
|
||||
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
|
||||
ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
|
||||
KMemoryPermission perm);
|
||||
ResultCode MapPages(VAddr* out_addr, std::size_t num_pages, std::size_t alignment,
|
||||
PAddr phys_addr, KMemoryState state, KMemoryPermission perm) {
|
||||
Result InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
|
||||
VAddr code_addr, std::size_t code_size, KMemoryManager::Pool pool);
|
||||
Result MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state,
|
||||
KMemoryPermission perm);
|
||||
Result MapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size);
|
||||
Result UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size,
|
||||
ICacheInvalidationStrategy icache_invalidation_strategy);
|
||||
Result UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table,
|
||||
VAddr src_addr);
|
||||
Result MapPhysicalMemory(VAddr addr, std::size_t size);
|
||||
Result UnmapPhysicalMemory(VAddr addr, std::size_t size);
|
||||
Result MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
|
||||
Result UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
|
||||
Result MapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state,
|
||||
KMemoryPermission perm);
|
||||
Result MapPages(VAddr* out_addr, std::size_t num_pages, std::size_t alignment, PAddr phys_addr,
|
||||
KMemoryState state, KMemoryPermission perm) {
|
||||
return this->MapPages(out_addr, num_pages, alignment, phys_addr, true,
|
||||
this->GetRegionAddress(state), this->GetRegionSize(state) / PageSize,
|
||||
state, perm);
|
||||
}
|
||||
ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state);
|
||||
ResultCode UnmapPages(VAddr address, std::size_t num_pages, KMemoryState state);
|
||||
ResultCode SetProcessMemoryPermission(VAddr addr, std::size_t size,
|
||||
Svc::MemoryPermission svc_perm);
|
||||
Result UnmapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state);
|
||||
Result UnmapPages(VAddr address, std::size_t num_pages, KMemoryState state);
|
||||
Result SetProcessMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission svc_perm);
|
||||
KMemoryInfo QueryInfo(VAddr addr);
|
||||
ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
|
||||
ResultCode ResetTransferMemory(VAddr addr, std::size_t size);
|
||||
ResultCode SetMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission perm);
|
||||
ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask, u32 attr);
|
||||
ResultCode SetMaxHeapSize(std::size_t size);
|
||||
ResultCode SetHeapSize(VAddr* out, std::size_t size);
|
||||
Result ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
|
||||
Result ResetTransferMemory(VAddr addr, std::size_t size);
|
||||
Result SetMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission perm);
|
||||
Result SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask, u32 attr);
|
||||
Result SetMaxHeapSize(std::size_t size);
|
||||
Result SetHeapSize(VAddr* out, std::size_t size);
|
||||
ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align,
|
||||
bool is_map_only, VAddr region_start,
|
||||
std::size_t region_num_pages, KMemoryState state,
|
||||
KMemoryPermission perm, PAddr map_addr = 0);
|
||||
ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size);
|
||||
ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size);
|
||||
ResultCode LockForCodeMemory(KPageLinkedList* out, VAddr addr, std::size_t size);
|
||||
ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size, const KPageLinkedList& pg);
|
||||
ResultCode MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr);
|
||||
Result LockForDeviceAddressSpace(VAddr addr, std::size_t size);
|
||||
Result UnlockForDeviceAddressSpace(VAddr addr, std::size_t size);
|
||||
Result LockForCodeMemory(KPageGroup* out, VAddr addr, std::size_t size);
|
||||
Result UnlockForCodeMemory(VAddr addr, std::size_t size, const KPageGroup& pg);
|
||||
Result MakeAndOpenPageGroup(KPageGroup* out, VAddr address, size_t num_pages,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr);
|
||||
|
||||
Common::PageTable& PageTableImpl() {
|
||||
return page_table_impl;
|
||||
@@ -102,83 +100,78 @@ private:
|
||||
KMemoryAttribute::IpcLocked |
|
||||
KMemoryAttribute::DeviceShared;
|
||||
|
||||
ResultCode InitializeMemoryLayout(VAddr start, VAddr end);
|
||||
ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list,
|
||||
KMemoryPermission perm);
|
||||
ResultCode MapPages(VAddr* out_addr, std::size_t num_pages, std::size_t alignment,
|
||||
PAddr phys_addr, bool is_pa_valid, VAddr region_start,
|
||||
std::size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
|
||||
ResultCode UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list);
|
||||
Result InitializeMemoryLayout(VAddr start, VAddr end);
|
||||
Result MapPages(VAddr addr, const KPageGroup& page_linked_list, KMemoryPermission perm);
|
||||
Result MapPages(VAddr* out_addr, std::size_t num_pages, std::size_t alignment, PAddr phys_addr,
|
||||
bool is_pa_valid, VAddr region_start, std::size_t region_num_pages,
|
||||
KMemoryState state, KMemoryPermission perm);
|
||||
Result UnmapPages(VAddr addr, const KPageGroup& page_linked_list);
|
||||
bool IsRegionMapped(VAddr address, u64 size);
|
||||
bool IsRegionContiguous(VAddr addr, u64 size) const;
|
||||
void AddRegionToPages(VAddr start, std::size_t num_pages, KPageLinkedList& page_linked_list);
|
||||
void AddRegionToPages(VAddr start, std::size_t num_pages, KPageGroup& page_linked_list);
|
||||
KMemoryInfo QueryInfoImpl(VAddr addr);
|
||||
VAddr AllocateVirtualMemory(VAddr start, std::size_t region_num_pages, u64 needed_num_pages,
|
||||
std::size_t align);
|
||||
ResultCode Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group,
|
||||
OperationType operation);
|
||||
ResultCode Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm,
|
||||
OperationType operation, PAddr map_addr = 0);
|
||||
Result Operate(VAddr addr, std::size_t num_pages, const KPageGroup& page_group,
|
||||
OperationType operation);
|
||||
Result Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm,
|
||||
OperationType operation, PAddr map_addr = 0);
|
||||
VAddr GetRegionAddress(KMemoryState state) const;
|
||||
std::size_t GetRegionSize(KMemoryState state) const;
|
||||
|
||||
VAddr FindFreeArea(VAddr region_start, std::size_t region_num_pages, std::size_t num_pages,
|
||||
std::size_t alignment, std::size_t offset, std::size_t guard_pages);
|
||||
|
||||
ResultCode CheckMemoryStateContiguous(std::size_t* out_blocks_needed, VAddr addr,
|
||||
std::size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr) const;
|
||||
ResultCode CheckMemoryStateContiguous(VAddr addr, std::size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr) const {
|
||||
Result CheckMemoryStateContiguous(std::size_t* out_blocks_needed, VAddr addr, std::size_t size,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
|
||||
Result CheckMemoryStateContiguous(VAddr addr, std::size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr) const {
|
||||
return this->CheckMemoryStateContiguous(nullptr, addr, size, state_mask, state, perm_mask,
|
||||
perm, attr_mask, attr);
|
||||
}
|
||||
|
||||
ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr) const;
|
||||
ResultCode CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
|
||||
KMemoryAttribute* out_attr, std::size_t* out_blocks_needed,
|
||||
VAddr addr, std::size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr,
|
||||
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const;
|
||||
ResultCode CheckMemoryState(std::size_t* out_blocks_needed, VAddr addr, std::size_t size,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
||||
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const {
|
||||
Result CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
|
||||
Result CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
|
||||
KMemoryAttribute* out_attr, std::size_t* out_blocks_needed, VAddr addr,
|
||||
std::size_t size, KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
||||
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const;
|
||||
Result CheckMemoryState(std::size_t* out_blocks_needed, VAddr addr, std::size_t size,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
||||
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const {
|
||||
return CheckMemoryState(nullptr, nullptr, nullptr, out_blocks_needed, addr, size,
|
||||
state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr);
|
||||
}
|
||||
ResultCode CheckMemoryState(VAddr addr, std::size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask,
|
||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||
KMemoryAttribute attr,
|
||||
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const {
|
||||
Result CheckMemoryState(VAddr addr, std::size_t size, KMemoryState state_mask,
|
||||
KMemoryState state, KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
||||
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const {
|
||||
return this->CheckMemoryState(nullptr, addr, size, state_mask, state, perm_mask, perm,
|
||||
attr_mask, attr, ignore_attr);
|
||||
}
|
||||
|
||||
ResultCode LockMemoryAndOpen(KPageLinkedList* out_pg, PAddr* out_paddr, VAddr addr, size_t size,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
||||
KMemoryPermission new_perm, KMemoryAttribute lock_attr);
|
||||
ResultCode UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
||||
KMemoryPermission new_perm, KMemoryAttribute lock_attr,
|
||||
const KPageLinkedList* pg);
|
||||
Result LockMemoryAndOpen(KPageGroup* out_pg, PAddr* out_paddr, VAddr addr, size_t size,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
||||
KMemoryPermission new_perm, KMemoryAttribute lock_attr);
|
||||
Result UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
||||
KMemoryPermission new_perm, KMemoryAttribute lock_attr,
|
||||
const KPageGroup* pg);
|
||||
|
||||
ResultCode MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages);
|
||||
bool IsValidPageGroup(const KPageLinkedList& pg, VAddr addr, size_t num_pages);
|
||||
Result MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages);
|
||||
bool IsValidPageGroup(const KPageGroup& pg, VAddr addr, size_t num_pages);
|
||||
|
||||
bool IsLockedByCurrentThread() const {
|
||||
return general_lock.IsLockedByCurrentThread();
|
||||
|
||||
@@ -50,7 +50,7 @@ bool KPort::IsServerClosed() const {
|
||||
return state == State::ServerClosed;
|
||||
}
|
||||
|
||||
ResultCode KPort::EnqueueSession(KServerSession* session) {
|
||||
Result KPort::EnqueueSession(KServerSession* session) {
|
||||
KScopedSchedulerLock sl{kernel};
|
||||
|
||||
R_UNLESS(state == State::Normal, ResultPortClosed);
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
|
||||
bool IsServerClosed() const;
|
||||
|
||||
ResultCode EnqueueSession(KServerSession* session);
|
||||
Result EnqueueSession(KServerSession* session);
|
||||
|
||||
KClientPort& GetClientPort() {
|
||||
return client;
|
||||
|
||||
@@ -67,8 +67,8 @@ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::string process_name,
|
||||
ProcessType type, KResourceLimit* res_limit) {
|
||||
Result KProcess::Initialize(KProcess* process, Core::System& system, std::string process_name,
|
||||
ProcessType type, KResourceLimit* res_limit) {
|
||||
auto& kernel = system.Kernel();
|
||||
|
||||
process->name = std::move(process_name);
|
||||
@@ -161,7 +161,7 @@ bool KProcess::ReleaseUserException(KThread* thread) {
|
||||
std::addressof(num_waiters),
|
||||
reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
|
||||
next != nullptr) {
|
||||
next->SetState(ThreadState::Runnable);
|
||||
next->EndWait(ResultSuccess);
|
||||
}
|
||||
|
||||
KScheduler::SetSchedulerUpdateNeeded(kernel);
|
||||
@@ -219,8 +219,8 @@ void KProcess::UnpinThread(KThread* thread) {
|
||||
KScheduler::SetSchedulerUpdateNeeded(kernel);
|
||||
}
|
||||
|
||||
ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
|
||||
[[maybe_unused]] size_t size) {
|
||||
Result KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
|
||||
[[maybe_unused]] size_t size) {
|
||||
// Lock ourselves, to prevent concurrent access.
|
||||
KScopedLightLock lk(state_lock);
|
||||
|
||||
@@ -284,7 +284,7 @@ void KProcess::UnregisterThread(KThread* thread) {
|
||||
thread_list.remove(thread);
|
||||
}
|
||||
|
||||
ResultCode KProcess::Reset() {
|
||||
Result KProcess::Reset() {
|
||||
// Lock the process and the scheduler.
|
||||
KScopedLightLock lk(state_lock);
|
||||
KScopedSchedulerLock sl{kernel};
|
||||
@@ -298,7 +298,7 @@ ResultCode KProcess::Reset() {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KProcess::SetActivity(ProcessActivity activity) {
|
||||
Result KProcess::SetActivity(ProcessActivity activity) {
|
||||
// Lock ourselves and the scheduler.
|
||||
KScopedLightLock lk{state_lock};
|
||||
KScopedLightLock list_lk{list_lock};
|
||||
@@ -342,8 +342,7 @@ ResultCode KProcess::SetActivity(ProcessActivity activity) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
|
||||
std::size_t code_size) {
|
||||
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size) {
|
||||
program_id = metadata.GetTitleID();
|
||||
ideal_core = metadata.GetMainThreadCore();
|
||||
is_64bit_process = metadata.Is64BitProgram();
|
||||
@@ -358,24 +357,24 @@ ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
|
||||
return ResultLimitReached;
|
||||
}
|
||||
// Initialize proces address space
|
||||
if (const ResultCode result{
|
||||
page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false, 0x8000000,
|
||||
code_size, KMemoryManager::Pool::Application)};
|
||||
if (const Result result{page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false,
|
||||
0x8000000, code_size,
|
||||
KMemoryManager::Pool::Application)};
|
||||
result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Map process code region
|
||||
if (const ResultCode result{page_table->MapProcessCode(page_table->GetCodeRegionStart(),
|
||||
code_size / PageSize, KMemoryState::Code,
|
||||
KMemoryPermission::None)};
|
||||
if (const Result result{page_table->MapProcessCode(page_table->GetCodeRegionStart(),
|
||||
code_size / PageSize, KMemoryState::Code,
|
||||
KMemoryPermission::None)};
|
||||
result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Initialize process capabilities
|
||||
const auto& caps{metadata.GetKernelCapabilities()};
|
||||
if (const ResultCode result{
|
||||
if (const Result result{
|
||||
capabilities.InitializeForUserProcess(caps.data(), caps.size(), *page_table)};
|
||||
result.IsError()) {
|
||||
return result;
|
||||
@@ -482,7 +481,7 @@ void KProcess::Finalize() {
|
||||
KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask>::Finalize();
|
||||
}
|
||||
|
||||
ResultCode KProcess::CreateThreadLocalRegion(VAddr* out) {
|
||||
Result KProcess::CreateThreadLocalRegion(VAddr* out) {
|
||||
KThreadLocalPage* tlp = nullptr;
|
||||
VAddr tlr = 0;
|
||||
|
||||
@@ -533,7 +532,7 @@ ResultCode KProcess::CreateThreadLocalRegion(VAddr* out) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KProcess::DeleteThreadLocalRegion(VAddr addr) {
|
||||
Result KProcess::DeleteThreadLocalRegion(VAddr addr) {
|
||||
KThreadLocalPage* page_to_free = nullptr;
|
||||
|
||||
// Release the region.
|
||||
@@ -664,7 +663,7 @@ void KProcess::ChangeStatus(ProcessStatus new_status) {
|
||||
NotifyAvailable();
|
||||
}
|
||||
|
||||
ResultCode KProcess::AllocateMainThreadStack(std::size_t stack_size) {
|
||||
Result KProcess::AllocateMainThreadStack(std::size_t stack_size) {
|
||||
ASSERT(stack_size);
|
||||
|
||||
// The kernel always ensures that the given stack size is page aligned.
|
||||
|
||||
@@ -110,8 +110,8 @@ public:
|
||||
|
||||
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
|
||||
|
||||
static ResultCode Initialize(KProcess* process, Core::System& system, std::string process_name,
|
||||
ProcessType type, KResourceLimit* res_limit);
|
||||
static Result Initialize(KProcess* process, Core::System& system, std::string process_name,
|
||||
ProcessType type, KResourceLimit* res_limit);
|
||||
|
||||
/// Gets a reference to the process' page table.
|
||||
KPageTable& PageTable() {
|
||||
@@ -133,11 +133,11 @@ public:
|
||||
return handle_table;
|
||||
}
|
||||
|
||||
ResultCode SignalToAddress(VAddr address) {
|
||||
Result SignalToAddress(VAddr address) {
|
||||
return condition_var.SignalToAddress(address);
|
||||
}
|
||||
|
||||
ResultCode WaitForAddress(Handle handle, VAddr address, u32 tag) {
|
||||
Result WaitForAddress(Handle handle, VAddr address, u32 tag) {
|
||||
return condition_var.WaitForAddress(handle, address, tag);
|
||||
}
|
||||
|
||||
@@ -145,17 +145,16 @@ public:
|
||||
return condition_var.Signal(cv_key, count);
|
||||
}
|
||||
|
||||
ResultCode WaitConditionVariable(VAddr address, u64 cv_key, u32 tag, s64 ns) {
|
||||
Result WaitConditionVariable(VAddr address, u64 cv_key, u32 tag, s64 ns) {
|
||||
return condition_var.Wait(address, cv_key, tag, ns);
|
||||
}
|
||||
|
||||
ResultCode SignalAddressArbiter(VAddr address, Svc::SignalType signal_type, s32 value,
|
||||
s32 count) {
|
||||
Result SignalAddressArbiter(VAddr address, Svc::SignalType signal_type, s32 value, s32 count) {
|
||||
return address_arbiter.SignalToAddress(address, signal_type, value, count);
|
||||
}
|
||||
|
||||
ResultCode WaitAddressArbiter(VAddr address, Svc::ArbitrationType arb_type, s32 value,
|
||||
s64 timeout) {
|
||||
Result WaitAddressArbiter(VAddr address, Svc::ArbitrationType arb_type, s32 value,
|
||||
s64 timeout) {
|
||||
return address_arbiter.WaitForAddress(address, arb_type, value, timeout);
|
||||
}
|
||||
|
||||
@@ -322,7 +321,7 @@ public:
|
||||
/// @pre The process must be in a signaled state. If this is called on a
|
||||
/// process instance that is not signaled, ERR_INVALID_STATE will be
|
||||
/// returned.
|
||||
ResultCode Reset();
|
||||
Result Reset();
|
||||
|
||||
/**
|
||||
* Loads process-specifics configuration info with metadata provided
|
||||
@@ -333,7 +332,7 @@ public:
|
||||
* @returns ResultSuccess if all relevant metadata was able to be
|
||||
* loaded and parsed. Otherwise, an error code is returned.
|
||||
*/
|
||||
ResultCode LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size);
|
||||
Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size);
|
||||
|
||||
/**
|
||||
* Starts the main application thread for this process.
|
||||
@@ -367,7 +366,7 @@ public:
|
||||
|
||||
void DoWorkerTaskImpl();
|
||||
|
||||
ResultCode SetActivity(ProcessActivity activity);
|
||||
Result SetActivity(ProcessActivity activity);
|
||||
|
||||
void PinCurrentThread(s32 core_id);
|
||||
void UnpinCurrentThread(s32 core_id);
|
||||
@@ -377,17 +376,17 @@ public:
|
||||
return state_lock;
|
||||
}
|
||||
|
||||
ResultCode AddSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
|
||||
Result AddSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
|
||||
void RemoveSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Thread-local storage management
|
||||
|
||||
// Marks the next available region as used and returns the address of the slot.
|
||||
[[nodiscard]] ResultCode CreateThreadLocalRegion(VAddr* out);
|
||||
[[nodiscard]] Result CreateThreadLocalRegion(VAddr* out);
|
||||
|
||||
// Frees a used TLS slot identified by the given address
|
||||
ResultCode DeleteThreadLocalRegion(VAddr addr);
|
||||
Result DeleteThreadLocalRegion(VAddr addr);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Debug watchpoint management
|
||||
@@ -423,7 +422,7 @@ private:
|
||||
void ChangeStatus(ProcessStatus new_status);
|
||||
|
||||
/// Allocates the main thread stack for the process, given the stack size in bytes.
|
||||
ResultCode AllocateMainThreadStack(std::size_t stack_size);
|
||||
Result AllocateMainThreadStack(std::size_t stack_size);
|
||||
|
||||
/// Memory manager for this process
|
||||
std::unique_ptr<KPageTable> page_table;
|
||||
|
||||
@@ -27,7 +27,7 @@ void KReadableEvent::Destroy() {
|
||||
}
|
||||
}
|
||||
|
||||
ResultCode KReadableEvent::Signal() {
|
||||
Result KReadableEvent::Signal() {
|
||||
KScopedSchedulerLock lk{kernel};
|
||||
|
||||
if (!is_signaled) {
|
||||
@@ -38,13 +38,13 @@ ResultCode KReadableEvent::Signal() {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KReadableEvent::Clear() {
|
||||
Result KReadableEvent::Clear() {
|
||||
Reset();
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KReadableEvent::Reset() {
|
||||
Result KReadableEvent::Reset() {
|
||||
KScopedSchedulerLock lk{kernel};
|
||||
|
||||
if (!is_signaled) {
|
||||
|
||||
@@ -33,9 +33,9 @@ public:
|
||||
bool IsSignaled() const override;
|
||||
void Destroy() override;
|
||||
|
||||
ResultCode Signal();
|
||||
ResultCode Clear();
|
||||
ResultCode Reset();
|
||||
Result Signal();
|
||||
Result Clear();
|
||||
Result Reset();
|
||||
|
||||
private:
|
||||
bool is_signaled{};
|
||||
|
||||
@@ -73,7 +73,7 @@ s64 KResourceLimit::GetFreeValue(LimitableResource which) const {
|
||||
return value;
|
||||
}
|
||||
|
||||
ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
|
||||
Result KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
|
||||
const auto index = static_cast<std::size_t>(which);
|
||||
KScopedLightLock lk(lock);
|
||||
R_UNLESS(current_values[index] <= value, ResultInvalidState);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "core/hle/kernel/k_light_condition_variable.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
|
||||
union ResultCode;
|
||||
union Result;
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
s64 GetPeakValue(LimitableResource which) const;
|
||||
s64 GetFreeValue(LimitableResource which) const;
|
||||
|
||||
ResultCode SetLimitValue(LimitableResource which, s64 value);
|
||||
Result SetLimitValue(LimitableResource which, s64 value);
|
||||
|
||||
bool Reserve(LimitableResource which, s64 value);
|
||||
bool Reserve(LimitableResource which, s64 value, s64 timeout);
|
||||
|
||||
@@ -622,7 +622,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
|
||||
}
|
||||
|
||||
KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} {
|
||||
switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
|
||||
switch_fiber = std::make_shared<Common::Fiber>([this] { SwitchToCurrent(); });
|
||||
state.needs_scheduling.store(true);
|
||||
state.interrupt_task_thread_runnable = false;
|
||||
state.should_count_idle = false;
|
||||
@@ -778,11 +778,6 @@ void KScheduler::ScheduleImpl() {
|
||||
next_scheduler.SwitchContextStep2();
|
||||
}
|
||||
|
||||
void KScheduler::OnSwitch(void* this_scheduler) {
|
||||
KScheduler* sched = static_cast<KScheduler*>(this_scheduler);
|
||||
sched->SwitchToCurrent();
|
||||
}
|
||||
|
||||
void KScheduler::SwitchToCurrent() {
|
||||
while (true) {
|
||||
{
|
||||
|
||||
@@ -55,6 +55,11 @@ public:
|
||||
return idle_thread;
|
||||
}
|
||||
|
||||
/// Returns true if the scheduler is idle
|
||||
[[nodiscard]] bool IsIdle() const {
|
||||
return GetSchedulerCurrentThread() == idle_thread;
|
||||
}
|
||||
|
||||
/// Gets the timestamp for the last context switch in ticks.
|
||||
[[nodiscard]] u64 GetLastContextSwitchTicks() const;
|
||||
|
||||
@@ -165,7 +170,6 @@ private:
|
||||
*/
|
||||
void UpdateLastContextSwitchTime(KThread* thread, KProcess* process);
|
||||
|
||||
static void OnSwitch(void* this_scheduler);
|
||||
void SwitchToCurrent();
|
||||
|
||||
KThread* prev_thread{};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user