Compare commits
156 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f62bae9e3 | ||
|
|
faa067f175 | ||
|
|
8acf739b3f | ||
|
|
8f638e81e9 | ||
|
|
d57b12193b | ||
|
|
b805ee653f | ||
|
|
d2c4dbde9e | ||
|
|
2c4615f3a6 | ||
|
|
a488b86e97 | ||
|
|
510f71d871 | ||
|
|
9f81221528 | ||
|
|
eae107d0e9 | ||
|
|
da22def511 | ||
|
|
f23760b1e1 | ||
|
|
1e983b19df | ||
|
|
ad5a5ef43f | ||
|
|
e02785be83 | ||
|
|
27a6ef64fd | ||
|
|
9434603450 | ||
|
|
703d7aaab6 | ||
|
|
9beb239634 | ||
|
|
2cdc7142b0 | ||
|
|
34abe4a905 | ||
|
|
f6d45b747e | ||
|
|
1b074b8984 | ||
|
|
50d2dc3b51 | ||
|
|
d23f9f75ff | ||
|
|
4356361faf | ||
|
|
51aa5a5364 | ||
|
|
25538db150 | ||
|
|
9bae3992e6 | ||
|
|
91d8657959 | ||
|
|
d3c166d4d5 | ||
|
|
0536004d91 | ||
|
|
57f80c74b6 | ||
|
|
caa11748c6 | ||
|
|
7866eb03bb | ||
|
|
4b03e6e776 | ||
|
|
8f5052a514 | ||
|
|
0b27c721c9 | ||
|
|
2a7eff57a8 | ||
|
|
bf380b8584 | ||
|
|
864841eb9e | ||
|
|
39a8dba9a6 | ||
|
|
626f746971 | ||
|
|
7a06864100 | ||
|
|
0297448fbc | ||
|
|
aa2844bcf9 | ||
|
|
b57c5a9b54 | ||
|
|
674122038a | ||
|
|
126aaeb6d3 | ||
|
|
c7d8b7421c | ||
|
|
7444963bbb | ||
|
|
2cb6106523 | ||
|
|
76a0814142 | ||
|
|
84bb772003 | ||
|
|
269d233a94 | ||
|
|
c2f6f2ba7a | ||
|
|
2e8d6fe9a0 | ||
|
|
eba3bb9d21 | ||
|
|
cfa7b92563 | ||
|
|
89edbe8aa2 | ||
|
|
b6156e735c | ||
|
|
ab704acab8 | ||
|
|
722195cf70 | ||
|
|
addc0bf037 | ||
|
|
086db71e94 | ||
|
|
7ccbdd4d8d | ||
|
|
5e5933256b | ||
|
|
da7e9553de | ||
|
|
6fca1c82fd | ||
|
|
de4746ff69 | ||
|
|
0eeecde67c | ||
|
|
479bd50b96 | ||
|
|
d3d0f2f451 | ||
|
|
34bed1ab41 | ||
|
|
d9df63583f | ||
|
|
3401676768 | ||
|
|
02c2b28cd0 | ||
|
|
66f2ad716b | ||
|
|
74120c5e3a | ||
|
|
f93d939426 | ||
|
|
34ce1dd7c7 | ||
|
|
b8751630e2 | ||
|
|
d9205f82b3 | ||
|
|
b99fc70191 | ||
|
|
260b841dc3 | ||
|
|
0b7a03bd65 | ||
|
|
860d73637e | ||
|
|
cc47a6a9c2 | ||
|
|
403cf6be69 | ||
|
|
9e726a9250 | ||
|
|
df51eb9bde | ||
|
|
898aa5fb66 | ||
|
|
ebb64d5bf4 | ||
|
|
7d257ce7bd | ||
|
|
707ed72a3c | ||
|
|
08d5bd36d8 | ||
|
|
6e81473574 | ||
|
|
c17a59b58e | ||
|
|
0d2d0844a5 | ||
|
|
01a57d4c8d | ||
|
|
1da72c7792 | ||
|
|
54dc22285b | ||
|
|
03b3c5800b | ||
|
|
07934f0e87 | ||
|
|
72b22fd433 | ||
|
|
1ed1dd3c89 | ||
|
|
fa3ffff8de | ||
|
|
aab57b7975 | ||
|
|
497ccfaedc | ||
|
|
922b0d9933 | ||
|
|
bea6fca9a1 | ||
|
|
fc84822266 | ||
|
|
29a06ad393 | ||
|
|
e1a196cfd7 | ||
|
|
0af182baa2 | ||
|
|
d95605cd24 | ||
|
|
b096ec68cd | ||
|
|
724c19a307 | ||
|
|
cfdec68d5a | ||
|
|
729545a946 | ||
|
|
cd80471c90 | ||
|
|
dec5680934 | ||
|
|
dcb91ca4a4 | ||
|
|
7412f314e4 | ||
|
|
3c5fb53634 | ||
|
|
609c11bab3 | ||
|
|
697a2c0018 | ||
|
|
3b5690c9e1 | ||
|
|
2ff39f6fdc | ||
|
|
ae758a236f | ||
|
|
75e0d16caa | ||
|
|
c413cafdac | ||
|
|
4c8c5ad1b6 | ||
|
|
98fb36cb0a | ||
|
|
a02c4686c3 | ||
|
|
1acd807176 | ||
|
|
f4610e77e2 | ||
|
|
c19ad21ae8 | ||
|
|
04d9c27120 | ||
|
|
4cc8ab8a86 | ||
|
|
2e268abe42 | ||
|
|
51c787bfc1 | ||
|
|
1c65b3ee53 | ||
|
|
19bbdedf00 | ||
|
|
d363b2c7d2 | ||
|
|
8805233f5e | ||
|
|
9c5248d101 | ||
|
|
502f3cef87 | ||
|
|
29cd40bded | ||
|
|
5ba49f188b | ||
|
|
6e2040c955 | ||
|
|
ae93402312 | ||
|
|
80d74d77d5 | ||
|
|
fd40d55a4f |
@@ -202,7 +202,7 @@ macro(yuzu_find_packages)
|
||||
endmacro()
|
||||
|
||||
if (NOT YUZU_USE_BUNDLED_BOOST)
|
||||
find_package(Boost 1.73.0 COMPONENTS context headers QUIET)
|
||||
find_package(Boost 1.73.0 CONFIG COMPONENTS context headers QUIET)
|
||||
endif()
|
||||
if (Boost_FOUND)
|
||||
set(Boost_LIBRARIES Boost::boost)
|
||||
@@ -224,7 +224,7 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR YUZU_USE_BUNDLED_BOOST)
|
||||
download_bundled_external("boost/" ${Boost_EXT_NAME} "")
|
||||
set(Boost_USE_DEBUG_RUNTIME FALSE)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
find_package(Boost 1.75.0 REQUIRED COMPONENTS context headers PATHS ${Boost_PATH} NO_DEFAULT_PATH)
|
||||
find_package(Boost 1.75.0 CONFIG REQUIRED COMPONENTS context headers PATHS ${Boost_PATH} NO_DEFAULT_PATH)
|
||||
# Manually set the include dirs since the find_package sets it incorrectly
|
||||
set(Boost_INCLUDE_DIRS ${Boost_PATH}/include CACHE PATH "Path to Boost headers" FORCE)
|
||||
include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
|
||||
|
||||
BIN
dist/icons/overlay/osk_button_B.png
vendored
|
Before Width: | Height: | Size: 741 B After Width: | Height: | Size: 2.6 KiB |
BIN
dist/icons/overlay/osk_button_B_dark.png
vendored
|
Before Width: | Height: | Size: 767 B After Width: | Height: | Size: 2.7 KiB |
BIN
dist/icons/overlay/osk_button_B_dark_disabled.png
vendored
|
Before Width: | Height: | Size: 781 B After Width: | Height: | Size: 2.6 KiB |
BIN
dist/icons/overlay/osk_button_B_disabled.png
vendored
|
Before Width: | Height: | Size: 791 B After Width: | Height: | Size: 2.6 KiB |
BIN
dist/icons/overlay/osk_button_Y.png
vendored
|
Before Width: | Height: | Size: 726 B After Width: | Height: | Size: 2.6 KiB |
BIN
dist/icons/overlay/osk_button_Y_dark.png
vendored
|
Before Width: | Height: | Size: 502 B After Width: | Height: | Size: 2.0 KiB |
BIN
dist/icons/overlay/osk_button_Y_dark_disabled.png
vendored
|
Before Width: | Height: | Size: 694 B After Width: | Height: | Size: 2.6 KiB |
BIN
dist/icons/overlay/osk_button_Y_disabled.png
vendored
|
Before Width: | Height: | Size: 699 B After Width: | Height: | Size: 2.6 KiB |
BIN
dist/icons/overlay/osk_button_plus.png
vendored
|
Before Width: | Height: | Size: 626 B After Width: | Height: | Size: 2.2 KiB |
BIN
dist/icons/overlay/osk_button_plus_dark.png
vendored
|
Before Width: | Height: | Size: 676 B After Width: | Height: | Size: 2.2 KiB |
BIN
dist/icons/overlay/osk_button_plus_dark_disabled.png
vendored
|
Before Width: | Height: | Size: 645 B After Width: | Height: | Size: 2.2 KiB |
BIN
dist/icons/overlay/osk_button_plus_disabled.png
vendored
|
Before Width: | Height: | Size: 664 B After Width: | Height: | Size: 2.2 KiB |
BIN
dist/icons/overlay/osk_button_shift_lock_off.png
vendored
|
Before Width: | Height: | Size: 281 B After Width: | Height: | Size: 936 B |
BIN
dist/icons/overlay/osk_button_shift_lock_on.png
vendored
|
Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 894 B |
3
dist/license.md
vendored
@@ -12,6 +12,7 @@ qt_themes/default/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/default/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/default/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team
|
||||
qt_themes/default/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/default/icons/48x48/star.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/qdarkstyle/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/qdarkstyle/icons/16x16/view-refresh.png | Apache 2.0 | https://material.io
|
||||
qt_themes/qdarkstyle/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||
@@ -20,6 +21,7 @@ qt_themes/qdarkstyle/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/qdarkstyle/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/qdarkstyle/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team
|
||||
qt_themes/qdarkstyle/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/qdarkstyle/icons/48x48/star.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/colorful/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/colorful/icons/16x16/view-refresh.png | Apache 2.0 | https://material.io
|
||||
qt_themes/colorful/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||
@@ -28,5 +30,6 @@ qt_themes/colorful/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/colorful/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/colorful/icons/48x48/plus.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/colorful/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/colorful/icons/48x48/star.png | CC BY-ND 3.0 | https://icons8.com
|
||||
|
||||
<!-- TODO: Add the license of the yuzu icon -->
|
||||
BIN
dist/qt_themes/colorful/icons/48x48/star.png
vendored
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
1
dist/qt_themes/colorful/style.qrc
vendored
@@ -7,6 +7,7 @@
|
||||
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
||||
<file alias="48x48/plus.png">icons/48x48/plus.png</file>
|
||||
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
||||
<file alias="48x48/star.png">icons/48x48/star.png</file>
|
||||
<file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="colorful">
|
||||
|
||||
1
dist/qt_themes/default/default.qrc
vendored
@@ -10,6 +10,7 @@
|
||||
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
||||
<file alias="48x48/plus.png">icons/48x48/plus.png</file>
|
||||
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
||||
<file alias="48x48/star.png">icons/48x48/star.png</file>
|
||||
<file alias="256x256/yuzu.png">icons/256x256/yuzu.png</file>
|
||||
<file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
|
||||
</qresource>
|
||||
|
||||
BIN
dist/qt_themes/default/icons/48x48/star.png
vendored
Normal file
|
After Width: | Height: | Size: 686 B |
36
dist/qt_themes/default/style.qss
vendored
@@ -515,45 +515,35 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
|
||||
background-position: right top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_B.png);
|
||||
image: url(:/overlay/osk_button_B.png);
|
||||
image-position: right;
|
||||
qproperty-icon: url(:/overlay/osk_button_backspace.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
|
||||
background-position: right top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_Y.png);
|
||||
image: url(:/overlay/osk_button_Y.png);
|
||||
image-position: right;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
|
||||
background-position: right top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_plus.png);
|
||||
image: url(:/overlay/osk_button_plus.png);
|
||||
image-position: right;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
|
||||
background-position: left top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image-position: left;
|
||||
qproperty-icon: url(:/overlay/osk_button_shift.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
|
||||
background-position: left top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image-position: left;
|
||||
qproperty-icon: url(:/overlay/osk_button_shift_on.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
@@ -645,16 +635,16 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
|
||||
background-image: url(:/overlay/osk_button_plus_disabled.png);
|
||||
image: url(:/overlay/osk_button_plus_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
|
||||
background-image: url(:/overlay/osk_button_B_disabled.png);
|
||||
image: url(:/overlay/osk_button_B_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
|
||||
background-image: url(:/overlay/osk_button_Y_disabled.png);
|
||||
image: url(:/overlay/osk_button_Y_disabled.png);
|
||||
}
|
||||
|
||||
BIN
dist/qt_themes/qdarkstyle/icons/48x48/star.png
vendored
Normal file
|
After Width: | Height: | Size: 725 B |
1
dist/qt_themes/qdarkstyle/style.qrc
vendored
@@ -8,6 +8,7 @@
|
||||
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
||||
<file alias="48x48/plus.png">icons/48x48/plus.png</file>
|
||||
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
||||
<file alias="48x48/star.png">icons/48x48/star.png</file>
|
||||
<file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="qss_icons">
|
||||
|
||||
36
dist/qt_themes/qdarkstyle/style.qss
vendored
@@ -1805,46 +1805,36 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
|
||||
background-position: right top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_B_dark.png);
|
||||
image: url(:/overlay/osk_button_B_dark.png);
|
||||
image-position: right;
|
||||
qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
|
||||
background-position: right top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_Y_dark.png);
|
||||
image: url(:/overlay/osk_button_Y_dark.png);
|
||||
image-position: right;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
|
||||
color: rgba(44, 44, 44, 1);
|
||||
background-position: right top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_plus_dark.png);
|
||||
image: url(:/overlay/osk_button_plus_dark.png);
|
||||
image-position: right;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
|
||||
background-position: left top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image-position: left;
|
||||
qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
|
||||
background-position: left top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image-position: left;
|
||||
qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
@@ -1936,18 +1926,18 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
|
||||
background-image: url(:/overlay/osk_button_plus_dark_disabled.png);
|
||||
image: url(:/overlay/osk_button_plus_dark_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
|
||||
background-image: url(:/overlay/osk_button_B_dark_disabled.png);
|
||||
image: url(:/overlay/osk_button_B_dark_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
|
||||
background-image: url(:/overlay/osk_button_Y_dark_disabled.png);
|
||||
image: url(:/overlay/osk_button_Y_dark_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QFrame,
|
||||
|
||||
BIN
dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/star.png
vendored
Normal file
|
After Width: | Height: | Size: 725 B |
@@ -8,6 +8,7 @@
|
||||
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
||||
<file alias="48x48/plus.png">icons/48x48/plus.png</file>
|
||||
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
||||
<file alias="48x48/star.png">icons/48x48/star.png</file>
|
||||
<file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="qss_icons">
|
||||
|
||||
@@ -2740,46 +2740,36 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
|
||||
background-position: right top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_B_dark.png);
|
||||
image: url(:/overlay/osk_button_B_dark.png);
|
||||
image-position: right;
|
||||
qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
|
||||
background-position: right top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_Y_dark.png);
|
||||
image: url(:/overlay/osk_button_Y_dark.png);
|
||||
image-position: right;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
|
||||
color: rgba(44, 44, 44, 1);
|
||||
background-position: right top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_plus_dark.png);
|
||||
image: url(:/overlay/osk_button_plus_dark.png);
|
||||
image-position: right;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
|
||||
background-position: left top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image-position: left;
|
||||
qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
|
||||
background-position: left top;
|
||||
background-repeat: no-repeat;
|
||||
background-origin: content;
|
||||
background-image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image-position: left;
|
||||
qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
@@ -2871,16 +2861,16 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
|
||||
background-image: url(:/overlay/osk_button_plus_dark_disabled.png);
|
||||
image: url(:/overlay/osk_button_plus_dark_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
|
||||
background-image: url(:/overlay/osk_button_B_dark_disabled.png);
|
||||
image: url(:/overlay/osk_button_B_dark_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
|
||||
background-image: url(:/overlay/osk_button_Y_dark_disabled.png);
|
||||
image: url(:/overlay/osk_button_Y_dark_disabled.png);
|
||||
}
|
||||
|
||||
@@ -358,6 +358,7 @@ chip.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com
|
||||
folder.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com
|
||||
plus.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com
|
||||
sd_card.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com
|
||||
star.png | CC BY-ND 3.0 | https://icons8.com
|
||||
|
||||
Note:
|
||||
Some icons are different in different themes, and they are separately listed
|
||||
|
||||
@@ -108,6 +108,14 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
} \
|
||||
}
|
||||
|
||||
#define YUZU_NON_COPYABLE(cls) \
|
||||
cls(const cls&) = delete; \
|
||||
cls& operator=(const cls&) = delete
|
||||
|
||||
#define YUZU_NON_MOVEABLE(cls) \
|
||||
cls(cls&&) = delete; \
|
||||
cls& operator=(cls&&) = delete
|
||||
|
||||
#define R_SUCCEEDED(res) (res.IsSuccess())
|
||||
|
||||
/// Evaluates an expression that returns a result, and returns the result if it would fail.
|
||||
@@ -128,4 +136,19 @@ namespace Common {
|
||||
return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24;
|
||||
}
|
||||
|
||||
// std::size() does not support zero-size C arrays. We're fixing that.
|
||||
template <class C>
|
||||
constexpr auto Size(const C& c) -> decltype(c.size()) {
|
||||
return std::size(c);
|
||||
}
|
||||
|
||||
template <class C>
|
||||
constexpr std::size_t Size(const C& c) {
|
||||
if constexpr (sizeof(C) == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return std::size(c);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -509,7 +509,6 @@ private:
|
||||
|
||||
private:
|
||||
static constexpr TypedStorage<Derived> DerivedStorage = {};
|
||||
static_assert(GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage));
|
||||
};
|
||||
|
||||
template <auto T, class Derived = impl::GetParentType<T>>
|
||||
|
||||
@@ -133,27 +133,27 @@ template <auto MemberPtr>
|
||||
using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member;
|
||||
|
||||
template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>>
|
||||
static inline std::ptrdiff_t OffsetOf = [] {
|
||||
constexpr std::ptrdiff_t OffsetOf() {
|
||||
using DeducedParentType = GetParentType<MemberPtr>;
|
||||
using MemberType = GetMemberType<MemberPtr>;
|
||||
static_assert(std::is_base_of<DeducedParentType, RealParentType>::value ||
|
||||
std::is_same<RealParentType, DeducedParentType>::value);
|
||||
|
||||
return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr);
|
||||
}();
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
||||
template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
||||
constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) {
|
||||
std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>;
|
||||
std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
|
||||
return *static_cast<RealParentType*>(
|
||||
static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset));
|
||||
}
|
||||
|
||||
template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
||||
constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) {
|
||||
std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>;
|
||||
std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
|
||||
return *static_cast<const RealParentType*>(static_cast<const void*>(
|
||||
static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset));
|
||||
}
|
||||
|
||||
@@ -144,31 +144,40 @@ add_library(core STATIC
|
||||
hle/kernel/board/nintendo/nx/k_system_control.cpp
|
||||
hle/kernel/board/nintendo/nx/k_system_control.h
|
||||
hle/kernel/board/nintendo/nx/secure_monitor.h
|
||||
hle/kernel/client_port.cpp
|
||||
hle/kernel/client_port.h
|
||||
hle/kernel/client_session.cpp
|
||||
hle/kernel/client_session.h
|
||||
hle/kernel/code_set.cpp
|
||||
hle/kernel/code_set.h
|
||||
hle/kernel/svc_results.h
|
||||
hle/kernel/global_scheduler_context.cpp
|
||||
hle/kernel/global_scheduler_context.h
|
||||
hle/kernel/handle_table.cpp
|
||||
hle/kernel/handle_table.h
|
||||
hle/kernel/hle_ipc.cpp
|
||||
hle/kernel/hle_ipc.h
|
||||
hle/kernel/init/init_slab_setup.cpp
|
||||
hle/kernel/init/init_slab_setup.h
|
||||
hle/kernel/k_address_arbiter.cpp
|
||||
hle/kernel/k_address_arbiter.h
|
||||
hle/kernel/k_address_space_info.cpp
|
||||
hle/kernel/k_address_space_info.h
|
||||
hle/kernel/k_auto_object.cpp
|
||||
hle/kernel/k_auto_object.h
|
||||
hle/kernel/k_auto_object_container.cpp
|
||||
hle/kernel/k_auto_object_container.h
|
||||
hle/kernel/k_affinity_mask.h
|
||||
hle/kernel/k_class_token.cpp
|
||||
hle/kernel/k_class_token.h
|
||||
hle/kernel/k_client_port.cpp
|
||||
hle/kernel/k_client_port.h
|
||||
hle/kernel/k_client_session.cpp
|
||||
hle/kernel/k_client_session.h
|
||||
hle/kernel/k_condition_variable.cpp
|
||||
hle/kernel/k_condition_variable.h
|
||||
hle/kernel/k_event.cpp
|
||||
hle/kernel/k_event.h
|
||||
hle/kernel/k_handle_table.cpp
|
||||
hle/kernel/k_handle_table.h
|
||||
hle/kernel/k_light_condition_variable.h
|
||||
hle/kernel/k_light_lock.cpp
|
||||
hle/kernel/k_light_lock.h
|
||||
hle/kernel/k_linked_list.h
|
||||
hle/kernel/k_memory_block.h
|
||||
hle/kernel/k_memory_block_manager.cpp
|
||||
hle/kernel/k_memory_block_manager.h
|
||||
@@ -185,7 +194,11 @@ add_library(core STATIC
|
||||
hle/kernel/k_page_linked_list.h
|
||||
hle/kernel/k_page_table.cpp
|
||||
hle/kernel/k_page_table.h
|
||||
hle/kernel/k_port.cpp
|
||||
hle/kernel/k_port.h
|
||||
hle/kernel/k_priority_queue.h
|
||||
hle/kernel/k_process.cpp
|
||||
hle/kernel/k_process.h
|
||||
hle/kernel/k_readable_event.cpp
|
||||
hle/kernel/k_readable_event.h
|
||||
hle/kernel/k_resource_limit.cpp
|
||||
@@ -196,6 +209,12 @@ add_library(core STATIC
|
||||
hle/kernel/k_scoped_lock.h
|
||||
hle/kernel/k_scoped_resource_reservation.h
|
||||
hle/kernel/k_scoped_scheduler_lock_and_sleep.h
|
||||
hle/kernel/k_server_port.cpp
|
||||
hle/kernel/k_server_port.h
|
||||
hle/kernel/k_server_session.cpp
|
||||
hle/kernel/k_server_session.h
|
||||
hle/kernel/k_session.cpp
|
||||
hle/kernel/k_session.h
|
||||
hle/kernel/k_shared_memory.cpp
|
||||
hle/kernel/k_shared_memory.h
|
||||
hle/kernel/k_slab_heap.h
|
||||
@@ -208,28 +227,21 @@ add_library(core STATIC
|
||||
hle/kernel/k_thread.h
|
||||
hle/kernel/k_thread_queue.h
|
||||
hle/kernel/k_trace.h
|
||||
hle/kernel/k_transfer_memory.cpp
|
||||
hle/kernel/k_transfer_memory.h
|
||||
hle/kernel/k_writable_event.cpp
|
||||
hle/kernel/k_writable_event.h
|
||||
hle/kernel/kernel.cpp
|
||||
hle/kernel/kernel.h
|
||||
hle/kernel/memory_types.h
|
||||
hle/kernel/object.cpp
|
||||
hle/kernel/object.h
|
||||
hle/kernel/physical_core.cpp
|
||||
hle/kernel/physical_core.h
|
||||
hle/kernel/physical_memory.h
|
||||
hle/kernel/process.cpp
|
||||
hle/kernel/process.h
|
||||
hle/kernel/process_capability.cpp
|
||||
hle/kernel/process_capability.h
|
||||
hle/kernel/server_port.cpp
|
||||
hle/kernel/server_port.h
|
||||
hle/kernel/server_session.cpp
|
||||
hle/kernel/server_session.h
|
||||
hle/kernel/service_thread.cpp
|
||||
hle/kernel/service_thread.h
|
||||
hle/kernel/session.cpp
|
||||
hle/kernel/session.h
|
||||
hle/kernel/slab_helpers.h
|
||||
hle/kernel/svc.cpp
|
||||
hle/kernel/svc.h
|
||||
hle/kernel/svc_common.h
|
||||
@@ -237,8 +249,6 @@ add_library(core STATIC
|
||||
hle/kernel/svc_wrap.h
|
||||
hle/kernel/time_manager.cpp
|
||||
hle/kernel/time_manager.h
|
||||
hle/kernel/transfer_memory.cpp
|
||||
hle/kernel/transfer_memory.h
|
||||
hle/lock.cpp
|
||||
hle/lock.h
|
||||
hle/result.h
|
||||
@@ -377,6 +387,8 @@ add_library(core STATIC
|
||||
hle/service/glue/arp.h
|
||||
hle/service/glue/bgtc.cpp
|
||||
hle/service/glue/bgtc.h
|
||||
hle/service/glue/ectx.cpp
|
||||
hle/service/glue/ectx.h
|
||||
hle/service/glue/errors.h
|
||||
hle/service/glue/glue.cpp
|
||||
hle/service/glue/glue.h
|
||||
@@ -391,6 +403,8 @@ add_library(core STATIC
|
||||
hle/service/hid/xcd.cpp
|
||||
hle/service/hid/xcd.h
|
||||
hle/service/hid/errors.h
|
||||
hle/service/hid/controllers/console_sixaxis.cpp
|
||||
hle/service/hid/controllers/console_sixaxis.h
|
||||
hle/service/hid/controllers/controller_base.cpp
|
||||
hle/service/hid/controllers/controller_base.h
|
||||
hle/service/hid/controllers/debug_pad.cpp
|
||||
|
||||
@@ -198,13 +198,13 @@ void ARM_Dynarmic_32::Step() {
|
||||
jit->Step();
|
||||
}
|
||||
|
||||
ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers,
|
||||
bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor,
|
||||
std::size_t core_index)
|
||||
: ARM_Interface{system, interrupt_handlers, uses_wall_clock},
|
||||
ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_,
|
||||
bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
|
||||
std::size_t core_index_)
|
||||
: ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
|
||||
cb(std::make_unique<DynarmicCallbacks32>(*this)),
|
||||
cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index},
|
||||
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
|
||||
cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_},
|
||||
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
|
||||
jit(MakeJit(nullptr)) {}
|
||||
|
||||
ARM_Dynarmic_32::~ARM_Dynarmic_32() = default;
|
||||
|
||||
@@ -29,8 +29,8 @@ class System;
|
||||
|
||||
class ARM_Dynarmic_32 final : public ARM_Interface {
|
||||
public:
|
||||
ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
|
||||
ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
||||
ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
|
||||
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
|
||||
~ARM_Dynarmic_32() override;
|
||||
|
||||
void SetPC(u64 pc) override;
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hardware_properties.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
@@ -238,12 +238,12 @@ void ARM_Dynarmic_64::Step() {
|
||||
cb->InterpreterFallback(jit->GetPC(), 1);
|
||||
}
|
||||
|
||||
ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers,
|
||||
bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor,
|
||||
std::size_t core_index)
|
||||
: ARM_Interface{system, interrupt_handlers, uses_wall_clock},
|
||||
cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
|
||||
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
|
||||
ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,
|
||||
bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
|
||||
std::size_t core_index_)
|
||||
: ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
|
||||
cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
|
||||
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
|
||||
jit(MakeJit(nullptr, 48)) {}
|
||||
|
||||
ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
|
||||
|
||||
@@ -26,8 +26,8 @@ class System;
|
||||
|
||||
class ARM_Dynarmic_64 final : public ARM_Interface {
|
||||
public:
|
||||
ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
|
||||
ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
||||
ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
|
||||
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
|
||||
~ARM_Dynarmic_64() override;
|
||||
|
||||
void SetPC(u64 pc) override;
|
||||
|
||||
@@ -94,12 +94,11 @@ CallbackOrAccessOneWord DynarmicCP15::CompileGetOneWord(bool two, unsigned opc1,
|
||||
CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) {
|
||||
if (!two && opc == 0 && CRm == CoprocReg::C14) {
|
||||
// CNTPCT
|
||||
const auto callback = static_cast<u64 (*)(Dynarmic::A32::Jit*, void*, u32, u32)>(
|
||||
[](Dynarmic::A32::Jit*, void* arg, u32, u32) -> u64 {
|
||||
ARM_Dynarmic_32& parent = *(ARM_Dynarmic_32*)arg;
|
||||
return parent.system.CoreTiming().GetClockTicks();
|
||||
});
|
||||
return Dynarmic::A32::Coprocessor::Callback{callback, (void*)&parent};
|
||||
const auto callback = [](Dynarmic::A32::Jit*, void* arg, u32, u32) -> u64 {
|
||||
const auto& parent_arg = *static_cast<ARM_Dynarmic_32*>(arg);
|
||||
return parent_arg.system.CoreTiming().GetClockTicks();
|
||||
};
|
||||
return Callback{callback, &parent};
|
||||
}
|
||||
|
||||
LOG_CRITICAL(Core_ARM, "CP15: mrrc{} p15, {}, <Rt>, <Rt2>, {}", two ? "2" : "", opc, CRm);
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
#include "core/file_sys/vfs_concat.h"
|
||||
#include "core/file_sys/vfs_real.h"
|
||||
#include "core/hardware_interrupt_manager.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/k_client_port.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/physical_core.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/apm/controller.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
@@ -166,9 +166,9 @@ struct System::Impl {
|
||||
cpu_manager.SetAsyncGpu(is_async_gpu);
|
||||
core_timing.SetMulticore(is_multicore);
|
||||
|
||||
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
|
||||
kernel.Initialize();
|
||||
cpu_manager.Initialize();
|
||||
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
|
||||
|
||||
const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch());
|
||||
@@ -233,8 +233,11 @@ struct System::Impl {
|
||||
}
|
||||
|
||||
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
|
||||
auto main_process =
|
||||
Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland);
|
||||
auto main_process = Kernel::KProcess::Create(system.Kernel());
|
||||
ASSERT(Kernel::KProcess::Initialize(main_process, system, "main",
|
||||
Kernel::KProcess::ProcessType::Userland)
|
||||
.IsSuccess());
|
||||
main_process->Open();
|
||||
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
|
||||
if (load_result != Loader::ResultStatus::Success) {
|
||||
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
|
||||
@@ -244,7 +247,7 @@ struct System::Impl {
|
||||
static_cast<u32>(load_result));
|
||||
}
|
||||
AddGlueRegistrationForProcess(*app_loader, *main_process);
|
||||
kernel.MakeCurrentProcess(main_process.get());
|
||||
kernel.MakeCurrentProcess(main_process);
|
||||
kernel.InitializeCores();
|
||||
|
||||
// Initialize cheat engine
|
||||
@@ -311,6 +314,7 @@ struct System::Impl {
|
||||
gpu_core.reset();
|
||||
perf_stats.reset();
|
||||
kernel.Shutdown();
|
||||
memory.Reset();
|
||||
applet_manager.ClearAll();
|
||||
|
||||
LOG_DEBUG(Core, "Shutdown OK");
|
||||
@@ -322,7 +326,7 @@ struct System::Impl {
|
||||
return app_loader->ReadTitle(out);
|
||||
}
|
||||
|
||||
void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::Process& process) {
|
||||
void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::KProcess& process) {
|
||||
std::vector<u8> nacp_data;
|
||||
FileSys::NACP nacp;
|
||||
if (loader.ReadControlData(nacp) == Loader::ResultStatus::Success) {
|
||||
@@ -513,7 +517,7 @@ const Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() const {
|
||||
return impl->kernel.GlobalSchedulerContext();
|
||||
}
|
||||
|
||||
Kernel::Process* System::CurrentProcess() {
|
||||
Kernel::KProcess* System::CurrentProcess() {
|
||||
return impl->kernel.CurrentProcess();
|
||||
}
|
||||
|
||||
@@ -525,7 +529,7 @@ const Core::DeviceMemory& System::DeviceMemory() const {
|
||||
return *impl->device_memory;
|
||||
}
|
||||
|
||||
const Kernel::Process* System::CurrentProcess() const {
|
||||
const Kernel::KProcess* System::CurrentProcess() const {
|
||||
return impl->kernel.CurrentProcess();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
class EmuWindow;
|
||||
@@ -29,7 +28,7 @@ namespace Kernel {
|
||||
class GlobalSchedulerContext;
|
||||
class KernelCore;
|
||||
class PhysicalCore;
|
||||
class Process;
|
||||
class KProcess;
|
||||
class KScheduler;
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -264,10 +263,10 @@ public:
|
||||
[[nodiscard]] const Core::DeviceMemory& DeviceMemory() const;
|
||||
|
||||
/// Provides a pointer to the current process
|
||||
[[nodiscard]] Kernel::Process* CurrentProcess();
|
||||
[[nodiscard]] Kernel::KProcess* CurrentProcess();
|
||||
|
||||
/// Provides a constant pointer to the current process.
|
||||
[[nodiscard]] const Kernel::Process* CurrentProcess() const;
|
||||
[[nodiscard]] const Kernel::KProcess* CurrentProcess() const;
|
||||
|
||||
/// Provides a reference to the core timing instance.
|
||||
[[nodiscard]] Timing::CoreTiming& CoreTiming();
|
||||
|
||||
@@ -133,8 +133,8 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||
}
|
||||
}
|
||||
|
||||
void CoreTiming::AddTicks(u64 ticks) {
|
||||
this->ticks += ticks;
|
||||
void CoreTiming::AddTicks(u64 ticks_to_add) {
|
||||
ticks += ticks_to_add;
|
||||
downcount -= static_cast<s64>(ticks);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ public:
|
||||
/// We only permit one event of each type in the queue at a time.
|
||||
void RemoveEvent(const std::shared_ptr<EventType>& event_type);
|
||||
|
||||
void AddTicks(u64 ticks);
|
||||
void AddTicks(u64 ticks_to_add);
|
||||
|
||||
void ResetTicks();
|
||||
|
||||
|
||||
@@ -35,13 +35,13 @@ public:
|
||||
CpuManager& operator=(CpuManager&&) = delete;
|
||||
|
||||
/// Sets if emulation is multicore or single core, must be set before Initialize
|
||||
void SetMulticore(bool is_multicore) {
|
||||
this->is_multicore = is_multicore;
|
||||
void SetMulticore(bool is_multi) {
|
||||
is_multicore = is_multi;
|
||||
}
|
||||
|
||||
/// Sets if emulation is using an asynchronous GPU.
|
||||
void SetAsyncGpu(bool is_async_gpu) {
|
||||
this->is_async_gpu = is_async_gpu;
|
||||
void SetAsyncGpu(bool is_async) {
|
||||
is_async_gpu = is_async;
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
|
||||
@@ -119,9 +119,9 @@ void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8*
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::SetIVImpl(const u8* data, std::size_t size) {
|
||||
ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, data, size) ||
|
||||
mbedtls_cipher_set_iv(&ctx->decryption_context, data, size)) == 0,
|
||||
void AESCipher<Key, KeySize>::SetIV(std::span<const u8> data) {
|
||||
ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, data.data(), data.size()) ||
|
||||
mbedtls_cipher_set_iv(&ctx->decryption_context, data.data(), data.size())) == 0,
|
||||
"Failed to set IV on mbedtls ciphers.");
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
@@ -33,10 +34,7 @@ public:
|
||||
AESCipher(Key key, Mode mode);
|
||||
~AESCipher();
|
||||
|
||||
template <typename ContiguousContainer>
|
||||
void SetIV(const ContiguousContainer& container) {
|
||||
SetIVImpl(std::data(container), std::size(container));
|
||||
}
|
||||
void SetIV(std::span<const u8> data);
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
void Transcode(const Source* src, std::size_t size, Dest* dest, Op op) const {
|
||||
@@ -60,8 +58,6 @@ public:
|
||||
std::size_t sector_size, Op op);
|
||||
|
||||
private:
|
||||
void SetIVImpl(const u8* data, std::size_t size);
|
||||
|
||||
std::unique_ptr<CipherContext> ctx;
|
||||
};
|
||||
} // namespace Core::Crypto
|
||||
|
||||
@@ -176,26 +176,30 @@ u64 XCI::GetProgramTitleID() const {
|
||||
|
||||
u32 XCI::GetSystemUpdateVersion() {
|
||||
const auto update = GetPartition(XCIPartition::Update);
|
||||
if (update == nullptr)
|
||||
if (update == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (const auto& file : update->GetFiles()) {
|
||||
NCA nca{file, nullptr, 0};
|
||||
for (const auto& update_file : update->GetFiles()) {
|
||||
NCA nca{update_file, nullptr, 0};
|
||||
|
||||
if (nca.GetStatus() != Loader::ResultStatus::Success)
|
||||
if (nca.GetStatus() != Loader::ResultStatus::Success) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nca.GetType() == NCAContentType::Meta && nca.GetTitleId() == 0x0100000000000816) {
|
||||
const auto dir = nca.GetSubdirectories()[0];
|
||||
const auto cnmt = dir->GetFile("SystemUpdate_0100000000000816.cnmt");
|
||||
if (cnmt == nullptr)
|
||||
if (cnmt == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CNMT cnmt_data{cnmt};
|
||||
|
||||
const auto metas = cnmt_data.GetMetaRecords();
|
||||
if (metas.empty())
|
||||
if (metas.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return metas[0].title_version;
|
||||
}
|
||||
@@ -262,8 +266,8 @@ VirtualDir XCI::ConcatenatedPseudoDirectory() {
|
||||
if (part == nullptr)
|
||||
continue;
|
||||
|
||||
for (const auto& file : part->GetFiles())
|
||||
out->AddFile(file);
|
||||
for (const auto& part_file : part->GetFiles())
|
||||
out->AddFile(part_file);
|
||||
}
|
||||
|
||||
return out;
|
||||
@@ -283,12 +287,12 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
|
||||
return Loader::ResultStatus::ErrorXCIMissingPartition;
|
||||
}
|
||||
|
||||
for (const VirtualFile& file : partition->GetFiles()) {
|
||||
if (file->GetExtension() != "nca") {
|
||||
for (const VirtualFile& partition_file : partition->GetFiles()) {
|
||||
if (partition_file->GetExtension() != "nca") {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto nca = std::make_shared<NCA>(file, nullptr, 0);
|
||||
auto nca = std::make_shared<NCA>(partition_file, nullptr, 0);
|
||||
if (nca->IsUpdate()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
@@ -136,12 +137,11 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_off
|
||||
return;
|
||||
}
|
||||
|
||||
has_rights_id = std::any_of(header.rights_id.begin(), header.rights_id.end(),
|
||||
[](char c) { return c != '\0'; });
|
||||
has_rights_id = std::ranges::any_of(header.rights_id, [](char c) { return c != '\0'; });
|
||||
|
||||
const std::vector<NCASectionHeader> sections = ReadSectionHeaders();
|
||||
is_update = std::any_of(sections.begin(), sections.end(), [](const NCASectionHeader& header) {
|
||||
return header.raw.header.crypto_type == NCASectionCryptoType::BKTR;
|
||||
is_update = std::ranges::any_of(sections, [](const NCASectionHeader& nca_header) {
|
||||
return nca_header.raw.header.crypto_type == NCASectionCryptoType::BKTR;
|
||||
});
|
||||
|
||||
if (!ReadSections(sections, bktr_base_ivfc_offset)) {
|
||||
@@ -202,8 +202,9 @@ bool NCA::HandlePotentialHeaderDecryption() {
|
||||
|
||||
std::vector<NCASectionHeader> NCA::ReadSectionHeaders() const {
|
||||
const std::ptrdiff_t number_sections =
|
||||
std::count_if(std::begin(header.section_tables), std::end(header.section_tables),
|
||||
[](NCASectionTableEntry entry) { return entry.media_offset > 0; });
|
||||
std::ranges::count_if(header.section_tables, [](const NCASectionTableEntry& entry) {
|
||||
return entry.media_offset > 0;
|
||||
});
|
||||
|
||||
std::vector<NCASectionHeader> sections(number_sections);
|
||||
const auto length_sections = SECTION_HEADER_SIZE * number_sections;
|
||||
@@ -312,11 +313,11 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl
|
||||
}
|
||||
|
||||
std::vector<RelocationBucket> relocation_buckets(relocation_buckets_raw.size());
|
||||
std::transform(relocation_buckets_raw.begin(), relocation_buckets_raw.end(),
|
||||
relocation_buckets.begin(), &ConvertRelocationBucketRaw);
|
||||
std::ranges::transform(relocation_buckets_raw, relocation_buckets.begin(),
|
||||
&ConvertRelocationBucketRaw);
|
||||
std::vector<SubsectionBucket> subsection_buckets(subsection_buckets_raw.size());
|
||||
std::transform(subsection_buckets_raw.begin(), subsection_buckets_raw.end(),
|
||||
subsection_buckets.begin(), &ConvertSubsectionBucketRaw);
|
||||
std::ranges::transform(subsection_buckets_raw, subsection_buckets.begin(),
|
||||
&ConvertSubsectionBucketRaw);
|
||||
|
||||
u32 ctr_low;
|
||||
std::memcpy(&ctr_low, section.raw.section_ctr.data(), sizeof(ctr_low));
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
namespace FileSys {
|
||||
|
||||
constexpr ResultCode ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1};
|
||||
constexpr ResultCode ERROR_PATH_ALREADY_EXISTS{ErrorModule::FS, 2};
|
||||
constexpr ResultCode ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002};
|
||||
constexpr ResultCode ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001};
|
||||
constexpr ResultCode ERROR_OUT_OF_BOUNDS{ErrorModule::FS, 3005};
|
||||
|
||||
@@ -126,16 +126,17 @@ static u64 romfs_get_hash_table_count(u64 num_entries) {
|
||||
return count;
|
||||
}
|
||||
|
||||
void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext,
|
||||
void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext_dir,
|
||||
std::shared_ptr<RomFSBuildDirectoryContext> parent) {
|
||||
std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> child_dirs;
|
||||
|
||||
VirtualDir dir;
|
||||
|
||||
if (parent->path_len == 0)
|
||||
if (parent->path_len == 0) {
|
||||
dir = root_romfs;
|
||||
else
|
||||
} else {
|
||||
dir = root_romfs->GetDirectoryRelative(parent->path);
|
||||
}
|
||||
|
||||
const auto entries = dir->GetEntries();
|
||||
|
||||
@@ -147,8 +148,9 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext,
|
||||
child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
|
||||
child->path = parent->path + "/" + kv.first;
|
||||
|
||||
if (ext != nullptr && ext->GetFileRelative(child->path + ".stub") != nullptr)
|
||||
if (ext_dir != nullptr && ext_dir->GetFileRelative(child->path + ".stub") != nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sanity check on path_len
|
||||
ASSERT(child->path_len < FS_MAX_PATH);
|
||||
@@ -163,21 +165,20 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext,
|
||||
child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
|
||||
child->path = parent->path + "/" + kv.first;
|
||||
|
||||
if (ext != nullptr && ext->GetFileRelative(child->path + ".stub") != nullptr)
|
||||
if (ext_dir != nullptr && ext_dir->GetFileRelative(child->path + ".stub") != nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sanity check on path_len
|
||||
ASSERT(child->path_len < FS_MAX_PATH);
|
||||
|
||||
child->source = root_romfs->GetFileRelative(child->path);
|
||||
|
||||
if (ext != nullptr) {
|
||||
const auto ips = ext->GetFileRelative(child->path + ".ips");
|
||||
|
||||
if (ips != nullptr) {
|
||||
auto patched = PatchIPS(child->source, ips);
|
||||
if (patched != nullptr)
|
||||
if (ext_dir != nullptr) {
|
||||
if (const auto ips = ext_dir->GetFileRelative(child->path + ".ips")) {
|
||||
if (auto patched = PatchIPS(child->source, ips)) {
|
||||
child->source = std::move(patched);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +189,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext,
|
||||
}
|
||||
|
||||
for (auto& child : child_dirs) {
|
||||
this->VisitDirectory(root_romfs, ext, child);
|
||||
this->VisitDirectory(root_romfs, ext_dir, child);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ private:
|
||||
u64 file_hash_table_size = 0;
|
||||
u64 file_partition_size = 0;
|
||||
|
||||
void VisitDirectory(VirtualDir filesys, VirtualDir ext,
|
||||
void VisitDirectory(VirtualDir filesys, VirtualDir ext_dir,
|
||||
std::shared_ptr<RomFSBuildDirectoryContext> parent);
|
||||
|
||||
bool AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx,
|
||||
|
||||
@@ -83,11 +83,14 @@ BKTR::~BKTR() = default;
|
||||
|
||||
std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||
// Read out of bounds.
|
||||
if (offset >= relocation.size)
|
||||
if (offset >= relocation.size) {
|
||||
return 0;
|
||||
const auto relocation = GetRelocationEntry(offset);
|
||||
const auto section_offset = offset - relocation.address_patch + relocation.address_source;
|
||||
const auto bktr_read = relocation.from_patch;
|
||||
}
|
||||
|
||||
const auto relocation_entry = GetRelocationEntry(offset);
|
||||
const auto section_offset =
|
||||
offset - relocation_entry.address_patch + relocation_entry.address_source;
|
||||
const auto bktr_read = relocation_entry.from_patch;
|
||||
|
||||
const auto next_relocation = GetNextRelocationEntry(offset);
|
||||
|
||||
@@ -106,15 +109,16 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||
return bktr_romfs->Read(data, length, section_offset);
|
||||
}
|
||||
|
||||
const auto subsection = GetSubsectionEntry(section_offset);
|
||||
const auto subsection_entry = GetSubsectionEntry(section_offset);
|
||||
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR);
|
||||
|
||||
// Calculate AES IV
|
||||
std::array<u8, 16> iv{};
|
||||
auto subsection_ctr = subsection.ctr;
|
||||
auto subsection_ctr = subsection_entry.ctr;
|
||||
auto offset_iv = section_offset + base_offset;
|
||||
for (std::size_t i = 0; i < section_ctr.size(); ++i)
|
||||
for (std::size_t i = 0; i < section_ctr.size(); ++i) {
|
||||
iv[i] = section_ctr[0x8 - i - 1];
|
||||
}
|
||||
offset_iv >>= 4;
|
||||
for (std::size_t i = 0; i < sizeof(u64); ++i) {
|
||||
iv[0xF - i] = static_cast<u8>(offset_iv & 0xFF);
|
||||
|
||||
@@ -58,7 +58,8 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
|
||||
result.LoadManual(
|
||||
true /*is_64_bit*/, FileSys::ProgramAddressSpaceType::Is39Bit /*address_space*/,
|
||||
0x2c /*main_thread_prio*/, 0 /*main_thread_core*/, 0x00100000 /*main_thread_stack_size*/,
|
||||
{}, 0xFFFFFFFFFFFFFFFF /*filesystem_permissions*/, {} /*capabilities*/);
|
||||
0 /*title_id*/, 0xFFFFFFFFFFFFFFFF /*filesystem_permissions*/,
|
||||
0x1FE00000 /*system_resource_size*/, {} /*capabilities*/);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -66,7 +67,7 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
|
||||
void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address_space,
|
||||
s32 main_thread_prio, u32 main_thread_core,
|
||||
u32 main_thread_stack_size, u64 title_id,
|
||||
u64 filesystem_permissions,
|
||||
u64 filesystem_permissions, u32 system_resource_size,
|
||||
KernelCapabilityDescriptors capabilities) {
|
||||
npdm_header.has_64_bit_instructions.Assign(is_64_bit);
|
||||
npdm_header.address_space_type.Assign(address_space);
|
||||
@@ -75,6 +76,7 @@ void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address
|
||||
npdm_header.main_stack_size = main_thread_stack_size;
|
||||
aci_header.title_id = title_id;
|
||||
aci_file_access.permissions = filesystem_permissions;
|
||||
npdm_header.system_resource_size = system_resource_size;
|
||||
aci_kernel_capabilities = std ::move(capabilities);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,12 @@ public:
|
||||
ProgramMetadata();
|
||||
~ProgramMetadata();
|
||||
|
||||
ProgramMetadata(const ProgramMetadata&) = default;
|
||||
ProgramMetadata& operator=(const ProgramMetadata&) = default;
|
||||
|
||||
ProgramMetadata(ProgramMetadata&&) = default;
|
||||
ProgramMetadata& operator=(ProgramMetadata&&) = default;
|
||||
|
||||
/// Gets a default ProgramMetadata configuration, should only be used for homebrew formats where
|
||||
/// we do not have an NPDM file
|
||||
static ProgramMetadata GetDefault();
|
||||
@@ -53,7 +59,8 @@ public:
|
||||
/// Load from parameters instead of NPDM file, used for KIP
|
||||
void LoadManual(bool is_64_bit, ProgramAddressSpaceType address_space, s32 main_thread_prio,
|
||||
u32 main_thread_core, u32 main_thread_stack_size, u64 title_id,
|
||||
u64 filesystem_permissions, KernelCapabilityDescriptors capabilities);
|
||||
u64 filesystem_permissions, u32 system_resource_size,
|
||||
KernelCapabilityDescriptors capabilities);
|
||||
|
||||
bool Is64BitProgram() const;
|
||||
ProgramAddressSpaceType GetAddressSpaceType() const;
|
||||
|
||||
@@ -281,14 +281,14 @@ NcaID PlaceholderCache::Generate() {
|
||||
return out;
|
||||
}
|
||||
|
||||
VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
|
||||
VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& open_dir,
|
||||
std::string_view path) const {
|
||||
const auto file = dir->GetFileRelative(path);
|
||||
const auto file = open_dir->GetFileRelative(path);
|
||||
if (file != nullptr) {
|
||||
return file;
|
||||
}
|
||||
|
||||
const auto nca_dir = dir->GetDirectoryRelative(path);
|
||||
const auto nca_dir = open_dir->GetDirectoryRelative(path);
|
||||
if (nca_dir == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -431,13 +431,15 @@ void RegisteredCache::ProcessFiles(const std::vector<NcaID>& ids) {
|
||||
}
|
||||
|
||||
void RegisteredCache::AccumulateYuzuMeta() {
|
||||
const auto dir = this->dir->GetSubdirectory("yuzu_meta");
|
||||
if (dir == nullptr)
|
||||
const auto meta_dir = dir->GetSubdirectory("yuzu_meta");
|
||||
if (meta_dir == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& file : dir->GetFiles()) {
|
||||
if (file->GetExtension() != "cnmt")
|
||||
for (const auto& file : meta_dir->GetFiles()) {
|
||||
if (file->GetExtension() != "cnmt") {
|
||||
continue;
|
||||
}
|
||||
|
||||
CNMT cnmt(file);
|
||||
yuzu_meta.insert_or_assign(cnmt.GetTitleID(), std::move(cnmt));
|
||||
@@ -445,8 +447,10 @@ void RegisteredCache::AccumulateYuzuMeta() {
|
||||
}
|
||||
|
||||
void RegisteredCache::Refresh() {
|
||||
if (dir == nullptr)
|
||||
if (dir == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto ids = AccumulateFiles();
|
||||
ProcessFiles(ids);
|
||||
AccumulateYuzuMeta();
|
||||
@@ -566,7 +570,7 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
|
||||
}
|
||||
|
||||
const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32);
|
||||
const auto meta_id = Common::HexStringToArray<16>(meta_id_raw);
|
||||
const auto meta_id_data = Common::HexStringToArray<16>(meta_id_raw);
|
||||
|
||||
if ((*meta_iter)->GetSubdirectories().empty()) {
|
||||
LOG_ERROR(Loader,
|
||||
@@ -591,7 +595,7 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
|
||||
const auto result = RemoveExistingEntry(title_id);
|
||||
|
||||
// Install Metadata File
|
||||
const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id);
|
||||
const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id_data);
|
||||
if (res != InstallResult::Success) {
|
||||
return res;
|
||||
}
|
||||
@@ -741,15 +745,15 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
|
||||
|
||||
bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) {
|
||||
// Reasoning behind this method can be found in the comment for InstallEntry, NCA overload.
|
||||
const auto dir = this->dir->CreateDirectoryRelative("yuzu_meta");
|
||||
const auto meta_dir = dir->CreateDirectoryRelative("yuzu_meta");
|
||||
const auto filename = GetCNMTName(cnmt.GetType(), cnmt.GetTitleID());
|
||||
if (dir->GetFile(filename) == nullptr) {
|
||||
auto out = dir->CreateFile(filename);
|
||||
if (meta_dir->GetFile(filename) == nullptr) {
|
||||
auto out = meta_dir->CreateFile(filename);
|
||||
const auto buffer = cnmt.Serialize();
|
||||
out->Resize(buffer.size());
|
||||
out->WriteBytes(buffer);
|
||||
} else {
|
||||
auto out = dir->GetFile(filename);
|
||||
auto out = meta_dir->GetFile(filename);
|
||||
CNMT old_cnmt(out);
|
||||
// Returns true on change
|
||||
if (old_cnmt.UnionRecords(cnmt)) {
|
||||
|
||||
@@ -182,7 +182,7 @@ private:
|
||||
void AccumulateYuzuMeta();
|
||||
std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const;
|
||||
VirtualFile GetFileAtID(NcaID id) const;
|
||||
VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const;
|
||||
VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& open_dir, std::string_view path) const;
|
||||
InstallResult RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
|
||||
bool overwrite_if_exists, std::optional<NcaID> override_id = {});
|
||||
bool RawInstallYuzuMeta(const CNMT& cnmt);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/romfs_factory.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
@@ -33,8 +33,8 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader, ContentProvider& provi
|
||||
|
||||
RomFSFactory::~RomFSFactory() = default;
|
||||
|
||||
void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {
|
||||
this->update_raw = std::move(update_raw);
|
||||
void RomFSFactory::SetPackedUpdate(VirtualFile update_raw_file) {
|
||||
update_raw = std::move(update_raw_file);
|
||||
}
|
||||
|
||||
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
Service::FileSystem::FileSystemController& controller);
|
||||
~RomFSFactory();
|
||||
|
||||
void SetPackedUpdate(VirtualFile update_raw);
|
||||
void SetPackedUpdate(VirtualFile update_raw_file);
|
||||
[[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const;
|
||||
[[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFS(u64 title_id,
|
||||
ContentRecordType type) const;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
@@ -170,26 +170,30 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId s
|
||||
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
||||
u128 user_id) const {
|
||||
const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
|
||||
const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
|
||||
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
||||
|
||||
const auto size_file = dir->GetFile(SAVE_DATA_SIZE_FILENAME);
|
||||
if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize))
|
||||
const auto size_file = relative_dir->GetFile(SAVE_DATA_SIZE_FILENAME);
|
||||
if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize)) {
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
SaveDataSize out;
|
||||
if (size_file->ReadObject(&out) != sizeof(SaveDataSize))
|
||||
if (size_file->ReadObject(&out) != sizeof(SaveDataSize)) {
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
|
||||
SaveDataSize new_value) const {
|
||||
const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
|
||||
const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
|
||||
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
||||
|
||||
const auto size_file = dir->CreateFile(SAVE_DATA_SIZE_FILENAME);
|
||||
if (size_file == nullptr)
|
||||
const auto size_file = relative_dir->CreateFile(SAVE_DATA_SIZE_FILENAME);
|
||||
if (size_file == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_file->Resize(sizeof(SaveDataSize));
|
||||
size_file->WriteObject(new_value);
|
||||
|
||||
@@ -232,15 +232,15 @@ void NSP::SetTicketKeys(const std::vector<VirtualFile>& files) {
|
||||
void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) {
|
||||
exefs = pfs;
|
||||
|
||||
const auto romfs_iter = std::find_if(files.begin(), files.end(), [](const VirtualFile& file) {
|
||||
return file->GetName().rfind(".romfs") != std::string::npos;
|
||||
const auto iter = std::find_if(files.begin(), files.end(), [](const VirtualFile& entry) {
|
||||
return entry->GetName().rfind(".romfs") != std::string::npos;
|
||||
});
|
||||
|
||||
if (romfs_iter == files.end()) {
|
||||
if (iter == files.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
romfs = *romfs_iter;
|
||||
romfs = *iter;
|
||||
}
|
||||
|
||||
void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
|
||||
|
||||
@@ -136,7 +136,7 @@ std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ConcatenatedVfsFile::Rename(std::string_view name) {
|
||||
bool ConcatenatedVfsFile::Rename(std::string_view new_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
bool IsReadable() const override;
|
||||
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
|
||||
std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
|
||||
bool Rename(std::string_view name) override;
|
||||
bool Rename(std::string_view new_name) override;
|
||||
|
||||
private:
|
||||
// Maps starting offset to file -- more efficient.
|
||||
|
||||
@@ -45,12 +45,12 @@ VirtualDir LayeredVfsDirectory::GetDirectoryRelative(std::string_view path) cons
|
||||
return MakeLayeredDirectory(std::move(out));
|
||||
}
|
||||
|
||||
VirtualFile LayeredVfsDirectory::GetFile(std::string_view name) const {
|
||||
return GetFileRelative(name);
|
||||
VirtualFile LayeredVfsDirectory::GetFile(std::string_view file_name) const {
|
||||
return GetFileRelative(file_name);
|
||||
}
|
||||
|
||||
VirtualDir LayeredVfsDirectory::GetSubdirectory(std::string_view name) const {
|
||||
return GetDirectoryRelative(name);
|
||||
VirtualDir LayeredVfsDirectory::GetSubdirectory(std::string_view subdir_name) const {
|
||||
return GetDirectoryRelative(subdir_name);
|
||||
}
|
||||
|
||||
std::string LayeredVfsDirectory::GetFullPath() const {
|
||||
@@ -105,24 +105,24 @@ VirtualDir LayeredVfsDirectory::GetParentDirectory() const {
|
||||
return dirs[0]->GetParentDirectory();
|
||||
}
|
||||
|
||||
VirtualDir LayeredVfsDirectory::CreateSubdirectory(std::string_view name) {
|
||||
VirtualDir LayeredVfsDirectory::CreateSubdirectory(std::string_view subdir_name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VirtualFile LayeredVfsDirectory::CreateFile(std::string_view name) {
|
||||
VirtualFile LayeredVfsDirectory::CreateFile(std::string_view file_name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool LayeredVfsDirectory::DeleteSubdirectory(std::string_view name) {
|
||||
bool LayeredVfsDirectory::DeleteSubdirectory(std::string_view subdir_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LayeredVfsDirectory::DeleteFile(std::string_view name) {
|
||||
bool LayeredVfsDirectory::DeleteFile(std::string_view file_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LayeredVfsDirectory::Rename(std::string_view name_) {
|
||||
name = name_;
|
||||
bool LayeredVfsDirectory::Rename(std::string_view new_name) {
|
||||
name = new_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ public:
|
||||
|
||||
VirtualFile GetFileRelative(std::string_view path) const override;
|
||||
VirtualDir GetDirectoryRelative(std::string_view path) const override;
|
||||
VirtualFile GetFile(std::string_view name) const override;
|
||||
VirtualDir GetSubdirectory(std::string_view name) const override;
|
||||
VirtualFile GetFile(std::string_view file_name) const override;
|
||||
VirtualDir GetSubdirectory(std::string_view subdir_name) const override;
|
||||
std::string GetFullPath() const override;
|
||||
|
||||
std::vector<VirtualFile> GetFiles() const override;
|
||||
@@ -33,11 +33,11 @@ public:
|
||||
bool IsReadable() const override;
|
||||
std::string GetName() const override;
|
||||
VirtualDir GetParentDirectory() const override;
|
||||
VirtualDir CreateSubdirectory(std::string_view name) override;
|
||||
VirtualFile CreateFile(std::string_view name) override;
|
||||
bool DeleteSubdirectory(std::string_view name) override;
|
||||
bool DeleteFile(std::string_view name) override;
|
||||
bool Rename(std::string_view name) override;
|
||||
VirtualDir CreateSubdirectory(std::string_view subdir_name) override;
|
||||
VirtualFile CreateFile(std::string_view file_name) override;
|
||||
bool DeleteSubdirectory(std::string_view subdir_name) override;
|
||||
bool DeleteFile(std::string_view file_name) override;
|
||||
bool Rename(std::string_view new_name) override;
|
||||
|
||||
private:
|
||||
std::vector<VirtualDir> dirs;
|
||||
|
||||
@@ -84,8 +84,8 @@ std::size_t OffsetVfsFile::WriteBytes(const std::vector<u8>& data, std::size_t r
|
||||
return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset);
|
||||
}
|
||||
|
||||
bool OffsetVfsFile::Rename(std::string_view name) {
|
||||
return file->Rename(name);
|
||||
bool OffsetVfsFile::Rename(std::string_view new_name) {
|
||||
return file->Rename(new_name);
|
||||
}
|
||||
|
||||
std::size_t OffsetVfsFile::GetOffset() const {
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
bool WriteByte(u8 data, std::size_t offset) override;
|
||||
std::size_t WriteBytes(const std::vector<u8>& data, std::size_t offset) override;
|
||||
|
||||
bool Rename(std::string_view name) override;
|
||||
bool Rename(std::string_view new_name) override;
|
||||
|
||||
std::size_t GetOffset() const;
|
||||
|
||||
|
||||
@@ -358,16 +358,16 @@ RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string&
|
||||
|
||||
RealVfsDirectory::~RealVfsDirectory() = default;
|
||||
|
||||
VirtualFile RealVfsDirectory::GetFileRelative(std::string_view path) const {
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
VirtualFile RealVfsDirectory::GetFileRelative(std::string_view relative_path) const {
|
||||
const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path));
|
||||
if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) {
|
||||
return nullptr;
|
||||
}
|
||||
return base.OpenFile(full_path, perms);
|
||||
}
|
||||
|
||||
VirtualDir RealVfsDirectory::GetDirectoryRelative(std::string_view path) const {
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
VirtualDir RealVfsDirectory::GetDirectoryRelative(std::string_view relative_path) const {
|
||||
const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path));
|
||||
if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -382,13 +382,13 @@ VirtualDir RealVfsDirectory::GetSubdirectory(std::string_view name) const {
|
||||
return GetDirectoryRelative(name);
|
||||
}
|
||||
|
||||
VirtualFile RealVfsDirectory::CreateFileRelative(std::string_view path) {
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
VirtualFile RealVfsDirectory::CreateFileRelative(std::string_view relative_path) {
|
||||
const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path));
|
||||
return base.CreateFile(full_path, perms);
|
||||
}
|
||||
|
||||
VirtualDir RealVfsDirectory::CreateDirectoryRelative(std::string_view path) {
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
VirtualDir RealVfsDirectory::CreateDirectoryRelative(std::string_view relative_path) {
|
||||
const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path));
|
||||
return base.CreateDirectory(full_path, perms);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,12 +79,12 @@ class RealVfsDirectory : public VfsDirectory {
|
||||
public:
|
||||
~RealVfsDirectory() override;
|
||||
|
||||
VirtualFile GetFileRelative(std::string_view path) const override;
|
||||
VirtualDir GetDirectoryRelative(std::string_view path) const override;
|
||||
VirtualFile GetFileRelative(std::string_view relative_path) const override;
|
||||
VirtualDir GetDirectoryRelative(std::string_view relative_path) const override;
|
||||
VirtualFile GetFile(std::string_view name) const override;
|
||||
VirtualDir GetSubdirectory(std::string_view name) const override;
|
||||
VirtualFile CreateFileRelative(std::string_view path) override;
|
||||
VirtualDir CreateDirectoryRelative(std::string_view path) override;
|
||||
VirtualFile CreateFileRelative(std::string_view relative_path) override;
|
||||
VirtualDir CreateDirectoryRelative(std::string_view relative_path) override;
|
||||
bool DeleteSubdirectoryRecursive(std::string_view name) override;
|
||||
std::vector<VirtualFile> GetFiles() const override;
|
||||
std::vector<VirtualDir> GetSubdirectories() const override;
|
||||
|
||||
@@ -103,12 +103,12 @@ static bool FindAndRemoveVectorElement(std::vector<T>& vec, std::string_view nam
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VectorVfsDirectory::DeleteSubdirectory(std::string_view name) {
|
||||
return FindAndRemoveVectorElement(dirs, name);
|
||||
bool VectorVfsDirectory::DeleteSubdirectory(std::string_view subdir_name) {
|
||||
return FindAndRemoveVectorElement(dirs, subdir_name);
|
||||
}
|
||||
|
||||
bool VectorVfsDirectory::DeleteFile(std::string_view name) {
|
||||
return FindAndRemoveVectorElement(files, name);
|
||||
bool VectorVfsDirectory::DeleteFile(std::string_view file_name) {
|
||||
return FindAndRemoveVectorElement(files, file_name);
|
||||
}
|
||||
|
||||
bool VectorVfsDirectory::Rename(std::string_view name_) {
|
||||
@@ -116,11 +116,11 @@ bool VectorVfsDirectory::Rename(std::string_view name_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
VirtualDir VectorVfsDirectory::CreateSubdirectory(std::string_view name) {
|
||||
VirtualDir VectorVfsDirectory::CreateSubdirectory(std::string_view subdir_name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VirtualFile VectorVfsDirectory::CreateFile(std::string_view name) {
|
||||
VirtualFile VectorVfsDirectory::CreateFile(std::string_view file_name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -112,11 +112,11 @@ public:
|
||||
bool IsReadable() const override;
|
||||
std::string GetName() const override;
|
||||
VirtualDir GetParentDirectory() const override;
|
||||
bool DeleteSubdirectory(std::string_view name) override;
|
||||
bool DeleteFile(std::string_view name) override;
|
||||
bool DeleteSubdirectory(std::string_view subdir_name) override;
|
||||
bool DeleteFile(std::string_view file_name) override;
|
||||
bool Rename(std::string_view name) override;
|
||||
VirtualDir CreateSubdirectory(std::string_view name) override;
|
||||
VirtualFile CreateFile(std::string_view name) override;
|
||||
VirtualDir CreateSubdirectory(std::string_view subdir_name) override;
|
||||
VirtualFile CreateFile(std::string_view file_name) override;
|
||||
|
||||
virtual void AddFile(VirtualFile file);
|
||||
virtual void AddDirectory(VirtualDir dir);
|
||||
|
||||
@@ -12,7 +12,7 @@ WebBrowserApplet::~WebBrowserApplet() = default;
|
||||
DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
|
||||
|
||||
void DefaultWebBrowserApplet::OpenLocalWebPage(
|
||||
std::string_view local_url, std::function<void()> extract_romfs_callback,
|
||||
const std::string& local_url, std::function<void()> extract_romfs_callback,
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}",
|
||||
local_url);
|
||||
@@ -21,7 +21,7 @@ void DefaultWebBrowserApplet::OpenLocalWebPage(
|
||||
}
|
||||
|
||||
void DefaultWebBrowserApplet::OpenExternalWebPage(
|
||||
std::string_view external_url,
|
||||
const std::string& external_url,
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}",
|
||||
external_url);
|
||||
|
||||
@@ -16,11 +16,11 @@ public:
|
||||
virtual ~WebBrowserApplet();
|
||||
|
||||
virtual void OpenLocalWebPage(
|
||||
std::string_view local_url, std::function<void()> extract_romfs_callback,
|
||||
const std::string& local_url, std::function<void()> extract_romfs_callback,
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0;
|
||||
|
||||
virtual void OpenExternalWebPage(
|
||||
std::string_view external_url,
|
||||
const std::string& external_url,
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0;
|
||||
};
|
||||
|
||||
@@ -28,11 +28,12 @@ class DefaultWebBrowserApplet final : public WebBrowserApplet {
|
||||
public:
|
||||
~DefaultWebBrowserApplet() override;
|
||||
|
||||
void OpenLocalWebPage(std::string_view local_url, std::function<void()> extract_romfs_callback,
|
||||
void OpenLocalWebPage(const std::string& local_url,
|
||||
std::function<void()> extract_romfs_callback,
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)>
|
||||
callback) const override;
|
||||
|
||||
void OpenExternalWebPage(std::string_view external_url,
|
||||
void OpenExternalWebPage(const std::string& external_url,
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)>
|
||||
callback) const override;
|
||||
};
|
||||
|
||||
@@ -60,23 +60,23 @@ EmuWindow::~EmuWindow() {
|
||||
* @param framebuffer_y Framebuffer y-coordinate to check
|
||||
* @return True if the coordinates are within the touchpad, otherwise false
|
||||
*/
|
||||
static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, unsigned framebuffer_x,
|
||||
unsigned framebuffer_y) {
|
||||
static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, u32 framebuffer_x,
|
||||
u32 framebuffer_y) {
|
||||
return (framebuffer_y >= layout.screen.top && framebuffer_y < layout.screen.bottom &&
|
||||
framebuffer_x >= layout.screen.left && framebuffer_x < layout.screen.right);
|
||||
}
|
||||
|
||||
std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) const {
|
||||
std::pair<u32, u32> EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const {
|
||||
new_x = std::max(new_x, framebuffer_layout.screen.left);
|
||||
new_x = std::min(new_x, framebuffer_layout.screen.right - 1);
|
||||
|
||||
new_y = std::max(new_y, framebuffer_layout.screen.top);
|
||||
new_y = std::min(new_y, framebuffer_layout.screen.bottom - 1);
|
||||
|
||||
return std::make_tuple(new_x, new_y);
|
||||
return std::make_pair(new_x, new_y);
|
||||
}
|
||||
|
||||
void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id) {
|
||||
void EmuWindow::TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id) {
|
||||
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) {
|
||||
return;
|
||||
}
|
||||
@@ -95,7 +95,7 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std
|
||||
touch_state->status[id] = std::make_tuple(x, y, true);
|
||||
}
|
||||
|
||||
void EmuWindow::TouchReleased(std::size_t id) {
|
||||
void EmuWindow::TouchReleased(size_t id) {
|
||||
if (id >= touch_state->status.size()) {
|
||||
return;
|
||||
}
|
||||
@@ -103,20 +103,23 @@ void EmuWindow::TouchReleased(std::size_t id) {
|
||||
touch_state->status[id] = std::make_tuple(0.0f, 0.0f, false);
|
||||
}
|
||||
|
||||
void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id) {
|
||||
void EmuWindow::TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id) {
|
||||
if (id >= touch_state->status.size()) {
|
||||
return;
|
||||
}
|
||||
if (!std::get<2>(touch_state->status[id]))
|
||||
return;
|
||||
|
||||
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
|
||||
if (!std::get<2>(touch_state->status[id])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) {
|
||||
std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);
|
||||
}
|
||||
|
||||
TouchPressed(framebuffer_x, framebuffer_y, id);
|
||||
}
|
||||
|
||||
void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) {
|
||||
void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height) {
|
||||
NotifyFramebufferLayoutChanged(Layout::DefaultFrameLayout(width, height));
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
bool fullscreen = false;
|
||||
int res_width = 0;
|
||||
int res_height = 0;
|
||||
std::pair<unsigned, unsigned> min_client_area_size;
|
||||
std::pair<u32, u32> min_client_area_size;
|
||||
};
|
||||
|
||||
/// Data describing host window system information
|
||||
@@ -119,13 +119,13 @@ public:
|
||||
* @param framebuffer_y Framebuffer y-coordinate that was pressed
|
||||
* @param id Touch event ID
|
||||
*/
|
||||
void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id);
|
||||
void TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id);
|
||||
|
||||
/**
|
||||
* Signal that a touch released event has occurred (e.g. mouse click released)
|
||||
* @param id Touch event ID
|
||||
*/
|
||||
void TouchReleased(std::size_t id);
|
||||
void TouchReleased(size_t id);
|
||||
|
||||
/**
|
||||
* Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window)
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
* @param framebuffer_y Framebuffer y-coordinate
|
||||
* @param id Touch event ID
|
||||
*/
|
||||
void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id);
|
||||
void TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id);
|
||||
|
||||
/**
|
||||
* Returns currently active configuration.
|
||||
@@ -173,7 +173,7 @@ public:
|
||||
* Convenience method to update the current frame layout
|
||||
* Read from the current settings to determine which layout to use.
|
||||
*/
|
||||
void UpdateCurrentFramebufferLayout(unsigned width, unsigned height);
|
||||
void UpdateCurrentFramebufferLayout(u32 width, u32 height);
|
||||
|
||||
protected:
|
||||
explicit EmuWindow();
|
||||
@@ -208,7 +208,7 @@ protected:
|
||||
* Update internal client area size with the given parameter.
|
||||
* @note EmuWindow implementations will usually use this in window resize event handlers.
|
||||
*/
|
||||
void NotifyClientAreaSizeChanged(const std::pair<unsigned, unsigned>& size) {
|
||||
void NotifyClientAreaSizeChanged(std::pair<u32, u32> size) {
|
||||
client_area_width = size.first;
|
||||
client_area_height = size.second;
|
||||
}
|
||||
@@ -221,14 +221,19 @@ private:
|
||||
* For the request to be honored, EmuWindow implementations will usually reimplement this
|
||||
* function.
|
||||
*/
|
||||
virtual void OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned>) {
|
||||
virtual void OnMinimalClientAreaChangeRequest(std::pair<u32, u32>) {
|
||||
// By default, ignore this request and do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Clip the provided coordinates to be inside the touchscreen area.
|
||||
*/
|
||||
std::pair<u32, u32> ClipToTouchScreen(u32 new_x, u32 new_y) const;
|
||||
|
||||
Layout::FramebufferLayout framebuffer_layout; ///< Current framebuffer layout
|
||||
|
||||
unsigned client_area_width; ///< Current client width, should be set by window impl.
|
||||
unsigned client_area_height; ///< Current client height, should be set by window impl.
|
||||
u32 client_area_width; ///< Current client width, should be set by window impl.
|
||||
u32 client_area_height; ///< Current client height, should be set by window impl.
|
||||
|
||||
WindowConfig config; ///< Internal configuration (changes pending for being applied in
|
||||
/// ProcessConfigurationChanges)
|
||||
@@ -236,11 +241,6 @@ private:
|
||||
|
||||
class TouchState;
|
||||
std::shared_ptr<TouchState> touch_state;
|
||||
|
||||
/**
|
||||
* Clip the provided coordinates to be inside the touchscreen area.
|
||||
*/
|
||||
std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y) const;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <utility>
|
||||
#include "common/logging/log.h"
|
||||
#include "common/param_package.h"
|
||||
#include "common/quaternion.h"
|
||||
#include "common/vector_math.h"
|
||||
|
||||
namespace Input {
|
||||
@@ -143,9 +144,10 @@ using VibrationDevice = InputDevice<u8>;
|
||||
|
||||
/**
|
||||
* A motion status is an object that returns a tuple of accelerometer state vector,
|
||||
* gyroscope state vector, rotation state vector and orientation state matrix.
|
||||
* gyroscope state vector, rotation state vector, orientation state matrix and quaterion state
|
||||
* vector.
|
||||
*
|
||||
* For both vectors:
|
||||
* For both 3D vectors:
|
||||
* x+ is the same direction as RIGHT on D-pad.
|
||||
* y+ is normal to the touch screen, pointing outward.
|
||||
* z+ is the same direction as UP on D-pad.
|
||||
@@ -164,9 +166,13 @@ using VibrationDevice = InputDevice<u8>;
|
||||
* x vector
|
||||
* y vector
|
||||
* z vector
|
||||
*
|
||||
* For quaternion state vector
|
||||
* xyz vector
|
||||
* w float
|
||||
*/
|
||||
using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common::Vec3<float>,
|
||||
std::array<Common::Vec3f, 3>>;
|
||||
std::array<Common::Vec3f, 3>, Common::Quaternion<f32>>;
|
||||
|
||||
/**
|
||||
* A motion device is an input device that returns a motion status object
|
||||
|
||||
@@ -13,12 +13,9 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/session.h"
|
||||
#include "core/hle/kernel/k_client_port.h"
|
||||
#include "core/hle/kernel/k_session.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace IPC {
|
||||
@@ -72,16 +69,16 @@ public:
|
||||
AlwaysMoveHandles = 1,
|
||||
};
|
||||
|
||||
explicit ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size,
|
||||
explicit ResponseBuilder(Kernel::HLERequestContext& ctx, u32 normal_params_size,
|
||||
u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0,
|
||||
Flags flags = Flags::None)
|
||||
: RequestHelperBase(context), normal_params_size(normal_params_size),
|
||||
: RequestHelperBase(ctx), normal_params_size(normal_params_size),
|
||||
num_handles_to_copy(num_handles_to_copy),
|
||||
num_objects_to_move(num_objects_to_move), kernel{context.kernel} {
|
||||
num_objects_to_move(num_objects_to_move), kernel{ctx.kernel} {
|
||||
|
||||
memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
|
||||
|
||||
context.ClearIncomingObjects();
|
||||
ctx.ClearIncomingObjects();
|
||||
|
||||
IPC::CommandHeader header{};
|
||||
|
||||
@@ -93,13 +90,13 @@ public:
|
||||
u32 num_domain_objects{};
|
||||
const bool always_move_handles{
|
||||
(static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0};
|
||||
if (!context.Session()->IsDomain() || always_move_handles) {
|
||||
if (!ctx.Session()->IsDomain() || always_move_handles) {
|
||||
num_handles_to_move = num_objects_to_move;
|
||||
} else {
|
||||
num_domain_objects = num_objects_to_move;
|
||||
}
|
||||
|
||||
if (context.Session()->IsDomain()) {
|
||||
if (ctx.Session()->IsDomain()) {
|
||||
raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;
|
||||
}
|
||||
|
||||
@@ -119,7 +116,7 @@ public:
|
||||
|
||||
AlignWithPadding();
|
||||
|
||||
if (context.Session()->IsDomain() && context.HasDomainMessageHeader()) {
|
||||
if (ctx.Session()->IsDomain() && ctx.HasDomainMessageHeader()) {
|
||||
IPC::DomainMessageHeader domain_header{};
|
||||
domain_header.num_objects = num_domain_objects;
|
||||
PushRaw(domain_header);
|
||||
@@ -137,9 +134,11 @@ public:
|
||||
if (context->Session()->IsDomain()) {
|
||||
context->AddDomainObject(std::move(iface));
|
||||
} else {
|
||||
auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName());
|
||||
context->AddMoveObject(std::move(client));
|
||||
iface->ClientConnected(std::move(server));
|
||||
auto* session = Kernel::KSession::Create(kernel);
|
||||
session->Initialize(nullptr, iface->GetServiceName());
|
||||
|
||||
context->AddMoveObject(&session->GetClientSession());
|
||||
iface->ClientConnected(&session->GetServerSession());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,10 +214,16 @@ public:
|
||||
void PushRaw(const T& value);
|
||||
|
||||
template <typename... O>
|
||||
void PushMoveObjects(std::shared_ptr<O>... pointers);
|
||||
void PushMoveObjects(O*... pointers);
|
||||
|
||||
template <typename... O>
|
||||
void PushCopyObjects(std::shared_ptr<O>... pointers);
|
||||
void PushMoveObjects(O&... pointers);
|
||||
|
||||
template <typename... O>
|
||||
void PushCopyObjects(O*... pointers);
|
||||
|
||||
template <typename... O>
|
||||
void PushCopyObjects(O&... pointers);
|
||||
|
||||
private:
|
||||
u32 normal_params_size{};
|
||||
@@ -301,18 +306,34 @@ void ResponseBuilder::Push(const First& first_value, const Other&... other_value
|
||||
}
|
||||
|
||||
template <typename... O>
|
||||
inline void ResponseBuilder::PushCopyObjects(std::shared_ptr<O>... pointers) {
|
||||
inline void ResponseBuilder::PushCopyObjects(O*... pointers) {
|
||||
auto objects = {pointers...};
|
||||
for (auto& object : objects) {
|
||||
context->AddCopyObject(std::move(object));
|
||||
context->AddCopyObject(object);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... O>
|
||||
inline void ResponseBuilder::PushMoveObjects(std::shared_ptr<O>... pointers) {
|
||||
inline void ResponseBuilder::PushCopyObjects(O&... pointers) {
|
||||
auto objects = {&pointers...};
|
||||
for (auto& object : objects) {
|
||||
context->AddCopyObject(object);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... O>
|
||||
inline void ResponseBuilder::PushMoveObjects(O*... pointers) {
|
||||
auto objects = {pointers...};
|
||||
for (auto& object : objects) {
|
||||
context->AddMoveObject(std::move(object));
|
||||
context->AddMoveObject(object);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... O>
|
||||
inline void ResponseBuilder::PushMoveObjects(O&... pointers) {
|
||||
auto objects = {&pointers...};
|
||||
for (auto& object : objects) {
|
||||
context->AddMoveObject(object);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,9 +341,9 @@ class RequestParser : public RequestHelperBase {
|
||||
public:
|
||||
explicit RequestParser(u32* command_buffer) : RequestHelperBase(command_buffer) {}
|
||||
|
||||
explicit RequestParser(Kernel::HLERequestContext& context) : RequestHelperBase(context) {
|
||||
ASSERT_MSG(context.GetDataPayloadOffset(), "context is incomplete");
|
||||
Skip(context.GetDataPayloadOffset(), false);
|
||||
explicit RequestParser(Kernel::HLERequestContext& ctx) : RequestHelperBase(ctx) {
|
||||
ASSERT_MSG(ctx.GetDataPayloadOffset(), "context is incomplete");
|
||||
Skip(ctx.GetDataPayloadOffset(), false);
|
||||
// Skip the u64 command id, it's already stored in the context
|
||||
static constexpr u32 CommandIdSize = 2;
|
||||
Skip(CommandIdSize, false);
|
||||
@@ -359,12 +380,6 @@ public:
|
||||
template <typename T>
|
||||
T PopRaw();
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> GetMoveObject(std::size_t index);
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> GetCopyObject(std::size_t index);
|
||||
|
||||
template <class T>
|
||||
std::shared_ptr<T> PopIpcInterface() {
|
||||
ASSERT(context->Session()->IsDomain());
|
||||
@@ -469,14 +484,4 @@ void RequestParser::Pop(First& first_value, Other&... other_values) {
|
||||
Pop(other_values...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> RequestParser::GetMoveObject(std::size_t index) {
|
||||
return context->GetMoveObject<T>(index);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> RequestParser::GetCopyObject(std::size_t index) {
|
||||
return context->GetCopyObject<T>(index);
|
||||
}
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright 2016 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/server_port.h"
|
||||
#include "core/hle/kernel/session.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {}
|
||||
ClientPort::~ClientPort() = default;
|
||||
|
||||
std::shared_ptr<ServerPort> ClientPort::GetServerPort() const {
|
||||
return server_port;
|
||||
}
|
||||
|
||||
ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
|
||||
if (active_sessions >= max_sessions) {
|
||||
return ResultMaxConnectionsReached;
|
||||
}
|
||||
active_sessions++;
|
||||
|
||||
auto [client, server] = Kernel::Session::Create(kernel, name);
|
||||
|
||||
if (server_port->HasHLEHandler()) {
|
||||
server_port->GetHLEHandler()->ClientConnected(std::move(server));
|
||||
} else {
|
||||
server_port->AppendPendingSession(std::move(server));
|
||||
}
|
||||
|
||||
return MakeResult(std::move(client));
|
||||
}
|
||||
|
||||
void ClientPort::ConnectionClosed() {
|
||||
if (active_sessions == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
--active_sessions;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -1,63 +0,0 @@
|
||||
// Copyright 2016 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class ClientSession;
|
||||
class KernelCore;
|
||||
class ServerPort;
|
||||
|
||||
class ClientPort final : public Object {
|
||||
public:
|
||||
explicit ClientPort(KernelCore& kernel);
|
||||
~ClientPort() override;
|
||||
|
||||
friend class ServerPort;
|
||||
std::string GetTypeName() const override {
|
||||
return "ClientPort";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ClientPort;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
std::shared_ptr<ServerPort> GetServerPort() const;
|
||||
|
||||
/**
|
||||
* Creates a new Session pair, adds the created ServerSession to the associated ServerPort's
|
||||
* list of pending sessions, and signals the ServerPort, causing any threads
|
||||
* waiting on it to awake.
|
||||
* @returns ClientSession The client endpoint of the created Session pair, or error code.
|
||||
*/
|
||||
ResultVal<std::shared_ptr<ClientSession>> Connect();
|
||||
|
||||
/**
|
||||
* Signifies that a previously active connection has been closed,
|
||||
* decreasing the total number of active connections to this port.
|
||||
*/
|
||||
void ConnectionClosed();
|
||||
|
||||
void Finalize() override {}
|
||||
|
||||
private:
|
||||
std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port.
|
||||
u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have
|
||||
u32 active_sessions = 0; ///< Number of currently open sessions to this port
|
||||
std::string name; ///< Name of client port (optional)
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright 2019 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/session.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ClientSession::ClientSession(KernelCore& kernel) : KSynchronizationObject{kernel} {}
|
||||
|
||||
ClientSession::~ClientSession() {
|
||||
// This destructor will be called automatically when the last ClientSession handle is closed by
|
||||
// the emulated application.
|
||||
if (parent->Server()) {
|
||||
parent->Server()->ClientDisconnected();
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientSession::IsSignaled() const {
|
||||
UNIMPLEMENTED();
|
||||
return true;
|
||||
}
|
||||
|
||||
ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel,
|
||||
std::shared_ptr<Session> parent,
|
||||
std::string name) {
|
||||
std::shared_ptr<ClientSession> client_session{std::make_shared<ClientSession>(kernel)};
|
||||
|
||||
client_session->name = std::move(name);
|
||||
client_session->parent = std::move(parent);
|
||||
|
||||
return MakeResult(std::move(client_session));
|
||||
}
|
||||
|
||||
ResultCode ClientSession::SendSyncRequest(std::shared_ptr<KThread> thread,
|
||||
Core::Memory::Memory& memory,
|
||||
Core::Timing::CoreTiming& core_timing) {
|
||||
// Keep ServerSession alive until we're done working with it.
|
||||
if (!parent->Server()) {
|
||||
return ResultSessionClosedByRemote;
|
||||
}
|
||||
|
||||
// Signal the server session that new data is available
|
||||
return parent->Server()->HandleSyncRequest(std::move(thread), memory, core_timing);
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright 2019 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
union ResultCode;
|
||||
|
||||
namespace Core::Memory {
|
||||
class Memory;
|
||||
}
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class Session;
|
||||
class KThread;
|
||||
|
||||
class ClientSession final : public KSynchronizationObject {
|
||||
public:
|
||||
explicit ClientSession(KernelCore& kernel);
|
||||
~ClientSession() override;
|
||||
|
||||
friend class Session;
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "ClientSession";
|
||||
}
|
||||
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
ResultCode SendSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory,
|
||||
Core::Timing::CoreTiming& core_timing);
|
||||
|
||||
bool IsSignaled() const override;
|
||||
|
||||
void Finalize() override {}
|
||||
|
||||
private:
|
||||
static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel,
|
||||
std::shared_ptr<Session> parent,
|
||||
std::string name = "Unknown");
|
||||
|
||||
/// The parent session, which links to the server endpoint.
|
||||
std::shared_ptr<Session> parent;
|
||||
|
||||
/// Name of the client session (optional)
|
||||
std::string name;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -17,12 +17,12 @@ GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel)
|
||||
|
||||
GlobalSchedulerContext::~GlobalSchedulerContext() = default;
|
||||
|
||||
void GlobalSchedulerContext::AddThread(std::shared_ptr<KThread> thread) {
|
||||
void GlobalSchedulerContext::AddThread(KThread* thread) {
|
||||
std::scoped_lock lock{global_list_guard};
|
||||
thread_list.push_back(std::move(thread));
|
||||
thread_list.push_back(thread);
|
||||
}
|
||||
|
||||
void GlobalSchedulerContext::RemoveThread(std::shared_ptr<KThread> thread) {
|
||||
void GlobalSchedulerContext::RemoveThread(KThread* thread) {
|
||||
std::scoped_lock lock{global_list_guard};
|
||||
thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
|
||||
thread_list.end());
|
||||
|
||||
@@ -38,13 +38,13 @@ public:
|
||||
~GlobalSchedulerContext();
|
||||
|
||||
/// Adds a new thread to the scheduler
|
||||
void AddThread(std::shared_ptr<KThread> thread);
|
||||
void AddThread(KThread* thread);
|
||||
|
||||
/// Removes a thread from the scheduler
|
||||
void RemoveThread(std::shared_ptr<KThread> thread);
|
||||
void RemoveThread(KThread* thread);
|
||||
|
||||
/// Returns a list of all threads managed by the scheduler
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<KThread>>& GetThreadList() const {
|
||||
[[nodiscard]] const std::vector<KThread*>& GetThreadList() const {
|
||||
return thread_list;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ private:
|
||||
LockType scheduler_lock;
|
||||
|
||||
/// Lists all thread ids that aren't deleted/etc.
|
||||
std::vector<std::shared_ptr<KThread>> thread_list;
|
||||
std::vector<KThread*> thread_list;
|
||||
Common::SpinLock global_list_guard{};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <utility>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
|
||||
namespace Kernel {
|
||||
namespace {
|
||||
constexpr u16 GetSlot(Handle handle) {
|
||||
return static_cast<u16>(handle >> 15);
|
||||
}
|
||||
|
||||
constexpr u16 GetGeneration(Handle handle) {
|
||||
return static_cast<u16>(handle & 0x7FFF);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
HandleTable::HandleTable(KernelCore& kernel) : kernel{kernel} {
|
||||
Clear();
|
||||
}
|
||||
|
||||
HandleTable::~HandleTable() = default;
|
||||
|
||||
ResultCode HandleTable::SetSize(s32 handle_table_size) {
|
||||
if (static_cast<u32>(handle_table_size) > MAX_COUNT) {
|
||||
LOG_ERROR(Kernel, "Handle table size {} is greater than {}", handle_table_size, MAX_COUNT);
|
||||
return ResultOutOfMemory;
|
||||
}
|
||||
|
||||
// Values less than or equal to zero indicate to use the maximum allowable
|
||||
// size for the handle table in the actual kernel, so we ignore the given
|
||||
// value in that case, since we assume this by default unless this function
|
||||
// is called.
|
||||
if (handle_table_size > 0) {
|
||||
table_size = static_cast<u16>(handle_table_size);
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultVal<Handle> HandleTable::Create(std::shared_ptr<Object> obj) {
|
||||
DEBUG_ASSERT(obj != nullptr);
|
||||
|
||||
const u16 slot = next_free_slot;
|
||||
if (slot >= table_size) {
|
||||
LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
|
||||
return ResultHandleTableFull;
|
||||
}
|
||||
next_free_slot = generations[slot];
|
||||
|
||||
const u16 generation = next_generation++;
|
||||
|
||||
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
|
||||
// Horizon OS uses zero to represent an invalid handle, so skip to 1.
|
||||
if (next_generation >= (1 << 15)) {
|
||||
next_generation = 1;
|
||||
}
|
||||
|
||||
generations[slot] = generation;
|
||||
objects[slot] = std::move(obj);
|
||||
|
||||
Handle handle = generation | (slot << 15);
|
||||
return MakeResult<Handle>(handle);
|
||||
}
|
||||
|
||||
ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
|
||||
std::shared_ptr<Object> object = GetGeneric(handle);
|
||||
if (object == nullptr) {
|
||||
LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle);
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
return Create(std::move(object));
|
||||
}
|
||||
|
||||
ResultCode HandleTable::Close(Handle handle) {
|
||||
if (!IsValid(handle)) {
|
||||
LOG_ERROR(Kernel, "Handle is not valid! handle={:08X}", handle);
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
|
||||
const u16 slot = GetSlot(handle);
|
||||
|
||||
if (objects[slot].use_count() == 1) {
|
||||
objects[slot]->Finalize();
|
||||
}
|
||||
|
||||
objects[slot] = nullptr;
|
||||
|
||||
generations[slot] = next_free_slot;
|
||||
next_free_slot = slot;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
bool HandleTable::IsValid(Handle handle) const {
|
||||
const std::size_t slot = GetSlot(handle);
|
||||
const u16 generation = GetGeneration(handle);
|
||||
|
||||
return slot < table_size && objects[slot] != nullptr && generations[slot] == generation;
|
||||
}
|
||||
|
||||
std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const {
|
||||
if (handle == CurrentThread) {
|
||||
return SharedFrom(kernel.CurrentScheduler()->GetCurrentThread());
|
||||
} else if (handle == CurrentProcess) {
|
||||
return SharedFrom(kernel.CurrentProcess());
|
||||
}
|
||||
|
||||
if (!IsValid(handle)) {
|
||||
return nullptr;
|
||||
}
|
||||
return objects[GetSlot(handle)];
|
||||
}
|
||||
|
||||
void HandleTable::Clear() {
|
||||
for (u16 i = 0; i < table_size; ++i) {
|
||||
generations[i] = static_cast<u16>(i + 1);
|
||||
objects[i] = nullptr;
|
||||
}
|
||||
next_free_slot = 0;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -1,144 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
|
||||
enum KernelHandle : Handle {
|
||||
InvalidHandle = 0,
|
||||
CurrentThread = 0xFFFF8000,
|
||||
CurrentProcess = 0xFFFF8001,
|
||||
};
|
||||
|
||||
/**
|
||||
* This class allows the creation of Handles, which are references to objects that can be tested
|
||||
* for validity and looked up. Here they are used to pass references to kernel objects to/from the
|
||||
* emulated process. it has been designed so that it follows the same handle format and has
|
||||
* approximately the same restrictions as the handle manager in the CTR-OS.
|
||||
*
|
||||
* Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0).
|
||||
* The slot index is used to index into the arrays in this class to access the data corresponding
|
||||
* to the Handle.
|
||||
*
|
||||
* To prevent accidental use of a freed Handle whose slot has already been reused, a global counter
|
||||
* is kept and incremented every time a Handle is created. This is the Handle's "generation". The
|
||||
* value of the counter is stored into the Handle as well as in the handle table (in the
|
||||
* "generations" array). When looking up a handle, the Handle's generation must match with the
|
||||
* value stored on the class, otherwise the Handle is considered invalid.
|
||||
*
|
||||
* To find free slots when allocating a Handle without needing to scan the entire object array, the
|
||||
* generations field of unallocated slots is re-purposed as a linked list of indices to free slots.
|
||||
* When a Handle is created, an index is popped off the list and used for the new Handle. When it
|
||||
* is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is
|
||||
* likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been
|
||||
* verified and isn't likely to cause any problems.
|
||||
*/
|
||||
class HandleTable final : NonCopyable {
|
||||
public:
|
||||
/// This is the maximum limit of handles allowed per process in Horizon
|
||||
static constexpr std::size_t MAX_COUNT = 1024;
|
||||
|
||||
explicit HandleTable(KernelCore& kernel);
|
||||
~HandleTable();
|
||||
|
||||
/**
|
||||
* Sets the number of handles that may be in use at one time
|
||||
* for this handle table.
|
||||
*
|
||||
* @param handle_table_size The desired size to limit the handle table to.
|
||||
*
|
||||
* @returns an error code indicating if initialization was successful.
|
||||
* If initialization was not successful, then ERR_OUT_OF_MEMORY
|
||||
* will be returned.
|
||||
*
|
||||
* @pre handle_table_size must be within the range [0, 1024]
|
||||
*/
|
||||
ResultCode SetSize(s32 handle_table_size);
|
||||
|
||||
/**
|
||||
* Allocates a handle for the given object.
|
||||
* @return The created Handle or one of the following errors:
|
||||
* - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded.
|
||||
*/
|
||||
ResultVal<Handle> Create(std::shared_ptr<Object> obj);
|
||||
|
||||
/**
|
||||
* Returns a new handle that points to the same object as the passed in handle.
|
||||
* @return The duplicated Handle or one of the following errors:
|
||||
* - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
|
||||
* - Any errors returned by `Create()`.
|
||||
*/
|
||||
ResultVal<Handle> Duplicate(Handle handle);
|
||||
|
||||
/**
|
||||
* Closes a handle, removing it from the table and decreasing the object's ref-count.
|
||||
* @return `RESULT_SUCCESS` or one of the following errors:
|
||||
* - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
|
||||
*/
|
||||
ResultCode Close(Handle handle);
|
||||
|
||||
/// Checks if a handle is valid and points to an existing object.
|
||||
bool IsValid(Handle handle) const;
|
||||
|
||||
/**
|
||||
* Looks up a handle.
|
||||
* @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
|
||||
*/
|
||||
std::shared_ptr<Object> GetGeneric(Handle handle) const;
|
||||
|
||||
/**
|
||||
* Looks up a handle while verifying its type.
|
||||
* @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
|
||||
* type differs from the requested one.
|
||||
*/
|
||||
template <class T>
|
||||
std::shared_ptr<T> Get(Handle handle) const {
|
||||
return DynamicObjectCast<T>(GetGeneric(handle));
|
||||
}
|
||||
|
||||
/// Closes all handles held in this table.
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
/// Stores the Object referenced by the handle or null if the slot is empty.
|
||||
std::array<std::shared_ptr<Object>, MAX_COUNT> objects;
|
||||
|
||||
/**
|
||||
* The value of `next_generation` when the handle was created, used to check for validity. For
|
||||
* empty slots, contains the index of the next free slot in the list.
|
||||
*/
|
||||
std::array<u16, MAX_COUNT> generations;
|
||||
|
||||
/**
|
||||
* The limited size of the handle table. This can be specified by process
|
||||
* capabilities in order to restrict the overall number of handles that
|
||||
* can be created in a process instance
|
||||
*/
|
||||
u16 table_size = static_cast<u16>(MAX_COUNT);
|
||||
|
||||
/**
|
||||
* Global counter of the number of created handles. Stored in `generations` when a handle is
|
||||
* created, and wraps around to 1 when it hits 0x8000.
|
||||
*/
|
||||
u16 next_generation = 1;
|
||||
|
||||
/// Head of the free slots linked list.
|
||||
u16 next_free_slot = 0;
|
||||
|
||||
/// Underlying kernel instance that this handle table operates under.
|
||||
KernelCore& kernel;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -14,17 +14,16 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/k_handle_table.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||
#include "core/hle/kernel/k_server_session.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
#include "core/hle/kernel/time_manager.h"
|
||||
#include "core/memory.h"
|
||||
@@ -35,28 +34,23 @@ SessionRequestHandler::SessionRequestHandler() = default;
|
||||
|
||||
SessionRequestHandler::~SessionRequestHandler() = default;
|
||||
|
||||
void SessionRequestHandler::ClientConnected(std::shared_ptr<ServerSession> server_session) {
|
||||
server_session->SetHleHandler(shared_from_this());
|
||||
connected_sessions.push_back(std::move(server_session));
|
||||
void SessionRequestHandler::ClientConnected(KServerSession* session) {
|
||||
session->SetHleHandler(shared_from_this());
|
||||
}
|
||||
|
||||
void SessionRequestHandler::ClientDisconnected(
|
||||
const std::shared_ptr<ServerSession>& server_session) {
|
||||
server_session->SetHleHandler(nullptr);
|
||||
boost::range::remove_erase(connected_sessions, server_session);
|
||||
void SessionRequestHandler::ClientDisconnected(KServerSession* session) {
|
||||
session->SetHleHandler(nullptr);
|
||||
}
|
||||
|
||||
HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
|
||||
std::shared_ptr<ServerSession> server_session,
|
||||
std::shared_ptr<KThread> thread)
|
||||
: server_session(std::move(server_session)),
|
||||
thread(std::move(thread)), kernel{kernel}, memory{memory} {
|
||||
HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,
|
||||
KServerSession* server_session_, KThread* thread_)
|
||||
: server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} {
|
||||
cmd_buf[0] = 0;
|
||||
}
|
||||
|
||||
HLERequestContext::~HLERequestContext() = default;
|
||||
|
||||
void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf,
|
||||
void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf,
|
||||
bool incoming) {
|
||||
IPC::RequestParser rp(src_cmdbuf);
|
||||
command_header = rp.PopRaw<IPC::CommandHeader>();
|
||||
@@ -77,12 +71,12 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
|
||||
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
|
||||
const u32 copy_handle{rp.Pop<Handle>()};
|
||||
copy_handles.push_back(copy_handle);
|
||||
copy_objects.push_back(handle_table.GetGeneric(copy_handle));
|
||||
copy_objects.push_back(handle_table.GetObject(copy_handle).GetPointerUnsafe());
|
||||
}
|
||||
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) {
|
||||
const u32 move_handle{rp.Pop<Handle>()};
|
||||
move_handles.push_back(move_handle);
|
||||
move_objects.push_back(handle_table.GetGeneric(move_handle));
|
||||
move_objects.push_back(handle_table.GetObject(move_handle).GetPointerUnsafe());
|
||||
}
|
||||
} else {
|
||||
// For responses we just ignore the handles, they're empty and will be populated when
|
||||
@@ -169,7 +163,7 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
|
||||
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
|
||||
}
|
||||
|
||||
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
|
||||
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
|
||||
u32_le* src_cmdbuf) {
|
||||
ParseCommandBuffer(handle_table, src_cmdbuf, true);
|
||||
if (command_header->type == IPC::CommandType::Close) {
|
||||
@@ -186,12 +180,12 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTabl
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) {
|
||||
auto& owner_process = *thread.GetOwnerProcess();
|
||||
ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) {
|
||||
auto& owner_process = *requesting_thread.GetOwnerProcess();
|
||||
auto& handle_table = owner_process.GetHandleTable();
|
||||
|
||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf;
|
||||
memory.ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
|
||||
memory.ReadBlock(owner_process, requesting_thread.GetTLSAddress(), dst_cmdbuf.data(),
|
||||
dst_cmdbuf.size() * sizeof(u32));
|
||||
|
||||
// The header was already built in the internal command buffer. Attempt to parse it to verify
|
||||
@@ -223,12 +217,12 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) {
|
||||
// for specific values in each of these descriptors.
|
||||
for (auto& object : copy_objects) {
|
||||
ASSERT(object != nullptr);
|
||||
dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap();
|
||||
R_TRY(handle_table.Add(&dst_cmdbuf[current_offset++], object));
|
||||
}
|
||||
|
||||
for (auto& object : move_objects) {
|
||||
ASSERT(object != nullptr);
|
||||
dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap();
|
||||
R_TRY(handle_table.Add(&dst_cmdbuf[current_offset++], object));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +242,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) {
|
||||
}
|
||||
|
||||
// Copy the translated command buffer back into the thread's command buffer area.
|
||||
memory.WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
|
||||
memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), dst_cmdbuf.data(),
|
||||
dst_cmdbuf.size() * sizeof(u32));
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
#include "common/concepts.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
#include "core/hle/kernel/svc_common.h"
|
||||
|
||||
union ResultCode;
|
||||
|
||||
@@ -35,13 +36,14 @@ class ServiceFrameworkBase;
|
||||
namespace Kernel {
|
||||
|
||||
class Domain;
|
||||
class HandleTable;
|
||||
class HLERequestContext;
|
||||
class KernelCore;
|
||||
class Process;
|
||||
class ServerSession;
|
||||
class KHandleTable;
|
||||
class KProcess;
|
||||
class KServerSession;
|
||||
class KThread;
|
||||
class KReadableEvent;
|
||||
class KSession;
|
||||
class KWritableEvent;
|
||||
|
||||
enum class ThreadWakeupReason;
|
||||
@@ -71,20 +73,14 @@ public:
|
||||
* associated ServerSession alive for the duration of the connection.
|
||||
* @param server_session Owning pointer to the ServerSession associated with the connection.
|
||||
*/
|
||||
void ClientConnected(std::shared_ptr<ServerSession> server_session);
|
||||
void ClientConnected(KServerSession* session);
|
||||
|
||||
/**
|
||||
* Signals that a client has just disconnected from this HLE handler and releases the
|
||||
* associated ServerSession.
|
||||
* @param server_session ServerSession associated with the connection.
|
||||
*/
|
||||
void ClientDisconnected(const std::shared_ptr<ServerSession>& server_session);
|
||||
|
||||
protected:
|
||||
/// List of sessions that are connected to this handler.
|
||||
/// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list
|
||||
/// for the duration of the connection.
|
||||
std::vector<std::shared_ptr<ServerSession>> connected_sessions;
|
||||
void ClientDisconnected(KServerSession* session);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -109,8 +105,7 @@ protected:
|
||||
class HLERequestContext {
|
||||
public:
|
||||
explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
|
||||
std::shared_ptr<ServerSession> session,
|
||||
std::shared_ptr<KThread> thread);
|
||||
KServerSession* session, KThread* thread);
|
||||
~HLERequestContext();
|
||||
|
||||
/// Returns a pointer to the IPC command buffer for this request.
|
||||
@@ -122,16 +117,16 @@ public:
|
||||
* Returns the session through which this request was made. This can be used as a map key to
|
||||
* access per-client data on services.
|
||||
*/
|
||||
const std::shared_ptr<Kernel::ServerSession>& Session() const {
|
||||
Kernel::KServerSession* Session() {
|
||||
return server_session;
|
||||
}
|
||||
|
||||
/// Populates this context with data from the requesting process/thread.
|
||||
ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
|
||||
ResultCode PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
|
||||
u32_le* src_cmdbuf);
|
||||
|
||||
/// Writes data from this context back to the requesting process/thread.
|
||||
ResultCode WriteToOutgoingCommandBuffer(KThread& thread);
|
||||
ResultCode WriteToOutgoingCommandBuffer(KThread& requesting_thread);
|
||||
|
||||
u32_le GetCommand() const {
|
||||
return command;
|
||||
@@ -218,22 +213,12 @@ public:
|
||||
return move_handles.at(index);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> GetCopyObject(std::size_t index) {
|
||||
return DynamicObjectCast<T>(copy_objects.at(index));
|
||||
void AddMoveObject(KAutoObject* object) {
|
||||
move_objects.emplace_back(object);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> GetMoveObject(std::size_t index) {
|
||||
return DynamicObjectCast<T>(move_objects.at(index));
|
||||
}
|
||||
|
||||
void AddMoveObject(std::shared_ptr<Object> object) {
|
||||
move_objects.emplace_back(std::move(object));
|
||||
}
|
||||
|
||||
void AddCopyObject(std::shared_ptr<Object> object) {
|
||||
copy_objects.emplace_back(std::move(object));
|
||||
void AddCopyObject(KAutoObject* object) {
|
||||
copy_objects.emplace_back(object);
|
||||
}
|
||||
|
||||
void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) {
|
||||
@@ -276,10 +261,6 @@ public:
|
||||
return *thread;
|
||||
}
|
||||
|
||||
const KThread& GetThread() const {
|
||||
return *thread;
|
||||
}
|
||||
|
||||
bool IsThreadWaiting() const {
|
||||
return is_thread_waiting;
|
||||
}
|
||||
@@ -287,16 +268,17 @@ public:
|
||||
private:
|
||||
friend class IPC::ResponseBuilder;
|
||||
|
||||
void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
|
||||
void ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
|
||||
|
||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||
std::shared_ptr<Kernel::ServerSession> server_session;
|
||||
std::shared_ptr<KThread> thread;
|
||||
Kernel::KServerSession* server_session{};
|
||||
KThread* thread;
|
||||
|
||||
// TODO(yuriks): Check common usage of this and optimize size accordingly
|
||||
boost::container::small_vector<Handle, 8> move_handles;
|
||||
boost::container::small_vector<Handle, 8> copy_handles;
|
||||
boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects;
|
||||
boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects;
|
||||
boost::container::small_vector<KAutoObject*, 8> move_objects;
|
||||
boost::container::small_vector<KAutoObject*, 8> copy_objects;
|
||||
boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects;
|
||||
|
||||
std::optional<IPC::CommandHeader> command_header;
|
||||
|
||||
192
src/core/hle/kernel/init/init_slab_setup.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hardware_properties.h"
|
||||
#include "core/hle/kernel/init/init_slab_setup.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_memory_layout.h"
|
||||
#include "core/hle/kernel/k_memory_manager.h"
|
||||
#include "core/hle/kernel/k_port.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
#include "core/hle/kernel/k_session.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/kernel/k_system_control.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/kernel/memory_types.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel::Init {
|
||||
|
||||
#define SLAB_COUNT(CLASS) kernel.SlabResourceCounts().num_##CLASS
|
||||
|
||||
#define FOREACH_SLAB_TYPE(HANDLER, ...) \
|
||||
HANDLER(KProcess, (SLAB_COUNT(KProcess)), ##__VA_ARGS__) \
|
||||
HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \
|
||||
HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \
|
||||
HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \
|
||||
HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \
|
||||
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
|
||||
HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
|
||||
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__)
|
||||
|
||||
namespace {
|
||||
|
||||
#define DEFINE_SLAB_TYPE_ENUM_MEMBER(NAME, COUNT, ...) KSlabType_##NAME,
|
||||
|
||||
enum KSlabType : u32 {
|
||||
FOREACH_SLAB_TYPE(DEFINE_SLAB_TYPE_ENUM_MEMBER) KSlabType_Count,
|
||||
};
|
||||
|
||||
#undef DEFINE_SLAB_TYPE_ENUM_MEMBER
|
||||
|
||||
// Constexpr counts.
|
||||
constexpr size_t SlabCountKProcess = 80;
|
||||
constexpr size_t SlabCountKThread = 800;
|
||||
constexpr size_t SlabCountKEvent = 700;
|
||||
constexpr size_t SlabCountKInterruptEvent = 100;
|
||||
constexpr size_t SlabCountKPort = 256 + 0x20; // Extra 0x20 ports over Nintendo for homebrew.
|
||||
constexpr size_t SlabCountKSharedMemory = 80;
|
||||
constexpr size_t SlabCountKTransferMemory = 200;
|
||||
constexpr size_t SlabCountKCodeMemory = 10;
|
||||
constexpr size_t SlabCountKDeviceAddressSpace = 300;
|
||||
constexpr size_t SlabCountKSession = 933;
|
||||
constexpr size_t SlabCountKLightSession = 100;
|
||||
constexpr size_t SlabCountKObjectName = 7;
|
||||
constexpr size_t SlabCountKResourceLimit = 5;
|
||||
constexpr size_t SlabCountKDebug = Core::Hardware::NUM_CPU_CORES;
|
||||
constexpr size_t SlabCountKAlpha = 1;
|
||||
constexpr size_t SlabCountKBeta = 6;
|
||||
|
||||
constexpr size_t SlabCountExtraKThread = 160;
|
||||
|
||||
template <typename T>
|
||||
VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address,
|
||||
size_t num_objects) {
|
||||
const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*));
|
||||
VAddr start = Common::AlignUp(address, alignof(T));
|
||||
|
||||
if (size > 0) {
|
||||
const KMemoryRegion* region = memory_layout.FindVirtual(start + size - 1);
|
||||
ASSERT(region != nullptr);
|
||||
ASSERT(region->IsDerivedFrom(KMemoryRegionType_KernelSlab));
|
||||
T::InitializeSlabHeap(system.Kernel(), system.Memory().GetKernelBuffer(start, size), size);
|
||||
}
|
||||
|
||||
return start + size;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
KSlabResourceCounts KSlabResourceCounts::CreateDefault() {
|
||||
return {
|
||||
.num_KProcess = SlabCountKProcess,
|
||||
.num_KThread = SlabCountKThread,
|
||||
.num_KEvent = SlabCountKEvent,
|
||||
.num_KInterruptEvent = SlabCountKInterruptEvent,
|
||||
.num_KPort = SlabCountKPort,
|
||||
.num_KSharedMemory = SlabCountKSharedMemory,
|
||||
.num_KTransferMemory = SlabCountKTransferMemory,
|
||||
.num_KCodeMemory = SlabCountKCodeMemory,
|
||||
.num_KDeviceAddressSpace = SlabCountKDeviceAddressSpace,
|
||||
.num_KSession = SlabCountKSession,
|
||||
.num_KLightSession = SlabCountKLightSession,
|
||||
.num_KObjectName = SlabCountKObjectName,
|
||||
.num_KResourceLimit = SlabCountKResourceLimit,
|
||||
.num_KDebug = SlabCountKDebug,
|
||||
.num_KAlpha = SlabCountKAlpha,
|
||||
.num_KBeta = SlabCountKBeta,
|
||||
};
|
||||
}
|
||||
|
||||
void InitializeSlabResourceCounts(KernelCore& kernel) {
|
||||
kernel.SlabResourceCounts() = KSlabResourceCounts::CreateDefault();
|
||||
if (KSystemControl::Init::ShouldIncreaseThreadResourceLimit()) {
|
||||
kernel.SlabResourceCounts().num_KThread += SlabCountExtraKThread;
|
||||
}
|
||||
}
|
||||
|
||||
size_t CalculateTotalSlabHeapSize(const KernelCore& kernel) {
|
||||
size_t size = 0;
|
||||
|
||||
#define ADD_SLAB_SIZE(NAME, COUNT, ...) \
|
||||
{ \
|
||||
size += alignof(NAME); \
|
||||
size += Common::AlignUp(sizeof(NAME) * (COUNT), alignof(void*)); \
|
||||
};
|
||||
|
||||
// Add the size required for each slab.
|
||||
FOREACH_SLAB_TYPE(ADD_SLAB_SIZE)
|
||||
|
||||
#undef ADD_SLAB_SIZE
|
||||
|
||||
// Add the reserved size.
|
||||
size += KernelSlabHeapGapsSize;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
|
||||
auto& kernel = system.Kernel();
|
||||
|
||||
// Get the start of the slab region, since that's where we'll be working.
|
||||
VAddr address = memory_layout.GetSlabRegionAddress();
|
||||
|
||||
// Initialize slab type array to be in sorted order.
|
||||
std::array<KSlabType, KSlabType_Count> slab_types;
|
||||
for (size_t i = 0; i < slab_types.size(); i++) {
|
||||
slab_types[i] = static_cast<KSlabType>(i);
|
||||
}
|
||||
|
||||
// N shuffles the slab type array with the following simple algorithm.
|
||||
for (size_t i = 0; i < slab_types.size(); i++) {
|
||||
const size_t rnd = KSystemControl::GenerateRandomRange(0, slab_types.size() - 1);
|
||||
std::swap(slab_types[i], slab_types[rnd]);
|
||||
}
|
||||
|
||||
// Create an array to represent the gaps between the slabs.
|
||||
const size_t total_gap_size = KernelSlabHeapGapsSize;
|
||||
std::array<size_t, slab_types.size()> slab_gaps;
|
||||
for (size_t i = 0; i < slab_gaps.size(); i++) {
|
||||
// Note: This is an off-by-one error from Nintendo's intention, because GenerateRandomRange
|
||||
// is inclusive. However, Nintendo also has the off-by-one error, and it's "harmless", so we
|
||||
// will include it ourselves.
|
||||
slab_gaps[i] = KSystemControl::GenerateRandomRange(0, total_gap_size);
|
||||
}
|
||||
|
||||
// Sort the array, so that we can treat differences between values as offsets to the starts of
|
||||
// slabs.
|
||||
for (size_t i = 1; i < slab_gaps.size(); i++) {
|
||||
for (size_t j = i; j > 0 && slab_gaps[j - 1] > slab_gaps[j]; j--) {
|
||||
std::swap(slab_gaps[j], slab_gaps[j - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < slab_types.size(); i++) {
|
||||
// Add the random gap to the address.
|
||||
address += (i == 0) ? slab_gaps[0] : slab_gaps[i] - slab_gaps[i - 1];
|
||||
|
||||
#define INITIALIZE_SLAB_HEAP(NAME, COUNT, ...) \
|
||||
case KSlabType_##NAME: \
|
||||
address = InitializeSlabHeap<NAME>(system, memory_layout, address, COUNT); \
|
||||
break;
|
||||
|
||||
// Initialize the slabheap.
|
||||
switch (slab_types[i]) {
|
||||
// For each of the slab types, we want to initialize that heap.
|
||||
FOREACH_SLAB_TYPE(INITIALIZE_SLAB_HEAP)
|
||||
// If we somehow get an invalid type, abort.
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Kernel::Init
|
||||
43
src/core/hle/kernel/init/init_slab_setup.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
} // namespace Core
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
class KMemoryLayout;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Kernel::Init {
|
||||
|
||||
struct KSlabResourceCounts {
|
||||
static KSlabResourceCounts CreateDefault();
|
||||
|
||||
size_t num_KProcess;
|
||||
size_t num_KThread;
|
||||
size_t num_KEvent;
|
||||
size_t num_KInterruptEvent;
|
||||
size_t num_KPort;
|
||||
size_t num_KSharedMemory;
|
||||
size_t num_KTransferMemory;
|
||||
size_t num_KCodeMemory;
|
||||
size_t num_KDeviceAddressSpace;
|
||||
size_t num_KSession;
|
||||
size_t num_KLightSession;
|
||||
size_t num_KObjectName;
|
||||
size_t num_KResourceLimit;
|
||||
size_t num_KDebug;
|
||||
size_t num_KAlpha;
|
||||
size_t num_KBeta;
|
||||
};
|
||||
|
||||
void InitializeSlabResourceCounts(KernelCore& kernel);
|
||||
size_t CalculateTotalSlabHeapSize(const KernelCore& kernel);
|
||||
void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout);
|
||||
|
||||
} // namespace Kernel::Init
|
||||
14
src/core/hle/kernel/k_auto_object.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
KAutoObject* KAutoObject::Create(KAutoObject* obj) {
|
||||
obj->m_ref_count = 1;
|
||||
return obj;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
302
src/core/hle/kernel/k_auto_object.h
Normal file
@@ -0,0 +1,302 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/intrusive_red_black_tree.h"
|
||||
#include "core/hle/kernel/k_class_token.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class KProcess;
|
||||
|
||||
#define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \
|
||||
YUZU_NON_COPYABLE(CLASS); \
|
||||
YUZU_NON_MOVEABLE(CLASS); \
|
||||
\
|
||||
private: \
|
||||
friend class ::Kernel::KClassTokenGenerator; \
|
||||
static constexpr inline auto ObjectType = ::Kernel::KClassTokenGenerator::ObjectType::CLASS; \
|
||||
static constexpr inline const char* const TypeName = #CLASS; \
|
||||
static constexpr inline ClassTokenType ClassToken() { \
|
||||
return ::Kernel::ClassToken<CLASS>; \
|
||||
} \
|
||||
\
|
||||
public: \
|
||||
using BaseClass = BASE_CLASS; \
|
||||
static constexpr TypeObj GetStaticTypeObj() { \
|
||||
constexpr ClassTokenType Token = ClassToken(); \
|
||||
return TypeObj(TypeName, Token); \
|
||||
} \
|
||||
static constexpr const char* GetStaticTypeName() { \
|
||||
return TypeName; \
|
||||
} \
|
||||
virtual TypeObj GetTypeObj() const { \
|
||||
return GetStaticTypeObj(); \
|
||||
} \
|
||||
virtual const char* GetTypeName() const { \
|
||||
return GetStaticTypeName(); \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
constexpr bool operator!=(const TypeObj& rhs)
|
||||
|
||||
class KAutoObject {
|
||||
protected:
|
||||
class TypeObj {
|
||||
public:
|
||||
constexpr explicit TypeObj(const char* n, ClassTokenType tok)
|
||||
: m_name(n), m_class_token(tok) {}
|
||||
|
||||
constexpr const char* GetName() const {
|
||||
return m_name;
|
||||
}
|
||||
constexpr ClassTokenType GetClassToken() const {
|
||||
return m_class_token;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const TypeObj& rhs) const {
|
||||
return this->GetClassToken() == rhs.GetClassToken();
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const TypeObj& rhs) const {
|
||||
return this->GetClassToken() != rhs.GetClassToken();
|
||||
}
|
||||
|
||||
constexpr bool IsDerivedFrom(const TypeObj& rhs) const {
|
||||
return (this->GetClassToken() | rhs.GetClassToken()) == this->GetClassToken();
|
||||
}
|
||||
|
||||
private:
|
||||
const char* m_name;
|
||||
ClassTokenType m_class_token;
|
||||
};
|
||||
|
||||
private:
|
||||
KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
|
||||
|
||||
public:
|
||||
explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {}
|
||||
virtual ~KAutoObject() = default;
|
||||
|
||||
static KAutoObject* Create(KAutoObject* ptr);
|
||||
|
||||
// Destroy is responsible for destroying the auto object's resources when ref_count hits zero.
|
||||
virtual void Destroy() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
// Finalize is responsible for cleaning up resource, but does not destroy the object.
|
||||
virtual void Finalize() {}
|
||||
|
||||
virtual KProcess* GetOwner() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
u32 GetReferenceCount() const {
|
||||
return m_ref_count.load();
|
||||
}
|
||||
|
||||
bool IsDerivedFrom(const TypeObj& rhs) const {
|
||||
return this->GetTypeObj().IsDerivedFrom(rhs);
|
||||
}
|
||||
|
||||
bool IsDerivedFrom(const KAutoObject& rhs) const {
|
||||
return this->IsDerivedFrom(rhs.GetTypeObj());
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
Derived DynamicCast() {
|
||||
static_assert(std::is_pointer_v<Derived>);
|
||||
using DerivedType = std::remove_pointer_t<Derived>;
|
||||
|
||||
if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) {
|
||||
return static_cast<Derived>(this);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
const Derived DynamicCast() const {
|
||||
static_assert(std::is_pointer_v<Derived>);
|
||||
using DerivedType = std::remove_pointer_t<Derived>;
|
||||
|
||||
if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) {
|
||||
return static_cast<Derived>(this);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Open() {
|
||||
// Atomically increment the reference count, only if it's positive.
|
||||
u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire);
|
||||
do {
|
||||
if (cur_ref_count == 0) {
|
||||
return false;
|
||||
}
|
||||
ASSERT(cur_ref_count < cur_ref_count + 1);
|
||||
} while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count + 1,
|
||||
std::memory_order_relaxed));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Close() {
|
||||
// Atomically decrement the reference count, not allowing it to become negative.
|
||||
u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire);
|
||||
do {
|
||||
ASSERT(cur_ref_count > 0);
|
||||
} while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count - 1,
|
||||
std::memory_order_relaxed));
|
||||
|
||||
// If ref count hits zero, destroy the object.
|
||||
if (cur_ref_count - 1 == 0) {
|
||||
this->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
KernelCore& kernel;
|
||||
std::string name;
|
||||
|
||||
private:
|
||||
std::atomic<u32> m_ref_count{};
|
||||
};
|
||||
|
||||
class KAutoObjectWithListContainer;
|
||||
|
||||
class KAutoObjectWithList : public KAutoObject {
|
||||
public:
|
||||
explicit KAutoObjectWithList(KernelCore& kernel_) : KAutoObject(kernel_) {}
|
||||
|
||||
static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) {
|
||||
const u64 lid = lhs.GetId();
|
||||
const u64 rid = rhs.GetId();
|
||||
|
||||
if (lid < rid) {
|
||||
return -1;
|
||||
} else if (lid > rid) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
virtual u64 GetId() const {
|
||||
return reinterpret_cast<u64>(this);
|
||||
}
|
||||
|
||||
virtual const std::string& GetName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class KAutoObjectWithListContainer;
|
||||
|
||||
Common::IntrusiveRedBlackTreeNode list_node;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class KScopedAutoObject {
|
||||
YUZU_NON_COPYABLE(KScopedAutoObject);
|
||||
|
||||
public:
|
||||
constexpr KScopedAutoObject() = default;
|
||||
|
||||
constexpr KScopedAutoObject(T* o) : m_obj(o) {
|
||||
if (m_obj != nullptr) {
|
||||
m_obj->Open();
|
||||
}
|
||||
}
|
||||
|
||||
~KScopedAutoObject() {
|
||||
if (m_obj != nullptr) {
|
||||
m_obj->Close();
|
||||
}
|
||||
m_obj = nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
requires(std::derived_from<T, U> ||
|
||||
std::derived_from<U, T>) constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) {
|
||||
if constexpr (std::derived_from<U, T>) {
|
||||
// Upcast.
|
||||
m_obj = rhs.m_obj;
|
||||
rhs.m_obj = nullptr;
|
||||
} else {
|
||||
// Downcast.
|
||||
T* derived = nullptr;
|
||||
if (rhs.m_obj != nullptr) {
|
||||
derived = rhs.m_obj->template DynamicCast<T*>();
|
||||
if (derived == nullptr) {
|
||||
rhs.m_obj->Close();
|
||||
}
|
||||
}
|
||||
|
||||
m_obj = derived;
|
||||
rhs.m_obj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr KScopedAutoObject<T>& operator=(KScopedAutoObject<T>&& rhs) {
|
||||
rhs.Swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr T* operator->() {
|
||||
return m_obj;
|
||||
}
|
||||
constexpr T& operator*() {
|
||||
return *m_obj;
|
||||
}
|
||||
|
||||
constexpr void Reset(T* o) {
|
||||
KScopedAutoObject(o).Swap(*this);
|
||||
}
|
||||
|
||||
constexpr T* GetPointerUnsafe() {
|
||||
return m_obj;
|
||||
}
|
||||
|
||||
constexpr T* GetPointerUnsafe() const {
|
||||
return m_obj;
|
||||
}
|
||||
|
||||
constexpr T* ReleasePointerUnsafe() {
|
||||
T* ret = m_obj;
|
||||
m_obj = nullptr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr bool IsNull() const {
|
||||
return m_obj == nullptr;
|
||||
}
|
||||
constexpr bool IsNotNull() const {
|
||||
return m_obj != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename U>
|
||||
friend class KScopedAutoObject;
|
||||
|
||||
private:
|
||||
T* m_obj{};
|
||||
|
||||
private:
|
||||
constexpr void Swap(KScopedAutoObject& rhs) noexcept {
|
||||
std::swap(m_obj, rhs.m_obj);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
28
src/core/hle/kernel/k_auto_object_container.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/kernel/k_auto_object_container.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
m_object_list.insert(*obj);
|
||||
}
|
||||
|
||||
void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
m_object_list.erase(m_object_list.iterator_to(*obj));
|
||||
}
|
||||
|
||||
size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
return std::count_if(m_object_list.begin(), m_object_list.end(),
|
||||
[&](const auto& obj) { return obj.GetOwner() == owner; });
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
70
src/core/hle/kernel/k_auto_object_container.h
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/intrusive_red_black_tree.h"
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class KProcess;
|
||||
|
||||
class KAutoObjectWithListContainer {
|
||||
YUZU_NON_COPYABLE(KAutoObjectWithListContainer);
|
||||
YUZU_NON_MOVEABLE(KAutoObjectWithListContainer);
|
||||
|
||||
public:
|
||||
using ListType = Common::IntrusiveRedBlackTreeMemberTraits<
|
||||
&KAutoObjectWithList::list_node>::TreeType<KAutoObjectWithList>;
|
||||
|
||||
public:
|
||||
class ListAccessor : public KScopedLightLock {
|
||||
public:
|
||||
explicit ListAccessor(KAutoObjectWithListContainer* container)
|
||||
: KScopedLightLock(container->m_lock), m_list(container->m_object_list) {}
|
||||
explicit ListAccessor(KAutoObjectWithListContainer& container)
|
||||
: KScopedLightLock(container.m_lock), m_list(container.m_object_list) {}
|
||||
|
||||
typename ListType::iterator begin() const {
|
||||
return m_list.begin();
|
||||
}
|
||||
|
||||
typename ListType::iterator end() const {
|
||||
return m_list.end();
|
||||
}
|
||||
|
||||
typename ListType::iterator find(typename ListType::const_reference ref) const {
|
||||
return m_list.find(ref);
|
||||
}
|
||||
|
||||
private:
|
||||
ListType& m_list;
|
||||
};
|
||||
|
||||
friend class ListAccessor;
|
||||
|
||||
public:
|
||||
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {}
|
||||
|
||||
void Initialize() {}
|
||||
void Finalize() {}
|
||||
|
||||
void Register(KAutoObjectWithList* obj);
|
||||
void Unregister(KAutoObjectWithList* obj);
|
||||
size_t GetOwnedCount(KProcess* owner);
|
||||
|
||||
private:
|
||||
KLightLock m_lock;
|
||||
ListType m_object_list;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
133
src/core/hle/kernel/k_class_token.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
#include "core/hle/kernel/k_class_token.h"
|
||||
#include "core/hle/kernel/k_client_port.h"
|
||||
#include "core/hle/kernel/k_client_session.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_port.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
#include "core/hle/kernel/k_server_port.h"
|
||||
#include "core/hle/kernel/k_server_session.h"
|
||||
#include "core/hle/kernel/k_session.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
// Ensure that we generate correct class tokens for all types.
|
||||
|
||||
// Ensure that the absolute token values are correct.
|
||||
static_assert(ClassToken<KAutoObject> == 0b00000000'00000000);
|
||||
static_assert(ClassToken<KSynchronizationObject> == 0b00000000'00000001);
|
||||
static_assert(ClassToken<KReadableEvent> == 0b00000000'00000011);
|
||||
// static_assert(ClassToken<KInterruptEvent> == 0b00000111'00000011);
|
||||
// static_assert(ClassToken<KDebug> == 0b00001011'00000001);
|
||||
static_assert(ClassToken<KThread> == 0b00010011'00000001);
|
||||
static_assert(ClassToken<KServerPort> == 0b00100011'00000001);
|
||||
static_assert(ClassToken<KServerSession> == 0b01000011'00000001);
|
||||
static_assert(ClassToken<KClientPort> == 0b10000011'00000001);
|
||||
static_assert(ClassToken<KClientSession> == 0b00001101'00000000);
|
||||
static_assert(ClassToken<KProcess> == 0b00010101'00000001);
|
||||
static_assert(ClassToken<KResourceLimit> == 0b00100101'00000000);
|
||||
// static_assert(ClassToken<KLightSession> == 0b01000101'00000000);
|
||||
static_assert(ClassToken<KPort> == 0b10000101'00000000);
|
||||
static_assert(ClassToken<KSession> == 0b00011001'00000000);
|
||||
static_assert(ClassToken<KSharedMemory> == 0b00101001'00000000);
|
||||
static_assert(ClassToken<KEvent> == 0b01001001'00000000);
|
||||
static_assert(ClassToken<KWritableEvent> == 0b10001001'00000000);
|
||||
// static_assert(ClassToken<KLightClientSession> == 0b00110001'00000000);
|
||||
// static_assert(ClassToken<KLightServerSession> == 0b01010001'00000000);
|
||||
static_assert(ClassToken<KTransferMemory> == 0b10010001'00000000);
|
||||
// static_assert(ClassToken<KDeviceAddressSpace> == 0b01100001'00000000);
|
||||
// static_assert(ClassToken<KSessionRequest> == 0b10100001'00000000);
|
||||
// static_assert(ClassToken<KCodeMemory> == 0b11000001'00000000);
|
||||
|
||||
// Ensure that the token hierarchy is correct.
|
||||
|
||||
// Base classes
|
||||
static_assert(ClassToken<KAutoObject> == (0b00000000));
|
||||
static_assert(ClassToken<KSynchronizationObject> == (0b00000001 | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KReadableEvent> == (0b00000010 | ClassToken<KSynchronizationObject>));
|
||||
|
||||
// Final classes
|
||||
// static_assert(ClassToken<KInterruptEvent> == ((0b00000111 << 8) | ClassToken<KReadableEvent>));
|
||||
// static_assert(ClassToken<KDebug> == ((0b00001011 << 8) | ClassToken<KSynchronizationObject>));
|
||||
static_assert(ClassToken<KThread> == ((0b00010011 << 8) | ClassToken<KSynchronizationObject>));
|
||||
static_assert(ClassToken<KServerPort> == ((0b00100011 << 8) | ClassToken<KSynchronizationObject>));
|
||||
static_assert(ClassToken<KServerSession> ==
|
||||
((0b01000011 << 8) | ClassToken<KSynchronizationObject>));
|
||||
static_assert(ClassToken<KClientPort> == ((0b10000011 << 8) | ClassToken<KSynchronizationObject>));
|
||||
static_assert(ClassToken<KClientSession> == ((0b00001101 << 8) | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KProcess> == ((0b00010101 << 8) | ClassToken<KSynchronizationObject>));
|
||||
static_assert(ClassToken<KResourceLimit> == ((0b00100101 << 8) | ClassToken<KAutoObject>));
|
||||
// static_assert(ClassToken<KLightSession> == ((0b01000101 << 8) | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KPort> == ((0b10000101 << 8) | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KSession> == ((0b00011001 << 8) | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KSharedMemory> == ((0b00101001 << 8) | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KEvent> == ((0b01001001 << 8) | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KWritableEvent> == ((0b10001001 << 8) | ClassToken<KAutoObject>));
|
||||
// static_assert(ClassToken<KLightClientSession> == ((0b00110001 << 8) | ClassToken<KAutoObject>));
|
||||
// static_assert(ClassToken<KLightServerSession> == ((0b01010001 << 8) | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAutoObject>));
|
||||
// static_assert(ClassToken<KDeviceAddressSpace> == ((0b01100001 << 8) | ClassToken<KAutoObject>));
|
||||
// static_assert(ClassToken<KSessionRequest> == ((0b10100001 << 8) | ClassToken<KAutoObject>));
|
||||
// static_assert(ClassToken<KCodeMemory> == ((0b11000001 << 8) | ClassToken<KAutoObject>));
|
||||
|
||||
// Ensure that the token hierarchy reflects the class hierarchy.
|
||||
|
||||
// Base classes.
|
||||
static_assert(!std::is_final<KSynchronizationObject>::value &&
|
||||
std::is_base_of<KAutoObject, KSynchronizationObject>::value);
|
||||
static_assert(!std::is_final<KReadableEvent>::value &&
|
||||
std::is_base_of<KSynchronizationObject, KReadableEvent>::value);
|
||||
|
||||
// Final classes
|
||||
// static_assert(std::is_final<KInterruptEvent>::value &&
|
||||
// std::is_base_of<KReadableEvent, KInterruptEvent>::value);
|
||||
// static_assert(std::is_final<KDebug>::value &&
|
||||
// std::is_base_of<KSynchronizationObject, KDebug>::value);
|
||||
static_assert(std::is_final<KThread>::value &&
|
||||
std::is_base_of<KSynchronizationObject, KThread>::value);
|
||||
static_assert(std::is_final<KServerPort>::value &&
|
||||
std::is_base_of<KSynchronizationObject, KServerPort>::value);
|
||||
static_assert(std::is_final<KServerSession>::value &&
|
||||
std::is_base_of<KSynchronizationObject, KServerSession>::value);
|
||||
static_assert(std::is_final<KClientPort>::value &&
|
||||
std::is_base_of<KSynchronizationObject, KClientPort>::value);
|
||||
static_assert(std::is_final<KClientSession>::value &&
|
||||
std::is_base_of<KAutoObject, KClientSession>::value);
|
||||
static_assert(std::is_final<KProcess>::value &&
|
||||
std::is_base_of<KSynchronizationObject, KProcess>::value);
|
||||
static_assert(std::is_final<KResourceLimit>::value &&
|
||||
std::is_base_of<KAutoObject, KResourceLimit>::value);
|
||||
// static_assert(std::is_final<KLightSession>::value &&
|
||||
// std::is_base_of<KAutoObject, KLightSession>::value);
|
||||
static_assert(std::is_final<KPort>::value && std::is_base_of<KAutoObject, KPort>::value);
|
||||
static_assert(std::is_final<KSession>::value && std::is_base_of<KAutoObject, KSession>::value);
|
||||
static_assert(std::is_final<KSharedMemory>::value &&
|
||||
std::is_base_of<KAutoObject, KSharedMemory>::value);
|
||||
static_assert(std::is_final<KEvent>::value && std::is_base_of<KAutoObject, KEvent>::value);
|
||||
static_assert(std::is_final<KWritableEvent>::value &&
|
||||
std::is_base_of<KAutoObject, KWritableEvent>::value);
|
||||
// static_assert(std::is_final<KLightClientSession>::value &&
|
||||
// std::is_base_of<KAutoObject, KLightClientSession>::value);
|
||||
// static_assert(std::is_final<KLightServerSession>::value &&
|
||||
// std::is_base_of<KAutoObject, KLightServerSession>::value);
|
||||
static_assert(std::is_final<KTransferMemory>::value &&
|
||||
std::is_base_of<KAutoObject, KTransferMemory>::value);
|
||||
// static_assert(std::is_final<KDeviceAddressSpace>::value &&
|
||||
// std::is_base_of<KAutoObject, KDeviceAddressSpace>::value);
|
||||
// static_assert(std::is_final<KSessionRequest>::value &&
|
||||
// std::is_base_of<KAutoObject, KSessionRequest>::value);
|
||||
// static_assert(std::is_final<KCodeMemory>::value &&
|
||||
// std::is_base_of<KAutoObject, KCodeMemory>::value);
|
||||
|
||||
} // namespace Kernel
|
||||
131
src/core/hle/kernel/k_class_token.h
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KAutoObject;
|
||||
|
||||
class KClassTokenGenerator {
|
||||
public:
|
||||
using TokenBaseType = u16;
|
||||
|
||||
public:
|
||||
static constexpr size_t BaseClassBits = 8;
|
||||
static constexpr size_t FinalClassBits = (sizeof(TokenBaseType) * CHAR_BIT) - BaseClassBits;
|
||||
// One bit per base class.
|
||||
static constexpr size_t NumBaseClasses = BaseClassBits;
|
||||
// Final classes are permutations of three bits.
|
||||
static constexpr size_t NumFinalClasses = [] {
|
||||
TokenBaseType index = 0;
|
||||
for (size_t i = 0; i < FinalClassBits; i++) {
|
||||
for (size_t j = i + 1; j < FinalClassBits; j++) {
|
||||
for (size_t k = j + 1; k < FinalClassBits; k++) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}();
|
||||
|
||||
private:
|
||||
template <TokenBaseType Index>
|
||||
static constexpr inline TokenBaseType BaseClassToken = 1U << Index;
|
||||
|
||||
template <TokenBaseType Index>
|
||||
static constexpr inline TokenBaseType FinalClassToken = [] {
|
||||
TokenBaseType index = 0;
|
||||
for (size_t i = 0; i < FinalClassBits; i++) {
|
||||
for (size_t j = i + 1; j < FinalClassBits; j++) {
|
||||
for (size_t k = j + 1; k < FinalClassBits; k++) {
|
||||
if ((index++) == Index) {
|
||||
return static_cast<TokenBaseType>(((1ULL << i) | (1ULL << j) | (1ULL << k))
|
||||
<< BaseClassBits);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
||||
template <typename T>
|
||||
static constexpr inline TokenBaseType GetClassToken() {
|
||||
static_assert(std::is_base_of<KAutoObject, T>::value);
|
||||
if constexpr (std::is_same<T, KAutoObject>::value) {
|
||||
static_assert(T::ObjectType == ObjectType::KAutoObject);
|
||||
return 0;
|
||||
} else if constexpr (!std::is_final<T>::value) {
|
||||
static_assert(ObjectType::BaseClassesStart <= T::ObjectType &&
|
||||
T::ObjectType < ObjectType::BaseClassesEnd);
|
||||
constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) -
|
||||
static_cast<TokenBaseType>(ObjectType::BaseClassesStart);
|
||||
return BaseClassToken<ClassIndex> | GetClassToken<typename T::BaseClass>();
|
||||
} else if constexpr (ObjectType::FinalClassesStart <= T::ObjectType &&
|
||||
T::ObjectType < ObjectType::FinalClassesEnd) {
|
||||
constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) -
|
||||
static_cast<TokenBaseType>(ObjectType::FinalClassesStart);
|
||||
return FinalClassToken<ClassIndex> | GetClassToken<typename T::BaseClass>();
|
||||
} else {
|
||||
static_assert(!std::is_same<T, T>::value, "GetClassToken: Invalid Type");
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
enum class ObjectType {
|
||||
KAutoObject,
|
||||
|
||||
BaseClassesStart,
|
||||
|
||||
KSynchronizationObject = BaseClassesStart,
|
||||
KReadableEvent,
|
||||
|
||||
BaseClassesEnd,
|
||||
|
||||
FinalClassesStart = BaseClassesEnd,
|
||||
|
||||
KInterruptEvent = FinalClassesStart,
|
||||
KDebug,
|
||||
KThread,
|
||||
KServerPort,
|
||||
KServerSession,
|
||||
KClientPort,
|
||||
KClientSession,
|
||||
KProcess,
|
||||
KResourceLimit,
|
||||
KLightSession,
|
||||
KPort,
|
||||
KSession,
|
||||
KSharedMemory,
|
||||
KEvent,
|
||||
KWritableEvent,
|
||||
KLightClientSession,
|
||||
KLightServerSession,
|
||||
KTransferMemory,
|
||||
KDeviceAddressSpace,
|
||||
KSessionRequest,
|
||||
KCodeMemory,
|
||||
|
||||
// NOTE: True order for these has not been determined yet.
|
||||
KAlpha,
|
||||
KBeta,
|
||||
|
||||
FinalClassesEnd = FinalClassesStart + NumFinalClasses,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static constexpr inline TokenBaseType ClassToken = GetClassToken<T>();
|
||||
};
|
||||
|
||||
using ClassTokenType = KClassTokenGenerator::TokenBaseType;
|
||||
|
||||
template <typename T>
|
||||
static constexpr inline ClassTokenType ClassToken = KClassTokenGenerator::ClassToken<T>;
|
||||
|
||||
} // namespace Kernel
|
||||
125
src/core/hle/kernel/k_client_port.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright 2021 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/k_client_port.h"
|
||||
#include "core/hle/kernel/k_port.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_scoped_resource_reservation.h"
|
||||
#include "core/hle/kernel/k_session.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
KClientPort::KClientPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
|
||||
KClientPort::~KClientPort() = default;
|
||||
|
||||
void KClientPort::Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_) {
|
||||
// Set member variables.
|
||||
num_sessions = 0;
|
||||
peak_sessions = 0;
|
||||
parent = parent_;
|
||||
max_sessions = max_sessions_;
|
||||
name = std::move(name_);
|
||||
}
|
||||
|
||||
void KClientPort::OnSessionFinalized() {
|
||||
KScopedSchedulerLock sl{kernel};
|
||||
|
||||
const auto prev = num_sessions--;
|
||||
if (prev == max_sessions) {
|
||||
this->NotifyAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
void KClientPort::OnServerClosed() {}
|
||||
|
||||
bool KClientPort::IsLight() const {
|
||||
return this->GetParent()->IsLight();
|
||||
}
|
||||
|
||||
bool KClientPort::IsServerClosed() const {
|
||||
return this->GetParent()->IsServerClosed();
|
||||
}
|
||||
|
||||
void KClientPort::Destroy() {
|
||||
// Note with our parent that we're closed.
|
||||
parent->OnClientClosed();
|
||||
|
||||
// Close our reference to our parent.
|
||||
parent->Close();
|
||||
}
|
||||
|
||||
bool KClientPort::IsSignaled() const {
|
||||
return num_sessions < max_sessions;
|
||||
}
|
||||
|
||||
ResultCode KClientPort::CreateSession(KClientSession** out) {
|
||||
// Reserve a new session from the resource limit.
|
||||
KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
|
||||
LimitableResource::Sessions);
|
||||
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
|
||||
|
||||
// Update the session counts.
|
||||
{
|
||||
// Atomically increment the number of sessions.
|
||||
s32 new_sessions;
|
||||
{
|
||||
const auto max = max_sessions;
|
||||
auto cur_sessions = num_sessions.load(std::memory_order_acquire);
|
||||
do {
|
||||
R_UNLESS(cur_sessions < max, ResultOutOfSessions);
|
||||
new_sessions = cur_sessions + 1;
|
||||
} while (!num_sessions.compare_exchange_weak(cur_sessions, new_sessions,
|
||||
std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
// Atomically update the peak session tracking.
|
||||
{
|
||||
auto peak = peak_sessions.load(std::memory_order_acquire);
|
||||
do {
|
||||
if (peak >= new_sessions) {
|
||||
break;
|
||||
}
|
||||
} while (!peak_sessions.compare_exchange_weak(peak, new_sessions,
|
||||
std::memory_order_relaxed));
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new session.
|
||||
KSession* session = KSession::Create(kernel);
|
||||
if (session == nullptr) {
|
||||
/* Decrement the session count. */
|
||||
const auto prev = num_sessions--;
|
||||
if (prev == max_sessions) {
|
||||
this->NotifyAvailable();
|
||||
}
|
||||
|
||||
return ResultOutOfResource;
|
||||
}
|
||||
|
||||
// Initialize the session.
|
||||
session->Initialize(this, parent->GetName());
|
||||
|
||||
// Commit the session reservation.
|
||||
session_reservation.Commit();
|
||||
|
||||
// Register the session.
|
||||
KSession::Register(kernel, session);
|
||||
auto session_guard = SCOPE_GUARD({
|
||||
session->GetClientSession().Close();
|
||||
session->GetServerSession().Close();
|
||||
});
|
||||
|
||||
// Enqueue the session with our parent.
|
||||
R_TRY(parent->EnqueueSession(std::addressof(session->GetServerSession())));
|
||||
|
||||
// We succeeded, so set the output.
|
||||
session_guard.Cancel();
|
||||
*out = std::addressof(session->GetClientSession());
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
61
src/core/hle/kernel/k_client_port.h
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2016 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KClientSession;
|
||||
class KernelCore;
|
||||
class KPort;
|
||||
|
||||
class KClientPort final : public KSynchronizationObject {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
|
||||
|
||||
public:
|
||||
explicit KClientPort(KernelCore& kernel_);
|
||||
virtual ~KClientPort() override;
|
||||
|
||||
void Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_);
|
||||
void OnSessionFinalized();
|
||||
void OnServerClosed();
|
||||
|
||||
const KPort* GetParent() const {
|
||||
return parent;
|
||||
}
|
||||
|
||||
s32 GetNumSessions() const {
|
||||
return num_sessions;
|
||||
}
|
||||
s32 GetPeakSessions() const {
|
||||
return peak_sessions;
|
||||
}
|
||||
s32 GetMaxSessions() const {
|
||||
return max_sessions;
|
||||
}
|
||||
|
||||
bool IsLight() const;
|
||||
bool IsServerClosed() const;
|
||||
|
||||
// Overridden virtual functions.
|
||||
virtual void Destroy() override;
|
||||
virtual bool IsSignaled() const override;
|
||||
|
||||
ResultCode CreateSession(KClientSession** out);
|
||||
|
||||
private:
|
||||
std::atomic<s32> num_sessions{};
|
||||
std::atomic<s32> peak_sessions{};
|
||||
s32 max_sessions{};
|
||||
KPort* parent{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
32
src/core/hle/kernel/k_client_session.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/k_client_session.h"
|
||||
#include "core/hle/kernel/k_server_session.h"
|
||||
#include "core/hle/kernel/k_session.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
KClientSession::KClientSession(KernelCore& kernel_)
|
||||
: KAutoObjectWithSlabHeapAndContainer{kernel_} {}
|
||||
KClientSession::~KClientSession() = default;
|
||||
|
||||
void KClientSession::Destroy() {
|
||||
parent->OnClientClosed();
|
||||
parent->Close();
|
||||
}
|
||||
|
||||
void KClientSession::OnServerClosed() {}
|
||||
|
||||
ResultCode KClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
|
||||
Core::Timing::CoreTiming& core_timing) {
|
||||
// Signal the server session that new data is available
|
||||
return parent->GetServerSession().HandleSyncRequest(thread, memory, core_timing);
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
61
src/core/hle/kernel/k_client_session.h
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
union ResultCode;
|
||||
|
||||
namespace Core::Memory {
|
||||
class Memory;
|
||||
}
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class KSession;
|
||||
class KThread;
|
||||
|
||||
class KClientSession final
|
||||
: public KAutoObjectWithSlabHeapAndContainer<KClientSession, KAutoObjectWithList> {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject);
|
||||
|
||||
public:
|
||||
explicit KClientSession(KernelCore& kernel_);
|
||||
virtual ~KClientSession();
|
||||
|
||||
void Initialize(KSession* parent_, std::string&& name_) {
|
||||
// Set member variables.
|
||||
parent = parent_;
|
||||
name = std::move(name_);
|
||||
}
|
||||
|
||||
virtual void Destroy() override;
|
||||
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
|
||||
|
||||
KSession* GetParent() const {
|
||||
return parent;
|
||||
}
|
||||
|
||||
ResultCode SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
|
||||
Core::Timing::CoreTiming& core_timing);
|
||||
|
||||
void OnServerClosed();
|
||||
|
||||
private:
|
||||
KSession* parent{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -7,12 +7,13 @@
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_condition_variable.h"
|
||||
#include "core/hle/kernel/k_linked_list.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/svc_common.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
#include "core/memory.h"
|
||||
@@ -107,8 +108,8 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
|
||||
|
||||
// Wait for the address.
|
||||
{
|
||||
std::shared_ptr<KThread> owner_thread;
|
||||
ASSERT(!owner_thread);
|
||||
KScopedAutoObject<KThread> owner_thread;
|
||||
ASSERT(owner_thread.IsNull());
|
||||
{
|
||||
KScopedSchedulerLock sl(kernel);
|
||||
cur_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
|
||||
@@ -126,8 +127,10 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
|
||||
R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), RESULT_SUCCESS);
|
||||
|
||||
// Get the lock owner thread.
|
||||
owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>(handle);
|
||||
R_UNLESS(owner_thread, ResultInvalidHandle);
|
||||
owner_thread =
|
||||
kernel.CurrentProcess()->GetHandleTable().GetObjectWithoutPseudoHandle<KThread>(
|
||||
handle);
|
||||
R_UNLESS(owner_thread.IsNotNull(), ResultInvalidHandle);
|
||||
|
||||
// Update the lock.
|
||||
cur_thread->SetAddressKey(addr, value);
|
||||
@@ -137,7 +140,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
|
||||
cur_thread->SetMutexWaitAddressForDebugging(addr);
|
||||
}
|
||||
}
|
||||
ASSERT(owner_thread);
|
||||
ASSERT(owner_thread.IsNotNull());
|
||||
}
|
||||
|
||||
// Remove the thread as a waiter from the lock owner.
|
||||
@@ -176,19 +179,22 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) {
|
||||
|
||||
KThread* thread_to_close = nullptr;
|
||||
if (can_access) {
|
||||
if (prev_tag == InvalidHandle) {
|
||||
if (prev_tag == Svc::InvalidHandle) {
|
||||
// If nobody held the lock previously, we're all good.
|
||||
thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
|
||||
thread->Wakeup();
|
||||
} else {
|
||||
// Get the previous owner.
|
||||
auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>(
|
||||
prev_tag & ~Svc::HandleWaitMask);
|
||||
KThread* owner_thread = kernel.CurrentProcess()
|
||||
->GetHandleTable()
|
||||
.GetObjectWithoutPseudoHandle<KThread>(
|
||||
static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))
|
||||
.ReleasePointerUnsafe();
|
||||
|
||||
if (owner_thread) {
|
||||
// Add the thread as a waiter on the owner.
|
||||
owner_thread->AddWaiter(thread);
|
||||
thread_to_close = owner_thread.get();
|
||||
thread_to_close = owner_thread;
|
||||
} else {
|
||||
// The lock was tagged with a thread that doesn't exist.
|
||||
thread->SetSyncedObject(nullptr, ResultInvalidState);
|
||||
@@ -208,9 +214,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
|
||||
// Prepare for signaling.
|
||||
constexpr int MaxThreads = 16;
|
||||
|
||||
// TODO(bunnei): This should just be Thread once we implement KAutoObject instead of using
|
||||
// std::shared_ptr.
|
||||
std::vector<std::shared_ptr<KThread>> thread_list;
|
||||
KLinkedList<KThread> thread_list{kernel};
|
||||
std::array<KThread*, MaxThreads> thread_array;
|
||||
s32 num_to_close{};
|
||||
|
||||
@@ -228,7 +232,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
|
||||
if (num_to_close < MaxThreads) {
|
||||
thread_array[num_to_close++] = thread;
|
||||
} else {
|
||||
thread_list.push_back(SharedFrom(thread));
|
||||
thread_list.push_back(*thread);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +255,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
|
||||
|
||||
// Close threads in the list.
|
||||
for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) {
|
||||
(*it)->Close();
|
||||
(*it).Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,30 +3,54 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
KEvent::KEvent(KernelCore& kernel, std::string&& name) : Object{kernel, std::move(name)} {}
|
||||
KEvent::KEvent(KernelCore& kernel_)
|
||||
: KAutoObjectWithSlabHeapAndContainer{kernel_}, readable_event{kernel_}, writable_event{
|
||||
kernel_} {}
|
||||
|
||||
KEvent::~KEvent() = default;
|
||||
|
||||
std::shared_ptr<KEvent> KEvent::Create(KernelCore& kernel, std::string&& name) {
|
||||
return std::make_shared<KEvent>(kernel, std::move(name));
|
||||
}
|
||||
void KEvent::Initialize(std::string&& name_) {
|
||||
// Increment reference count.
|
||||
// Because reference count is one on creation, this will result
|
||||
// in a reference count of two. Thus, when both readable and
|
||||
// writable events are closed this object will be destroyed.
|
||||
Open();
|
||||
|
||||
void KEvent::Initialize() {
|
||||
// Create our sub events.
|
||||
readable_event = std::make_shared<KReadableEvent>(kernel, GetName() + ":Readable");
|
||||
writable_event = std::make_shared<KWritableEvent>(kernel, GetName() + ":Writable");
|
||||
KAutoObject::Create(std::addressof(readable_event));
|
||||
KAutoObject::Create(std::addressof(writable_event));
|
||||
|
||||
// Initialize our sub sessions.
|
||||
readable_event->Initialize(this);
|
||||
writable_event->Initialize(this);
|
||||
readable_event.Initialize(this, name_ + ":Readable");
|
||||
writable_event.Initialize(this, name_ + ":Writable");
|
||||
|
||||
// Set our owner process.
|
||||
owner = kernel.CurrentProcess();
|
||||
if (owner) {
|
||||
owner->Open();
|
||||
}
|
||||
|
||||
// Mark initialized.
|
||||
name = std::move(name_);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void KEvent::Finalize() {
|
||||
KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList>::Finalize();
|
||||
}
|
||||
|
||||
void KEvent::PostDestroy(uintptr_t arg) {
|
||||
// Release the event count resource the owner process holds.
|
||||
KProcess* owner = reinterpret_cast<KProcess*>(arg);
|
||||
if (owner) {
|
||||
owner->GetResourceLimit()->Release(LimitableResource::Events, 1);
|
||||
owner->Close();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -4,53 +4,54 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class KReadableEvent;
|
||||
class KWritableEvent;
|
||||
class KProcess;
|
||||
|
||||
class KEvent final : public KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList> {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KEvent, KAutoObject);
|
||||
|
||||
class KEvent final : public Object {
|
||||
public:
|
||||
explicit KEvent(KernelCore& kernel, std::string&& name);
|
||||
~KEvent() override;
|
||||
explicit KEvent(KernelCore& kernel_);
|
||||
virtual ~KEvent();
|
||||
|
||||
static std::shared_ptr<KEvent> Create(KernelCore& kernel, std::string&& name);
|
||||
void Initialize(std::string&& name);
|
||||
|
||||
void Initialize();
|
||||
virtual void Finalize() override;
|
||||
|
||||
void Finalize() override {}
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "KEvent";
|
||||
virtual bool IsInitialized() const override {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::Event;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
virtual uintptr_t GetPostDestroyArgument() const override {
|
||||
return reinterpret_cast<uintptr_t>(owner);
|
||||
}
|
||||
|
||||
std::shared_ptr<KReadableEvent>& GetReadableEvent() {
|
||||
static void PostDestroy(uintptr_t arg);
|
||||
|
||||
virtual KProcess* GetOwner() const override {
|
||||
return owner;
|
||||
}
|
||||
|
||||
KReadableEvent& GetReadableEvent() {
|
||||
return readable_event;
|
||||
}
|
||||
|
||||
std::shared_ptr<KWritableEvent>& GetWritableEvent() {
|
||||
return writable_event;
|
||||
}
|
||||
|
||||
const std::shared_ptr<KReadableEvent>& GetReadableEvent() const {
|
||||
return readable_event;
|
||||
}
|
||||
|
||||
const std::shared_ptr<KWritableEvent>& GetWritableEvent() const {
|
||||
KWritableEvent& GetWritableEvent() {
|
||||
return writable_event;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<KReadableEvent> readable_event;
|
||||
std::shared_ptr<KWritableEvent> writable_event;
|
||||
KReadableEvent readable_event;
|
||||
KWritableEvent writable_event;
|
||||
KProcess* owner{};
|
||||
bool initialized{};
|
||||
};
|
||||
|
||||
|
||||
135
src/core/hle/kernel/k_handle_table.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/kernel/k_handle_table.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
KHandleTable::KHandleTable(KernelCore& kernel_) : kernel{kernel_} {}
|
||||
KHandleTable ::~KHandleTable() = default;
|
||||
|
||||
ResultCode KHandleTable::Finalize() {
|
||||
// Get the table and clear our record of it.
|
||||
u16 saved_table_size = 0;
|
||||
{
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
std::swap(m_table_size, saved_table_size);
|
||||
}
|
||||
|
||||
// Close and free all entries.
|
||||
for (size_t i = 0; i < saved_table_size; i++) {
|
||||
if (KAutoObject* obj = m_objects[i]; obj != nullptr) {
|
||||
obj->Close();
|
||||
}
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
bool KHandleTable::Remove(Handle handle) {
|
||||
// Don't allow removal of a pseudo-handle.
|
||||
if (Svc::IsPseudoHandle(handle)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handles must not have reserved bits set.
|
||||
const auto handle_pack = HandlePack(handle);
|
||||
if (handle_pack.reserved != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the object and free the entry.
|
||||
KAutoObject* obj = nullptr;
|
||||
{
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
if (this->IsValidHandle(handle)) {
|
||||
const auto index = handle_pack.index;
|
||||
|
||||
obj = m_objects[index];
|
||||
this->FreeEntry(index);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Close the object.
|
||||
obj->Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) {
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
// Never exceed our capacity.
|
||||
R_UNLESS(m_count < m_table_size, ResultOutOfHandles);
|
||||
|
||||
// Allocate entry, set output handle.
|
||||
{
|
||||
const auto linear_id = this->AllocateLinearId();
|
||||
const auto index = this->AllocateEntry();
|
||||
|
||||
m_entry_infos[index].info = {.linear_id = linear_id, .type = type};
|
||||
m_objects[index] = obj;
|
||||
|
||||
obj->Open();
|
||||
|
||||
*out_handle = EncodeHandle(static_cast<u16>(index), linear_id);
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode KHandleTable::Reserve(Handle* out_handle) {
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
// Never exceed our capacity.
|
||||
R_UNLESS(m_count < m_table_size, ResultOutOfHandles);
|
||||
|
||||
*out_handle = EncodeHandle(static_cast<u16>(this->AllocateEntry()), this->AllocateLinearId());
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void KHandleTable::Unreserve(Handle handle) {
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
// Unpack the handle.
|
||||
const auto handle_pack = HandlePack(handle);
|
||||
const auto index = handle_pack.index;
|
||||
const auto linear_id = handle_pack.linear_id;
|
||||
const auto reserved = handle_pack.reserved;
|
||||
ASSERT(reserved == 0);
|
||||
ASSERT(linear_id != 0);
|
||||
|
||||
if (index < m_table_size) {
|
||||
// NOTE: This code does not check the linear id.
|
||||
ASSERT(m_objects[index] == nullptr);
|
||||
this->FreeEntry(index);
|
||||
}
|
||||
}
|
||||
|
||||
void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) {
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
// Unpack the handle.
|
||||
const auto handle_pack = HandlePack(handle);
|
||||
const auto index = handle_pack.index;
|
||||
const auto linear_id = handle_pack.linear_id;
|
||||
const auto reserved = handle_pack.reserved;
|
||||
ASSERT(reserved == 0);
|
||||
ASSERT(linear_id != 0);
|
||||
|
||||
if (index < m_table_size) {
|
||||
// Set the entry.
|
||||
ASSERT(m_objects[index] == nullptr);
|
||||
|
||||
m_entry_infos[index].info = {.linear_id = static_cast<u16>(linear_id), .type = type};
|
||||
m_objects[index] = obj;
|
||||
|
||||
obj->Open();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||