Compare commits
462 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ccf2a7b82 | ||
|
|
cfac942e63 | ||
|
|
b9b23c98ff | ||
|
|
50048d9f5a | ||
|
|
ca7ca2919c | ||
|
|
b73ea457cc | ||
|
|
2c679cda51 | ||
|
|
b46e615551 | ||
|
|
7ea07c6063 | ||
|
|
cf0d01a5d7 | ||
|
|
00f0827a26 | ||
|
|
e70f16fff7 | ||
|
|
1edf018319 | ||
|
|
ed74a3cb8b | ||
|
|
75561d190a | ||
|
|
9b2d38582f | ||
|
|
e3608578e4 | ||
|
|
665b7e8e18 | ||
|
|
cfd885163f | ||
|
|
2eb4d27c48 | ||
|
|
21c0b4dec8 | ||
|
|
84928e6d67 | ||
|
|
46e2ca5475 | ||
|
|
944c07ac7d | ||
|
|
f95bdb5088 | ||
|
|
180f22f17e | ||
|
|
37eaf39b44 | ||
|
|
90c9d703ba | ||
|
|
bb248a2710 | ||
|
|
f97e206348 | ||
|
|
91300bdfb2 | ||
|
|
0fa039d8d0 | ||
|
|
e5159cfb84 | ||
|
|
4b80dd23a4 | ||
|
|
88cd5e888e | ||
|
|
6640f631e2 | ||
|
|
d61199721d | ||
|
|
ef3c0f54d0 | ||
|
|
c03fb00ac1 | ||
|
|
5d645c6dd9 | ||
|
|
9218e347cd | ||
|
|
5a4564bd8e | ||
|
|
e86d2e2e5b | ||
|
|
68c9c9222d | ||
|
|
3c0280cf66 | ||
|
|
bb06b98d81 | ||
|
|
16bf791939 | ||
|
|
b3d7180164 | ||
|
|
cf9cc41478 | ||
|
|
f5d416e071 | ||
|
|
6f2a8fbb13 | ||
|
|
1a2d90ab09 | ||
|
|
59f110ef31 | ||
|
|
d4f8fe24d9 | ||
|
|
c70404eab5 | ||
|
|
e7ab0e9127 | ||
|
|
11e9bee91d | ||
|
|
943f6da1ac | ||
|
|
2b1fcc8a14 | ||
|
|
e3b2539986 | ||
|
|
8cd3d9be26 | ||
|
|
b6dcb1ae4d | ||
|
|
228e58d0a5 | ||
|
|
87b4c1ac5e | ||
|
|
3e7d37301a | ||
|
|
d0e200a894 | ||
|
|
819d229e76 | ||
|
|
195b54602f | ||
|
|
f4c15db9e8 | ||
|
|
de23847184 | ||
|
|
69215b5a55 | ||
|
|
c03b8c4c19 | ||
|
|
75e7b45d69 | ||
|
|
f78ef617b6 | ||
|
|
f49a04ba39 | ||
|
|
938d6dca30 | ||
|
|
9ffc60b5b3 | ||
|
|
dbcff5d574 | ||
|
|
9a17b20896 | ||
|
|
9c3461604c | ||
|
|
ada79fa8ad | ||
|
|
bc32474901 | ||
|
|
ed2fedac13 | ||
|
|
7a82d6f394 | ||
|
|
486c3e6085 | ||
|
|
922d8c6cb4 | ||
|
|
fd34732e26 | ||
|
|
317f1263fb | ||
|
|
58a0c13e34 | ||
|
|
6fb29764d6 | ||
|
|
784d2b6c3d | ||
|
|
0adb54abc1 | ||
|
|
73ee85e9ae | ||
|
|
911fafb967 | ||
|
|
91ec251c4a | ||
|
|
d49efbfb4a | ||
|
|
13dda1d8ed | ||
|
|
2318c394a8 | ||
|
|
d9c4d64ed5 | ||
|
|
428d8098a7 | ||
|
|
17255cd835 | ||
|
|
3039211c20 | ||
|
|
c9c4208c4a | ||
|
|
aa83639b78 | ||
|
|
4d2da5a40a | ||
|
|
b94b08fa6f | ||
|
|
d81d4a0f68 | ||
|
|
7e650088dd | ||
|
|
05235ccaa9 | ||
|
|
5f01ec338e | ||
|
|
d00ca5c6c8 | ||
|
|
d184224e8f | ||
|
|
f8b1e53369 | ||
|
|
2aebbe9bf9 | ||
|
|
fadf66993c | ||
|
|
9e98100c94 | ||
|
|
6fd247c84a | ||
|
|
18cdbdafa2 | ||
|
|
594328f494 | ||
|
|
9175bffbdb | ||
|
|
ac3775e6ae | ||
|
|
b54bd3f018 | ||
|
|
3bd5f01240 | ||
|
|
a6ed792ac4 | ||
|
|
3ff0c70c72 | ||
|
|
4452195d41 | ||
|
|
8e9a1e4249 | ||
|
|
dfddb12255 | ||
|
|
f9ad88f9d7 | ||
|
|
edf8c0a545 | ||
|
|
209a0dfa35 | ||
|
|
27033de2e5 | ||
|
|
30c984dc97 | ||
|
|
256e5c9583 | ||
|
|
b42ca9888d | ||
|
|
ffd9a1f3ef | ||
|
|
2437ca04d7 | ||
|
|
aa61478d8c | ||
|
|
e310d943b8 | ||
|
|
212b148923 | ||
|
|
81e7e63080 | ||
|
|
e09ee0ff23 | ||
|
|
bc6972caf9 | ||
|
|
ce04ab38bb | ||
|
|
3356ea5bc2 | ||
|
|
0a7f09a99b | ||
|
|
634b78a4c6 | ||
|
|
7fdc644c44 | ||
|
|
683c4e523f | ||
|
|
5e4c227608 | ||
|
|
f417be9d3b | ||
|
|
22324e3ef1 | ||
|
|
d77d1a0207 | ||
|
|
cad4f2ed29 | ||
|
|
a059b9eed4 | ||
|
|
242273788a | ||
|
|
5993133d5e | ||
|
|
d5cce86431 | ||
|
|
88c263ee8e | ||
|
|
a47aaa7f1b | ||
|
|
8d6342384b | ||
|
|
21ea8b2fcb | ||
|
|
52340c3294 | ||
|
|
a652e58c54 | ||
|
|
fb85d5670d | ||
|
|
6f1720a5b7 | ||
|
|
865025f612 | ||
|
|
1975d32f2d | ||
|
|
4cf64f8e09 | ||
|
|
69265e4504 | ||
|
|
5f877d9458 | ||
|
|
e6c60b419c | ||
|
|
a6fb6ccc83 | ||
|
|
fc975e9021 | ||
|
|
b01cce716e | ||
|
|
9b6d993e52 | ||
|
|
ec1c69258a | ||
|
|
0f83c8dffa | ||
|
|
5db1b54b58 | ||
|
|
48ce5880a0 | ||
|
|
c212fc9b2c | ||
|
|
d6d809db87 | ||
|
|
c5129a3a58 | ||
|
|
c4d549919f | ||
|
|
dadcf317dc | ||
|
|
8b933e77cd | ||
|
|
3e8e335a5c | ||
|
|
940a71089d | ||
|
|
9ef45f00bf | ||
|
|
c823cf6594 | ||
|
|
716fbaef74 | ||
|
|
d4bcd006b2 | ||
|
|
fd12788967 | ||
|
|
53afe47cec | ||
|
|
5235b053b4 | ||
|
|
b6408e9671 | ||
|
|
e43ba3acd4 | ||
|
|
e3c45b4338 | ||
|
|
175fe8aaeb | ||
|
|
6d28d288a3 | ||
|
|
ba165b1092 | ||
|
|
c56d893e77 | ||
|
|
c4d03f0154 | ||
|
|
7cb17834c7 | ||
|
|
f3317cf2db | ||
|
|
daca045fcd | ||
|
|
f69d3a6351 | ||
|
|
5907619a04 | ||
|
|
9567b3a293 | ||
|
|
c6f3831320 | ||
|
|
8abf0add04 | ||
|
|
5b6571c170 | ||
|
|
c27b81cb85 | ||
|
|
0e9a17b029 | ||
|
|
f3c18d622e | ||
|
|
8bdef4f951 | ||
|
|
d955944869 | ||
|
|
bf1829a717 | ||
|
|
a97120efc1 | ||
|
|
4ef3329f81 | ||
|
|
70c6506a7e | ||
|
|
6ca7241bd9 | ||
|
|
495a8d8d95 | ||
|
|
3a08c3207b | ||
|
|
0964444529 | ||
|
|
c63e68c480 | ||
|
|
4aefd45193 | ||
|
|
6743982d28 | ||
|
|
57db3f6763 | ||
|
|
a206418846 | ||
|
|
10c4f23953 | ||
|
|
9e15193ef8 | ||
|
|
5d0dca73c6 | ||
|
|
08b270676b | ||
|
|
a6f7a44aab | ||
|
|
1230a0e7ce | ||
|
|
1f72bb733f | ||
|
|
d4df803b2b | ||
|
|
5321cdd276 | ||
|
|
28bffb1ffa | ||
|
|
fe700e1856 | ||
|
|
c6f9e651b2 | ||
|
|
71aa9d0877 | ||
|
|
b7d412c99b | ||
|
|
bd81a03d9d | ||
|
|
06b363c9b5 | ||
|
|
002ecbea19 | ||
|
|
7632a7d6d2 | ||
|
|
e64c41efe8 | ||
|
|
2bcb8a20b4 | ||
|
|
03746be097 | ||
|
|
de93507a5a | ||
|
|
4aa081b4e7 | ||
|
|
95261639fb | ||
|
|
75a8b304d4 | ||
|
|
fb420358a9 | ||
|
|
79e54abe19 | ||
|
|
19632d2421 | ||
|
|
d672c6e759 | ||
|
|
69a2003a8e | ||
|
|
91e239d66f | ||
|
|
2be32eb3d2 | ||
|
|
c52233ec8b | ||
|
|
9a3737120d | ||
|
|
565fce71b1 | ||
|
|
2156e52014 | ||
|
|
b77b4b76bb | ||
|
|
0b91087a1e | ||
|
|
4e462d1fd7 | ||
|
|
851c01c45e | ||
|
|
1aa2b99a98 | ||
|
|
c40cff454d | ||
|
|
f0db2e3ef3 | ||
|
|
e25a7891e9 | ||
|
|
daf5b8c61b | ||
|
|
ca5638a142 | ||
|
|
78574e7a47 | ||
|
|
94db649205 | ||
|
|
ee2252b6e1 | ||
|
|
53f746fa9a | ||
|
|
0592869076 | ||
|
|
1a3ff252a4 | ||
|
|
3091b40691 | ||
|
|
9db2c734c9 | ||
|
|
3fe542cf60 | ||
|
|
b3118ee316 | ||
|
|
8df9449bb8 | ||
|
|
b2fbcaae30 | ||
|
|
f1e5314f1a | ||
|
|
e140e2ebc6 | ||
|
|
021d28c9b8 | ||
|
|
4fad91ca45 | ||
|
|
9cab042674 | ||
|
|
701ce1c9d0 | ||
|
|
e4ff140b99 | ||
|
|
a91d3fc639 | ||
|
|
b5889cbd6f | ||
|
|
68b707711a | ||
|
|
01100f8afd | ||
|
|
4c36b78567 | ||
|
|
623b2e4b8f | ||
|
|
92c274d4bb | ||
|
|
da0c3bc658 | ||
|
|
788497fd9d | ||
|
|
650d9b1044 | ||
|
|
08cdcc2871 | ||
|
|
a3eb91ed8c | ||
|
|
db4b2bc798 | ||
|
|
62c2404d3c | ||
|
|
cd38eadcc1 | ||
|
|
b6faea0dd2 | ||
|
|
40dc893c37 | ||
|
|
d74cb16535 | ||
|
|
f8be3f55da | ||
|
|
19f8f86bdb | ||
|
|
fbe8d1ceaa | ||
|
|
83b830eb2f | ||
|
|
4294062516 | ||
|
|
5bd5140bde | ||
|
|
2adb226b26 | ||
|
|
8f8049e846 | ||
|
|
a04d36c5a4 | ||
|
|
76452cd5b3 | ||
|
|
f6e2295055 | ||
|
|
80c9e4d3ab | ||
|
|
d9f6715d45 | ||
|
|
de3cfb1d37 | ||
|
|
d273bec68f | ||
|
|
f7540157e4 | ||
|
|
ec0bc3061e | ||
|
|
6cea62b756 | ||
|
|
e51d33f0ce | ||
|
|
c268ffd831 | ||
|
|
433b59c112 | ||
|
|
6b2bece81f | ||
|
|
54e9f9b6ed | ||
|
|
52e43734c4 | ||
|
|
fbfc347351 | ||
|
|
0cfbd3325b | ||
|
|
21d498bc06 | ||
|
|
be6b9e2d2b | ||
|
|
1b83f255c2 | ||
|
|
2654eb659e | ||
|
|
382fbbb198 | ||
|
|
819c21d99e | ||
|
|
b6a87b422e | ||
|
|
d0082de82a | ||
|
|
da91e6e4b6 | ||
|
|
13d626fc21 | ||
|
|
06d1c5a991 | ||
|
|
6fc562a9aa | ||
|
|
ef381e6924 | ||
|
|
367704aa82 | ||
|
|
3e96c367bd | ||
|
|
9186f76b07 | ||
|
|
fc64156533 | ||
|
|
a7c3275b8b | ||
|
|
c1e35d117c | ||
|
|
bec28d692d | ||
|
|
ef8245bed2 | ||
|
|
f43995ec53 | ||
|
|
abcbcb1b2a | ||
|
|
64613db605 | ||
|
|
90cbf89303 | ||
|
|
acf618afbc | ||
|
|
ae46ad48ed | ||
|
|
aa471274d9 | ||
|
|
1f3cc036da | ||
|
|
b67be7154d | ||
|
|
d28bb56c91 | ||
|
|
a9f58593d4 | ||
|
|
3283aa1e20 | ||
|
|
8a099ac99f | ||
|
|
773d955dfa | ||
|
|
4620ed47a3 | ||
|
|
bf561e4340 | ||
|
|
e3566e6c1d | ||
|
|
09caf8a756 | ||
|
|
f15c59a164 | ||
|
|
5c280e6ff0 | ||
|
|
1f4dfb3998 | ||
|
|
c9454c8422 | ||
|
|
6088898b02 | ||
|
|
a788c861bd | ||
|
|
ee2206a1b7 | ||
|
|
065f83c6c3 | ||
|
|
ee3f576495 | ||
|
|
4d293bb5cb | ||
|
|
76a2465655 | ||
|
|
b42595fa6b | ||
|
|
0faf7b17a1 | ||
|
|
382722b9c4 | ||
|
|
0d8ef2d3b9 | ||
|
|
612e1388df | ||
|
|
32a6ceb4e5 | ||
|
|
a4b0a8559c | ||
|
|
6d0551196d | ||
|
|
f2331a804a | ||
|
|
ea80e2bc57 | ||
|
|
83a2fb3c3a | ||
|
|
e2f2155dab | ||
|
|
c0b2b7020d | ||
|
|
66b73fd399 | ||
|
|
9cb4b7be40 | ||
|
|
598954436f | ||
|
|
b569641098 | ||
|
|
6300ccbc3c | ||
|
|
dffa1a872a | ||
|
|
ca96dc4676 | ||
|
|
93af663683 | ||
|
|
6df25e9c7b | ||
|
|
dae2449880 | ||
|
|
0032cf3818 | ||
|
|
0032821864 | ||
|
|
75d23a3679 | ||
|
|
58ad8dfac6 | ||
|
|
4667ed8e22 | ||
|
|
676172e20d | ||
|
|
d316d248ab | ||
|
|
b758c861b0 | ||
|
|
fec4eb9776 | ||
|
|
ca51f99840 | ||
|
|
13aa664f3f | ||
|
|
ad53b233c5 | ||
|
|
970d9e57c8 | ||
|
|
8676832064 | ||
|
|
fc436bb09b | ||
|
|
e1101d3e20 | ||
|
|
b47c0c8a80 | ||
|
|
dbf13f8169 | ||
|
|
cf6cdd20f8 | ||
|
|
c4ba717491 | ||
|
|
8c05dfaa61 | ||
|
|
e28a5b0d18 | ||
|
|
7c458311d3 | ||
|
|
b0aa8ad736 | ||
|
|
be6466d5c0 | ||
|
|
ef8be408d3 | ||
|
|
492040bd9c | ||
|
|
797e351bf8 | ||
|
|
c60b0b8432 | ||
|
|
a77e9a27b0 | ||
|
|
fd4e994de3 | ||
|
|
4841440382 | ||
|
|
189bd1980c | ||
|
|
ac3ba9a33e | ||
|
|
90d06acfed | ||
|
|
7af82ca022 | ||
|
|
fe392fff24 | ||
|
|
e28fd3d0a5 | ||
|
|
c4ac05c82c | ||
|
|
b117ca5fce | ||
|
|
04979560fb | ||
|
|
24abeb9a67 | ||
|
|
576ad9a012 | ||
|
|
c5047540c9 | ||
|
|
9ebc27234d | ||
|
|
bbb396d7f1 | ||
|
|
9ff72ca9f2 | ||
|
|
5f2d9f282a | ||
|
|
f2a2f818b6 | ||
|
|
c6a0ab9792 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -43,3 +43,6 @@
|
||||
[submodule "externals/zstd"]
|
||||
path = externals/zstd
|
||||
url = https://github.com/facebook/zstd
|
||||
[submodule "sirit"]
|
||||
path = externals/sirit
|
||||
url = https://github.com/ReinUsesLisp/sirit
|
||||
|
||||
@@ -24,7 +24,7 @@ matrix:
|
||||
- os: osx
|
||||
env: NAME="macos build"
|
||||
sudo: false
|
||||
osx_image: xcode10.1
|
||||
osx_image: xcode10.2
|
||||
install: "./.travis/macos/deps.sh"
|
||||
script: "./.travis/macos/build.sh"
|
||||
after_success: "./.travis/macos/upload.sh"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash -ex
|
||||
mkdir "$HOME/.ccache" || true
|
||||
docker run --env-file .travis/common/travis-ci.env -v $(pwd):/yuzu -v "$HOME/.ccache":/root/.ccache ubuntu:18.04 /bin/bash -ex /yuzu/.travis/linux-mingw/docker.sh
|
||||
docker run --env-file .travis/common/travis-ci.env -v $(pwd):/yuzu -v "$HOME/.ccache":/root/.ccache yuzuemu/build-environments:linux-mingw /bin/bash -ex /yuzu/.travis/linux-mingw/docker.sh
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
docker pull ubuntu:18.04
|
||||
docker pull yuzuemu/build-environments:linux-mingw
|
||||
|
||||
@@ -1,16 +1,6 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
cd /yuzu
|
||||
MINGW_PACKAGES="sdl2-mingw-w64 qt5base-mingw-w64 qt5tools-mingw-w64 libsamplerate-mingw-w64 qt5multimedia-mingw-w64"
|
||||
apt-get update
|
||||
apt-get install -y gpg wget git python3-pip python ccache g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 mingw-w64-tools cmake
|
||||
echo 'deb http://ppa.launchpad.net/tobydox/mingw-w64/ubuntu bionic main ' > /etc/apt/sources.list.d/extras.list
|
||||
apt-key adv --keyserver keyserver.ubuntu.com --recv '72931B477E22FEFD47F8DECE02FE5F12ADDE29B2'
|
||||
apt-get update
|
||||
apt-get install -y ${MINGW_PACKAGES}
|
||||
|
||||
# fix a problem in current MinGW headers
|
||||
wget -q https://raw.githubusercontent.com/Alexpux/mingw-w64/d0d7f784833bbb0b2d279310ddc6afb52fe47a46/mingw-w64-headers/crt/errno.h -O /usr/x86_64-w64-mingw32/include/errno.h
|
||||
# override Travis CI unreasonable ccache size
|
||||
echo 'max_size = 3.0G' > "$HOME/.ccache/ccache.conf"
|
||||
|
||||
@@ -23,8 +13,8 @@ echo '' >> /bin/cmd
|
||||
chmod +x /bin/cmd
|
||||
|
||||
mkdir build && cd build
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release
|
||||
make -j4
|
||||
cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release
|
||||
ninja
|
||||
|
||||
# Clean up the dirty hacks
|
||||
rm /bin/uname && mv /bin/uname1 /bin/uname
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
mkdir -p "$HOME/.ccache"
|
||||
docker run -e ENABLE_COMPATIBILITY_REPORTING --env-file .travis/common/travis-ci.env -v $(pwd):/yuzu -v "$HOME/.ccache":/root/.ccache ubuntu:18.04 /bin/bash /yuzu/.travis/linux/docker.sh
|
||||
docker run -e ENABLE_COMPATIBILITY_REPORTING --env-file .travis/common/travis-ci.env -v $(pwd):/yuzu -v "$HOME/.ccache":/root/.ccache yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.travis/linux/docker.sh
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
docker pull ubuntu:18.04
|
||||
docker pull yuzuemu/build-environments:linux-fresh
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
apt-get update
|
||||
apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev qtwebengine5-dev wget cmake ninja-build ccache
|
||||
|
||||
cd /yuzu
|
||||
|
||||
mkdir build && cd build
|
||||
cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -G Ninja
|
||||
cmake .. -G Ninja -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON
|
||||
ninja
|
||||
|
||||
ccache -s
|
||||
|
||||
@@ -7,6 +7,7 @@ export Qt5_DIR=$(brew --prefix)/opt/qt5
|
||||
export UNICORNDIR=$(pwd)/externals/unicorn
|
||||
export PATH="/usr/local/opt/ccache/libexec:$PATH"
|
||||
|
||||
# TODO: Build using ninja instead of make
|
||||
mkdir build && cd build
|
||||
cmake --version
|
||||
cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON
|
||||
|
||||
@@ -19,18 +19,6 @@ $(brew --prefix)/opt/qt5/bin/macdeployqt "${REV_NAME}/yuzu.app" -executable="${R
|
||||
# move libs into folder for deployment
|
||||
macpack "${REV_NAME}/yuzu-cmd" -d "libs"
|
||||
|
||||
# Make the yuzu.app application launch a debugging terminal.
|
||||
# Store away the actual binary
|
||||
mv ${REV_NAME}/yuzu.app/Contents/MacOS/yuzu ${REV_NAME}/yuzu.app/Contents/MacOS/yuzu-bin
|
||||
|
||||
cat > ${REV_NAME}/yuzu.app/Contents/MacOS/yuzu <<EOL
|
||||
#!/usr/bin/env bash
|
||||
cd "\`dirname "\$0"\`"
|
||||
chmod +x yuzu-bin
|
||||
open yuzu-bin --args "\$@"
|
||||
EOL
|
||||
# Content that will serve as the launching script for yuzu (within the .app folder)
|
||||
|
||||
# Make the launching script executable
|
||||
chmod +x ${REV_NAME}/yuzu.app/Contents/MacOS/yuzu
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ find_package(Threads REQUIRED)
|
||||
if (ENABLE_SDL2)
|
||||
if (YUZU_USE_BUNDLED_SDL2)
|
||||
# Detect toolchain and platform
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
|
||||
set(SDL2_VER "SDL2-2.0.8")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
|
||||
@@ -165,7 +165,7 @@ if (YUZU_USE_BUNDLED_UNICORN)
|
||||
if (MSVC)
|
||||
message(STATUS "unicorn not found, falling back to bundled")
|
||||
# Detect toolchain and platform
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
|
||||
set(UNICORN_VER "unicorn-yuzu")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled Unicorn binaries for your toolchain. Disable YUZU_USE_BUNDLED_UNICORN and provide your own.")
|
||||
@@ -233,7 +233,7 @@ endif()
|
||||
|
||||
if (ENABLE_QT)
|
||||
if (YUZU_USE_BUNDLED_QT)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
|
||||
set(QT_VER qt-5.12.0-msvc2017_64)
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.")
|
||||
|
||||
@@ -19,7 +19,7 @@ set(BUILD_VERSION "0")
|
||||
if (BUILD_REPOSITORY)
|
||||
# regex capture the string nightly or canary into CMAKE_MATCH_1
|
||||
string(REGEX MATCH "yuzu-emu/yuzu-?(.*)" OUTVAR ${BUILD_REPOSITORY})
|
||||
if (${CMAKE_MATCH_COUNT} GREATER 0)
|
||||
if ("${CMAKE_MATCH_COUNT}" GREATER 0)
|
||||
# capitalize the first letter of each word in the repo name.
|
||||
string(REPLACE "-" ";" REPO_NAME_LIST ${CMAKE_MATCH_1})
|
||||
foreach(WORD ${REPO_NAME_LIST})
|
||||
|
||||
13
externals/CMakeLists.txt
vendored
13
externals/CMakeLists.txt
vendored
@@ -7,6 +7,10 @@ include(DownloadExternals)
|
||||
add_library(catch-single-include INTERFACE)
|
||||
target_include_directories(catch-single-include INTERFACE catch/single_include)
|
||||
|
||||
# libfmt
|
||||
add_subdirectory(fmt)
|
||||
add_library(fmt::fmt ALIAS fmt)
|
||||
|
||||
# Dynarmic
|
||||
if (ARCHITECTURE_x86_64)
|
||||
set(DYNARMIC_TESTS OFF)
|
||||
@@ -14,10 +18,6 @@ if (ARCHITECTURE_x86_64)
|
||||
add_subdirectory(dynarmic)
|
||||
endif()
|
||||
|
||||
# libfmt
|
||||
add_subdirectory(fmt)
|
||||
add_library(fmt::fmt ALIAS fmt)
|
||||
|
||||
# getopt
|
||||
if (MSVC)
|
||||
add_subdirectory(getopt)
|
||||
@@ -72,6 +72,11 @@ if (USE_DISCORD_PRESENCE)
|
||||
target_include_directories(discord-rpc INTERFACE ./discord-rpc/include)
|
||||
endif()
|
||||
|
||||
# Sirit
|
||||
if (ENABLE_VULKAN)
|
||||
add_subdirectory(sirit)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
# LibreSSL
|
||||
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
|
||||
|
||||
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: 4e6848d1c9...2683a9a3e3
12
externals/glad/include/KHR/khrplatform.h
vendored
12
externals/glad/include/KHR/khrplatform.h
vendored
@@ -90,12 +90,20 @@
|
||||
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||
*/
|
||||
|
||||
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
|
||||
# define KHRONOS_STATIC 1
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APICALL
|
||||
*-------------------------------------------------------------------------
|
||||
* This precedes the return type of the function in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
#if defined(KHRONOS_STATIC)
|
||||
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
|
||||
* header compatible with static linking. */
|
||||
# define KHRONOS_APICALL
|
||||
#elif defined(_WIN32)
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
@@ -111,7 +119,7 @@
|
||||
* This follows the return type of the function and precedes the function
|
||||
* name in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(KHRONOS_STATIC)
|
||||
/* Win32 but not WinCE */
|
||||
# define KHRONOS_APIENTRY __stdcall
|
||||
#else
|
||||
|
||||
2388
externals/glad/include/glad/glad.h
vendored
2388
externals/glad/include/glad/glad.h
vendored
File diff suppressed because one or more lines are too long
1125
externals/glad/src/glad.c
vendored
1125
externals/glad/src/glad.c
vendored
File diff suppressed because one or more lines are too long
1
externals/sirit
vendored
Submodule
1
externals/sirit
vendored
Submodule
Submodule externals/sirit added at f7c4b07a7e
@@ -18,15 +18,32 @@ if (MSVC)
|
||||
# Avoid windows.h from including some usually unused libs like winsocks.h, since this might cause some redefinition errors.
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||
|
||||
# /W3 - Level 3 warnings
|
||||
# /MP - Multi-threaded compilation
|
||||
# /Zi - Output debugging information
|
||||
# /Zo - enhanced debug info for optimized builds
|
||||
# /permissive- - enables stricter C++ standards conformance checks
|
||||
# /EHsc - C++-only exception handling semantics
|
||||
# /Zc:throwingNew - let codegen assume `operator new` will never return null
|
||||
# /Zc:inline - let codegen omit inline functions in object files
|
||||
add_compile_options(/W3 /MP /Zi /Zo /permissive- /EHsc /std:c++latest /Zc:throwingNew,inline)
|
||||
# Ensure that projects build with Unicode support.
|
||||
add_definitions(-DUNICODE -D_UNICODE)
|
||||
|
||||
# /W3 - Level 3 warnings
|
||||
# /MP - Multi-threaded compilation
|
||||
# /Zi - Output debugging information
|
||||
# /Zo - Enhanced debug info for optimized builds
|
||||
# /permissive- - Enables stricter C++ standards conformance checks
|
||||
# /EHsc - C++-only exception handling semantics
|
||||
# /volatile:iso - Use strict standards-compliant volatile semantics.
|
||||
# /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates
|
||||
# /Zc:inline - Let codegen omit inline functions in object files
|
||||
# /Zc:throwingNew - Let codegen assume `operator new` (without std::nothrow) will never return null
|
||||
add_compile_options(
|
||||
/W3
|
||||
/MP
|
||||
/Zi
|
||||
/Zo
|
||||
/permissive-
|
||||
/EHsc
|
||||
/std:c++latest
|
||||
/volatile:iso
|
||||
/Zc:externConstexpr
|
||||
/Zc:inline
|
||||
/Zc:throwingNew
|
||||
)
|
||||
|
||||
# /GS- - No stack buffer overflow checks
|
||||
add_compile_options("$<$<CONFIG:Release>:/GS->")
|
||||
@@ -34,7 +51,10 @@ if (MSVC)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG /MANIFEST:NO" CACHE STRING "" FORCE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /MANIFEST:NO /INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE)
|
||||
else()
|
||||
add_compile_options("-Wno-attributes")
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wno-attributes
|
||||
)
|
||||
|
||||
if (APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
||||
add_compile_options("-stdlib=libc++")
|
||||
|
||||
@@ -123,6 +123,8 @@ add_library(common STATIC
|
||||
timer.h
|
||||
uint128.cpp
|
||||
uint128.h
|
||||
uuid.cpp
|
||||
uuid.h
|
||||
vector_math.h
|
||||
web_result.h
|
||||
zstd_compression.cpp
|
||||
|
||||
@@ -78,16 +78,17 @@ namespace FileUtil {
|
||||
// Remove any ending forward slashes from directory paths
|
||||
// Modifies argument.
|
||||
static void StripTailDirSlashes(std::string& fname) {
|
||||
if (fname.length() > 1) {
|
||||
std::size_t i = fname.length();
|
||||
while (i > 0 && fname[i - 1] == DIR_SEP_CHR)
|
||||
--i;
|
||||
fname.resize(i);
|
||||
if (fname.length() <= 1) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
std::size_t i = fname.length();
|
||||
while (i > 0 && fname[i - 1] == DIR_SEP_CHR) {
|
||||
--i;
|
||||
}
|
||||
fname.resize(i);
|
||||
}
|
||||
|
||||
// Returns true if file filename exists
|
||||
bool Exists(const std::string& filename) {
|
||||
struct stat file_info;
|
||||
|
||||
@@ -107,7 +108,6 @@ bool Exists(const std::string& filename) {
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
// Returns true if filename is a directory
|
||||
bool IsDirectory(const std::string& filename) {
|
||||
struct stat file_info;
|
||||
|
||||
@@ -132,8 +132,6 @@ bool IsDirectory(const std::string& filename) {
|
||||
return S_ISDIR(file_info.st_mode);
|
||||
}
|
||||
|
||||
// Deletes a given filename, return true on success
|
||||
// Doesn't supports deleting a directory
|
||||
bool Delete(const std::string& filename) {
|
||||
LOG_TRACE(Common_Filesystem, "file {}", filename);
|
||||
|
||||
@@ -165,7 +163,6 @@ bool Delete(const std::string& filename) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if successful, or path already exists.
|
||||
bool CreateDir(const std::string& path) {
|
||||
LOG_TRACE(Common_Filesystem, "directory {}", path);
|
||||
#ifdef _WIN32
|
||||
@@ -194,7 +191,6 @@ bool CreateDir(const std::string& path) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Creates the full path of fullPath returns true on success
|
||||
bool CreateFullPath(const std::string& fullPath) {
|
||||
int panicCounter = 100;
|
||||
LOG_TRACE(Common_Filesystem, "path {}", fullPath);
|
||||
@@ -230,7 +226,6 @@ bool CreateFullPath(const std::string& fullPath) {
|
||||
}
|
||||
}
|
||||
|
||||
// Deletes a directory filename, returns true on success
|
||||
bool DeleteDir(const std::string& filename) {
|
||||
LOG_TRACE(Common_Filesystem, "directory {}", filename);
|
||||
|
||||
@@ -252,7 +247,6 @@ bool DeleteDir(const std::string& filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// renames file srcFilename to destFilename, returns true on success
|
||||
bool Rename(const std::string& srcFilename, const std::string& destFilename) {
|
||||
LOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename);
|
||||
#ifdef _WIN32
|
||||
@@ -268,7 +262,6 @@ bool Rename(const std::string& srcFilename, const std::string& destFilename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// copies file srcFilename to destFilename, returns true on success
|
||||
bool Copy(const std::string& srcFilename, const std::string& destFilename) {
|
||||
LOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename);
|
||||
#ifdef _WIN32
|
||||
@@ -324,7 +317,6 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns the size of filename (64bit)
|
||||
u64 GetSize(const std::string& filename) {
|
||||
if (!Exists(filename)) {
|
||||
LOG_ERROR(Common_Filesystem, "failed {}: No such file", filename);
|
||||
@@ -351,7 +343,6 @@ u64 GetSize(const std::string& filename) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Overloaded GetSize, accepts file descriptor
|
||||
u64 GetSize(const int fd) {
|
||||
struct stat buf;
|
||||
if (fstat(fd, &buf) != 0) {
|
||||
@@ -361,7 +352,6 @@ u64 GetSize(const int fd) {
|
||||
return buf.st_size;
|
||||
}
|
||||
|
||||
// Overloaded GetSize, accepts FILE*
|
||||
u64 GetSize(FILE* f) {
|
||||
// can't use off_t here because it can be 32-bit
|
||||
u64 pos = ftello(f);
|
||||
@@ -377,7 +367,6 @@ u64 GetSize(FILE* f) {
|
||||
return size;
|
||||
}
|
||||
|
||||
// creates an empty file filename, returns true on success
|
||||
bool CreateEmptyFile(const std::string& filename) {
|
||||
LOG_TRACE(Common_Filesystem, "{}", filename);
|
||||
|
||||
@@ -502,7 +491,6 @@ bool DeleteDirRecursively(const std::string& directory, unsigned int recursion)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create directory and copy contents (does not overwrite existing files)
|
||||
void CopyDir(const std::string& source_path, const std::string& dest_path) {
|
||||
#ifndef _WIN32
|
||||
if (source_path == dest_path)
|
||||
@@ -539,8 +527,7 @@ void CopyDir(const std::string& source_path, const std::string& dest_path) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns the current directory
|
||||
std::string GetCurrentDir() {
|
||||
std::optional<std::string> GetCurrentDir() {
|
||||
// Get the current working directory (getcwd uses malloc)
|
||||
#ifdef _WIN32
|
||||
wchar_t* dir;
|
||||
@@ -550,7 +537,7 @@ std::string GetCurrentDir() {
|
||||
if (!(dir = getcwd(nullptr, 0))) {
|
||||
#endif
|
||||
LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: {}", GetLastErrorMsg());
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
#ifdef _WIN32
|
||||
std::string strDir = Common::UTF16ToUTF8(dir);
|
||||
@@ -561,7 +548,6 @@ std::string GetCurrentDir() {
|
||||
return strDir;
|
||||
}
|
||||
|
||||
// Sets the current directory to the given directory
|
||||
bool SetCurrentDir(const std::string& directory) {
|
||||
#ifdef _WIN32
|
||||
return _wchdir(Common::UTF8ToUTF16W(directory).c_str()) == 0;
|
||||
@@ -673,8 +659,6 @@ std::string GetSysDirectory() {
|
||||
return sysDir;
|
||||
}
|
||||
|
||||
// Returns a string with a yuzu data dir or file in the user's home
|
||||
// directory. To be used in "multi-user" mode (that is, installed).
|
||||
const std::string& GetUserPath(UserPath path, const std::string& new_path) {
|
||||
static std::unordered_map<UserPath, std::string> paths;
|
||||
auto& user_path = paths[UserPath::UserDir];
|
||||
@@ -762,11 +746,11 @@ std::string GetNANDRegistrationDir(bool system) {
|
||||
return GetUserPath(UserPath::NANDDir) + "user/Contents/registered/";
|
||||
}
|
||||
|
||||
std::size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename) {
|
||||
return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
|
||||
std::size_t WriteStringToFile(bool text_file, const std::string& filename, std::string_view str) {
|
||||
return IOFile(filename, text_file ? "w" : "wb").WriteString(str);
|
||||
}
|
||||
|
||||
std::size_t ReadFileToString(bool text_file, const char* filename, std::string& str) {
|
||||
std::size_t ReadFileToString(bool text_file, const std::string& filename, std::string& str) {
|
||||
IOFile file(filename, text_file ? "r" : "rb");
|
||||
|
||||
if (!file.IsOpen())
|
||||
@@ -776,13 +760,6 @@ std::size_t ReadFileToString(bool text_file, const char* filename, std::string&
|
||||
return file.ReadArray(&str[0], str.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the filename into 8.3 format
|
||||
* Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename
|
||||
* @param filename The normal filename to use
|
||||
* @param short_name A 9-char array in which the short name will be written
|
||||
* @param extension A 4-char array in which the extension will be written
|
||||
*/
|
||||
void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name,
|
||||
std::array<char, 4>& extension) {
|
||||
const std::string forbidden_characters = ".\"/\\[]:;=, ";
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
@@ -118,7 +119,7 @@ u64 ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
|
||||
bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256);
|
||||
|
||||
// Returns the current directory
|
||||
std::string GetCurrentDir();
|
||||
std::optional<std::string> GetCurrentDir();
|
||||
|
||||
// Create directory and copy contents (does not overwrite existing files)
|
||||
void CopyDir(const std::string& source_path, const std::string& dest_path);
|
||||
@@ -146,9 +147,9 @@ const std::string& GetExeDirectory();
|
||||
std::string AppDataRoamingDirectory();
|
||||
#endif
|
||||
|
||||
std::size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename);
|
||||
std::size_t WriteStringToFile(bool text_file, const std::string& filename, std::string_view str);
|
||||
|
||||
std::size_t ReadFileToString(bool text_file, const char* filename, std::string& str);
|
||||
std::size_t ReadFileToString(bool text_file, const std::string& filename, std::string& str);
|
||||
|
||||
/**
|
||||
* Splits the filename into 8.3 format
|
||||
@@ -257,8 +258,8 @@ public:
|
||||
return WriteArray(&object, 1);
|
||||
}
|
||||
|
||||
std::size_t WriteString(const std::string& str) {
|
||||
return WriteArray(str.c_str(), str.length());
|
||||
std::size_t WriteString(std::string_view str) {
|
||||
return WriteArray(str.data(), str.length());
|
||||
}
|
||||
|
||||
bool IsOpen() const {
|
||||
@@ -286,8 +287,8 @@ private:
|
||||
template <typename T>
|
||||
void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) {
|
||||
#ifdef _MSC_VER
|
||||
fstream.open(Common::UTF8ToUTF16W(filename).c_str(), openmode);
|
||||
fstream.open(Common::UTF8ToUTF16W(filename), openmode);
|
||||
#else
|
||||
fstream.open(filename.c_str(), openmode);
|
||||
fstream.open(filename, openmode);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -41,4 +41,7 @@ struct Rectangle {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
Rectangle(T, T, T, T)->Rectangle<T>;
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -20,7 +20,7 @@ struct ScopeExitHelper {
|
||||
|
||||
template <typename Func>
|
||||
ScopeExitHelper<Func> ScopeExit(Func&& func) {
|
||||
return ScopeExitHelper<Func>(std::move(func));
|
||||
return ScopeExitHelper<Func>(std::forward<Func>(func));
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
|
||||
@@ -21,11 +21,6 @@
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <cstdlib>
|
||||
#elif defined(__linux__)
|
||||
#include <byteswap.h>
|
||||
#elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
|
||||
defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
#include <sys/endian.h>
|
||||
#endif
|
||||
#include <cstring>
|
||||
#include "common/common_types.h"
|
||||
@@ -62,86 +57,49 @@
|
||||
namespace Common {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
inline u16 swap16(u16 _data) {
|
||||
return _byteswap_ushort(_data);
|
||||
[[nodiscard]] inline u16 swap16(u16 data) noexcept {
|
||||
return _byteswap_ushort(data);
|
||||
}
|
||||
inline u32 swap32(u32 _data) {
|
||||
return _byteswap_ulong(_data);
|
||||
[[nodiscard]] inline u32 swap32(u32 data) noexcept {
|
||||
return _byteswap_ulong(data);
|
||||
}
|
||||
inline u64 swap64(u64 _data) {
|
||||
return _byteswap_uint64(_data);
|
||||
[[nodiscard]] inline u64 swap64(u64 data) noexcept {
|
||||
return _byteswap_uint64(data);
|
||||
}
|
||||
#elif defined(ARCHITECTURE_ARM) && (__ARM_ARCH >= 6)
|
||||
inline u16 swap16(u16 _data) {
|
||||
u32 data = _data;
|
||||
__asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data));
|
||||
return (u16)data;
|
||||
}
|
||||
inline u32 swap32(u32 _data) {
|
||||
__asm__("rev %0, %1\n" : "=l"(_data) : "l"(_data));
|
||||
return _data;
|
||||
}
|
||||
inline u64 swap64(u64 _data) {
|
||||
return ((u64)swap32(_data) << 32) | swap32(_data >> 32);
|
||||
}
|
||||
#elif __linux__
|
||||
inline u16 swap16(u16 _data) {
|
||||
return bswap_16(_data);
|
||||
}
|
||||
inline u32 swap32(u32 _data) {
|
||||
return bswap_32(_data);
|
||||
}
|
||||
inline u64 swap64(u64 _data) {
|
||||
return bswap_64(_data);
|
||||
}
|
||||
#elif __APPLE__
|
||||
inline __attribute__((always_inline)) u16 swap16(u16 _data) {
|
||||
return (_data >> 8) | (_data << 8);
|
||||
}
|
||||
inline __attribute__((always_inline)) u32 swap32(u32 _data) {
|
||||
return __builtin_bswap32(_data);
|
||||
}
|
||||
inline __attribute__((always_inline)) u64 swap64(u64 _data) {
|
||||
return __builtin_bswap64(_data);
|
||||
}
|
||||
#elif defined(__Bitrig__) || defined(__OpenBSD__)
|
||||
#elif defined(__clang__) || defined(__GNUC__)
|
||||
#if defined(__Bitrig__) || defined(__OpenBSD__)
|
||||
// redefine swap16, swap32, swap64 as inline functions
|
||||
#undef swap16
|
||||
#undef swap32
|
||||
#undef swap64
|
||||
inline u16 swap16(u16 _data) {
|
||||
return __swap16(_data);
|
||||
#endif
|
||||
[[nodiscard]] inline u16 swap16(u16 data) noexcept {
|
||||
return __builtin_bswap16(data);
|
||||
}
|
||||
inline u32 swap32(u32 _data) {
|
||||
return __swap32(_data);
|
||||
[[nodiscard]] inline u32 swap32(u32 data) noexcept {
|
||||
return __builtin_bswap32(data);
|
||||
}
|
||||
inline u64 swap64(u64 _data) {
|
||||
return __swap64(_data);
|
||||
}
|
||||
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
inline u16 swap16(u16 _data) {
|
||||
return bswap16(_data);
|
||||
}
|
||||
inline u32 swap32(u32 _data) {
|
||||
return bswap32(_data);
|
||||
}
|
||||
inline u64 swap64(u64 _data) {
|
||||
return bswap64(_data);
|
||||
[[nodiscard]] inline u64 swap64(u64 data) noexcept {
|
||||
return __builtin_bswap64(data);
|
||||
}
|
||||
#else
|
||||
// Slow generic implementation.
|
||||
inline u16 swap16(u16 data) {
|
||||
// Generic implementation.
|
||||
[[nodiscard]] inline u16 swap16(u16 data) noexcept {
|
||||
return (data >> 8) | (data << 8);
|
||||
}
|
||||
inline u32 swap32(u32 data) {
|
||||
return (swap16(data) << 16) | swap16(data >> 16);
|
||||
[[nodiscard]] inline u32 swap32(u32 data) noexcept {
|
||||
return ((data & 0xFF000000U) >> 24) | ((data & 0x00FF0000U) >> 8) |
|
||||
((data & 0x0000FF00U) << 8) | ((data & 0x000000FFU) << 24);
|
||||
}
|
||||
inline u64 swap64(u64 data) {
|
||||
return ((u64)swap32(data) << 32) | swap32(data >> 32);
|
||||
[[nodiscard]] inline u64 swap64(u64 data) noexcept {
|
||||
return ((data & 0xFF00000000000000ULL) >> 56) | ((data & 0x00FF000000000000ULL) >> 40) |
|
||||
((data & 0x0000FF0000000000ULL) >> 24) | ((data & 0x000000FF00000000ULL) >> 8) |
|
||||
((data & 0x00000000FF000000ULL) << 8) | ((data & 0x0000000000FF0000ULL) << 24) |
|
||||
((data & 0x000000000000FF00ULL) << 40) | ((data & 0x00000000000000FFULL) << 56);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline float swapf(float f) {
|
||||
[[nodiscard]] inline float swapf(float f) noexcept {
|
||||
static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t.");
|
||||
|
||||
u32 value;
|
||||
@@ -153,7 +111,7 @@ inline float swapf(float f) {
|
||||
return f;
|
||||
}
|
||||
|
||||
inline double swapd(double f) {
|
||||
[[nodiscard]] inline double swapd(double f) noexcept {
|
||||
static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t.");
|
||||
|
||||
u64 value;
|
||||
|
||||
33
src/common/uuid.cpp
Normal file
33
src/common/uuid.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2018 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "common/uuid.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
UUID UUID::Generate() {
|
||||
std::random_device device;
|
||||
std::mt19937 gen(device());
|
||||
std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
|
||||
return UUID{distribution(gen), distribution(gen)};
|
||||
}
|
||||
|
||||
std::string UUID::Format() const {
|
||||
return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
|
||||
}
|
||||
|
||||
std::string UUID::FormatSwitch() const {
|
||||
std::array<u8, 16> s{};
|
||||
std::memcpy(s.data(), uuid.data(), sizeof(u128));
|
||||
return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
|
||||
":02x}{:02x}{:02x}{:02x}{:02x}",
|
||||
s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
|
||||
s[12], s[13], s[14], s[15]);
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
48
src/common/uuid.h
Normal file
48
src/common/uuid.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2018 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
constexpr u128 INVALID_UUID{{0, 0}};
|
||||
|
||||
struct UUID {
|
||||
// UUIDs which are 0 are considered invalid!
|
||||
u128 uuid = INVALID_UUID;
|
||||
constexpr UUID() = default;
|
||||
constexpr explicit UUID(const u128& id) : uuid{id} {}
|
||||
constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
|
||||
|
||||
constexpr explicit operator bool() const {
|
||||
return uuid[0] != INVALID_UUID[0] && uuid[1] != INVALID_UUID[1];
|
||||
}
|
||||
|
||||
constexpr bool operator==(const UUID& rhs) const {
|
||||
// TODO(DarkLordZach): Replace with uuid == rhs.uuid with C++20
|
||||
return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1];
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const UUID& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
// TODO(ogniK): Properly generate uuids based on RFC-4122
|
||||
static UUID Generate();
|
||||
|
||||
// Set the UUID to {0,0} to be considered an invalid user
|
||||
constexpr void Invalidate() {
|
||||
uuid = INVALID_UUID;
|
||||
}
|
||||
|
||||
std::string Format() const;
|
||||
std::string FormatSwitch() const;
|
||||
};
|
||||
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
|
||||
|
||||
} // namespace Common
|
||||
@@ -2,8 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <zstd.h>
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -88,6 +88,10 @@ add_library(core STATIC
|
||||
file_sys/vfs_vector.h
|
||||
file_sys/xts_archive.cpp
|
||||
file_sys/xts_archive.h
|
||||
frontend/applets/error.cpp
|
||||
frontend/applets/error.h
|
||||
frontend/applets/general_frontend.cpp
|
||||
frontend/applets/general_frontend.h
|
||||
frontend/applets/profile_select.cpp
|
||||
frontend/applets/profile_select.h
|
||||
frontend/applets/software_keyboard.cpp
|
||||
@@ -177,12 +181,14 @@ add_library(core STATIC
|
||||
hle/service/am/applet_oe.h
|
||||
hle/service/am/applets/applets.cpp
|
||||
hle/service/am/applets/applets.h
|
||||
hle/service/am/applets/error.cpp
|
||||
hle/service/am/applets/error.h
|
||||
hle/service/am/applets/general_backend.cpp
|
||||
hle/service/am/applets/general_backend.h
|
||||
hle/service/am/applets/profile_select.cpp
|
||||
hle/service/am/applets/profile_select.h
|
||||
hle/service/am/applets/software_keyboard.cpp
|
||||
hle/service/am/applets/software_keyboard.h
|
||||
hle/service/am/applets/stub_applet.cpp
|
||||
hle/service/am/applets/stub_applet.h
|
||||
hle/service/am/applets/web_browser.cpp
|
||||
hle/service/am/applets/web_browser.h
|
||||
hle/service/am/idle.cpp
|
||||
@@ -304,6 +310,8 @@ add_library(core STATIC
|
||||
hle/service/mig/mig.h
|
||||
hle/service/mii/mii.cpp
|
||||
hle/service/mii/mii.h
|
||||
hle/service/mii/mii_manager.cpp
|
||||
hle/service/mii/mii_manager.h
|
||||
hle/service/mm/mm_u.cpp
|
||||
hle/service/mm/mm_u.h
|
||||
hle/service/ncm/ncm.cpp
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
#include <array>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common {
|
||||
struct PageTable;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
enum class VMAPermission : u8;
|
||||
}
|
||||
@@ -49,8 +53,14 @@ public:
|
||||
/// Clear all instruction cache
|
||||
virtual void ClearInstructionCache() = 0;
|
||||
|
||||
/// Notify CPU emulation that page tables have changed
|
||||
virtual void PageTableChanged() = 0;
|
||||
/// Notifies CPU emulation that the current page table has changed.
|
||||
///
|
||||
/// @param new_page_table The new page table.
|
||||
/// @param new_address_space_size_in_bits The new usable size of the address space in bits.
|
||||
/// This can be either 32, 36, or 39 on official software.
|
||||
///
|
||||
virtual void PageTableChanged(Common::PageTable& new_page_table,
|
||||
std::size_t new_address_space_size_in_bits) = 0;
|
||||
|
||||
/**
|
||||
* Set the Program Counter to an address
|
||||
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
}
|
||||
|
||||
void CallSVC(u32 swi) override {
|
||||
Kernel::CallSVC(swi);
|
||||
Kernel::CallSVC(parent.system, swi);
|
||||
}
|
||||
|
||||
void AddTicks(u64 ticks) override {
|
||||
@@ -112,14 +112,14 @@ public:
|
||||
// Always execute at least one tick.
|
||||
amortized_ticks = std::max<u64>(amortized_ticks, 1);
|
||||
|
||||
parent.core_timing.AddTicks(amortized_ticks);
|
||||
parent.system.CoreTiming().AddTicks(amortized_ticks);
|
||||
num_interpreted_instructions = 0;
|
||||
}
|
||||
u64 GetTicksRemaining() override {
|
||||
return std::max(parent.core_timing.GetDowncount(), 0);
|
||||
return std::max(parent.system.CoreTiming().GetDowncount(), 0);
|
||||
}
|
||||
u64 GetCNTPCT() override {
|
||||
return Timing::CpuCyclesToClockCycles(parent.core_timing.GetTicks());
|
||||
return Timing::CpuCyclesToClockCycles(parent.system.CoreTiming().GetTicks());
|
||||
}
|
||||
|
||||
ARM_Dynarmic& parent;
|
||||
@@ -128,18 +128,16 @@ public:
|
||||
u64 tpidr_el0 = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
|
||||
auto* current_process = Core::CurrentProcess();
|
||||
auto** const page_table = current_process->VMManager().page_table.pointers.data();
|
||||
|
||||
std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit(Common::PageTable& page_table,
|
||||
std::size_t address_space_bits) const {
|
||||
Dynarmic::A64::UserConfig config;
|
||||
|
||||
// Callbacks
|
||||
config.callbacks = cb.get();
|
||||
|
||||
// Memory
|
||||
config.page_table = reinterpret_cast<void**>(page_table);
|
||||
config.page_table_address_space_bits = current_process->VMManager().GetAddressSpaceWidth();
|
||||
config.page_table = reinterpret_cast<void**>(page_table.pointers.data());
|
||||
config.page_table_address_space_bits = address_space_bits;
|
||||
config.silently_mirror_page_table = false;
|
||||
|
||||
// Multi-process state
|
||||
@@ -171,16 +169,11 @@ void ARM_Dynarmic::Step() {
|
||||
cb->InterpreterFallback(jit->GetPC(), 1);
|
||||
}
|
||||
|
||||
ARM_Dynarmic::ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
|
||||
ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor,
|
||||
std::size_t core_index)
|
||||
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{core_timing},
|
||||
core_index{core_index}, core_timing{core_timing},
|
||||
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {
|
||||
ThreadContext ctx{};
|
||||
inner_unicorn.SaveContext(ctx);
|
||||
PageTableChanged();
|
||||
LoadContext(ctx);
|
||||
}
|
||||
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system},
|
||||
core_index{core_index}, system{system},
|
||||
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
|
||||
|
||||
ARM_Dynarmic::~ARM_Dynarmic() = default;
|
||||
|
||||
@@ -275,8 +268,9 @@ void ARM_Dynarmic::ClearExclusiveState() {
|
||||
jit->ClearExclusiveState();
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::PageTableChanged() {
|
||||
jit = MakeJit();
|
||||
void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table,
|
||||
std::size_t new_address_space_size_in_bits) {
|
||||
jit = MakeJit(page_table, new_address_space_size_in_bits);
|
||||
}
|
||||
|
||||
DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {}
|
||||
|
||||
@@ -12,19 +12,15 @@
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#include "core/arm/unicorn/arm_unicorn.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
|
||||
class ARM_Dynarmic_Callbacks;
|
||||
class DynarmicExclusiveMonitor;
|
||||
class System;
|
||||
|
||||
class ARM_Dynarmic final : public ARM_Interface {
|
||||
public:
|
||||
ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
|
||||
std::size_t core_index);
|
||||
ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
||||
~ARM_Dynarmic() override;
|
||||
|
||||
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
|
||||
@@ -52,10 +48,12 @@ public:
|
||||
void ClearExclusiveState() override;
|
||||
|
||||
void ClearInstructionCache() override;
|
||||
void PageTableChanged() override;
|
||||
void PageTableChanged(Common::PageTable& new_page_table,
|
||||
std::size_t new_address_space_size_in_bits) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Dynarmic::A64::Jit> MakeJit() const;
|
||||
std::unique_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable& page_table,
|
||||
std::size_t address_space_bits) const;
|
||||
|
||||
friend class ARM_Dynarmic_Callbacks;
|
||||
std::unique_ptr<ARM_Dynarmic_Callbacks> cb;
|
||||
@@ -63,7 +61,7 @@ private:
|
||||
ARM_Unicorn inner_unicorn;
|
||||
|
||||
std::size_t core_index;
|
||||
Timing::CoreTiming& core_timing;
|
||||
System& system;
|
||||
DynarmicExclusiveMonitor& exclusive_monitor;
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
@@ -49,20 +48,6 @@ static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_
|
||||
}
|
||||
}
|
||||
|
||||
static void InterruptHook(uc_engine* uc, u32 intNo, void* user_data) {
|
||||
u32 esr{};
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
|
||||
|
||||
auto ec = esr >> 26;
|
||||
auto iss = esr & 0xFFFFFF;
|
||||
|
||||
switch (ec) {
|
||||
case 0x15: // SVC
|
||||
Kernel::CallSVC(iss);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value,
|
||||
void* user_data) {
|
||||
ARM_Interface::ThreadContext ctx{};
|
||||
@@ -72,7 +57,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
|
||||
return {};
|
||||
}
|
||||
|
||||
ARM_Unicorn::ARM_Unicorn(Timing::CoreTiming& core_timing) : core_timing{core_timing} {
|
||||
ARM_Unicorn::ARM_Unicorn(System& system) : system{system} {
|
||||
CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc));
|
||||
|
||||
auto fpv = 3 << 20;
|
||||
@@ -177,7 +162,7 @@ void ARM_Unicorn::Run() {
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
ExecuteInstructions(std::max(4000000, 0));
|
||||
} else {
|
||||
ExecuteInstructions(std::max(core_timing.GetDowncount(), 0));
|
||||
ExecuteInstructions(std::max(system.CoreTiming().GetDowncount(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +175,7 @@ MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
|
||||
void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
|
||||
MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
|
||||
CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
|
||||
core_timing.AddTicks(num_instructions);
|
||||
system.CoreTiming().AddTicks(num_instructions);
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) {
|
||||
uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
|
||||
@@ -273,4 +258,20 @@ void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {
|
||||
last_bkpt_hit = true;
|
||||
}
|
||||
|
||||
void ARM_Unicorn::InterruptHook(uc_engine* uc, u32 int_no, void* user_data) {
|
||||
u32 esr{};
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
|
||||
|
||||
const auto ec = esr >> 26;
|
||||
const auto iss = esr & 0xFFFFFF;
|
||||
|
||||
auto* const arm_instance = static_cast<ARM_Unicorn*>(user_data);
|
||||
|
||||
switch (ec) {
|
||||
case 0x15: // SVC
|
||||
Kernel::CallSVC(arm_instance->system, iss);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -9,15 +9,13 @@
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
|
||||
class System;
|
||||
|
||||
class ARM_Unicorn final : public ARM_Interface {
|
||||
public:
|
||||
explicit ARM_Unicorn(Timing::CoreTiming& core_timing);
|
||||
explicit ARM_Unicorn(System& system);
|
||||
~ARM_Unicorn() override;
|
||||
|
||||
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
|
||||
@@ -43,12 +41,14 @@ public:
|
||||
void Run() override;
|
||||
void Step() override;
|
||||
void ClearInstructionCache() override;
|
||||
void PageTableChanged() override{};
|
||||
void PageTableChanged(Common::PageTable&, std::size_t) override {}
|
||||
void RecordBreak(GDBStub::BreakpointAddress bkpt);
|
||||
|
||||
private:
|
||||
static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
|
||||
|
||||
uc_engine* uc{};
|
||||
Timing::CoreTiming& core_timing;
|
||||
System& system;
|
||||
GDBStub::BreakpointAddress last_bkpt{};
|
||||
bool last_bkpt_hit = false;
|
||||
};
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include "common/file_util.h"
|
||||
@@ -20,13 +18,18 @@
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/vfs_concat.h"
|
||||
#include "core/file_sys/vfs_real.h"
|
||||
#include "core/frontend/applets/error.h"
|
||||
#include "core/frontend/applets/general_frontend.h"
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
#include "core/frontend/applets/web_browser.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/scheduler.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/service/am/applets/software_keyboard.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/loader/loader.h"
|
||||
@@ -38,8 +41,6 @@
|
||||
#include "frontend/applets/software_keyboard.h"
|
||||
#include "frontend/applets/web_browser.h"
|
||||
#include "video_core/debug_utils/debug_utils.h"
|
||||
#include "video_core/gpu_asynch.h"
|
||||
#include "video_core/gpu_synch.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
@@ -81,7 +82,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
return vfs->OpenFile(path, FileSys::Mode::Read);
|
||||
}
|
||||
struct System::Impl {
|
||||
explicit Impl(System& system) : kernel{system} {}
|
||||
explicit Impl(System& system) : kernel{system}, cpu_core_manager{system} {}
|
||||
|
||||
Cpu& CurrentCpuCore() {
|
||||
return cpu_core_manager.GetCurrentCore();
|
||||
@@ -99,6 +100,7 @@ struct System::Impl {
|
||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||
|
||||
core_timing.Initialize();
|
||||
cpu_core_manager.Initialize();
|
||||
kernel.Initialize();
|
||||
|
||||
const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
@@ -113,15 +115,7 @@ struct System::Impl {
|
||||
content_provider = std::make_unique<FileSys::ContentProviderUnion>();
|
||||
|
||||
/// Create default implementations of applets if one is not provided.
|
||||
if (profile_selector == nullptr)
|
||||
profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
|
||||
if (software_keyboard == nullptr)
|
||||
software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
|
||||
if (web_browser == nullptr)
|
||||
web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
|
||||
|
||||
auto main_process = Kernel::Process::Create(system, "main");
|
||||
kernel.MakeCurrentProcess(main_process.get());
|
||||
applet_manager.SetDefaultAppletsIfMissing();
|
||||
|
||||
telemetry_session = std::make_unique<Core::TelemetrySession>();
|
||||
service_manager = std::make_shared<Service::SM::ServiceManager>();
|
||||
@@ -134,16 +128,10 @@ struct System::Impl {
|
||||
return ResultStatus::ErrorVideoCore;
|
||||
}
|
||||
|
||||
gpu_core = VideoCore::CreateGPU(system);
|
||||
|
||||
is_powered_on = true;
|
||||
|
||||
if (Settings::values.use_asynchronous_gpu_emulation) {
|
||||
gpu_core = std::make_unique<VideoCommon::GPUAsynch>(system, *renderer);
|
||||
} else {
|
||||
gpu_core = std::make_unique<VideoCommon::GPUSynch>(system, *renderer);
|
||||
}
|
||||
|
||||
cpu_core_manager.Initialize(system);
|
||||
|
||||
LOG_DEBUG(Core, "Initialized OK");
|
||||
|
||||
// Reset counters and set time origin to current frame
|
||||
@@ -179,7 +167,8 @@ struct System::Impl {
|
||||
return init_result;
|
||||
}
|
||||
|
||||
const Loader::ResultStatus load_result{app_loader->Load(*kernel.CurrentProcess())};
|
||||
auto main_process = Kernel::Process::Create(system, "main");
|
||||
const auto [load_result, load_parameters] = app_loader->Load(*main_process);
|
||||
if (load_result != Loader::ResultStatus::Success) {
|
||||
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
|
||||
Shutdown();
|
||||
@@ -187,6 +176,16 @@ struct System::Impl {
|
||||
return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) +
|
||||
static_cast<u32>(load_result));
|
||||
}
|
||||
kernel.MakeCurrentProcess(main_process.get());
|
||||
|
||||
// Main process has been loaded and been made current.
|
||||
// Begin GPU and CPU execution.
|
||||
gpu_core->Start();
|
||||
cpu_core_manager.StartThreads();
|
||||
|
||||
// All threads are started, begin main process execution, now that we're in the clear.
|
||||
main_process->Run(load_parameters->main_thread_priority,
|
||||
load_parameters->main_thread_stack_size);
|
||||
|
||||
status = ResultStatus::Success;
|
||||
return status;
|
||||
@@ -224,9 +223,7 @@ struct System::Impl {
|
||||
app_loader.reset();
|
||||
|
||||
// Clear all applets
|
||||
profile_selector.reset();
|
||||
software_keyboard.reset();
|
||||
web_browser.reset();
|
||||
applet_manager.ClearAll();
|
||||
|
||||
LOG_DEBUG(Core, "Shutdown OK");
|
||||
}
|
||||
@@ -265,9 +262,7 @@ struct System::Impl {
|
||||
std::unique_ptr<FileSys::CheatEngine> cheat_engine;
|
||||
|
||||
/// Frontend applets
|
||||
std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector;
|
||||
std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
|
||||
std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser;
|
||||
Service::AM::Applets::AppletManager applet_manager;
|
||||
|
||||
/// Service manager
|
||||
std::shared_ptr<Service::SM::ServiceManager> service_manager;
|
||||
@@ -477,20 +472,20 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const {
|
||||
return impl->virtual_filesystem;
|
||||
}
|
||||
|
||||
void System::SetProfileSelector(std::unique_ptr<Frontend::ProfileSelectApplet> applet) {
|
||||
impl->profile_selector = std::move(applet);
|
||||
void System::SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set) {
|
||||
impl->applet_manager.SetAppletFrontendSet(std::move(set));
|
||||
}
|
||||
|
||||
const Frontend::ProfileSelectApplet& System::GetProfileSelector() const {
|
||||
return *impl->profile_selector;
|
||||
void System::SetDefaultAppletFrontendSet() {
|
||||
impl->applet_manager.SetDefaultAppletFrontendSet();
|
||||
}
|
||||
|
||||
void System::SetSoftwareKeyboard(std::unique_ptr<Frontend::SoftwareKeyboardApplet> applet) {
|
||||
impl->software_keyboard = std::move(applet);
|
||||
Service::AM::Applets::AppletManager& System::GetAppletManager() {
|
||||
return impl->applet_manager;
|
||||
}
|
||||
|
||||
const Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const {
|
||||
return *impl->software_keyboard;
|
||||
const Service::AM::Applets::AppletManager& System::GetAppletManager() const {
|
||||
return impl->applet_manager;
|
||||
}
|
||||
|
||||
void System::SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider) {
|
||||
@@ -514,18 +509,6 @@ void System::ClearContentProvider(FileSys::ContentProviderUnionSlot slot) {
|
||||
impl->content_provider->ClearSlot(slot);
|
||||
}
|
||||
|
||||
void System::SetWebBrowser(std::unique_ptr<Frontend::WebBrowserApplet> applet) {
|
||||
impl->web_browser = std::move(applet);
|
||||
}
|
||||
|
||||
Frontend::WebBrowserApplet& System::GetWebBrowser() {
|
||||
return *impl->web_browser;
|
||||
}
|
||||
|
||||
const Frontend::WebBrowserApplet& System::GetWebBrowser() const {
|
||||
return *impl->web_browser;
|
||||
}
|
||||
|
||||
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
|
||||
return impl->Init(*this, emu_window);
|
||||
}
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
|
||||
namespace Core::Frontend {
|
||||
class EmuWindow;
|
||||
class ProfileSelectApplet;
|
||||
class SoftwareKeyboardApplet;
|
||||
class WebBrowserApplet;
|
||||
} // namespace Core::Frontend
|
||||
|
||||
namespace FileSys {
|
||||
@@ -38,9 +35,18 @@ class AppLoader;
|
||||
enum class ResultStatus : u16;
|
||||
} // namespace Loader
|
||||
|
||||
namespace Service::SM {
|
||||
namespace Service {
|
||||
|
||||
namespace AM::Applets {
|
||||
struct AppletFrontendSet;
|
||||
class AppletManager;
|
||||
} // namespace AM::Applets
|
||||
|
||||
namespace SM {
|
||||
class ServiceManager;
|
||||
} // namespace Service::SM
|
||||
} // namespace SM
|
||||
|
||||
} // namespace Service
|
||||
|
||||
namespace Tegra {
|
||||
class DebugContext;
|
||||
@@ -260,18 +266,13 @@ public:
|
||||
void RegisterCheatList(const std::vector<FileSys::CheatList>& list, const std::string& build_id,
|
||||
VAddr code_region_start, VAddr code_region_end);
|
||||
|
||||
void SetProfileSelector(std::unique_ptr<Frontend::ProfileSelectApplet> applet);
|
||||
void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set);
|
||||
|
||||
const Frontend::ProfileSelectApplet& GetProfileSelector() const;
|
||||
void SetDefaultAppletFrontendSet();
|
||||
|
||||
void SetSoftwareKeyboard(std::unique_ptr<Frontend::SoftwareKeyboardApplet> applet);
|
||||
Service::AM::Applets::AppletManager& GetAppletManager();
|
||||
|
||||
const Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const;
|
||||
|
||||
void SetWebBrowser(std::unique_ptr<Frontend::WebBrowserApplet> applet);
|
||||
|
||||
Frontend::WebBrowserApplet& GetWebBrowser();
|
||||
const Frontend::WebBrowserApplet& GetWebBrowser() const;
|
||||
const Service::AM::Applets::AppletManager& GetAppletManager() const;
|
||||
|
||||
void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider);
|
||||
|
||||
|
||||
@@ -55,13 +55,13 @@ Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_ba
|
||||
: cpu_barrier{cpu_barrier}, core_timing{system.CoreTiming()}, core_index{core_index} {
|
||||
if (Settings::values.use_cpu_jit) {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
arm_interface = std::make_unique<ARM_Dynarmic>(core_timing, exclusive_monitor, core_index);
|
||||
arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index);
|
||||
#else
|
||||
arm_interface = std::make_unique<ARM_Unicorn>();
|
||||
arm_interface = std::make_unique<ARM_Unicorn>(system);
|
||||
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
||||
#endif
|
||||
} else {
|
||||
arm_interface = std::make_unique<ARM_Unicorn>(core_timing);
|
||||
arm_interface = std::make_unique<ARM_Unicorn>(system);
|
||||
}
|
||||
|
||||
scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface);
|
||||
|
||||
@@ -14,11 +14,11 @@ namespace Core::Timing {
|
||||
constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE;
|
||||
|
||||
s64 usToCycles(s64 us) {
|
||||
if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) {
|
||||
if (static_cast<u64>(us / 1000000) > MAX_VALUE_TO_MULTIPLY) {
|
||||
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
|
||||
return std::numeric_limits<s64>::max();
|
||||
}
|
||||
if (us > MAX_VALUE_TO_MULTIPLY) {
|
||||
if (static_cast<u64>(us) > MAX_VALUE_TO_MULTIPLY) {
|
||||
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
|
||||
return BASE_CLOCK_RATE * (us / 1000000);
|
||||
}
|
||||
@@ -38,11 +38,11 @@ s64 usToCycles(u64 us) {
|
||||
}
|
||||
|
||||
s64 nsToCycles(s64 ns) {
|
||||
if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) {
|
||||
if (static_cast<u64>(ns / 1000000000) > MAX_VALUE_TO_MULTIPLY) {
|
||||
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
|
||||
return std::numeric_limits<s64>::max();
|
||||
}
|
||||
if (ns > MAX_VALUE_TO_MULTIPLY) {
|
||||
if (static_cast<u64>(ns) > MAX_VALUE_TO_MULTIPLY) {
|
||||
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
|
||||
return BASE_CLOCK_RATE * (ns / 1000000000);
|
||||
}
|
||||
|
||||
@@ -19,17 +19,19 @@ void RunCpuCore(const System& system, Cpu& cpu_state) {
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
CpuCoreManager::CpuCoreManager() = default;
|
||||
CpuCoreManager::CpuCoreManager(System& system) : system{system} {}
|
||||
CpuCoreManager::~CpuCoreManager() = default;
|
||||
|
||||
void CpuCoreManager::Initialize(System& system) {
|
||||
void CpuCoreManager::Initialize() {
|
||||
barrier = std::make_unique<CpuBarrier>();
|
||||
exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
|
||||
|
||||
for (std::size_t index = 0; index < cores.size(); ++index) {
|
||||
cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuCoreManager::StartThreads() {
|
||||
// Create threads for CPU cores 1-3, and build thread_to_cpu map
|
||||
// CPU core 0 is run on the main thread
|
||||
thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
|
||||
|
||||
@@ -18,7 +18,7 @@ class System;
|
||||
|
||||
class CpuCoreManager {
|
||||
public:
|
||||
CpuCoreManager();
|
||||
explicit CpuCoreManager(System& system);
|
||||
CpuCoreManager(const CpuCoreManager&) = delete;
|
||||
CpuCoreManager(CpuCoreManager&&) = delete;
|
||||
|
||||
@@ -27,7 +27,8 @@ public:
|
||||
CpuCoreManager& operator=(const CpuCoreManager&) = delete;
|
||||
CpuCoreManager& operator=(CpuCoreManager&&) = delete;
|
||||
|
||||
void Initialize(System& system);
|
||||
void Initialize();
|
||||
void StartThreads();
|
||||
void Shutdown();
|
||||
|
||||
Cpu& GetCore(std::size_t index);
|
||||
@@ -54,6 +55,8 @@ private:
|
||||
|
||||
/// Map of guest threads to CPU cores
|
||||
std::map<std::thread::id, Cpu*> thread_to_cpu;
|
||||
|
||||
System& system;
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
|
||||
34
src/core/frontend/applets/error.cpp
Normal file
34
src/core/frontend/applets/error.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2019 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/frontend/applets/error.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
ErrorApplet::~ErrorApplet() = default;
|
||||
|
||||
void DefaultErrorApplet::ShowError(ResultCode error, std::function<void()> finished) const {
|
||||
LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})",
|
||||
static_cast<u32>(error.module.Value()), error.description.Value(), error.raw);
|
||||
}
|
||||
|
||||
void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
|
||||
std::function<void()> finished) const {
|
||||
LOG_CRITICAL(
|
||||
Service_Fatal,
|
||||
"Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}",
|
||||
static_cast<u32>(error.module.Value()), error.description.Value(), error.raw, time.count());
|
||||
}
|
||||
|
||||
void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_text,
|
||||
std::string detail_text,
|
||||
std::function<void()> finished) const {
|
||||
LOG_CRITICAL(Service_Fatal,
|
||||
"Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})",
|
||||
static_cast<u32>(error.module.Value()), error.description.Value(), error.raw);
|
||||
LOG_CRITICAL(Service_Fatal, " Main Text: {}", main_text);
|
||||
LOG_CRITICAL(Service_Fatal, " Detail Text: {}", detail_text);
|
||||
}
|
||||
|
||||
} // namespace Core::Frontend
|
||||
37
src/core/frontend/applets/error.h
Normal file
37
src/core/frontend/applets/error.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2019 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
class ErrorApplet {
|
||||
public:
|
||||
virtual ~ErrorApplet();
|
||||
|
||||
virtual void ShowError(ResultCode error, std::function<void()> finished) const = 0;
|
||||
|
||||
virtual void ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
|
||||
std::function<void()> finished) const = 0;
|
||||
|
||||
virtual void ShowCustomErrorText(ResultCode 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,
|
||||
std::function<void()> finished) const override;
|
||||
void ShowCustomErrorText(ResultCode error, std::string main_text, std::string detail_text,
|
||||
std::function<void()> finished) const override;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
27
src/core/frontend/applets/general_frontend.cpp
Normal file
27
src/core/frontend/applets/general_frontend.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2019 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/frontend/applets/general_frontend.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
PhotoViewerApplet::~PhotoViewerApplet() = default;
|
||||
|
||||
DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() {}
|
||||
|
||||
void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id,
|
||||
std::function<void()> finished) const {
|
||||
LOG_INFO(Service_AM,
|
||||
"Application requested frontend to display stored photos for title_id={:016X}",
|
||||
title_id);
|
||||
finished();
|
||||
}
|
||||
|
||||
void DefaultPhotoViewerApplet::ShowAllPhotos(std::function<void()> finished) const {
|
||||
LOG_INFO(Service_AM, "Application requested frontend to display all stored photos.");
|
||||
finished();
|
||||
}
|
||||
|
||||
} // namespace Core::Frontend
|
||||
28
src/core/frontend/applets/general_frontend.h
Normal file
28
src/core/frontend/applets/general_frontend.h
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2019 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
class PhotoViewerApplet {
|
||||
public:
|
||||
virtual ~PhotoViewerApplet();
|
||||
|
||||
virtual void ShowPhotosForApplication(u64 title_id, std::function<void()> finished) const = 0;
|
||||
virtual void ShowAllPhotos(std::function<void()> finished) const = 0;
|
||||
};
|
||||
|
||||
class DefaultPhotoViewerApplet final : public PhotoViewerApplet {
|
||||
public:
|
||||
~DefaultPhotoViewerApplet() override;
|
||||
|
||||
void ShowPhotosForApplication(u64 title_id, std::function<void()> finished) const override;
|
||||
void ShowAllPhotos(std::function<void()> finished) const override;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
@@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
@@ -10,9 +11,9 @@ namespace Core::Frontend {
|
||||
ProfileSelectApplet::~ProfileSelectApplet() = default;
|
||||
|
||||
void DefaultProfileSelectApplet::SelectProfile(
|
||||
std::function<void(std::optional<Service::Account::UUID>)> callback) const {
|
||||
std::function<void(std::optional<Common::UUID>)> callback) const {
|
||||
Service::Account::ProfileManager manager;
|
||||
callback(manager.GetUser(Settings::values.current_user).value_or(Service::Account::UUID{}));
|
||||
callback(manager.GetUser(Settings::values.current_user).value_or(Common::UUID{}));
|
||||
LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "common/uuid.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
@@ -14,14 +14,12 @@ class ProfileSelectApplet {
|
||||
public:
|
||||
virtual ~ProfileSelectApplet();
|
||||
|
||||
virtual void SelectProfile(
|
||||
std::function<void(std::optional<Service::Account::UUID>)> callback) const = 0;
|
||||
virtual void SelectProfile(std::function<void(std::optional<Common::UUID>)> callback) const = 0;
|
||||
};
|
||||
|
||||
class DefaultProfileSelectApplet final : public ProfileSelectApplet {
|
||||
public:
|
||||
void SelectProfile(
|
||||
std::function<void(std::optional<Service::Account::UUID>)> callback) const override;
|
||||
void SelectProfile(std::function<void(std::optional<Common::UUID>)> callback) const override;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
GraphicsContext::~GraphicsContext() = default;
|
||||
|
||||
class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>,
|
||||
public std::enable_shared_from_this<TouchState> {
|
||||
public:
|
||||
|
||||
@@ -12,6 +12,25 @@
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
/**
|
||||
* Represents a graphics context that can be used for background computation or drawing. If the
|
||||
* graphics backend doesn't require the context, then the implementation of these methods can be
|
||||
* stubs
|
||||
*/
|
||||
class GraphicsContext {
|
||||
public:
|
||||
virtual ~GraphicsContext();
|
||||
|
||||
/// Makes the graphics context current for the caller thread
|
||||
virtual void MakeCurrent() = 0;
|
||||
|
||||
/// Releases (dunno if this is the "right" word) the context from the caller thread
|
||||
virtual void DoneCurrent() = 0;
|
||||
|
||||
/// Swap buffers to display the next frame
|
||||
virtual void SwapBuffers() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstraction class used to provide an interface between emulation code and the frontend
|
||||
* (e.g. SDL, QGLWidget, GLFW, etc...).
|
||||
@@ -30,7 +49,7 @@ namespace Core::Frontend {
|
||||
* - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please
|
||||
* re-read the upper points again and think about it if you don't see this.
|
||||
*/
|
||||
class EmuWindow {
|
||||
class EmuWindow : public GraphicsContext {
|
||||
public:
|
||||
/// Data structure to store emuwindow configuration
|
||||
struct WindowConfig {
|
||||
@@ -40,17 +59,21 @@ public:
|
||||
std::pair<unsigned, unsigned> min_client_area_size;
|
||||
};
|
||||
|
||||
/// Swap buffers to display the next frame
|
||||
virtual void SwapBuffers() = 0;
|
||||
|
||||
/// Polls window events
|
||||
virtual void PollEvents() = 0;
|
||||
|
||||
/// Makes the graphics context current for the caller thread
|
||||
virtual void MakeCurrent() = 0;
|
||||
|
||||
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
|
||||
virtual void DoneCurrent() = 0;
|
||||
/**
|
||||
* Returns a GraphicsContext that the frontend provides that is shared with the emu window. This
|
||||
* context can be used from other threads for background graphics computation. If the frontend
|
||||
* is using a graphics backend that doesn't need anything specific to run on a different thread,
|
||||
* then it can use a stubbed implemenation for GraphicsContext.
|
||||
*
|
||||
* If the return value is null, then the core should assume that the frontend cannot provide a
|
||||
* Shared Context
|
||||
*/
|
||||
virtual std::unique_ptr<GraphicsContext> CreateSharedContext() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal that a touch pressed event has occurred (e.g. mouse click pressed)
|
||||
@@ -146,8 +169,7 @@ private:
|
||||
* For the request to be honored, EmuWindow implementations will usually reimplement this
|
||||
* function.
|
||||
*/
|
||||
virtual void OnMinimalClientAreaChangeRequest(
|
||||
const std::pair<unsigned, unsigned>& minimal_size) {
|
||||
virtual void OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned>) {
|
||||
// By default, ignore this request and do nothing.
|
||||
}
|
||||
|
||||
|
||||
@@ -438,7 +438,7 @@ inline float RequestParser::Pop() {
|
||||
template <>
|
||||
inline double RequestParser::Pop() {
|
||||
const u64 value = Pop<u64>();
|
||||
float real;
|
||||
double real;
|
||||
std::memcpy(&real, &value, sizeof(real));
|
||||
return real;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ClientPort;
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ClientPort;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ClientSession;
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ void SessionRequestHandler::ClientDisconnected(const SharedPtr<ServerSession>& s
|
||||
}
|
||||
|
||||
SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
|
||||
SharedPtr<Thread> thread, const std::string& reason, u64 timeout, WakeupCallback&& callback,
|
||||
const std::string& reason, u64 timeout, WakeupCallback&& callback,
|
||||
SharedPtr<WritableEvent> writable_event) {
|
||||
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
|
||||
thread->SetWakeupCallback([context = *this, callback](
|
||||
@@ -58,7 +58,7 @@ SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
if (!writable_event) {
|
||||
// Create event if not provided
|
||||
const auto pair = WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
const auto pair = WritableEvent::CreateEventPair(kernel, ResetType::Automatic,
|
||||
"HLE Pause Event: " + reason);
|
||||
writable_event = pair.writable;
|
||||
}
|
||||
@@ -76,8 +76,9 @@ SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
|
||||
return writable_event;
|
||||
}
|
||||
|
||||
HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)
|
||||
: server_session(std::move(server_session)) {
|
||||
HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session,
|
||||
SharedPtr<Thread> thread)
|
||||
: server_session(std::move(server_session)), thread(std::move(thread)) {
|
||||
cmd_buf[0] = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ protected:
|
||||
*/
|
||||
class HLERequestContext {
|
||||
public:
|
||||
explicit HLERequestContext(SharedPtr<ServerSession> session);
|
||||
explicit HLERequestContext(SharedPtr<ServerSession> session, SharedPtr<Thread> thread);
|
||||
~HLERequestContext();
|
||||
|
||||
/// Returns a pointer to the IPC command buffer for this request.
|
||||
@@ -119,7 +119,6 @@ public:
|
||||
/**
|
||||
* Puts the specified guest thread to sleep until the returned event is signaled or until the
|
||||
* specified timeout expires.
|
||||
* @param thread Thread to be put to sleep.
|
||||
* @param reason Reason for pausing the thread, to be used for debugging purposes.
|
||||
* @param timeout Timeout in nanoseconds after which the thread will be awoken and the callback
|
||||
* invoked with a Timeout reason.
|
||||
@@ -130,8 +129,8 @@ public:
|
||||
* created.
|
||||
* @returns Event that when signaled will resume the thread and call the callback function.
|
||||
*/
|
||||
SharedPtr<WritableEvent> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason,
|
||||
u64 timeout, WakeupCallback&& callback,
|
||||
SharedPtr<WritableEvent> SleepClientThread(const std::string& reason, u64 timeout,
|
||||
WakeupCallback&& callback,
|
||||
SharedPtr<WritableEvent> writable_event = nullptr);
|
||||
|
||||
/// Populates this context with data from the requesting process/thread.
|
||||
@@ -268,6 +267,7 @@ private:
|
||||
|
||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||
SharedPtr<Kernel::ServerSession> server_session;
|
||||
SharedPtr<Thread> thread;
|
||||
// TODO(yuriks): Check common usage of this and optimize size accordingly
|
||||
boost::container::small_vector<SharedPtr<Object>, 8> move_objects;
|
||||
boost::container::small_vector<SharedPtr<Object>, 8> copy_objects;
|
||||
|
||||
@@ -46,8 +46,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
|
||||
|
||||
bool resume = true;
|
||||
|
||||
if (thread->GetStatus() == ThreadStatus::WaitSynchAny ||
|
||||
thread->GetStatus() == ThreadStatus::WaitSynchAll ||
|
||||
if (thread->GetStatus() == ThreadStatus::WaitSynch ||
|
||||
thread->GetStatus() == ThreadStatus::WaitHLEEvent) {
|
||||
// Remove the thread from each of its waiting objects' waitlists
|
||||
for (const auto& object : thread->GetWaitObjects()) {
|
||||
@@ -182,7 +181,12 @@ void KernelCore::AppendNewProcess(SharedPtr<Process> process) {
|
||||
|
||||
void KernelCore::MakeCurrentProcess(Process* process) {
|
||||
impl->current_process = process;
|
||||
Memory::SetCurrentPageTable(&process->VMManager().page_table);
|
||||
|
||||
if (process == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Memory::SetCurrentPageTable(*process);
|
||||
}
|
||||
|
||||
Process* KernelCore::CurrentProcess() {
|
||||
|
||||
@@ -33,8 +33,8 @@ enum class HandleType : u32 {
|
||||
};
|
||||
|
||||
enum class ResetType {
|
||||
OneShot, ///< Reset automatically on object acquisition
|
||||
Sticky, ///< Never reset automatically
|
||||
Automatic, ///< Reset automatically on object acquisition
|
||||
Manual, ///< Never reset automatically
|
||||
};
|
||||
|
||||
class Object : NonCopyable {
|
||||
|
||||
@@ -28,21 +28,20 @@ namespace {
|
||||
*
|
||||
* @param owner_process The parent process for the main thread
|
||||
* @param kernel The kernel instance to create the main thread under.
|
||||
* @param entry_point The address at which the thread should start execution
|
||||
* @param priority The priority to give the main thread
|
||||
*/
|
||||
void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_point, u32 priority) {
|
||||
// Initialize new "main" thread
|
||||
const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress();
|
||||
void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority) {
|
||||
const auto& vm_manager = owner_process.VMManager();
|
||||
const VAddr entry_point = vm_manager.GetCodeRegionBaseAddress();
|
||||
const VAddr stack_top = vm_manager.GetTLSIORegionEndAddress();
|
||||
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0,
|
||||
owner_process.GetIdealCore(), stack_top, owner_process);
|
||||
|
||||
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
|
||||
|
||||
// Register 1 must be a handle to the main thread
|
||||
const Handle guest_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
|
||||
thread->SetGuestHandle(guest_handle);
|
||||
thread->GetContext().cpu_registers[1] = guest_handle;
|
||||
const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
|
||||
thread->GetContext().cpu_registers[1] = thread_handle;
|
||||
|
||||
// Threads by default are dormant, wake up the main thread so it runs when the scheduler fires
|
||||
thread->ResumeFromWait();
|
||||
@@ -106,8 +105,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
|
||||
is_64bit_process = metadata.Is64BitProgram();
|
||||
|
||||
vm_manager.Reset(metadata.GetAddressSpaceType());
|
||||
// Ensure that the potentially resized page table is seen by CPU backends.
|
||||
Memory::SetCurrentPageTable(&vm_manager.page_table);
|
||||
|
||||
const auto& caps = metadata.GetKernelCapabilities();
|
||||
const auto capability_init_result =
|
||||
@@ -119,7 +116,7 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
|
||||
return handle_table.SetSize(capabilities.GetHandleTableSize());
|
||||
}
|
||||
|
||||
void Process::Run(VAddr entry_point, s32 main_thread_priority, u64 stack_size) {
|
||||
void Process::Run(s32 main_thread_priority, u64 stack_size) {
|
||||
// The kernel always ensures that the given stack size is page aligned.
|
||||
main_thread_stack_size = Common::AlignUp(stack_size, Memory::PAGE_SIZE);
|
||||
|
||||
@@ -135,7 +132,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u64 stack_size) {
|
||||
vm_manager.LogLayout();
|
||||
ChangeStatus(ProcessStatus::Running);
|
||||
|
||||
SetupMainThread(*this, kernel, entry_point, main_thread_priority);
|
||||
SetupMainThread(*this, kernel, main_thread_priority);
|
||||
}
|
||||
|
||||
void Process::PrepareForTermination() {
|
||||
@@ -150,8 +147,7 @@ void Process::PrepareForTermination() {
|
||||
continue;
|
||||
|
||||
// TODO(Subv): When are the other running/ready threads terminated?
|
||||
ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynchAny ||
|
||||
thread->GetStatus() == ThreadStatus::WaitSynchAll,
|
||||
ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynch,
|
||||
"Exiting processes with non-waiting threads is currently unimplemented");
|
||||
|
||||
thread->Stop();
|
||||
@@ -242,13 +238,11 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
|
||||
MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeData);
|
||||
|
||||
code_memory_size += module_.memory.size();
|
||||
|
||||
// Clear instruction cache in CPU JIT
|
||||
system.InvalidateCpuInstructionCaches();
|
||||
}
|
||||
|
||||
Process::Process(Core::System& system)
|
||||
: WaitObject{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {}
|
||||
: WaitObject{system.Kernel()}, vm_manager{system},
|
||||
address_arbiter{system}, mutex{system}, system{system} {}
|
||||
|
||||
Process::~Process() = default;
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Process;
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::Process;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
@@ -225,9 +225,12 @@ public:
|
||||
ResultCode LoadFromMetadata(const FileSys::ProgramMetadata& metadata);
|
||||
|
||||
/**
|
||||
* Applies address space changes and launches the process main thread.
|
||||
* Starts the main application thread for this process.
|
||||
*
|
||||
* @param main_thread_priority The priority for the main thread.
|
||||
* @param stack_size The stack size for the main thread in bytes.
|
||||
*/
|
||||
void Run(VAddr entry_point, s32 main_thread_priority, u64 stack_size);
|
||||
void Run(s32 main_thread_priority, u64 stack_size);
|
||||
|
||||
/**
|
||||
* Prepares a process for termination by stopping all of its threads
|
||||
|
||||
@@ -21,8 +21,9 @@ bool ReadableEvent::ShouldWait(const Thread* thread) const {
|
||||
void ReadableEvent::Acquire(Thread* thread) {
|
||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
||||
|
||||
if (reset_type == ResetType::OneShot)
|
||||
if (reset_type == ResetType::Automatic) {
|
||||
signaled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadableEvent::Signal() {
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
return reset_type;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ReadableEvent;
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
return GetTypeName();
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ResourceLimit;
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ServerPort;
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ServerPort;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
|
||||
// The ServerSession received a sync request, this means that there's new data available
|
||||
// from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
|
||||
// similar.
|
||||
Kernel::HLERequestContext context(this);
|
||||
Kernel::HLERequestContext context(this, thread);
|
||||
u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress());
|
||||
context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ServerSession;
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::SharedMemory;
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::SharedMemory;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,12 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
void CallSVC(u32 immediate);
|
||||
void CallSVC(Core::System& system, u32 immediate);
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -11,278 +11,319 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
static inline u64 Param(int n) {
|
||||
return Core::CurrentArmInterface().GetReg(n);
|
||||
static inline u64 Param(const Core::System& system, int n) {
|
||||
return system.CurrentArmInterface().GetReg(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* HLE a function return from the current ARM userland process
|
||||
* @param res Result to return
|
||||
* @param system System context
|
||||
* @param result Result to return
|
||||
*/
|
||||
static inline void FuncReturn(u64 res) {
|
||||
Core::CurrentArmInterface().SetReg(0, res);
|
||||
static inline void FuncReturn(Core::System& system, u64 result) {
|
||||
system.CurrentArmInterface().SetReg(0, result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function wrappers that return type ResultCode
|
||||
|
||||
template <ResultCode func(u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0)).raw);
|
||||
template <ResultCode func(Core::System&, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0))).raw);
|
||||
template <ResultCode func(Core::System&, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw);
|
||||
template <ResultCode func(Core::System&, u32, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(
|
||||
system,
|
||||
func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32, u64, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
|
||||
Param(system, 2), Param(system, 3))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(Core::System&, u32*)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param = 0;
|
||||
const u32 retval = func(¶m).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m).raw;
|
||||
system.CurrentArmInterface().SetReg(1, param);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, static_cast<u32>(Param(1))).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, static_cast<u32>(Param(system, 1))).raw;
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u32*)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u32*)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
u32 param_2 = 0;
|
||||
const u32 retval = func(¶m_1, ¶m_2).raw;
|
||||
const u32 retval = func(system, ¶m_1, ¶m_2).raw;
|
||||
|
||||
auto& arm_interface = Core::CurrentArmInterface();
|
||||
auto& arm_interface = system.CurrentArmInterface();
|
||||
arm_interface.SetReg(1, param_1);
|
||||
arm_interface.SetReg(2, param_2);
|
||||
|
||||
FuncReturn(retval);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
const u32 retval = func(¶m_1, Param(1)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1)).raw;
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u64, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
const u32 retval = func(¶m_1, Param(1), static_cast<u32>(Param(2))).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval =
|
||||
func(system, ¶m_1, Param(system, 1), static_cast<u32>(Param(system, 2))).raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u64*, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u64 param_1 = 0;
|
||||
const u32 retval = func(¶m_1, static_cast<u32>(Param(1))).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, static_cast<u32>(Param(system, 1))).raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, s32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), static_cast<s32>(Param(1))).raw);
|
||||
template <ResultCode func(Core::System&, u64, s32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), static_cast<s32>(Param(system, 1))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), static_cast<u32>(Param(1))).raw);
|
||||
template <ResultCode func(Core::System&, u64, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u64)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u64*, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, Param(1)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1)).raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u32, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u64*, u32, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, static_cast<u32>(Param(1)), static_cast<u32>(Param(2))).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, static_cast<u32>(Param(system, 1)),
|
||||
static_cast<u32>(Param(system, 2)))
|
||||
.raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0)), Param(1)).raw);
|
||||
template <ResultCode func(Core::System&, u32, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u32, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1)), Param(2)).raw);
|
||||
template <ResultCode func(Core::System&, u32, u32, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
|
||||
static_cast<u32>(Param(system, 1)), Param(system, 2))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u32*, u64*)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32, u32*, u64*)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
u64 param_2 = 0;
|
||||
ResultCode retval = func(static_cast<u32>(Param(2)), ¶m_1, ¶m_2);
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
Core::CurrentArmInterface().SetReg(2, param_2);
|
||||
FuncReturn(retval.raw);
|
||||
const ResultCode retval = func(system, static_cast<u32>(Param(system, 2)), ¶m_1, ¶m_2);
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
system.CurrentArmInterface().SetReg(2, param_2);
|
||||
FuncReturn(system, retval.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u32, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u64, u64, u32, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
|
||||
static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(Core::System&, u64, u64, u32, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
|
||||
static_cast<u32>(Param(system, 2)), Param(system, 3))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(Core::System&, u32, u64, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
|
||||
static_cast<u32>(Param(system, 2)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(Core::System&, u64, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), Param(system, 1), Param(system, 2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(Core::System&, u64, u64, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(
|
||||
func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw);
|
||||
system,
|
||||
func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u32, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2)), Param(3)).raw);
|
||||
template <ResultCode func(Core::System&, u32, u64, u64, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
|
||||
Param(system, 2), static_cast<u32>(Param(system, 3)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0)), Param(1), static_cast<u32>(Param(2))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), Param(1), Param(2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u64, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(
|
||||
func(static_cast<u32>(Param(0)), Param(1), Param(2), static_cast<u32>(Param(3))).raw);
|
||||
system,
|
||||
func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0)), Param(1), Param(2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64, u64, s64)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u64, u64, s64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
ResultCode retval =
|
||||
func(¶m_1, Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3)));
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval.raw);
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast<u32>(Param(system, 2)),
|
||||
static_cast<s64>(Param(system, 3)))
|
||||
.raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u32, s64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(
|
||||
func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3))).raw);
|
||||
template <ResultCode func(Core::System&, u64, u64, u32, s64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
|
||||
static_cast<u32>(Param(system, 2)), static_cast<s64>(Param(system, 3)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u64, u64, u64)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u64*, u64, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, Param(1), Param(2), Param(3)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval =
|
||||
func(system, ¶m_1, Param(system, 1), Param(system, 2), Param(system, 3)).raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64, u64, u64, u32, s32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u64, u64, u64, u32, s32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, Param(1), Param(2), Param(3), static_cast<u32>(Param(4)),
|
||||
static_cast<s32>(Param(5)))
|
||||
.raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2), Param(system, 3),
|
||||
static_cast<u32>(Param(system, 4)), static_cast<s32>(Param(system, 5)))
|
||||
.raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64, u64, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u64, u64, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, Param(1), Param(2), static_cast<u32>(Param(3))).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2),
|
||||
static_cast<u32>(Param(system, 3)))
|
||||
.raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(Handle*, u64, u32, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, Handle*, u64, u32, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
u32 retval =
|
||||
func(¶m_1, Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast<u32>(Param(system, 2)),
|
||||
static_cast<u32>(Param(system, 3)))
|
||||
.raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u32, s32, s64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)),
|
||||
static_cast<s64>(Param(3)))
|
||||
.raw);
|
||||
template <ResultCode func(Core::System&, u64, u32, s32, s64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
|
||||
static_cast<s32>(Param(system, 2)), static_cast<s64>(Param(system, 3)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u32, s32, s32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)),
|
||||
static_cast<s32>(Param(3)))
|
||||
.raw);
|
||||
template <ResultCode func(Core::System&, u64, u32, s32, s32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
|
||||
static_cast<s32>(Param(system, 2)), static_cast<s32>(Param(system, 3)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function wrappers that return type u32
|
||||
|
||||
template <u32 func()>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func());
|
||||
template <u32 func(Core::System&)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function wrappers that return type u64
|
||||
|
||||
template <u64 func()>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func());
|
||||
template <u64 func(Core::System&)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Function wrappers that return type void
|
||||
|
||||
template <void func()>
|
||||
void SvcWrap() {
|
||||
func();
|
||||
template <void func(Core::System&)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
func(system);
|
||||
}
|
||||
|
||||
template <void func(s64)>
|
||||
void SvcWrap() {
|
||||
func(static_cast<s64>(Param(0)));
|
||||
template <void func(Core::System&, s64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
func(system, static_cast<s64>(Param(system, 0)));
|
||||
}
|
||||
|
||||
template <void func(u64, u64 len)>
|
||||
void SvcWrap() {
|
||||
func(Param(0), Param(1));
|
||||
template <void func(Core::System&, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
func(system, Param(system, 0), Param(system, 1));
|
||||
}
|
||||
|
||||
template <void func(u64, u64, u64)>
|
||||
void SvcWrap() {
|
||||
func(Param(0), Param(1), Param(2));
|
||||
template <void func(Core::System&, u64, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
func(system, Param(system, 0), Param(system, 1), Param(system, 2));
|
||||
}
|
||||
|
||||
template <void func(u32, u64, u64)>
|
||||
void SvcWrap() {
|
||||
func(static_cast<u32>(Param(0)), Param(1), Param(2));
|
||||
template <void func(Core::System&, u32, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2));
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -101,8 +101,7 @@ void Thread::ResumeFromWait() {
|
||||
ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects");
|
||||
|
||||
switch (status) {
|
||||
case ThreadStatus::WaitSynchAll:
|
||||
case ThreadStatus::WaitSynchAny:
|
||||
case ThreadStatus::WaitSynch:
|
||||
case ThreadStatus::WaitHLEEvent:
|
||||
case ThreadStatus::WaitSleep:
|
||||
case ThreadStatus::WaitIPC:
|
||||
@@ -142,6 +141,12 @@ void Thread::ResumeFromWait() {
|
||||
ChangeScheduler();
|
||||
}
|
||||
|
||||
void Thread::CancelWait() {
|
||||
ASSERT(GetStatus() == ThreadStatus::WaitSynch);
|
||||
SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED);
|
||||
ResumeFromWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a thread context, making it ready to be scheduled and run by the CPU
|
||||
* @param context Thread context to reset
|
||||
@@ -220,11 +225,6 @@ void Thread::SetPriority(u32 priority) {
|
||||
UpdatePriority();
|
||||
}
|
||||
|
||||
void Thread::BoostPriority(u32 priority) {
|
||||
scheduler->SetThreadPriority(this, priority);
|
||||
current_priority = priority;
|
||||
}
|
||||
|
||||
void Thread::SetWaitSynchronizationResult(ResultCode result) {
|
||||
context.cpu_registers[0] = result.raw;
|
||||
}
|
||||
|
||||
@@ -30,12 +30,21 @@ enum ThreadPriority : u32 {
|
||||
};
|
||||
|
||||
enum ThreadProcessorId : s32 {
|
||||
THREADPROCESSORID_IDEAL = -2, ///< Run thread on the ideal core specified by the process.
|
||||
THREADPROCESSORID_0 = 0, ///< Run thread on core 0
|
||||
THREADPROCESSORID_1 = 1, ///< Run thread on core 1
|
||||
THREADPROCESSORID_2 = 2, ///< Run thread on core 2
|
||||
THREADPROCESSORID_3 = 3, ///< Run thread on core 3
|
||||
THREADPROCESSORID_MAX = 4, ///< Processor ID must be less than this
|
||||
/// Indicates that no particular processor core is preferred.
|
||||
THREADPROCESSORID_DONT_CARE = -1,
|
||||
|
||||
/// Run thread on the ideal core specified by the process.
|
||||
THREADPROCESSORID_IDEAL = -2,
|
||||
|
||||
/// Indicates that the preferred processor ID shouldn't be updated in
|
||||
/// a core mask setting operation.
|
||||
THREADPROCESSORID_DONT_UPDATE = -3,
|
||||
|
||||
THREADPROCESSORID_0 = 0, ///< Run thread on core 0
|
||||
THREADPROCESSORID_1 = 1, ///< Run thread on core 1
|
||||
THREADPROCESSORID_2 = 2, ///< Run thread on core 2
|
||||
THREADPROCESSORID_3 = 3, ///< Run thread on core 3
|
||||
THREADPROCESSORID_MAX = 4, ///< Processor ID must be less than this
|
||||
|
||||
/// Allowed CPU mask
|
||||
THREADPROCESSORID_DEFAULT_MASK = (1 << THREADPROCESSORID_0) | (1 << THREADPROCESSORID_1) |
|
||||
@@ -49,8 +58,7 @@ enum class ThreadStatus {
|
||||
WaitHLEEvent, ///< Waiting for hle event to finish
|
||||
WaitSleep, ///< Waiting due to a SleepThread SVC
|
||||
WaitIPC, ///< Waiting for the reply from an IPC request
|
||||
WaitSynchAny, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
|
||||
WaitSynchAll, ///< Waiting due to WaitSynchronizationN with wait_all = true
|
||||
WaitSynch, ///< Waiting due to WaitSynchronization
|
||||
WaitMutex, ///< Waiting due to an ArbitrateLock svc
|
||||
WaitCondVar, ///< Waiting due to an WaitProcessWideKey svc
|
||||
WaitArb, ///< Waiting due to a SignalToAddress/WaitForAddress svc
|
||||
@@ -102,11 +110,16 @@ public:
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
void SetName(std::string new_name) {
|
||||
name = std::move(new_name);
|
||||
}
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "Thread";
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Thread;
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::Thread;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
@@ -136,12 +149,6 @@ public:
|
||||
*/
|
||||
void SetPriority(u32 priority);
|
||||
|
||||
/**
|
||||
* Temporarily boosts the thread's priority until the next time it is scheduled
|
||||
* @param priority The new priority
|
||||
*/
|
||||
void BoostPriority(u32 priority);
|
||||
|
||||
/// Adds a thread to the list of threads that are waiting for a lock held by this thread.
|
||||
void AddMutexWaiter(SharedPtr<Thread> thread);
|
||||
|
||||
@@ -170,11 +177,17 @@ public:
|
||||
return tls_memory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes a thread from waiting
|
||||
*/
|
||||
/// Resumes a thread from waiting
|
||||
void ResumeFromWait();
|
||||
|
||||
/// Cancels a waiting operation that this thread may or may not be within.
|
||||
///
|
||||
/// When the thread is within a waiting state, this will set the thread's
|
||||
/// waiting result to signal a canceled wait. The function will then resume
|
||||
/// this thread.
|
||||
///
|
||||
void CancelWait();
|
||||
|
||||
/**
|
||||
* Schedules an event to wake up the specified thread after the specified delay
|
||||
* @param nanoseconds The time this thread will be allowed to sleep for
|
||||
@@ -185,24 +198,27 @@ public:
|
||||
void CancelWakeupTimer();
|
||||
|
||||
/**
|
||||
* Sets the result after the thread awakens (from either WaitSynchronization SVC)
|
||||
* Sets the result after the thread awakens (from svcWaitSynchronization)
|
||||
* @param result Value to set to the returned result
|
||||
*/
|
||||
void SetWaitSynchronizationResult(ResultCode result);
|
||||
|
||||
/**
|
||||
* Sets the output parameter value after the thread awakens (from WaitSynchronizationN SVC only)
|
||||
* Sets the output parameter value after the thread awakens (from svcWaitSynchronization)
|
||||
* @param output Value to set to the output parameter
|
||||
*/
|
||||
void SetWaitSynchronizationOutput(s32 output);
|
||||
|
||||
/**
|
||||
* Retrieves the index that this particular object occupies in the list of objects
|
||||
* that the thread passed to WaitSynchronizationN, starting the search from the last element.
|
||||
* It is used to set the output value of WaitSynchronizationN when the thread is awakened.
|
||||
* that the thread passed to WaitSynchronization, starting the search from the last element.
|
||||
*
|
||||
* It is used to set the output index of WaitSynchronization when the thread is awakened.
|
||||
*
|
||||
* When a thread wakes up due to an object signal, the kernel will use the index of the last
|
||||
* matching object in the wait objects list in case of having multiple instances of the same
|
||||
* object in the list.
|
||||
*
|
||||
* @param object Object to query the index of.
|
||||
*/
|
||||
s32 GetWaitObjectIndex(const WaitObject* object) const;
|
||||
@@ -239,13 +255,9 @@ public:
|
||||
*/
|
||||
VAddr GetCommandBufferAddress() const;
|
||||
|
||||
/**
|
||||
* Returns whether this thread is waiting for all the objects in
|
||||
* its wait list to become ready, as a result of a WaitSynchronizationN call
|
||||
* with wait_all = true.
|
||||
*/
|
||||
bool IsSleepingOnWaitAll() const {
|
||||
return status == ThreadStatus::WaitSynchAll;
|
||||
/// Returns whether this thread is waiting on objects from a WaitSynchronization call.
|
||||
bool IsSleepingOnWait() const {
|
||||
return status == ThreadStatus::WaitSynch;
|
||||
}
|
||||
|
||||
ThreadContext& GetContext() {
|
||||
@@ -345,10 +357,6 @@ public:
|
||||
arb_wait_address = address;
|
||||
}
|
||||
|
||||
void SetGuestHandle(Handle handle) {
|
||||
guest_handle = handle;
|
||||
}
|
||||
|
||||
bool HasWakeupCallback() const {
|
||||
return wakeup_callback != nullptr;
|
||||
}
|
||||
@@ -423,7 +431,7 @@ private:
|
||||
Process* owner_process;
|
||||
|
||||
/// Objects that the thread is waiting on, in the same order as they were
|
||||
/// passed to WaitSynchronization1/N.
|
||||
/// passed to WaitSynchronization.
|
||||
ThreadWaitObjects wait_objects;
|
||||
|
||||
/// List of threads that are waiting for a mutex that is held by this thread.
|
||||
@@ -442,14 +450,11 @@ private:
|
||||
/// If waiting for an AddressArbiter, this is the address being waited on.
|
||||
VAddr arb_wait_address{0};
|
||||
|
||||
/// Handle used by guest emulated application to access this thread
|
||||
Handle guest_handle = 0;
|
||||
|
||||
/// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
|
||||
Handle callback_handle = 0;
|
||||
|
||||
/// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
|
||||
/// was waiting via WaitSynchronizationN then the object will be the last object that became
|
||||
/// was waiting via WaitSynchronization then the object will be the last object that became
|
||||
/// available. In case of a timeout, the object will be nullptr.
|
||||
WakeupCallback wakeup_callback;
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
VMManager::VMManager() {
|
||||
VMManager::VMManager(Core::System& system) : system{system} {
|
||||
// Default to assuming a 39-bit address space. This way we have a sane
|
||||
// starting point with executables that don't provide metadata.
|
||||
Reset(FileSys::ProgramAddressSpaceType::Is39Bit);
|
||||
@@ -111,7 +111,6 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
|
||||
VirtualMemoryArea& final_vma = vma_handle->second;
|
||||
ASSERT(final_vma.size == size);
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
system.ArmInterface(0).MapBackingMemory(target, size, block->data() + offset,
|
||||
VMAPermission::ReadWriteExecute);
|
||||
system.ArmInterface(1).MapBackingMemory(target, size, block->data() + offset,
|
||||
@@ -140,7 +139,6 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me
|
||||
VirtualMemoryArea& final_vma = vma_handle->second;
|
||||
ASSERT(final_vma.size == size);
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
system.ArmInterface(0).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
|
||||
system.ArmInterface(1).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
|
||||
system.ArmInterface(2).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
|
||||
@@ -223,7 +221,6 @@ ResultCode VMManager::UnmapRange(VAddr target, u64 size) {
|
||||
|
||||
ASSERT(FindVMA(target)->second.size >= size);
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
system.ArmInterface(0).UnmapMemory(target, size);
|
||||
system.ArmInterface(1).UnmapMemory(target, size);
|
||||
system.ArmInterface(2).UnmapMemory(target, size);
|
||||
@@ -302,6 +299,86 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) {
|
||||
return MakeResult<VAddr>(heap_region_base);
|
||||
}
|
||||
|
||||
ResultCode VMManager::MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) {
|
||||
constexpr auto ignore_attribute = MemoryAttribute::LockedForIPC | MemoryAttribute::DeviceMapped;
|
||||
const auto src_check_result = CheckRangeState(
|
||||
src_address, size, MemoryState::All, MemoryState::Heap, VMAPermission::All,
|
||||
VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None, ignore_attribute);
|
||||
|
||||
if (src_check_result.Failed()) {
|
||||
return src_check_result.Code();
|
||||
}
|
||||
|
||||
const auto mirror_result =
|
||||
MirrorMemory(dst_address, src_address, size, MemoryState::ModuleCode);
|
||||
if (mirror_result.IsError()) {
|
||||
return mirror_result;
|
||||
}
|
||||
|
||||
// Ensure we lock the source memory region.
|
||||
const auto src_vma_result = CarveVMARange(src_address, size);
|
||||
if (src_vma_result.Failed()) {
|
||||
return src_vma_result.Code();
|
||||
}
|
||||
auto src_vma_iter = *src_vma_result;
|
||||
src_vma_iter->second.attribute = MemoryAttribute::Locked;
|
||||
Reprotect(src_vma_iter, VMAPermission::Read);
|
||||
|
||||
// The destination memory region is fine as is, however we need to make it read-only.
|
||||
return ReprotectRange(dst_address, size, VMAPermission::Read);
|
||||
}
|
||||
|
||||
ResultCode VMManager::UnmapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) {
|
||||
constexpr auto ignore_attribute = MemoryAttribute::LockedForIPC | MemoryAttribute::DeviceMapped;
|
||||
const auto src_check_result = CheckRangeState(
|
||||
src_address, size, MemoryState::All, MemoryState::Heap, VMAPermission::None,
|
||||
VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked, ignore_attribute);
|
||||
|
||||
if (src_check_result.Failed()) {
|
||||
return src_check_result.Code();
|
||||
}
|
||||
|
||||
// Yes, the kernel only checks the first page of the region.
|
||||
const auto dst_check_result =
|
||||
CheckRangeState(dst_address, Memory::PAGE_SIZE, MemoryState::FlagModule,
|
||||
MemoryState::FlagModule, VMAPermission::None, VMAPermission::None,
|
||||
MemoryAttribute::Mask, MemoryAttribute::None, ignore_attribute);
|
||||
|
||||
if (dst_check_result.Failed()) {
|
||||
return dst_check_result.Code();
|
||||
}
|
||||
|
||||
const auto dst_memory_state = std::get<MemoryState>(*dst_check_result);
|
||||
const auto dst_contiguous_check_result = CheckRangeState(
|
||||
dst_address, size, MemoryState::All, dst_memory_state, VMAPermission::None,
|
||||
VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::None, ignore_attribute);
|
||||
|
||||
if (dst_contiguous_check_result.Failed()) {
|
||||
return dst_contiguous_check_result.Code();
|
||||
}
|
||||
|
||||
const auto unmap_result = UnmapRange(dst_address, size);
|
||||
if (unmap_result.IsError()) {
|
||||
return unmap_result;
|
||||
}
|
||||
|
||||
// With the mirrored portion unmapped, restore the original region's traits.
|
||||
const auto src_vma_result = CarveVMARange(src_address, size);
|
||||
if (src_vma_result.Failed()) {
|
||||
return src_vma_result.Code();
|
||||
}
|
||||
auto src_vma_iter = *src_vma_result;
|
||||
src_vma_iter->second.state = MemoryState::Heap;
|
||||
src_vma_iter->second.attribute = MemoryAttribute::None;
|
||||
Reprotect(src_vma_iter, VMAPermission::ReadWrite);
|
||||
|
||||
if (dst_memory_state == MemoryState::ModuleCode) {
|
||||
system.InvalidateCpuInstructionCaches();
|
||||
}
|
||||
|
||||
return unmap_result;
|
||||
}
|
||||
|
||||
MemoryInfo VMManager::QueryMemory(VAddr address) const {
|
||||
const auto vma = FindVMA(address);
|
||||
MemoryInfo memory_info{};
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
#include "core/hle/result.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace FileSys {
|
||||
enum class ProgramAddressSpaceType : u8;
|
||||
}
|
||||
@@ -43,6 +47,9 @@ enum class VMAPermission : u8 {
|
||||
ReadExecute = Read | Execute,
|
||||
WriteExecute = Write | Execute,
|
||||
ReadWriteExecute = Read | Write | Execute,
|
||||
|
||||
// Used as a wildcard when checking permissions across memory ranges
|
||||
All = 0xFF,
|
||||
};
|
||||
|
||||
constexpr VMAPermission operator|(VMAPermission lhs, VMAPermission rhs) {
|
||||
@@ -152,6 +159,9 @@ enum class MemoryState : u32 {
|
||||
FlagUncached = 1U << 24,
|
||||
FlagCodeMemory = 1U << 25,
|
||||
|
||||
// Wildcard used in range checking to indicate all states.
|
||||
All = 0xFFFFFFFF,
|
||||
|
||||
// Convenience flag sets to reduce repetition
|
||||
IPCFlags = FlagIPC0 | FlagIPC3 | FlagIPC1,
|
||||
|
||||
@@ -315,7 +325,7 @@ class VMManager final {
|
||||
public:
|
||||
using VMAHandle = VMAMap::const_iterator;
|
||||
|
||||
VMManager();
|
||||
explicit VMManager(Core::System& system);
|
||||
~VMManager();
|
||||
|
||||
/// Clears the address space map, re-initializing with a single free area.
|
||||
@@ -415,6 +425,49 @@ public:
|
||||
///
|
||||
ResultVal<VAddr> SetHeapSize(u64 size);
|
||||
|
||||
/// Maps a region of memory as code memory.
|
||||
///
|
||||
/// @param dst_address The base address of the region to create the aliasing memory region.
|
||||
/// @param src_address The base address of the region to be aliased.
|
||||
/// @param size The total amount of memory to map in bytes.
|
||||
///
|
||||
/// @pre Both memory regions lie within the actual addressable address space.
|
||||
///
|
||||
/// @post After this function finishes execution, assuming success, then the address range
|
||||
/// [dst_address, dst_address+size) will alias the memory region,
|
||||
/// [src_address, src_address+size).
|
||||
/// <p>
|
||||
/// What this also entails is as follows:
|
||||
/// 1. The aliased region gains the Locked memory attribute.
|
||||
/// 2. The aliased region becomes read-only.
|
||||
/// 3. The aliasing region becomes read-only.
|
||||
/// 4. The aliasing region is created with a memory state of MemoryState::CodeModule.
|
||||
///
|
||||
ResultCode MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size);
|
||||
|
||||
/// Unmaps a region of memory designated as code module memory.
|
||||
///
|
||||
/// @param dst_address The base address of the memory region aliasing the source memory region.
|
||||
/// @param src_address The base address of the memory region being aliased.
|
||||
/// @param size The size of the memory region to unmap in bytes.
|
||||
///
|
||||
/// @pre Both memory ranges lie within the actual addressable address space.
|
||||
///
|
||||
/// @pre The memory region being unmapped has been previously been mapped
|
||||
/// by a call to MapCodeMemory.
|
||||
///
|
||||
/// @post After execution of the function, if successful. the aliasing memory region
|
||||
/// will be unmapped and the aliased region will have various traits about it
|
||||
/// restored to what they were prior to the original mapping call preceding
|
||||
/// this function call.
|
||||
/// <p>
|
||||
/// What this also entails is as follows:
|
||||
/// 1. The state of the memory region will now indicate a general heap region.
|
||||
/// 2. All memory attributes for the memory region are cleared.
|
||||
/// 3. Memory permissions for the region are restored to user read/write.
|
||||
///
|
||||
ResultCode UnmapCodeMemory(VAddr dst_address, VAddr src_address, u64 size);
|
||||
|
||||
/// Queries the memory manager for information about the given address.
|
||||
///
|
||||
/// @param address The address to query the memory manager about for information.
|
||||
@@ -663,5 +716,7 @@ private:
|
||||
// The end of the currently allocated heap. This is not an inclusive
|
||||
// end of the range. This is essentially 'base_address + current_size'.
|
||||
VAddr heap_end = 0;
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -30,7 +30,7 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
|
||||
waiting_threads.erase(itr);
|
||||
}
|
||||
|
||||
SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
|
||||
SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() const {
|
||||
Thread* candidate = nullptr;
|
||||
u32 candidate_priority = THREADPRIO_LOWEST + 1;
|
||||
|
||||
@@ -38,8 +38,7 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
|
||||
const ThreadStatus thread_status = thread->GetStatus();
|
||||
|
||||
// The list of waiting threads must not contain threads that are not waiting to be awakened.
|
||||
ASSERT_MSG(thread_status == ThreadStatus::WaitSynchAny ||
|
||||
thread_status == ThreadStatus::WaitSynchAll ||
|
||||
ASSERT_MSG(thread_status == ThreadStatus::WaitSynch ||
|
||||
thread_status == ThreadStatus::WaitHLEEvent,
|
||||
"Inconsistent thread statuses in waiting_threads");
|
||||
|
||||
@@ -49,10 +48,10 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
|
||||
if (ShouldWait(thread.get()))
|
||||
continue;
|
||||
|
||||
// A thread is ready to run if it's either in ThreadStatus::WaitSynchAny or
|
||||
// in ThreadStatus::WaitSynchAll and the rest of the objects it is waiting on are ready.
|
||||
// A thread is ready to run if it's either in ThreadStatus::WaitSynch
|
||||
// and the rest of the objects it is waiting on are ready.
|
||||
bool ready_to_run = true;
|
||||
if (thread_status == ThreadStatus::WaitSynchAll) {
|
||||
if (thread_status == ThreadStatus::WaitSynch) {
|
||||
ready_to_run = thread->AllWaitObjectsReady();
|
||||
}
|
||||
|
||||
@@ -68,33 +67,35 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
|
||||
void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) {
|
||||
ASSERT(!ShouldWait(thread.get()));
|
||||
|
||||
if (!thread)
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!thread->IsSleepingOnWaitAll()) {
|
||||
Acquire(thread.get());
|
||||
} else {
|
||||
if (thread->IsSleepingOnWait()) {
|
||||
for (const auto& object : thread->GetWaitObjects()) {
|
||||
ASSERT(!object->ShouldWait(thread.get()));
|
||||
object->Acquire(thread.get());
|
||||
}
|
||||
} else {
|
||||
Acquire(thread.get());
|
||||
}
|
||||
|
||||
const std::size_t index = thread->GetWaitObjectIndex(this);
|
||||
|
||||
for (const auto& object : thread->GetWaitObjects())
|
||||
for (const auto& object : thread->GetWaitObjects()) {
|
||||
object->RemoveWaitingThread(thread.get());
|
||||
}
|
||||
thread->ClearWaitObjects();
|
||||
|
||||
thread->CancelWakeupTimer();
|
||||
|
||||
bool resume = true;
|
||||
|
||||
if (thread->HasWakeupCallback())
|
||||
if (thread->HasWakeupCallback()) {
|
||||
resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, this, index);
|
||||
|
||||
if (resume)
|
||||
}
|
||||
if (resume) {
|
||||
thread->ResumeFromWait();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitObject::WakeupAllWaitingThreads() {
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
void WakeupWaitingThread(SharedPtr<Thread> thread);
|
||||
|
||||
/// Obtains the highest priority thread that is ready to run from this object's waiting list.
|
||||
SharedPtr<Thread> GetHighestPriorityReadyThread();
|
||||
SharedPtr<Thread> GetHighestPriorityReadyThread() const;
|
||||
|
||||
/// Get a const reference to the waiting threads list for debug use
|
||||
const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const;
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::WritableEvent;
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ constexpr std::array<u8, backup_jpeg_size> backup_jpeg{{
|
||||
0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9,
|
||||
}};
|
||||
|
||||
static std::string GetImagePath(UUID uuid) {
|
||||
static std::string GetImagePath(Common::UUID uuid) {
|
||||
return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
"/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
|
||||
}
|
||||
@@ -46,7 +46,7 @@ static constexpr u32 SanitizeJPEGSize(std::size_t size) {
|
||||
|
||||
class IProfile final : public ServiceFramework<IProfile> {
|
||||
public:
|
||||
explicit IProfile(UUID user_id, ProfileManager& profile_manager)
|
||||
explicit IProfile(Common::UUID user_id, ProfileManager& profile_manager)
|
||||
: ServiceFramework("IProfile"), profile_manager(profile_manager), user_id(user_id) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IProfile::Get, "Get"},
|
||||
@@ -131,12 +131,13 @@ private:
|
||||
}
|
||||
|
||||
const ProfileManager& profile_manager;
|
||||
UUID user_id; ///< The user id this profile refers to.
|
||||
Common::UUID user_id; ///< The user id this profile refers to.
|
||||
};
|
||||
|
||||
class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
|
||||
public:
|
||||
IManagerForApplication() : ServiceFramework("IManagerForApplication") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IManagerForApplication::CheckAvailability, "CheckAvailability"},
|
||||
{1, &IManagerForApplication::GetAccountId, "GetAccountId"},
|
||||
@@ -145,7 +146,10 @@ public:
|
||||
{130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"},
|
||||
{150, nullptr, "CreateAuthorizationRequest"},
|
||||
{160, nullptr, "StoreOpenContext"},
|
||||
{170, nullptr, "LoadNetworkServiceLicenseKindAsync"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -175,7 +179,7 @@ void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
UUID user_id = rp.PopRaw<UUID>();
|
||||
Common::UUID user_id = rp.PopRaw<Common::UUID>();
|
||||
LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
@@ -201,12 +205,12 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_ACC, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<UUID>(profile_manager->GetLastOpenedUser());
|
||||
rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser());
|
||||
}
|
||||
|
||||
void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
UUID user_id = rp.PopRaw<UUID>();
|
||||
Common::UUID user_id = rp.PopRaw<Common::UUID>();
|
||||
LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
@@ -241,15 +245,15 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
if (profile_manager->GetUserCount() != 1) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u128>(INVALID_UUID);
|
||||
rb.PushRaw<u128>(Common::INVALID_UUID);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto user_list = profile_manager->GetAllUsers();
|
||||
if (std::all_of(user_list.begin(), user_list.end(),
|
||||
[](const auto& user) { return user.uuid == INVALID_UUID; })) {
|
||||
[](const auto& user) { return user.uuid == Common::INVALID_UUID; })) {
|
||||
rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code
|
||||
rb.PushRaw<u128>(INVALID_UUID);
|
||||
rb.PushRaw<u128>(Common::INVALID_UUID);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Service::Account {
|
||||
|
||||
ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager)
|
||||
: Module::Interface(std::move(module), std::move(profile_manager), "acc:su") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ACC_SU::GetUserCount, "GetUserCount"},
|
||||
{1, &ACC_SU::GetUserExistence, "GetUserExistence"},
|
||||
@@ -19,6 +20,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
|
||||
{51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
|
||||
{60, nullptr, "ListOpenContextStoredUsers"},
|
||||
{99, nullptr, "DebugActivateOpenContextRetention"},
|
||||
{100, nullptr, "GetUserRegistrationNotifier"},
|
||||
{101, nullptr, "GetUserStateChangeNotifier"},
|
||||
{102, nullptr, "GetBaasAccountManagerForSystemService"},
|
||||
@@ -29,6 +31,8 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{111, nullptr, "ClearSaveDataThumbnail"},
|
||||
{112, nullptr, "LoadSaveDataThumbnail"},
|
||||
{113, nullptr, "GetSaveDataThumbnailExistence"},
|
||||
{130, nullptr, "ActivateOpenContextRetention"},
|
||||
{140, nullptr, "ListQualifiedUsers"},
|
||||
{190, nullptr, "GetUserLastOpenedApplication"},
|
||||
{191, nullptr, "ActivateOpenContextHolder"},
|
||||
{200, nullptr, "BeginUserRegistration"},
|
||||
@@ -48,6 +52,8 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{998, nullptr, "DebugSetUserStateClose"},
|
||||
{999, nullptr, "DebugSetUserStateOpen"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Service::Account {
|
||||
|
||||
ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager)
|
||||
: Module::Interface(std::move(module), std::move(profile_manager), "acc:u0") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ACC_U0::GetUserCount, "GetUserCount"},
|
||||
{1, &ACC_U0::GetUserExistence, "GetUserExistence"},
|
||||
@@ -19,6 +20,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
|
||||
{51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
|
||||
{60, nullptr, "ListOpenContextStoredUsers"},
|
||||
{99, nullptr, "DebugActivateOpenContextRetention"},
|
||||
{100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"},
|
||||
{101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"},
|
||||
{102, nullptr, "AuthenticateApplicationAsync"},
|
||||
@@ -27,7 +29,13 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{111, nullptr, "ClearSaveDataThumbnail"},
|
||||
{120, nullptr, "CreateGuestLoginRequest"},
|
||||
{130, nullptr, "LoadOpenContext"},
|
||||
{131, nullptr, "ListOpenContextStoredUsers"},
|
||||
{140, nullptr, "InitializeApplicationInfo"},
|
||||
{141, nullptr, "ListQualifiedUsers"},
|
||||
{150, nullptr, "IsUserAccountSwitchLocked"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Service::Account {
|
||||
|
||||
ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager)
|
||||
: Module::Interface(std::move(module), std::move(profile_manager), "acc:u1") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ACC_U1::GetUserCount, "GetUserCount"},
|
||||
{1, &ACC_U1::GetUserExistence, "GetUserExistence"},
|
||||
@@ -19,6 +20,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
|
||||
{51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
|
||||
{60, nullptr, "ListOpenContextStoredUsers"},
|
||||
{99, nullptr, "DebugActivateOpenContextRetention"},
|
||||
{100, nullptr, "GetUserRegistrationNotifier"},
|
||||
{101, nullptr, "GetUserStateChangeNotifier"},
|
||||
{102, nullptr, "GetBaasAccountManagerForSystemService"},
|
||||
@@ -29,12 +31,16 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{111, nullptr, "ClearSaveDataThumbnail"},
|
||||
{112, nullptr, "LoadSaveDataThumbnail"},
|
||||
{113, nullptr, "GetSaveDataThumbnailExistence"},
|
||||
{130, nullptr, "ActivateOpenContextRetention"},
|
||||
{140, nullptr, "ListQualifiedUsers"},
|
||||
{190, nullptr, "GetUserLastOpenedApplication"},
|
||||
{191, nullptr, "ActivateOpenContextHolder"},
|
||||
{997, nullptr, "DebugInvalidateTokenCacheForUser"},
|
||||
{998, nullptr, "DebugSetUserStateClose"},
|
||||
{999, nullptr, "DebugSetUserStateOpen"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
namespace Service::Account {
|
||||
|
||||
using Common::UUID;
|
||||
|
||||
struct UserRaw {
|
||||
UUID uuid;
|
||||
UUID uuid2;
|
||||
@@ -35,26 +37,6 @@ constexpr ResultCode ERROR_ARGUMENT_IS_NULL(ErrorModule::Account, 20);
|
||||
|
||||
constexpr char ACC_SAVE_AVATORS_BASE_PATH[] = "/system/save/8000000000000010/su/avators/";
|
||||
|
||||
UUID UUID::Generate() {
|
||||
std::random_device device;
|
||||
std::mt19937 gen(device());
|
||||
std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
|
||||
return UUID{distribution(gen), distribution(gen)};
|
||||
}
|
||||
|
||||
std::string UUID::Format() const {
|
||||
return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
|
||||
}
|
||||
|
||||
std::string UUID::FormatSwitch() const {
|
||||
std::array<u8, 16> s{};
|
||||
std::memcpy(s.data(), uuid.data(), sizeof(u128));
|
||||
return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
|
||||
":02x}{:02x}{:02x}{:02x}{:02x}",
|
||||
s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
|
||||
s[12], s[13], s[14], s[15]);
|
||||
}
|
||||
|
||||
ProfileManager::ProfileManager() {
|
||||
ParseUserSaveFile();
|
||||
|
||||
@@ -217,7 +199,7 @@ bool ProfileManager::UserExists(UUID uuid) const {
|
||||
bool ProfileManager::UserExistsIndex(std::size_t index) const {
|
||||
if (index >= MAX_USERS)
|
||||
return false;
|
||||
return profiles[index].user_uuid.uuid != INVALID_UUID;
|
||||
return profiles[index].user_uuid.uuid != Common::INVALID_UUID;
|
||||
}
|
||||
|
||||
/// Opens a specific user
|
||||
@@ -311,7 +293,7 @@ bool ProfileManager::RemoveUser(UUID uuid) {
|
||||
|
||||
bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) {
|
||||
const auto index = GetUserIndex(uuid);
|
||||
if (!index || profile_new.user_uuid == UUID(INVALID_UUID)) {
|
||||
if (!index || profile_new.user_uuid == UUID(Common::INVALID_UUID)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -342,7 +324,7 @@ void ProfileManager::ParseUserSaveFile() {
|
||||
}
|
||||
|
||||
for (const auto& user : data.users) {
|
||||
if (user.uuid == UUID(INVALID_UUID)) {
|
||||
if (user.uuid == UUID(Common::INVALID_UUID)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,47 +9,15 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
#include "common/uuid.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Service::Account {
|
||||
constexpr std::size_t MAX_USERS = 8;
|
||||
constexpr u128 INVALID_UUID{{0, 0}};
|
||||
|
||||
struct UUID {
|
||||
// UUIDs which are 0 are considered invalid!
|
||||
u128 uuid = INVALID_UUID;
|
||||
UUID() = default;
|
||||
explicit UUID(const u128& id) : uuid{id} {}
|
||||
explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
|
||||
|
||||
explicit operator bool() const {
|
||||
return uuid != INVALID_UUID;
|
||||
}
|
||||
|
||||
bool operator==(const UUID& rhs) const {
|
||||
return uuid == rhs.uuid;
|
||||
}
|
||||
|
||||
bool operator!=(const UUID& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
// TODO(ogniK): Properly generate uuids based on RFC-4122
|
||||
static UUID Generate();
|
||||
|
||||
// Set the UUID to {0,0} to be considered an invalid user
|
||||
void Invalidate() {
|
||||
uuid = INVALID_UUID;
|
||||
}
|
||||
|
||||
std::string Format() const;
|
||||
std::string FormatSwitch() const;
|
||||
};
|
||||
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
|
||||
|
||||
constexpr std::size_t profile_username_size = 32;
|
||||
using ProfileUsername = std::array<u8, profile_username_size>;
|
||||
using UserIDArray = std::array<UUID, MAX_USERS>;
|
||||
using UserIDArray = std::array<Common::UUID, MAX_USERS>;
|
||||
|
||||
/// Contains extra data related to a user.
|
||||
/// TODO: RE this structure
|
||||
@@ -66,7 +34,7 @@ static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect
|
||||
/// This holds general information about a users profile. This is where we store all the information
|
||||
/// based on a specific user
|
||||
struct ProfileInfo {
|
||||
UUID user_uuid;
|
||||
Common::UUID user_uuid;
|
||||
ProfileUsername username;
|
||||
u64 creation_time;
|
||||
ProfileData data; // TODO(ognik): Work out what this is
|
||||
@@ -74,7 +42,7 @@ struct ProfileInfo {
|
||||
};
|
||||
|
||||
struct ProfileBase {
|
||||
UUID user_uuid;
|
||||
Common::UUID user_uuid;
|
||||
u64_le timestamp;
|
||||
ProfileUsername username;
|
||||
|
||||
@@ -96,33 +64,33 @@ public:
|
||||
~ProfileManager();
|
||||
|
||||
ResultCode AddUser(const ProfileInfo& user);
|
||||
ResultCode CreateNewUser(UUID uuid, const ProfileUsername& username);
|
||||
ResultCode CreateNewUser(UUID uuid, const std::string& username);
|
||||
std::optional<UUID> GetUser(std::size_t index) const;
|
||||
std::optional<std::size_t> GetUserIndex(const UUID& uuid) const;
|
||||
ResultCode CreateNewUser(Common::UUID uuid, const ProfileUsername& username);
|
||||
ResultCode CreateNewUser(Common::UUID uuid, const std::string& username);
|
||||
std::optional<Common::UUID> GetUser(std::size_t index) const;
|
||||
std::optional<std::size_t> GetUserIndex(const Common::UUID& uuid) const;
|
||||
std::optional<std::size_t> GetUserIndex(const ProfileInfo& user) const;
|
||||
bool GetProfileBase(std::optional<std::size_t> index, ProfileBase& profile) const;
|
||||
bool GetProfileBase(UUID uuid, ProfileBase& profile) const;
|
||||
bool GetProfileBase(Common::UUID uuid, ProfileBase& profile) const;
|
||||
bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const;
|
||||
bool GetProfileBaseAndData(std::optional<std::size_t> index, ProfileBase& profile,
|
||||
ProfileData& data) const;
|
||||
bool GetProfileBaseAndData(UUID uuid, ProfileBase& profile, ProfileData& data) const;
|
||||
bool GetProfileBaseAndData(Common::UUID uuid, ProfileBase& profile, ProfileData& data) const;
|
||||
bool GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile,
|
||||
ProfileData& data) const;
|
||||
std::size_t GetUserCount() const;
|
||||
std::size_t GetOpenUserCount() const;
|
||||
bool UserExists(UUID uuid) const;
|
||||
bool UserExists(Common::UUID uuid) const;
|
||||
bool UserExistsIndex(std::size_t index) const;
|
||||
void OpenUser(UUID uuid);
|
||||
void CloseUser(UUID uuid);
|
||||
void OpenUser(Common::UUID uuid);
|
||||
void CloseUser(Common::UUID uuid);
|
||||
UserIDArray GetOpenUsers() const;
|
||||
UserIDArray GetAllUsers() const;
|
||||
UUID GetLastOpenedUser() const;
|
||||
Common::UUID GetLastOpenedUser() const;
|
||||
|
||||
bool CanSystemRegisterUser() const;
|
||||
|
||||
bool RemoveUser(UUID uuid);
|
||||
bool SetProfileBase(UUID uuid, const ProfileBase& profile_new);
|
||||
bool RemoveUser(Common::UUID uuid);
|
||||
bool SetProfileBase(Common::UUID uuid, const ProfileBase& profile_new);
|
||||
|
||||
private:
|
||||
void ParseUserSaveFile();
|
||||
@@ -132,7 +100,7 @@ private:
|
||||
|
||||
std::array<ProfileInfo, MAX_USERS> profiles{};
|
||||
std::size_t user_count = 0;
|
||||
UUID last_opened_user{INVALID_UUID};
|
||||
Common::UUID last_opened_user{Common::INVALID_UUID};
|
||||
};
|
||||
|
||||
}; // namespace Service::Account
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/applets/profile_select.h"
|
||||
#include "core/hle/service/am/applets/software_keyboard.h"
|
||||
#include "core/hle/service/am/applets/stub_applet.h"
|
||||
#include "core/hle/service/am/applets/web_browser.h"
|
||||
#include "core/hle/service/am/idle.h"
|
||||
#include "core/hle/service/am/omm.h"
|
||||
@@ -42,12 +41,6 @@ constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2};
|
||||
constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3};
|
||||
constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7};
|
||||
|
||||
enum class AppletId : u32 {
|
||||
ProfileSelect = 0x10,
|
||||
SoftwareKeyboard = 0x11,
|
||||
LibAppletOff = 0x17,
|
||||
};
|
||||
|
||||
constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA;
|
||||
|
||||
struct LaunchParameters {
|
||||
@@ -224,6 +217,7 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {
|
||||
{20, nullptr, "InvalidateTransitionLayer"},
|
||||
{30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
|
||||
{40, nullptr, "GetAppletResourceUsageInfo"},
|
||||
{41, nullptr, "SetCpuBoostModeForApplet"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -256,6 +250,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
|
||||
{40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
|
||||
{41, nullptr, "IsSystemBufferSharingEnabled"},
|
||||
{42, nullptr, "GetSystemSharedLayerHandle"},
|
||||
{43, nullptr, "GetSystemSharedBufferHandle"},
|
||||
{50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
|
||||
{51, nullptr, "ApproveToDisplay"},
|
||||
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
|
||||
@@ -269,9 +264,11 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
|
||||
{68, nullptr, "SetAutoSleepDisabled"},
|
||||
{69, nullptr, "IsAutoSleepDisabled"},
|
||||
{70, nullptr, "ReportMultimediaError"},
|
||||
{71, nullptr, "GetCurrentIlluminanceEx"},
|
||||
{80, nullptr, "SetWirelessPriorityMode"},
|
||||
{90, nullptr, "GetAccumulatedSuspendedTickValue"},
|
||||
{91, nullptr, "GetAccumulatedSuspendedTickChangedEvent"},
|
||||
{100, nullptr, "SetAlbumImageTakenNotificationEnabled"},
|
||||
{1000, nullptr, "GetDebugStorageChannel"},
|
||||
};
|
||||
// clang-format on
|
||||
@@ -279,7 +276,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
"ISelfController:LaunchableEvent");
|
||||
}
|
||||
|
||||
@@ -445,10 +442,10 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
|
||||
|
||||
AppletMessageQueue::AppletMessageQueue() {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
"AMMessageQueue:OnMessageRecieved");
|
||||
on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::OneShot, "AMMessageQueue:OperationModeChanged");
|
||||
kernel, Kernel::ResetType::Automatic, "AMMessageQueue:OperationModeChanged");
|
||||
}
|
||||
|
||||
AppletMessageQueue::~AppletMessageQueue() = default;
|
||||
@@ -516,11 +513,20 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q
|
||||
{50, nullptr, "IsVrModeEnabled"},
|
||||
{51, nullptr, "SetVrModeEnabled"},
|
||||
{52, nullptr, "SwitchLcdBacklight"},
|
||||
{53, nullptr, "BeginVrModeEx"},
|
||||
{54, nullptr, "EndVrModeEx"},
|
||||
{55, nullptr, "IsInControllerFirmwareUpdateSection"},
|
||||
{60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
|
||||
{61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
|
||||
{62, nullptr, "GetHdcpAuthenticationState"},
|
||||
{63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
|
||||
{64, nullptr, "SetTvPowerStateMatchingMode"},
|
||||
{65, nullptr, "GetApplicationIdByContentActionName"},
|
||||
{66, nullptr, "SetCpuBoostMode"},
|
||||
{80, nullptr, "PerformSystemButtonPressingIfInFocus"},
|
||||
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
|
||||
{91, nullptr, "GetCurrentPerformanceConfiguration"},
|
||||
{200, nullptr, "GetOperationModeSystemInfo"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -829,6 +835,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
|
||||
return;
|
||||
}
|
||||
|
||||
std::memcpy(backing.buffer.data() + offset, data.data(), data.size());
|
||||
@@ -851,6 +858,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(backing.buffer.data() + offset, size);
|
||||
@@ -873,30 +881,16 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple
|
||||
|
||||
ILibraryAppletCreator::~ILibraryAppletCreator() = default;
|
||||
|
||||
static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) {
|
||||
switch (id) {
|
||||
case AppletId::ProfileSelect:
|
||||
return std::make_shared<Applets::ProfileSelect>();
|
||||
case AppletId::SoftwareKeyboard:
|
||||
return std::make_shared<Applets::SoftwareKeyboard>();
|
||||
case AppletId::LibAppletOff:
|
||||
return std::make_shared<Applets::WebBrowser>();
|
||||
default:
|
||||
LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!",
|
||||
static_cast<u32>(id));
|
||||
return std::make_shared<Applets::StubApplet>();
|
||||
}
|
||||
}
|
||||
|
||||
void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_id = rp.PopRaw<AppletId>();
|
||||
const auto applet_id = rp.PopRaw<Applets::AppletId>();
|
||||
const auto applet_mode = rp.PopRaw<u32>();
|
||||
|
||||
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}",
|
||||
static_cast<u32>(applet_id), applet_mode);
|
||||
|
||||
const auto applet = GetAppletFromId(applet_id);
|
||||
const auto& applet_manager{Core::System::GetInstance().GetAppletManager()};
|
||||
const auto applet = applet_manager.GetApplet(applet_id);
|
||||
|
||||
if (applet == nullptr) {
|
||||
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id));
|
||||
@@ -960,6 +954,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
|
||||
{11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
|
||||
{12, nullptr, "CreateApplicationAndRequestToStart"},
|
||||
{13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"},
|
||||
{14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
|
||||
{15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
|
||||
{20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"},
|
||||
{21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"},
|
||||
{22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
|
||||
@@ -1233,6 +1229,7 @@ IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStat
|
||||
{2, nullptr, "StartSleepSequence"},
|
||||
{3, nullptr, "StartShutdownSequence"},
|
||||
{4, nullptr, "StartRebootSequence"},
|
||||
{9, nullptr, "IsAutoPowerDownRequested"},
|
||||
{10, nullptr, "LoadAndApplyIdlePolicySettings"},
|
||||
{11, nullptr, "NotifyCecSettingsChanged"},
|
||||
{12, nullptr, "SetDefaultHomeButtonLongPressTime"},
|
||||
|
||||
@@ -16,6 +16,7 @@ public:
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue)
|
||||
: ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)),
|
||||
msg_queue(std::move(msg_queue)) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
|
||||
{1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"},
|
||||
@@ -25,8 +26,11 @@ public:
|
||||
{10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"},
|
||||
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
|
||||
{20, &ILibraryAppletProxy::GetApplicationFunctions, "GetApplicationFunctions"},
|
||||
{21, nullptr, "GetAppletCommonFunctions"},
|
||||
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -113,6 +117,7 @@ public:
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue)
|
||||
: ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)),
|
||||
msg_queue(std::move(msg_queue)) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
|
||||
{1, &ISystemAppletProxy::GetSelfController, "GetSelfController"},
|
||||
@@ -124,8 +129,11 @@ public:
|
||||
{20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
|
||||
{21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
|
||||
{22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"},
|
||||
{23, nullptr, "GetAppletCommonFunctions"},
|
||||
{1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,22 +5,32 @@
|
||||
#include <cstring>
|
||||
#include "common/assert.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/error.h"
|
||||
#include "core/frontend/applets/general_frontend.h"
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
#include "core/frontend/applets/web_browser.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/applets/error.h"
|
||||
#include "core/hle/service/am/applets/general_backend.h"
|
||||
#include "core/hle/service/am/applets/profile_select.h"
|
||||
#include "core/hle/service/am/applets/software_keyboard.h"
|
||||
#include "core/hle/service/am/applets/web_browser.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
AppletDataBroker::AppletDataBroker() {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
state_changed_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:StateChangedEvent");
|
||||
kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:StateChangedEvent");
|
||||
pop_out_data_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopDataOutEvent");
|
||||
kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:PopDataOutEvent");
|
||||
pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
||||
kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
||||
}
|
||||
|
||||
AppletDataBroker::~AppletDataBroker() = default;
|
||||
@@ -111,4 +121,76 @@ void Applet::Initialize() {
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
AppletManager::AppletManager() = default;
|
||||
|
||||
AppletManager::~AppletManager() = default;
|
||||
|
||||
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
|
||||
if (set.error != nullptr)
|
||||
frontend.error = std::move(set.error);
|
||||
if (set.photo_viewer != nullptr)
|
||||
frontend.photo_viewer = std::move(set.photo_viewer);
|
||||
if (set.profile_select != nullptr)
|
||||
frontend.profile_select = std::move(set.profile_select);
|
||||
if (set.software_keyboard != nullptr)
|
||||
frontend.software_keyboard = std::move(set.software_keyboard);
|
||||
if (set.web_browser != nullptr)
|
||||
frontend.web_browser = std::move(set.web_browser);
|
||||
}
|
||||
|
||||
void AppletManager::SetDefaultAppletFrontendSet() {
|
||||
frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
|
||||
frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
|
||||
frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
|
||||
frontend.software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
|
||||
frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
|
||||
}
|
||||
|
||||
void AppletManager::SetDefaultAppletsIfMissing() {
|
||||
if (frontend.error == nullptr) {
|
||||
frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
|
||||
}
|
||||
|
||||
if (frontend.photo_viewer == nullptr) {
|
||||
frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
|
||||
}
|
||||
|
||||
if (frontend.profile_select == nullptr) {
|
||||
frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
|
||||
}
|
||||
|
||||
if (frontend.software_keyboard == nullptr) {
|
||||
frontend.software_keyboard =
|
||||
std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
|
||||
}
|
||||
|
||||
if (frontend.web_browser == nullptr) {
|
||||
frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
|
||||
}
|
||||
}
|
||||
|
||||
void AppletManager::ClearAll() {
|
||||
frontend = {};
|
||||
}
|
||||
|
||||
std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
|
||||
switch (id) {
|
||||
case AppletId::Error:
|
||||
return std::make_shared<Error>(*frontend.error);
|
||||
case AppletId::ProfileSelect:
|
||||
return std::make_shared<ProfileSelect>(*frontend.profile_select);
|
||||
case AppletId::SoftwareKeyboard:
|
||||
return std::make_shared<SoftwareKeyboard>(*frontend.software_keyboard);
|
||||
case AppletId::PhotoViewer:
|
||||
return std::make_shared<PhotoViewer>(*frontend.photo_viewer);
|
||||
case AppletId::LibAppletOff:
|
||||
return std::make_shared<WebBrowser>(*frontend.web_browser);
|
||||
default:
|
||||
UNIMPLEMENTED_MSG(
|
||||
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
|
||||
static_cast<u8>(id));
|
||||
return std::make_shared<StubApplet>();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
|
||||
@@ -12,12 +12,43 @@
|
||||
|
||||
union ResultCode;
|
||||
|
||||
namespace Core::Frontend {
|
||||
class ErrorApplet;
|
||||
class PhotoViewerApplet;
|
||||
class ProfileSelectApplet;
|
||||
class SoftwareKeyboardApplet;
|
||||
class WebBrowserApplet;
|
||||
} // namespace Core::Frontend
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IStorage;
|
||||
|
||||
namespace Applets {
|
||||
|
||||
enum class AppletId : u32 {
|
||||
OverlayDisplay = 0x02,
|
||||
QLaunch = 0x03,
|
||||
Starter = 0x04,
|
||||
Auth = 0x0A,
|
||||
Cabinet = 0x0B,
|
||||
Controller = 0x0C,
|
||||
DataErase = 0x0D,
|
||||
Error = 0x0E,
|
||||
NetConnect = 0x0F,
|
||||
ProfileSelect = 0x10,
|
||||
SoftwareKeyboard = 0x11,
|
||||
MiiEdit = 0x12,
|
||||
LibAppletWeb = 0x13,
|
||||
LibAppletShop = 0x14,
|
||||
PhotoViewer = 0x15,
|
||||
Settings = 0x16,
|
||||
LibAppletOff = 0x17,
|
||||
LibAppletWhitelisted = 0x18,
|
||||
LibAppletAuth = 0x19,
|
||||
MyPage = 0x1A,
|
||||
};
|
||||
|
||||
class AppletDataBroker final {
|
||||
public:
|
||||
AppletDataBroker();
|
||||
@@ -105,5 +136,29 @@ protected:
|
||||
bool initialized = false;
|
||||
};
|
||||
|
||||
struct AppletFrontendSet {
|
||||
std::unique_ptr<Core::Frontend::ErrorApplet> error;
|
||||
std::unique_ptr<Core::Frontend::PhotoViewerApplet> photo_viewer;
|
||||
std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_select;
|
||||
std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
|
||||
std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser;
|
||||
};
|
||||
|
||||
class AppletManager {
|
||||
public:
|
||||
AppletManager();
|
||||
~AppletManager();
|
||||
|
||||
void SetAppletFrontendSet(AppletFrontendSet set);
|
||||
void SetDefaultAppletFrontendSet();
|
||||
void SetDefaultAppletsIfMissing();
|
||||
void ClearAll();
|
||||
|
||||
std::shared_ptr<Applet> GetApplet(AppletId id) const;
|
||||
|
||||
private:
|
||||
AppletFrontendSet frontend;
|
||||
};
|
||||
|
||||
} // namespace Applets
|
||||
} // namespace Service::AM
|
||||
|
||||
182
src/core/hle/service/am/applets/error.cpp
Normal file
182
src/core/hle/service/am/applets/error.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
// Copyright 2019 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/error.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/error.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct ShowError {
|
||||
u8 mode;
|
||||
bool jump;
|
||||
INSERT_PADDING_BYTES(4);
|
||||
bool use_64bit_error_code;
|
||||
INSERT_PADDING_BYTES(1);
|
||||
u64 error_code_64;
|
||||
u32 error_code_32;
|
||||
};
|
||||
static_assert(sizeof(ShowError) == 0x14, "ShowError has incorrect size.");
|
||||
#pragma pack(pop)
|
||||
|
||||
struct ShowErrorRecord {
|
||||
u8 mode;
|
||||
bool jump;
|
||||
INSERT_PADDING_BYTES(6);
|
||||
u64 error_code_64;
|
||||
u64 posix_time;
|
||||
};
|
||||
static_assert(sizeof(ShowErrorRecord) == 0x18, "ShowErrorRecord has incorrect size.");
|
||||
|
||||
struct SystemErrorArg {
|
||||
u8 mode;
|
||||
bool jump;
|
||||
INSERT_PADDING_BYTES(6);
|
||||
u64 error_code_64;
|
||||
std::array<char, 8> language_code;
|
||||
std::array<char, 0x800> main_text;
|
||||
std::array<char, 0x800> detail_text;
|
||||
};
|
||||
static_assert(sizeof(SystemErrorArg) == 0x1018, "SystemErrorArg has incorrect size.");
|
||||
|
||||
struct ApplicationErrorArg {
|
||||
u8 mode;
|
||||
bool jump;
|
||||
INSERT_PADDING_BYTES(6);
|
||||
u32 error_code;
|
||||
std::array<char, 8> language_code;
|
||||
std::array<char, 0x800> main_text;
|
||||
std::array<char, 0x800> detail_text;
|
||||
};
|
||||
static_assert(sizeof(ApplicationErrorArg) == 0x1014, "ApplicationErrorArg has incorrect size.");
|
||||
|
||||
union Error::ErrorArguments {
|
||||
ShowError error;
|
||||
ShowErrorRecord error_record;
|
||||
SystemErrorArg system_error;
|
||||
ApplicationErrorArg application_error;
|
||||
};
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
void CopyArgumentData(const std::vector<u8>& data, T& variable) {
|
||||
ASSERT(data.size() >= sizeof(T));
|
||||
std::memcpy(&variable, data.data(), sizeof(T));
|
||||
}
|
||||
|
||||
ResultCode Decode64BitError(u64 error) {
|
||||
const auto description = (error >> 32) & 0x1FFF;
|
||||
auto module = error & 0x3FF;
|
||||
if (module >= 2000)
|
||||
module -= 2000;
|
||||
module &= 0x1FF;
|
||||
return {static_cast<ErrorModule>(module), static_cast<u32>(description)};
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
Error::Error(const Core::Frontend::ErrorApplet& frontend) : frontend(frontend) {}
|
||||
|
||||
Error::~Error() = default;
|
||||
|
||||
void Error::Initialize() {
|
||||
Applet::Initialize();
|
||||
args = std::make_unique<ErrorArguments>();
|
||||
complete = false;
|
||||
|
||||
const auto storage = broker.PopNormalDataToApplet();
|
||||
ASSERT(storage != nullptr);
|
||||
const auto data = storage->GetData();
|
||||
|
||||
ASSERT(!data.empty());
|
||||
std::memcpy(&mode, data.data(), sizeof(ErrorAppletMode));
|
||||
|
||||
switch (mode) {
|
||||
case ErrorAppletMode::ShowError:
|
||||
CopyArgumentData(data, args->error);
|
||||
if (args->error.use_64bit_error_code) {
|
||||
error_code = Decode64BitError(args->error.error_code_64);
|
||||
} else {
|
||||
error_code = ResultCode(args->error.error_code_32);
|
||||
}
|
||||
break;
|
||||
case ErrorAppletMode::ShowSystemError:
|
||||
CopyArgumentData(data, args->system_error);
|
||||
error_code = ResultCode(Decode64BitError(args->system_error.error_code_64));
|
||||
break;
|
||||
case ErrorAppletMode::ShowApplicationError:
|
||||
CopyArgumentData(data, args->application_error);
|
||||
error_code = ResultCode(args->application_error.error_code);
|
||||
break;
|
||||
case ErrorAppletMode::ShowErrorRecord:
|
||||
CopyArgumentData(data, args->error_record);
|
||||
error_code = Decode64BitError(args->error_record.error_code_64);
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", static_cast<u8>(mode));
|
||||
}
|
||||
}
|
||||
|
||||
bool Error::TransactionComplete() const {
|
||||
return complete;
|
||||
}
|
||||
|
||||
ResultCode Error::GetStatus() const {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void Error::ExecuteInteractive() {
|
||||
UNREACHABLE_MSG("Unexpected interactive applet data!");
|
||||
}
|
||||
|
||||
void Error::Execute() {
|
||||
if (complete) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto callback = [this] { DisplayCompleted(); };
|
||||
|
||||
switch (mode) {
|
||||
case ErrorAppletMode::ShowError:
|
||||
frontend.ShowError(error_code, callback);
|
||||
break;
|
||||
case ErrorAppletMode::ShowSystemError:
|
||||
case ErrorAppletMode::ShowApplicationError: {
|
||||
const auto system = mode == ErrorAppletMode::ShowSystemError;
|
||||
const auto& main_text =
|
||||
system ? args->system_error.main_text : args->application_error.main_text;
|
||||
const auto& detail_text =
|
||||
system ? args->system_error.detail_text : args->application_error.detail_text;
|
||||
|
||||
frontend.ShowCustomErrorText(
|
||||
error_code,
|
||||
Common::StringFromFixedZeroTerminatedBuffer(main_text.data(), main_text.size()),
|
||||
Common::StringFromFixedZeroTerminatedBuffer(detail_text.data(), detail_text.size()),
|
||||
callback);
|
||||
break;
|
||||
}
|
||||
case ErrorAppletMode::ShowErrorRecord:
|
||||
frontend.ShowErrorWithTimestamp(
|
||||
error_code, std::chrono::seconds{args->error_record.posix_time}, callback);
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", static_cast<u8>(mode));
|
||||
DisplayCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
void Error::DisplayCompleted() {
|
||||
complete = true;
|
||||
broker.PushNormalDataFromApplet(IStorage{{}});
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
47
src/core/hle/service/am/applets/error.h
Normal file
47
src/core/hle/service/am/applets/error.h
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2019 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
enum class ErrorAppletMode : u8 {
|
||||
ShowError = 0,
|
||||
ShowSystemError = 1,
|
||||
ShowApplicationError = 2,
|
||||
ShowEula = 3,
|
||||
ShowErrorPctl = 4,
|
||||
ShowErrorRecord = 5,
|
||||
ShowUpdateEula = 8,
|
||||
};
|
||||
|
||||
class Error final : public Applet {
|
||||
public:
|
||||
explicit Error(const Core::Frontend::ErrorApplet& frontend);
|
||||
~Error() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
ResultCode GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
||||
void DisplayCompleted();
|
||||
|
||||
private:
|
||||
union ErrorArguments;
|
||||
|
||||
const Core::Frontend::ErrorApplet& frontend;
|
||||
ResultCode error_code = RESULT_SUCCESS;
|
||||
ErrorAppletMode mode = ErrorAppletMode::ShowError;
|
||||
std::unique_ptr<ErrorArguments> args;
|
||||
|
||||
bool complete = false;
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
@@ -4,11 +4,15 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/general_frontend.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/stub_applet.h"
|
||||
#include "core/hle/service/am/applets/general_backend.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
@@ -30,6 +34,55 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string prefix) {
|
||||
}
|
||||
}
|
||||
|
||||
PhotoViewer::PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend) : frontend(frontend) {}
|
||||
|
||||
PhotoViewer::~PhotoViewer() = default;
|
||||
|
||||
void PhotoViewer::Initialize() {
|
||||
Applet::Initialize();
|
||||
complete = false;
|
||||
|
||||
const auto storage = broker.PopNormalDataToApplet();
|
||||
ASSERT(storage != nullptr);
|
||||
const auto data = storage->GetData();
|
||||
ASSERT(!data.empty());
|
||||
mode = static_cast<PhotoViewerAppletMode>(data[0]);
|
||||
}
|
||||
|
||||
bool PhotoViewer::TransactionComplete() const {
|
||||
return complete;
|
||||
}
|
||||
|
||||
ResultCode PhotoViewer::GetStatus() const {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void PhotoViewer::ExecuteInteractive() {
|
||||
UNREACHABLE_MSG("Unexpected interactive applet data.");
|
||||
}
|
||||
|
||||
void PhotoViewer::Execute() {
|
||||
if (complete)
|
||||
return;
|
||||
|
||||
const auto callback = [this] { ViewFinished(); };
|
||||
switch (mode) {
|
||||
case PhotoViewerAppletMode::CurrentApp:
|
||||
frontend.ShowPhotosForApplication(Core::CurrentProcess()->GetTitleID(), callback);
|
||||
break;
|
||||
case PhotoViewerAppletMode::AllApps:
|
||||
frontend.ShowAllPhotos(callback);
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", static_cast<u8>(mode));
|
||||
}
|
||||
}
|
||||
|
||||
void PhotoViewer::ViewFinished() {
|
||||
broker.PushNormalDataFromApplet(IStorage{{}});
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
StubApplet::StubApplet() = default;
|
||||
|
||||
StubApplet::~StubApplet() = default;
|
||||
@@ -67,4 +120,5 @@ void StubApplet::Execute() {
|
||||
broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
48
src/core/hle/service/am/applets/general_backend.h
Normal file
48
src/core/hle/service/am/applets/general_backend.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2019 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
enum class PhotoViewerAppletMode : u8 {
|
||||
CurrentApp = 0,
|
||||
AllApps = 1,
|
||||
};
|
||||
|
||||
class PhotoViewer final : public Applet {
|
||||
public:
|
||||
explicit PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend);
|
||||
~PhotoViewer() override;
|
||||
|
||||
void Initialize() override;
|
||||
bool TransactionComplete() const override;
|
||||
ResultCode GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
||||
void ViewFinished();
|
||||
|
||||
private:
|
||||
const Core::Frontend::PhotoViewerApplet& frontend;
|
||||
bool complete = false;
|
||||
PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
|
||||
};
|
||||
|
||||
class StubApplet final : public Applet {
|
||||
public:
|
||||
StubApplet();
|
||||
~StubApplet() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
ResultCode GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
@@ -15,7 +15,9 @@ namespace Service::AM::Applets {
|
||||
|
||||
constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
|
||||
|
||||
ProfileSelect::ProfileSelect() = default;
|
||||
ProfileSelect::ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend)
|
||||
: frontend(frontend) {}
|
||||
|
||||
ProfileSelect::~ProfileSelect() = default;
|
||||
|
||||
void ProfileSelect::Initialize() {
|
||||
@@ -51,21 +53,19 @@ void ProfileSelect::Execute() {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& frontend{Core::System::GetInstance().GetProfileSelector()};
|
||||
|
||||
frontend.SelectProfile([this](std::optional<Account::UUID> uuid) { SelectionComplete(uuid); });
|
||||
frontend.SelectProfile([this](std::optional<Common::UUID> uuid) { SelectionComplete(uuid); });
|
||||
}
|
||||
|
||||
void ProfileSelect::SelectionComplete(std::optional<Account::UUID> uuid) {
|
||||
void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
|
||||
UserSelectionOutput output{};
|
||||
|
||||
if (uuid.has_value() && uuid->uuid != Account::INVALID_UUID) {
|
||||
if (uuid.has_value() && uuid->uuid != Common::INVALID_UUID) {
|
||||
output.result = 0;
|
||||
output.uuid_selected = uuid->uuid;
|
||||
} else {
|
||||
status = ERR_USER_CANCELLED_SELECTION;
|
||||
output.result = ERR_USER_CANCELLED_SELECTION.raw;
|
||||
output.uuid_selected = Account::INVALID_UUID;
|
||||
output.uuid_selected = Common::INVALID_UUID;
|
||||
}
|
||||
|
||||
final_data = std::vector<u8>(sizeof(UserSelectionOutput));
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "common/uuid.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
@@ -28,7 +29,7 @@ static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has inco
|
||||
|
||||
class ProfileSelect final : public Applet {
|
||||
public:
|
||||
ProfileSelect();
|
||||
explicit ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend);
|
||||
~ProfileSelect() override;
|
||||
|
||||
void Initialize() override;
|
||||
@@ -38,9 +39,11 @@ public:
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
||||
void SelectionComplete(std::optional<Account::UUID> uuid);
|
||||
void SelectionComplete(std::optional<Common::UUID> uuid);
|
||||
|
||||
private:
|
||||
const Core::Frontend::ProfileSelectApplet& frontend;
|
||||
|
||||
UserSelectionConfig config;
|
||||
bool complete = false;
|
||||
ResultCode status = RESULT_SUCCESS;
|
||||
|
||||
@@ -39,7 +39,8 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
|
||||
return params;
|
||||
}
|
||||
|
||||
SoftwareKeyboard::SoftwareKeyboard() = default;
|
||||
SoftwareKeyboard::SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend)
|
||||
: frontend(frontend) {}
|
||||
|
||||
SoftwareKeyboard::~SoftwareKeyboard() = default;
|
||||
|
||||
@@ -90,8 +91,6 @@ void SoftwareKeyboard::ExecuteInteractive() {
|
||||
if (status == INTERACTIVE_STATUS_OK) {
|
||||
complete = true;
|
||||
} else {
|
||||
const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};
|
||||
|
||||
std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
|
||||
std::memcpy(string.data(), data.data() + 4, string.size() * 2);
|
||||
frontend.SendTextCheckDialog(
|
||||
@@ -106,8 +105,6 @@ void SoftwareKeyboard::Execute() {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};
|
||||
|
||||
const auto parameters = ConvertToFrontendParameters(config, initial_text);
|
||||
|
||||
frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); },
|
||||
|
||||
@@ -55,7 +55,7 @@ static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect siz
|
||||
|
||||
class SoftwareKeyboard final : public Applet {
|
||||
public:
|
||||
SoftwareKeyboard();
|
||||
explicit SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend);
|
||||
~SoftwareKeyboard() override;
|
||||
|
||||
void Initialize() override;
|
||||
@@ -68,6 +68,8 @@ public:
|
||||
void WriteText(std::optional<std::u16string> text);
|
||||
|
||||
private:
|
||||
const Core::Frontend::SoftwareKeyboardApplet& frontend;
|
||||
|
||||
KeyboardConfig config;
|
||||
std::u16string initial_text;
|
||||
bool complete = false;
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
class StubApplet final : public Applet {
|
||||
public:
|
||||
StubApplet();
|
||||
~StubApplet() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
ResultCode GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
@@ -95,7 +95,7 @@ static FileSys::VirtualFile GetManualRomFS() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WebBrowser::WebBrowser() = default;
|
||||
WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend) : frontend(frontend) {}
|
||||
|
||||
WebBrowser::~WebBrowser() = default;
|
||||
|
||||
@@ -152,8 +152,6 @@ void WebBrowser::Execute() {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& frontend{Core::System::GetInstance().GetWebBrowser()};
|
||||
|
||||
frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Service::AM::Applets {
|
||||
|
||||
class WebBrowser final : public Applet {
|
||||
public:
|
||||
WebBrowser();
|
||||
WebBrowser(Core::Frontend::WebBrowserApplet& frontend);
|
||||
~WebBrowser() override;
|
||||
|
||||
void Initialize() override;
|
||||
@@ -32,6 +32,8 @@ public:
|
||||
void Finalize();
|
||||
|
||||
private:
|
||||
Core::Frontend::WebBrowserApplet& frontend;
|
||||
|
||||
bool complete = false;
|
||||
bool unpacked = false;
|
||||
ResultCode status = RESULT_SUCCESS;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
#include "core/file_sys/partition_filesystem.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
@@ -18,7 +17,6 @@
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/aoc/aoc_u.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
@@ -50,6 +48,7 @@ static std::vector<u64> AccumulateAOCTitleIDs() {
|
||||
}
|
||||
|
||||
AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs()) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "CountAddOnContentByApplicationId"},
|
||||
{1, nullptr, "ListAddOnContentByApplicationId"},
|
||||
@@ -60,18 +59,29 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
|
||||
{6, nullptr, "PrepareAddOnContentByApplicationId"},
|
||||
{7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
|
||||
{8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
|
||||
{100, nullptr, "CreateEcPurchasedEventManager"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
"GetAddOnContentListChanged:Event");
|
||||
}
|
||||
|
||||
AOC_U::~AOC_U() = default;
|
||||
|
||||
void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AOC, "called");
|
||||
struct Parameters {
|
||||
u64 process_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 8);
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto params = rp.PopRaw<Parameters>();
|
||||
|
||||
LOG_DEBUG(Service_AOC, "called. process_id={}", params.process_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -90,23 +100,32 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
u32 offset;
|
||||
u32 count;
|
||||
u64 process_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 16);
|
||||
|
||||
const auto offset = rp.PopRaw<u32>();
|
||||
auto count = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_AOC, "called with offset={}, count={}", offset, count);
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto [offset, count, process_id] = rp.PopRaw<Parameters>();
|
||||
|
||||
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
|
||||
process_id);
|
||||
|
||||
const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID();
|
||||
|
||||
std::vector<u32> out;
|
||||
for (size_t i = 0; i < add_on_content.size(); ++i) {
|
||||
if ((add_on_content[i] & DLC_BASE_TITLE_ID_MASK) == current)
|
||||
out.push_back(static_cast<u32>(add_on_content[i] & 0x7FF));
|
||||
}
|
||||
|
||||
const auto& disabled = Settings::values.disabled_addons[current];
|
||||
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end())
|
||||
out = {};
|
||||
if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) {
|
||||
for (u64 content_id : add_on_content) {
|
||||
if ((content_id & DLC_BASE_TITLE_ID_MASK) != current) {
|
||||
continue;
|
||||
}
|
||||
|
||||
out.push_back(static_cast<u32>(content_id & 0x7FF));
|
||||
}
|
||||
}
|
||||
|
||||
if (out.size() < offset) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -115,22 +134,31 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
|
||||
const auto out_count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
|
||||
std::rotate(out.begin(), out.begin() + offset, out.end());
|
||||
out.resize(count);
|
||||
out.resize(out_count);
|
||||
|
||||
ctx.WriteBuffer(out);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(count);
|
||||
rb.Push(out_count);
|
||||
}
|
||||
|
||||
void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AOC, "called");
|
||||
struct Parameters {
|
||||
u64 process_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 8);
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto params = rp.PopRaw<Parameters>();
|
||||
|
||||
LOG_DEBUG(Service_AOC, "called. process_id={}", params.process_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
|
||||
FileSys::PatchManager pm{title_id};
|
||||
|
||||
@@ -144,10 +172,17 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
s32 addon_index;
|
||||
u64 process_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 16);
|
||||
|
||||
const auto aoc_id = rp.PopRaw<u32>();
|
||||
LOG_WARNING(Service_AOC, "(STUBBED) called with aoc_id={:08X}", aoc_id);
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto [addon_index, process_id] = rp.PopRaw<Parameters>();
|
||||
|
||||
LOG_WARNING(Service_AOC, "(STUBBED) called with addon_index={}, process_id={}", addon_index,
|
||||
process_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -87,6 +87,8 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
|
||||
{3, nullptr, "GetLastThrottlingState"},
|
||||
{4, nullptr, "ClearLastThrottlingState"},
|
||||
{5, nullptr, "LoadAndApplySettings"},
|
||||
{6, nullptr, "SetCpuBoostMode"},
|
||||
{7, nullptr, "GetCurrentPerformanceConfiguration"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/audio/audctl.h"
|
||||
|
||||
namespace Service::Audio {
|
||||
@@ -11,8 +13,8 @@ AudCtl::AudCtl() : ServiceFramework{"audctl"} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetTargetVolume"},
|
||||
{1, nullptr, "SetTargetVolume"},
|
||||
{2, nullptr, "GetTargetVolumeMin"},
|
||||
{3, nullptr, "GetTargetVolumeMax"},
|
||||
{2, &AudCtl::GetTargetVolumeMin, "GetTargetVolumeMin"},
|
||||
{3, &AudCtl::GetTargetVolumeMax, "GetTargetVolumeMax"},
|
||||
{4, nullptr, "IsTargetMute"},
|
||||
{5, nullptr, "SetTargetMute"},
|
||||
{6, nullptr, "IsTargetConnected"},
|
||||
@@ -44,4 +46,28 @@ AudCtl::AudCtl() : ServiceFramework{"audctl"} {
|
||||
|
||||
AudCtl::~AudCtl() = default;
|
||||
|
||||
void AudCtl::GetTargetVolumeMin(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Audio, "called.");
|
||||
|
||||
// This service function is currently hardcoded on the
|
||||
// actual console to this value (as of 8.0.0).
|
||||
constexpr s32 target_min_volume = 0;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(target_min_volume);
|
||||
}
|
||||
|
||||
void AudCtl::GetTargetVolumeMax(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Audio, "called.");
|
||||
|
||||
// This service function is currently hardcoded on the
|
||||
// actual console to this value (as of 8.0.0).
|
||||
constexpr s32 target_max_volume = 15;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(target_max_volume);
|
||||
}
|
||||
|
||||
} // namespace Service::Audio
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user