Compare commits
282 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8ba632606 | ||
|
|
dbcb1e1564 | ||
|
|
15381409dc | ||
|
|
10ad6934ac | ||
|
|
03e66efd85 | ||
|
|
7040e8976d | ||
|
|
296a6af058 | ||
|
|
2c332d1cf8 | ||
|
|
243d7dc777 | ||
|
|
355010ad84 | ||
|
|
ef0c15b764 | ||
|
|
0dc308d92a | ||
|
|
eb5542963f | ||
|
|
18673d96cb | ||
|
|
36f6bdc3a0 | ||
|
|
d6fff49845 | ||
|
|
d05e8fb23a | ||
|
|
0767d9f8da | ||
|
|
21f3d29df7 | ||
|
|
4f16106702 | ||
|
|
19be54ff95 | ||
|
|
ed80d6ec8c | ||
|
|
57b6c71c1c | ||
|
|
0a11d341b7 | ||
|
|
8010290472 | ||
|
|
fbc526d163 | ||
|
|
5bb790e4a7 | ||
|
|
0a6219e6e0 | ||
|
|
037b04ac60 | ||
|
|
9e563d590b | ||
|
|
bdcf02a3ef | ||
|
|
88ac85c423 | ||
|
|
2e1a93f1d1 | ||
|
|
997e4dd665 | ||
|
|
aa2d03d8e1 | ||
|
|
274c1deae4 | ||
|
|
d5bbf32a26 | ||
|
|
97a251b4b2 | ||
|
|
9d30917f4e | ||
|
|
c67c29ebd5 | ||
|
|
88dd414721 | ||
|
|
0f6f13a1ac | ||
|
|
b24784f5c1 | ||
|
|
3b3082cf58 | ||
|
|
38a2fdcd76 | ||
|
|
0ca2f962de | ||
|
|
03a98635d8 | ||
|
|
461e2ced6f | ||
|
|
b2d2f65b87 | ||
|
|
b2b0c50802 | ||
|
|
1118421fa6 | ||
|
|
b1b3914ccf | ||
|
|
9be8b32311 | ||
|
|
57c8bc432d | ||
|
|
58776f5ba8 | ||
|
|
affeeb2724 | ||
|
|
822875ecf5 | ||
|
|
e3a65b1405 | ||
|
|
20a7fa1588 | ||
|
|
315b7bdf22 | ||
|
|
ec988c5a99 | ||
|
|
21b883a75c | ||
|
|
e93d71d932 | ||
|
|
dc6a0d7562 | ||
|
|
1d2be0a2eb | ||
|
|
96937a611d | ||
|
|
dc7862882f | ||
|
|
6faa3534bf | ||
|
|
afb1d68d06 | ||
|
|
911e431d65 | ||
|
|
ee91063bbb | ||
|
|
cbdf33260e | ||
|
|
c62a7381f8 | ||
|
|
b4498734e4 | ||
|
|
4407237f5b | ||
|
|
15956fcf9a | ||
|
|
6a368d3d1a | ||
|
|
8e4be9aef9 | ||
|
|
0f8b7be2d2 | ||
|
|
a1e137cc1c | ||
|
|
504472af4e | ||
|
|
19b253fd17 | ||
|
|
01f5c89902 | ||
|
|
44ccbc2a7b | ||
|
|
6e4664ee05 | ||
|
|
85f9355184 | ||
|
|
60b5bd73b7 | ||
|
|
53e7aa0a20 | ||
|
|
561a16a348 | ||
|
|
1fce7b08b1 | ||
|
|
c216f92a91 | ||
|
|
2f930c2d5f | ||
|
|
256eb92f4c | ||
|
|
ec1d9c4c49 | ||
|
|
3356eddcba | ||
|
|
f67d1b7026 | ||
|
|
e64fef109c | ||
|
|
1b2cf173b3 | ||
|
|
2fb258ca7e | ||
|
|
962cf97150 | ||
|
|
b3bd443636 | ||
|
|
4b9e7c7d27 | ||
|
|
46612156f4 | ||
|
|
279bb863df | ||
|
|
252ea97ca5 | ||
|
|
f89cfe41da | ||
|
|
e3e3679cfe | ||
|
|
75a2052144 | ||
|
|
5666c59657 | ||
|
|
c99ce36d7d | ||
|
|
d84dcb653d | ||
|
|
aff0da9427 | ||
|
|
8d9174b227 | ||
|
|
c8404e8452 | ||
|
|
79e4c82d7e | ||
|
|
3afd9a737c | ||
|
|
a7564cf303 | ||
|
|
5362ee9450 | ||
|
|
021d4c88fa | ||
|
|
deb4aece9a | ||
|
|
a6729171d3 | ||
|
|
c9015581ca | ||
|
|
35c816d62f | ||
|
|
18031ae107 | ||
|
|
c7e4f963e8 | ||
|
|
97875c7d2f | ||
|
|
0da3b2b273 | ||
|
|
3cbd99a709 | ||
|
|
6ce2076d92 | ||
|
|
cee1ecd06f | ||
|
|
a739e3fb20 | ||
|
|
953246a175 | ||
|
|
d8faa37de0 | ||
|
|
64c7c6b2a5 | ||
|
|
1c974a387c | ||
|
|
b5ab491603 | ||
|
|
8b32b9eadf | ||
|
|
ce149f996c | ||
|
|
0ec54ed492 | ||
|
|
72de4d85f3 | ||
|
|
d0673aa2fb | ||
|
|
f7fcb54622 | ||
|
|
ec643789ab | ||
|
|
70caadafd5 | ||
|
|
7667104961 | ||
|
|
0c791f2279 | ||
|
|
f71943c03a | ||
|
|
536e3e99a8 | ||
|
|
abff428212 | ||
|
|
1541985222 | ||
|
|
61929d6e21 | ||
|
|
f0ef9fb918 | ||
|
|
7621bd4e13 | ||
|
|
d20bceff75 | ||
|
|
1961cb1034 | ||
|
|
9daec3a66a | ||
|
|
e79417c37c | ||
|
|
b371487525 | ||
|
|
5c97469348 | ||
|
|
99a38dce32 | ||
|
|
f28a410ba0 | ||
|
|
5fc1981061 | ||
|
|
1bd0094bee | ||
|
|
870b45f208 | ||
|
|
9fbbb9fadb | ||
|
|
dec06ff649 | ||
|
|
b898241112 | ||
|
|
10255f7f51 | ||
|
|
cb5a706659 | ||
|
|
4d86863f2c | ||
|
|
79a3f442d6 | ||
|
|
7485a1968a | ||
|
|
3be005b638 | ||
|
|
d60b1abed0 | ||
|
|
1867c31f63 | ||
|
|
82757cd1b4 | ||
|
|
f5e98de1a3 | ||
|
|
0880cebc4d | ||
|
|
1f03b11dbc | ||
|
|
b925344c3b | ||
|
|
42cf3f50d7 | ||
|
|
70aae4e27a | ||
|
|
87165e0f08 | ||
|
|
e20c2450ce | ||
|
|
968ce12492 | ||
|
|
00ab210e66 | ||
|
|
4cb6c63516 | ||
|
|
1963ae7ec0 | ||
|
|
889f144b27 | ||
|
|
4408ad6a47 | ||
|
|
4ed665bcd3 | ||
|
|
df3d62df84 | ||
|
|
0977ee72ca | ||
|
|
2cdfde6637 | ||
|
|
6fc24d8883 | ||
|
|
4e9bc617bb | ||
|
|
679fec2ddc | ||
|
|
8f85cc17dc | ||
|
|
e40eece74e | ||
|
|
2341f18edd | ||
|
|
c9c41e0e8d | ||
|
|
c59388caf1 | ||
|
|
c878123274 | ||
|
|
1687bf2e07 | ||
|
|
cf99f54a34 | ||
|
|
83c1c175ba | ||
|
|
fc060d3777 | ||
|
|
eb50e99748 | ||
|
|
287f4e6fa1 | ||
|
|
cbf3ba9b75 | ||
|
|
95a6b0828f | ||
|
|
1545fa9d44 | ||
|
|
71add1add8 | ||
|
|
a96786fd2c | ||
|
|
74e4e70053 | ||
|
|
26b6216fa0 | ||
|
|
fe5c850e69 | ||
|
|
2b825d56dc | ||
|
|
13b17a5848 | ||
|
|
621520c30b | ||
|
|
846cc0b47a | ||
|
|
e82ad1cdc5 | ||
|
|
b40da8f445 | ||
|
|
a9c6476416 | ||
|
|
c1d93a9495 | ||
|
|
201b17f100 | ||
|
|
c0e3cee657 | ||
|
|
26d8db74f8 | ||
|
|
ee2e9d50fd | ||
|
|
fd1a39996e | ||
|
|
8eb65ab401 | ||
|
|
bcda834980 | ||
|
|
408b81b881 | ||
|
|
d854b94382 | ||
|
|
63440cab18 | ||
|
|
4fa585a23f | ||
|
|
e521ae805d | ||
|
|
6950989552 | ||
|
|
ffbdf29c10 | ||
|
|
135d42ffee | ||
|
|
1306d03136 | ||
|
|
97aa209c43 | ||
|
|
4ce2a6deb3 | ||
|
|
e45d8cd7d8 | ||
|
|
79211e1159 | ||
|
|
ca8e8ce487 | ||
|
|
b30311be65 | ||
|
|
6694d8c2d9 | ||
|
|
658389fc60 | ||
|
|
d6477cf024 | ||
|
|
400f5142ee | ||
|
|
8bf8df43e2 | ||
|
|
a28c60970f | ||
|
|
b5f72b9f20 | ||
|
|
8d10584a51 | ||
|
|
366c265ab2 | ||
|
|
42964992d1 | ||
|
|
4a82d9bf28 | ||
|
|
4190281b2f | ||
|
|
48830d190f | ||
|
|
3389aaefc3 | ||
|
|
f8f987aa8d | ||
|
|
e87e146112 | ||
|
|
5751bcc117 | ||
|
|
eb1e979257 | ||
|
|
204539664b | ||
|
|
f5c6736431 | ||
|
|
d00ebaa28a | ||
|
|
402e4d1adb | ||
|
|
ed7c0605f9 | ||
|
|
c848a830ee | ||
|
|
dbe8add4f4 | ||
|
|
e4e278bb3d | ||
|
|
3761f80592 | ||
|
|
9878c18e47 | ||
|
|
3bb94aa146 | ||
|
|
83c04fa5d7 | ||
|
|
dc4ee1a5bc | ||
|
|
5191f0e305 | ||
|
|
170034aed3 | ||
|
|
21236020cb | ||
|
|
f06de12bea |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -95,3 +95,5 @@ sept/sept-secondary/KEYS.py
|
|||||||
**/build_nintendo_nx_arm
|
**/build_nintendo_nx_arm
|
||||||
**/build_nintendo_nx_x64
|
**/build_nintendo_nx_x64
|
||||||
**/build_nintendo_nx_x86
|
**/build_nintendo_nx_x86
|
||||||
|
|
||||||
|
stratosphere/test/
|
||||||
|
|||||||
52
Makefile
52
Makefile
@@ -1,3 +1,9 @@
|
|||||||
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPro)
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITPRO)/devkitA64/base_tools
|
||||||
|
|
||||||
TOPTARGETS := all clean dist-no-debug dist
|
TOPTARGETS := all clean dist-no-debug dist
|
||||||
AMSBRANCH := $(shell git symbolic-ref --short HEAD)
|
AMSBRANCH := $(shell git symbolic-ref --short HEAD)
|
||||||
AMSHASH := $(shell git rev-parse --short HEAD)
|
AMSHASH := $(shell git rev-parse --short HEAD)
|
||||||
@@ -56,18 +62,11 @@ dist-no-debug: all
|
|||||||
mkdir atmosphere-$(AMSVER)/atmosphere
|
mkdir atmosphere-$(AMSVER)/atmosphere
|
||||||
mkdir atmosphere-$(AMSVER)/sept
|
mkdir atmosphere-$(AMSVER)/sept
|
||||||
mkdir atmosphere-$(AMSVER)/switch
|
mkdir atmosphere-$(AMSVER)/switch
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000008
|
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000000D
|
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000002B
|
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032
|
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034
|
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036
|
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037
|
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000003C
|
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000042
|
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors
|
mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/config_templates
|
mkdir -p atmosphere-$(AMSVER)/atmosphere/config_templates
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/config
|
mkdir -p atmosphere-$(AMSVER)/atmosphere/config
|
||||||
|
mkdir -p atmosphere-$(AMSVER)/atmosphere/flags
|
||||||
|
touch atmosphere-$(AMSVER)/atmosphere/flags/clean_stratosphere_for_0.19.0.flag
|
||||||
cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin
|
cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin
|
||||||
cp fusee/fusee-mtc/fusee-mtc.bin atmosphere-$(AMSVER)/atmosphere/fusee-mtc.bin
|
cp fusee/fusee-mtc/fusee-mtc.bin atmosphere-$(AMSVER)/atmosphere/fusee-mtc.bin
|
||||||
cp fusee/fusee-secondary/fusee-secondary-experimental.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin
|
cp fusee/fusee-secondary/fusee-secondary-experimental.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin
|
||||||
@@ -84,19 +83,27 @@ dist-no-debug: all
|
|||||||
cp config_templates/exosphere.ini atmosphere-$(AMSVER)/atmosphere/config_templates/exosphere.ini
|
cp config_templates/exosphere.ini atmosphere-$(AMSVER)/atmosphere/config_templates/exosphere.ini
|
||||||
cp -r config_templates/kip_patches atmosphere-$(AMSVER)/atmosphere/kip_patches
|
cp -r config_templates/kip_patches atmosphere-$(AMSVER)/atmosphere/kip_patches
|
||||||
cp -r config_templates/hbl_html atmosphere-$(AMSVER)/atmosphere/hbl_html
|
cp -r config_templates/hbl_html atmosphere-$(AMSVER)/atmosphere/hbl_html
|
||||||
cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000008/exefs.nsp
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008
|
||||||
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/atmosphere/contents/010000000000000D/exefs.nsp
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008
|
||||||
cp stratosphere/erpt/erpt.nsp atmosphere-$(AMSVER)/atmosphere/contents/010000000000002B/exefs.nsp
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000000D
|
||||||
cp stratosphere/eclct.stub/eclct.stub.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/exefs.nsp
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000002B
|
||||||
cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034/exefs.nsp
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000032
|
||||||
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036/exefs.nsp
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000034
|
||||||
cp stratosphere/ro/ro.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/exefs.nsp
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000036
|
||||||
cp stratosphere/jpegdec/jpegdec.nsp atmosphere-$(AMSVER)/atmosphere/contents/010000000000003C/exefs.nsp
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000037
|
||||||
cp stratosphere/pgl/pgl.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000042/exefs.nsp
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000003C
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/flags
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042
|
||||||
touch atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/flags/boot2.flag
|
cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008/exefs.nsp
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/flags
|
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000000D/exefs.nsp
|
||||||
touch atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/flags/boot2.flag
|
cp stratosphere/erpt/erpt.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000002B/exefs.nsp
|
||||||
|
cp stratosphere/eclct.stub/eclct.stub.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000032/exefs.nsp
|
||||||
|
cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000034/exefs.nsp
|
||||||
|
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000036/exefs.nsp
|
||||||
|
cp stratosphere/ro/ro.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000037/exefs.nsp
|
||||||
|
cp stratosphere/jpegdec/jpegdec.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000003C/exefs.nsp
|
||||||
|
cp stratosphere/pgl/pgl.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp
|
||||||
|
@build_romfs atmosphere-$(AMSVER)/stratosphere_romfs atmosphere-$(AMSVER)/atmosphere/stratosphere.romfs
|
||||||
|
rm -r atmosphere-$(AMSVER)/stratosphere_romfs
|
||||||
cp troposphere/reboot_to_payload/reboot_to_payload.nro atmosphere-$(AMSVER)/switch/reboot_to_payload.nro
|
cp troposphere/reboot_to_payload/reboot_to_payload.nro atmosphere-$(AMSVER)/switch/reboot_to_payload.nro
|
||||||
cp troposphere/daybreak/daybreak.nro atmosphere-$(AMSVER)/switch/daybreak.nro
|
cp troposphere/daybreak/daybreak.nro atmosphere-$(AMSVER)/switch/daybreak.nro
|
||||||
cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../;
|
cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../;
|
||||||
@@ -135,6 +142,7 @@ dist: dist-no-debug
|
|||||||
cp exosphere/program/sc7fw/sc7fw.elf atmosphere-$(AMSVER)-debug/exosphere-sc7fw.elf
|
cp exosphere/program/sc7fw/sc7fw.elf atmosphere-$(AMSVER)-debug/exosphere-sc7fw.elf
|
||||||
cp exosphere/program/rebootstub/rebootstub.elf atmosphere-$(AMSVER)-debug/exosphere-rebootstub.elf
|
cp exosphere/program/rebootstub/rebootstub.elf atmosphere-$(AMSVER)-debug/exosphere-rebootstub.elf
|
||||||
cp mesosphere/kernel_ldr/kernel_ldr.elf atmosphere-$(AMSVER)-debug/kernel_ldr.elf
|
cp mesosphere/kernel_ldr/kernel_ldr.elf atmosphere-$(AMSVER)-debug/kernel_ldr.elf
|
||||||
|
cp mesosphere/kernel/kernel.elf atmosphere-$(AMSVER)-debug/kernel.elf
|
||||||
cp stratosphere/ams_mitm/ams_mitm.elf atmosphere-$(AMSVER)-debug/ams_mitm.elf
|
cp stratosphere/ams_mitm/ams_mitm.elf atmosphere-$(AMSVER)-debug/ams_mitm.elf
|
||||||
cp stratosphere/boot/boot.elf atmosphere-$(AMSVER)-debug/boot.elf
|
cp stratosphere/boot/boot.elf atmosphere-$(AMSVER)-debug/boot.elf
|
||||||
cp stratosphere/boot2/boot2.elf atmosphere-$(AMSVER)-debug/boot2.elf
|
cp stratosphere/boot2/boot2.elf atmosphere-$(AMSVER)-debug/boot2.elf
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,9 +1,13 @@
|
|||||||
; Disable uploading error reports to Nintendo
|
|
||||||
[eupld]
|
[eupld]
|
||||||
|
; Disable uploading error reports to Nintendo
|
||||||
; upload_enabled = u8!0x0
|
; upload_enabled = u8!0x0
|
||||||
|
[usb]
|
||||||
|
; Enable USB 3.0 superspeed for homebrew
|
||||||
|
; 0 = USB 3.0 support is system default (usually disabled), 1 = USB 3.0 support is enabled.
|
||||||
|
; usb30_force_enabled = u8!0x0
|
||||||
|
[ro]
|
||||||
; Control whether RO should ease its validation of NROs.
|
; Control whether RO should ease its validation of NROs.
|
||||||
; (note: this is normally not necessary, and ips patches can be used.)
|
; (note: this is normally not necessary, and ips patches can be used.)
|
||||||
[ro]
|
|
||||||
; ease_nro_restriction = u8!0x1
|
; ease_nro_restriction = u8!0x1
|
||||||
; Atmosphere custom settings
|
; Atmosphere custom settings
|
||||||
[atmosphere]
|
[atmosphere]
|
||||||
@@ -32,16 +36,23 @@
|
|||||||
; NOTE: EXPERIMENTAL
|
; NOTE: EXPERIMENTAL
|
||||||
; If you do not know what you are doing, do not touch this yet.
|
; If you do not know what you are doing, do not touch this yet.
|
||||||
; fsmitm_redirect_saves_to_sd = u8!0x0
|
; fsmitm_redirect_saves_to_sd = u8!0x0
|
||||||
; Controls whether to enable the deprecated hid mitm
|
|
||||||
; to fix compatibility with old homebrew.
|
|
||||||
; 0 = Do not enable, 1 = Enable.
|
|
||||||
; Please note this setting may be removed in a
|
|
||||||
; future release of Atmosphere.
|
|
||||||
; enable_deprecated_hid_mitm = u8!0x0
|
|
||||||
; Controls whether am sees system settings "DebugModeFlag" as
|
; Controls whether am sees system settings "DebugModeFlag" as
|
||||||
; enabled or disabled.
|
; enabled or disabled.
|
||||||
; 0 = Disabled (not debug mode), 1 = Enabled (debug mode)
|
; 0 = Disabled (not debug mode), 1 = Enabled (debug mode)
|
||||||
; enable_am_debug_mode = u8!0x0
|
; enable_am_debug_mode = u8!0x0
|
||||||
|
; Controls whether dns.mitm is enabled
|
||||||
|
; 0 = Disabled, 1 = Enabled
|
||||||
|
; enable_dns_mitm = u8!0x1
|
||||||
|
; Controls whether dns.mitm uses the default redirections in addition to
|
||||||
|
; whatever is specified in the user's hosts file.
|
||||||
|
; 0 = Disabled (use hosts file contents), 1 = Enabled (use defaults and hosts file contents)
|
||||||
|
; add_defaults_to_dns_hosts = u8!0x1
|
||||||
|
; Controls whether dns.mitm logs to the sd card for debugging
|
||||||
|
; 0 = Disabled, 1 = Enabled
|
||||||
|
; enable_dns_mitm_debug_log = u8!0x0
|
||||||
|
; Controls whether htc is enabled
|
||||||
|
; 0 = Disabled, 1 = Enabled
|
||||||
|
; enable_htc = u8!0x0
|
||||||
[hbloader]
|
[hbloader]
|
||||||
; Controls the size of the homebrew heap when running as applet.
|
; Controls the size of the homebrew heap when running as applet.
|
||||||
; If set to zero, all available applet memory is used as heap.
|
; If set to zero, all available applet memory is used as heap.
|
||||||
|
|||||||
@@ -1,4 +1,88 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
## 0.19.2
|
||||||
|
+ Atmosphère's components were further updated to reflect latest official behaviors as of 12.0.0.
|
||||||
|
+ Notably, `erpt` was updated to implement the new forced shutdown detection feature.
|
||||||
|
+ When a forced-shutdown occurs, an erpt_report will be generated and saved to the SD card on the next boot.
|
||||||
|
+ Atmosphere-libs was updated to use GCC 11 (latest devkitA64/devkitARM releases).
|
||||||
|
+ Initial inspections show mild-to-moderate optimizer improvements in several important places (kernel is 0x3000 smaller).
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
+ A number of minor issues were fixed, including:
|
||||||
|
+ A bug was fixed that caused a black screen when attempting to boot firmware versions 2.0.0-4.1.0.
|
||||||
|
+ A bug was fixed that caused sm to abort when at the session limit, rather than returning error codes.
|
||||||
|
+ A bug was fixed that allowed for resource exhaustion on 12.0.0, under certain circumstances.
|
||||||
|
+ Several issues were fixed, and usability and stability were improved.
|
||||||
|
## 0.19.1
|
||||||
|
+ An issue was fixed that caused a fatal error when using official `migration` services to transfer data between consoles.
|
||||||
|
+ An issue was fixed in `ncm` that caused an error when the OS tried to enumerate installed SD card content.
|
||||||
|
+ Several issues were fixed, and usability and stability were improved.
|
||||||
|
## 0.19.0
|
||||||
|
+ Support was added for 12.0.0.
|
||||||
|
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
||||||
|
+ `sm`, `boot2`, `pgl` were updated to reflect the latest official behaviors.
|
||||||
|
+ **Please Note**: 12.0.0 added a new protocol for IPC ("tipc"), which has been freshly reimplemented in its entirety.
|
||||||
|
+ It is possible there may be as of yet unfound issues; if there are, please send the appropriate crash reports to SciresM (SciresM#0524 on discord).
|
||||||
|
+ Homebrew which uses atmosphere extensions (including the mitm API) will need to be re-compiled in order to function on 0.19.0.
|
||||||
|
+ I apologize for this, but it's unavoidable for technical reasons. If you're affected by this and mad about it, please contact SciresM to complain.
|
||||||
|
+ `erpt` was partially updated to reflect the latest official behaviors.
|
||||||
|
+ New features were added to erpt to track the activity of running applets, and to detect when a forced shutdown occurs.
|
||||||
|
+ These behaviors have been temporarily stubbed, as they are not necessary for 12.0.0 to run (and their outputs won't be saved anywhere).
|
||||||
|
+ A future atmosphère update will implement these behaviors, in the interest of reflecting official logic as faithfully as we can.
|
||||||
|
+ Atmosphère no longer uses the /contents/ folder for its own programs.
|
||||||
|
+ Atmosphère's system modules are now bundled together in the single file "stratosphere.romfs".
|
||||||
|
+ For those working on developing for atmosphère, executables inside the /contents/ directory will be preferred to those in "stratosphere.romfs".
|
||||||
|
+ **Please Note**: In order to facilitate this change (and the desired behavior), the first time you boot after extracting a release zip, atmosphère system modules inside /contents/ will be deleted.
|
||||||
|
+ This will have no impact on user programs (it only removes programs with specific program ids).
|
||||||
|
+ Improvements were made to mesosphere, including:
|
||||||
|
+ An extension InfoType was added for getting the current process handle, without having to spawn a thread and do IPC with oneself.
|
||||||
|
+ An issue was fixed in SvcSetDebugThreadContext.
|
||||||
|
+ An issue was fixed when doing IPC with user buffers.
|
||||||
|
+ Support was fixed for toggling the custom setting `usb!usb30_force_enabled` on 9.0.0+.
|
||||||
|
+ This was broken by Nintendo's introducing a dependency that made USB a requirement to launch before custom settings are parsed.
|
||||||
|
+ Since the fix, you can now toggle the setting (as you could prior to atmosphère 0.9.4), and it will work as expected.
|
||||||
|
+ **Please Note**: Enabling USB 3.0 often severely impacts wireless communications.
|
||||||
|
+ Because of this, the setting will default to off. If you experience issues with it enabled, consider disabling it.
|
||||||
|
+ A warning was added to daybreak when resetting the console to factory settings.
|
||||||
|
+ Substantial work was completed towards atmosphere's upcoming implementation of the host target connection protocol.
|
||||||
|
+ Once completed, users will be able to interact with a Switch running atmosphère via a PC application ("Starlink") currently under development.
|
||||||
|
+ Planned eventual features for connected consoles include a gdbstub, interacting with memory (for cheat development), streaming gameplay audio and video, and accessing the Switch's SD card filesystem.
|
||||||
|
+ Switch homebrew will also have access to a (configurable and sandboxed) filesystem on the host PC, while connected.
|
||||||
|
+ Towards this end, the following was accomplished:
|
||||||
|
+ The "htc" system module was reimplemented completely.
|
||||||
|
+ The system module which provides remote access to the SD card was reimplemented completely.
|
||||||
|
+ This is currently the active focus of atmosphère's development.
|
||||||
|
+ **Please Note**: Support is not yet completed, and users are disadvised from interacting with the related settings for the time being, unless they particularly know what they're doing.
|
||||||
|
+ A number of minor issues were fixed, including:
|
||||||
|
+ A bug was fixed in `dmnt` that could cause a fatal when launching certain games with cheats active.
|
||||||
|
+ An issue was fixed that could cause an abort in `sm` when using a large number of custom system modules.
|
||||||
|
+ An issue was fixed that prevented launching gamecards on 1.0.0.
|
||||||
|
+ Minor issues were fixed in the cheat virtual machine's behavior.
|
||||||
|
+ Several issues were fixed, and usability and stability were improved.
|
||||||
|
## 0.18.1
|
||||||
|
+ A number of minor issues were fixed, including:
|
||||||
|
+ The new `dns.mitm` module added in 0.18.0 no longer fatal errors when receiving port=nullptr.
|
||||||
|
+ This fixes youtube ad-blocking, and possibly other usecases.
|
||||||
|
+ A bug was fixed that caused ams.mitm to incorrectly cache data storages.
|
||||||
|
+ This potentially broke DLC when using romfs mods, and could have caused other issues (e.g. with custom themes, and maybe other cases).
|
||||||
|
+ A bug was fixed in power state control module registration.
|
||||||
|
+ This might fix a weird edge case with system module dependencies on sleep/wake, but probably nobody should notice any differences.
|
||||||
|
+ A bug was fixed where mesosphere sometimes treated virtual core IDs as though they were physical core IDs.
|
||||||
|
+ This had zero impact, because for Switch virtual core == physical core, but it could have affected future platforms if it had remained unresolved.
|
||||||
|
+ Several issues were fixed, and usability and stability were improved.
|
||||||
|
## 0.18.0
|
||||||
|
+ A new mitm module was added (`dns.mitm`).
|
||||||
|
+ This provides a highly configurable mechanism for redirecting DNS resolution requests.
|
||||||
|
+ By default atmosphère redirects resolution requests for official telemetry servers to a loopback address.
|
||||||
|
+ Documentation on how to configure `dns.mitm` to meet your more specific needs may be found [here](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/features/dns_mitm.md).
|
||||||
|
+ The service framework API (`sf`) was refactored to be more accurate to official logic and greatly reduce memory requirements.
|
||||||
|
+ The comparison of atmosphère module memory usage versus Nintendo's found [here](https://github.com/Atmosphere-NX/Atmosphere/wiki/Memory-Comparisons) was updated to reflect this.
|
||||||
|
+ **Please Note**: If you are a developer using the libstratosphere service APIs, some updating may be required. Contact SciresM#0524 on discord for assistance if required.
|
||||||
|
+ A number of deprecations were removed, following a general codebase cleanup:
|
||||||
|
+ The `sm` extension to not unregister services on connection close was superseded by official opt-in logic in 11.0.0, and has been removed in favor of official logic.
|
||||||
|
+ This should have zero impact on users.
|
||||||
|
+ The temporary `hid-mitm` added in 0.9.0 has finally been removed, following over a year of deprecation.
|
||||||
|
+ There shouldn't be any homebrew in use still affected by this, but the situation will be monitored.
|
||||||
|
+ If this is somehow still a real issue, an unaffiliated hid mitm sysmodule providing the same functionality can be created and released, separate from atmosphère itself.
|
||||||
|
+ Several issues were fixed, and usability and stability were improved.
|
||||||
## 0.17.1
|
## 0.17.1
|
||||||
+ A number of atmosphère's modules were using more memory than their Nintendo equivalent's in 0.17.0; a number of code generatio tweaks have been applied to fix this across the board.
|
+ A number of atmosphère's modules were using more memory than their Nintendo equivalent's in 0.17.0; a number of code generatio tweaks have been applied to fix this across the board.
|
||||||
+ A detailed comparison of atmosphère module memory usage versus Nintendo's was made and can be found [here](https://github.com/Atmosphere-NX/Atmosphere/wiki/Memory-Comparisons).
|
+ A detailed comparison of atmosphère module memory usage versus Nintendo's was made and can be found [here](https://github.com/Atmosphere-NX/Atmosphere/wiki/Memory-Comparisons).
|
||||||
@@ -15,7 +99,7 @@
|
|||||||
+ This also substantially improves power drain when the system is shut off; consoles powered off from Atmosphere should now drain battery at the same reduced rate as original firmware.
|
+ This also substantially improves power drain when the system is shut off; consoles powered off from Atmosphere should now drain battery at the same reduced rate as original firmware.
|
||||||
+ A number of minor changes were made, including:
|
+ A number of minor changes were made, including:
|
||||||
+ A number of inconsistencies in the build system were fixed.
|
+ A number of inconsistencies in the build system were fixed.
|
||||||
+ Fow those building atmosphère at home, the `boot` sysmodule will no longer rebuild every time make is invoked.
|
+ For those building atmosphère at home, the `boot` sysmodule will no longer rebuild every time make is invoked.
|
||||||
+ This substantially improves build times during development iteration.
|
+ This substantially improves build times during development iteration.
|
||||||
+ `sm` was updated to more accurately reflect how official code manages request deferral.
|
+ `sm` was updated to more accurately reflect how official code manages request deferral.
|
||||||
+ `mesosphère` was updated to more accurately reflect official kernel management of the trace buffer.
|
+ `mesosphère` was updated to more accurately reflect official kernel management of the trace buffer.
|
||||||
|
|||||||
@@ -33,3 +33,8 @@ in settings as `#.#.#|AMS #.#.#|?` with `? = S` when running under system eMMC o
|
|||||||
### System Settings
|
### System Settings
|
||||||
set_mitm intercepts the `GetSettingsItemValueSize` and `GetSettingsItemValue` commands for all requesters.
|
set_mitm intercepts the `GetSettingsItemValueSize` and `GetSettingsItemValue` commands for all requesters.
|
||||||
It does so in order to enable user configuration of system settings, which are parsed from `/atmosphere/system_settings.ini` on boot. See [here](../../features/configurations.md) for more information on the system settings format.
|
It does so in order to enable user configuration of system settings, which are parsed from `/atmosphere/system_settings.ini` on boot. See [here](../../features/configurations.md) for more information on the system settings format.
|
||||||
|
|
||||||
|
## dns_mitm
|
||||||
|
dns_mitm enables intercepting requests to dns resolution services, to enable redirecting requests for specified hostnames.
|
||||||
|
|
||||||
|
For documentation, see [here](../../features/dns_mitm.md).
|
||||||
|
|||||||
53
docs/features/dns_mitm.md
Normal file
53
docs/features/dns_mitm.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# DNS.mitm
|
||||||
|
As of 0.18.0, atmosphère provides a mechanism for redirecting DNS resolution requests.
|
||||||
|
|
||||||
|
By default, atmosphère redirects resolution requests for official telemetry servers, redirecting them to a loopback address.
|
||||||
|
|
||||||
|
## Hosts files
|
||||||
|
|
||||||
|
DNS.mitm can be configured through the usage of a slightly-extended `hosts` file format, which is parsed only once on system startup.
|
||||||
|
|
||||||
|
In particular, hosts files parsed by DNS.mitm have the following extensions to the usual format:
|
||||||
|
+ `*` is treated as a wildcard character, matching any collection of 0 or more characters wherever it occurs in a hostname.
|
||||||
|
+ `%` is treated as a stand-in for the value of `nsd!environment_identifier`. This is always `lp1`, on production devices.
|
||||||
|
|
||||||
|
If multiple entries in a host file match a domain, the last-defined match is used.
|
||||||
|
|
||||||
|
Please note that homebrew may trigger a hosts file re-parse by sending the extension IPC command 65000 ("AtmosphereReloadHostsFile") to a connected `sfdnsres` session.
|
||||||
|
|
||||||
|
### Hosts file selection
|
||||||
|
|
||||||
|
Atmosphère will try to read hosts from the following file paths, in order, stopping once it successfully performs a file read:
|
||||||
|
|
||||||
|
+ (emummc only) `/atmosphere/hosts/emummc_%04lx.txt`, formatted with the emummc's id number (see `emummc.ini`).
|
||||||
|
+ (emummc only) `/atmosphere/hosts/emummc.txt`.
|
||||||
|
+ (sysmmc only) `/atmosphere/hosts/sysmmc.txt`.
|
||||||
|
+ `/atmosphere/hosts/default.txt`
|
||||||
|
|
||||||
|
If `/atmosphere/hosts/default.txt` does not exist, atmosphère will create it to contain the defaults.
|
||||||
|
|
||||||
|
### Atmosphère defaults
|
||||||
|
|
||||||
|
By default, atmosphère's default redirections are parsed **in addition to** the contents of the loaded hosts file.
|
||||||
|
|
||||||
|
This is equivalent to thinking of the loaded hosts file as having the atmosphère defaults prepended to it.
|
||||||
|
|
||||||
|
This setting is considered desirable, because it minimizes the telemetry risks if a user forgets to update a custom hosts file on a system update which changes the telemetry servers.
|
||||||
|
|
||||||
|
This behavior can be opted-out from by setting `atmosphere!add_defaults_to_dns_hosts = u8!0x0` in `system_settings.ini`.
|
||||||
|
|
||||||
|
The current default redirections are:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Nintendo telemetry servers
|
||||||
|
127.0.0.1 receive-%.dg.srv.nintendo.net receive-%.er.srv.nintendo.net
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
On startup (or on hosts file re-parse), DNS.mitm will log both what hosts file it selected and the contents of all redirections it parses to `/atmosphere/logs/dns_mitm_startup.log`.
|
||||||
|
|
||||||
|
In addition, if the user sets `atmosphere!enable_dns_mitm_debug_log = u8!0x1` in `system_settings.ini`, DNS.mitm will log all requests to GetHostByName/GetAddrInfo to `/atmosphere/logs/dns_mitm_debug.log`. All redirections will be noted when they occur.
|
||||||
|
|
||||||
|
## Opting-out of DNS.mitm entirely
|
||||||
|
If you wish to disable DNS.mitm entirely, `system_settings.ini` can be edited to set `atmosphere!enable_dns_mitm = u8!0x0`.
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
[subrepo]
|
[subrepo]
|
||||||
remote = https://github.com/m4xw/emuMMC
|
remote = https://github.com/m4xw/emuMMC
|
||||||
branch = develop
|
branch = develop
|
||||||
commit = 5eed18eb527bbaa63aee5323c26de5b0cca6d28e
|
commit = b355ee6a8f376faa615785419c7d73a8814d9d65
|
||||||
parent = 021b29d2dbc8ed0469bc822393e58c9f0d174d57
|
parent = b24784f5c13a142bd0cb5d7edb82691c71f4bd00
|
||||||
method = rebase
|
method = rebase
|
||||||
cmdver = 0.4.1
|
cmdver = 0.4.1
|
||||||
|
|||||||
@@ -51,6 +51,8 @@
|
|||||||
#include "offsets/1020_exfat.h"
|
#include "offsets/1020_exfat.h"
|
||||||
#include "offsets/1100.h"
|
#include "offsets/1100.h"
|
||||||
#include "offsets/1100_exfat.h"
|
#include "offsets/1100_exfat.h"
|
||||||
|
#include "offsets/1200.h"
|
||||||
|
#include "offsets/1200_exfat.h"
|
||||||
#include "../utils/fatal.h"
|
#include "../utils/fatal.h"
|
||||||
|
|
||||||
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
||||||
@@ -113,6 +115,8 @@ DEFINE_OFFSET_STRUCT(_1020);
|
|||||||
DEFINE_OFFSET_STRUCT(_1020_EXFAT);
|
DEFINE_OFFSET_STRUCT(_1020_EXFAT);
|
||||||
DEFINE_OFFSET_STRUCT(_1100);
|
DEFINE_OFFSET_STRUCT(_1100);
|
||||||
DEFINE_OFFSET_STRUCT(_1100_EXFAT);
|
DEFINE_OFFSET_STRUCT(_1100_EXFAT);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1200);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1200_EXFAT);
|
||||||
|
|
||||||
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
@@ -186,6 +190,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
|||||||
return &(GET_OFFSET_STRUCT_NAME(_1100));
|
return &(GET_OFFSET_STRUCT_NAME(_1100));
|
||||||
case FS_VER_11_0_0_EXFAT:
|
case FS_VER_11_0_0_EXFAT:
|
||||||
return &(GET_OFFSET_STRUCT_NAME(_1100_EXFAT));
|
return &(GET_OFFSET_STRUCT_NAME(_1100_EXFAT));
|
||||||
|
case FS_VER_12_0_0:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1200));
|
||||||
|
case FS_VER_12_0_0_EXFAT:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1200_EXFAT));
|
||||||
default:
|
default:
|
||||||
fatal_abort(Fatal_UnknownVersion);
|
fatal_abort(Fatal_UnknownVersion);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,9 @@ enum FS_VER
|
|||||||
FS_VER_11_0_0,
|
FS_VER_11_0_0,
|
||||||
FS_VER_11_0_0_EXFAT,
|
FS_VER_11_0_0_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_12_0_0,
|
||||||
|
FS_VER_12_0_0_EXFAT,
|
||||||
|
|
||||||
FS_VER_MAX,
|
FS_VER_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
59
emummc/source/FS/offsets/1200.h
Normal file
59
emummc/source/FS/offsets/1200.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||||
|
* Copyright (c) 2019 Atmosphere-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef __FS_1200_H__
|
||||||
|
#define __FS_1200_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1200_SDMMC_ACCESSOR_GC 0x154FD0
|
||||||
|
#define FS_OFFSET_1200_SDMMC_ACCESSOR_SD 0x156DE0
|
||||||
|
#define FS_OFFSET_1200_SDMMC_ACCESSOR_NAND 0x155500
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1200_SDMMC_WRAPPER_READ 0x150970
|
||||||
|
#define FS_OFFSET_1200_SDMMC_WRAPPER_WRITE 0x150A30
|
||||||
|
#define FS_OFFSET_1200_RTLD 0x688
|
||||||
|
#define FS_OFFSET_1200_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1200_CLKRST_SET_MIN_V_CLK_RATE 0x14FCC0
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1200_LOCK_MUTEX 0x29350
|
||||||
|
#define FS_OFFSET_1200_UNLOCK_MUTEX 0x293A0
|
||||||
|
|
||||||
|
#define FS_OFFSET_1200_SDMMC_WRAPPER_CONTROLLER_OPEN 0x150850
|
||||||
|
#define FS_OFFSET_1200_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1508E0
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1200_SD_MUTEX 0xE3D3E8
|
||||||
|
#define FS_OFFSET_1200_NAND_MUTEX 0xE38768
|
||||||
|
#define FS_OFFSET_1200_ACTIVE_PARTITION 0xE387A8
|
||||||
|
#define FS_OFFSET_1200_SDMMC_DAS_HANDLE 0xE20DB0
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1200_SD_DAS_INIT 0x27244
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1200_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x0006E810, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x0007AEC0, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x00081254, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x00092850, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1200_H__
|
||||||
59
emummc/source/FS/offsets/1200_exfat.h
Normal file
59
emummc/source/FS/offsets/1200_exfat.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||||
|
* Copyright (c) 2019 Atmosphere-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef __FS_1200_EXFAT_H__
|
||||||
|
#define __FS_1200_EXFAT_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1200_EXFAT_SDMMC_ACCESSOR_GC 0x154FD0
|
||||||
|
#define FS_OFFSET_1200_EXFAT_SDMMC_ACCESSOR_SD 0x156DE0
|
||||||
|
#define FS_OFFSET_1200_EXFAT_SDMMC_ACCESSOR_NAND 0x155500
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_READ 0x150970
|
||||||
|
#define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_WRITE 0x150A30
|
||||||
|
#define FS_OFFSET_1200_EXFAT_RTLD 0x688
|
||||||
|
#define FS_OFFSET_1200_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1200_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x14FCC0
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1200_EXFAT_LOCK_MUTEX 0x29350
|
||||||
|
#define FS_OFFSET_1200_EXFAT_UNLOCK_MUTEX 0x293A0
|
||||||
|
|
||||||
|
#define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x150850
|
||||||
|
#define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1508E0
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1200_EXFAT_SD_MUTEX 0xE4B3E8
|
||||||
|
#define FS_OFFSET_1200_EXFAT_NAND_MUTEX 0xE46768
|
||||||
|
#define FS_OFFSET_1200_EXFAT_ACTIVE_PARTITION 0xE467A8
|
||||||
|
#define FS_OFFSET_1200_EXFAT_SDMMC_DAS_HANDLE 0xE2EDB0
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1200_EXFAT_SD_DAS_INIT 0x27244
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1200_EXFAT_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x0006E810, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x0007AEC0, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x00081254, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x00092850, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1200_EXFAT_H__
|
||||||
@@ -328,13 +328,13 @@ uint64_t sdmmc_wrapper_controller_open(int mmc_id)
|
|||||||
if (_this != NULL)
|
if (_this != NULL)
|
||||||
{
|
{
|
||||||
// Lock eMMC xfer while SD card is being initialized by FS.
|
// Lock eMMC xfer while SD card is being initialized by FS.
|
||||||
if (_this == sdmmc_accessor_get(FS_SDMMC_SD))
|
if (mmc_id == FS_SDMMC_SD)
|
||||||
mutex_lock_handler(FS_SDMMC_EMMC); // Recursive Mutex, handler will lock SD as well if custom_driver
|
mutex_lock_handler(FS_SDMMC_EMMC); // Recursive Mutex, handler will lock SD as well if custom_driver
|
||||||
|
|
||||||
result = _this->vtab->sdmmc_accessor_controller_open(_this);
|
result = _this->vtab->sdmmc_accessor_controller_open(_this);
|
||||||
|
|
||||||
// Unlock eMMC.
|
// Unlock eMMC.
|
||||||
if (_this == sdmmc_accessor_get(FS_SDMMC_SD))
|
if (mmc_id == FS_SDMMC_SD)
|
||||||
mutex_unlock_handler(FS_SDMMC_EMMC);
|
mutex_unlock_handler(FS_SDMMC_EMMC);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
%rename link old_link
|
%rename link old_link
|
||||||
|
|
||||||
*link:
|
*link:
|
||||||
%(old_link) -T %:getenv(TOPDIR /loader_stub.ld) --gc-sections --nmagic -nostdlib -nostartfiles
|
%(old_link) -T %:getenv(TOPDIR /loader_stub.ld) --gc-sections --nmagic
|
||||||
|
|
||||||
*startfile:
|
|
||||||
crti%O%s crtbegin%O%s
|
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
%rename link old_link
|
%rename link old_link
|
||||||
|
|
||||||
*link:
|
*link:
|
||||||
%(old_link) -T %:getenv(TOPDIR /mariko_fatal.ld) --gc-sections --nmagic -nostdlib -nostartfiles
|
%(old_link) -T %:getenv(TOPDIR /mariko_fatal.ld) --gc-sections --nmagic
|
||||||
|
|
||||||
*startfile:
|
|
||||||
crti%O%s crtbegin%O%s
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
%rename link old_link
|
%rename link old_link
|
||||||
|
|
||||||
*link:
|
*link:
|
||||||
%(old_link) -T %:getenv(TOPDIR /program.ld) --gc-sections --nmagic -nostdlib -nostartfiles
|
%(old_link) -T %:getenv(TOPDIR /program.ld) --gc-sections --nmagic
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
%rename link old_link
|
%rename link old_link
|
||||||
|
|
||||||
*link:
|
*link:
|
||||||
%(old_link) -T %:getenv(TOPDIR /rebootstub.ld) --gc-sections --nmagic -nostdlib -nostartfiles
|
%(old_link) -T %:getenv(TOPDIR /rebootstub.ld) --gc-sections --nmagic
|
||||||
|
|
||||||
*startfile:
|
|
||||||
crti%O%s crtbegin%O%s
|
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
%rename link old_link
|
%rename link old_link
|
||||||
|
|
||||||
*link:
|
*link:
|
||||||
%(old_link) -T %:getenv(TOPDIR /sc7fw.ld) --gc-sections --nmagic -nostdlib -nostartfiles
|
%(old_link) -T %:getenv(TOPDIR /sc7fw.ld) --gc-sections --nmagic
|
||||||
|
|
||||||
*startfile:
|
|
||||||
crti%O%s crtbegin%O%s
|
|
||||||
@@ -47,9 +47,9 @@ namespace ams::secmon::smc {
|
|||||||
[fuse::DramId_IcosaSamsung4GB] = pkg1::MemorySize_4GB,
|
[fuse::DramId_IcosaSamsung4GB] = pkg1::MemorySize_4GB,
|
||||||
[fuse::DramId_IcosaHynix4GB] = pkg1::MemorySize_4GB,
|
[fuse::DramId_IcosaHynix4GB] = pkg1::MemorySize_4GB,
|
||||||
[fuse::DramId_IcosaMicron4GB] = pkg1::MemorySize_4GB,
|
[fuse::DramId_IcosaMicron4GB] = pkg1::MemorySize_4GB,
|
||||||
[fuse::DramId_AulaHynix1y4GB] = pkg1::MemorySize_4GB,
|
[fuse::DramId_IowaHynix1y4GB] = pkg1::MemorySize_4GB,
|
||||||
[fuse::DramId_IcosaSamsung6GB] = pkg1::MemorySize_6GB,
|
[fuse::DramId_IcosaSamsung6GB] = pkg1::MemorySize_6GB,
|
||||||
[fuse::DramId_CopperHynix4GB] = pkg1::MemorySize_4GB,
|
[fuse::DramId_HoagHynix1y4GB] = pkg1::MemorySize_4GB,
|
||||||
[fuse::DramId_CopperMicron4GB] = pkg1::MemorySize_4GB,
|
[fuse::DramId_CopperMicron4GB] = pkg1::MemorySize_4GB,
|
||||||
[fuse::DramId_IowaX1X2Samsung4GB] = pkg1::MemorySize_4GB,
|
[fuse::DramId_IowaX1X2Samsung4GB] = pkg1::MemorySize_4GB,
|
||||||
[fuse::DramId_IowaSansung4GB] = pkg1::MemorySize_4GB,
|
[fuse::DramId_IowaSansung4GB] = pkg1::MemorySize_4GB,
|
||||||
@@ -286,6 +286,10 @@ namespace ams::secmon::smc {
|
|||||||
/* Get the log configuration. */
|
/* Get the log configuration. */
|
||||||
args.r[1] = (static_cast<u64>(static_cast<u8>(secmon::GetLogPort())) << 32) | static_cast<u64>(secmon::GetLogBaudRate());
|
args.r[1] = (static_cast<u64>(static_cast<u8>(secmon::GetLogPort())) << 32) | static_cast<u64>(secmon::GetLogBaudRate());
|
||||||
break;
|
break;
|
||||||
|
case ConfigItem::ExosphereForceEnableUsb30:
|
||||||
|
/* Get whether usb 3.0 should be force-enabled. */
|
||||||
|
args.r[1] = GetSecmonConfiguration().IsUsb30ForceEnabled();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return SmcResult::InvalidArgument;
|
return SmcResult::InvalidArgument;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ namespace ams::secmon::smc {
|
|||||||
ExosphereEmummcType = 65007,
|
ExosphereEmummcType = 65007,
|
||||||
ExospherePayloadAddress = 65008,
|
ExospherePayloadAddress = 65008,
|
||||||
ExosphereLogConfiguration = 65009,
|
ExosphereLogConfiguration = 65009,
|
||||||
|
ExosphereForceEnableUsb30 = 65010,
|
||||||
};
|
};
|
||||||
|
|
||||||
SmcResult SmcGetConfigUser(SmcArguments &args);
|
SmcResult SmcGetConfigUser(SmcArguments &args);
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
%rename link old_link
|
%rename link old_link
|
||||||
|
|
||||||
*link:
|
*link:
|
||||||
%(old_link) -T %:getenv(TOPDIR /sdmmc_test.ld) --gc-sections --nmagic -nostdlib -nostartfiles
|
%(old_link) -T %:getenv(TOPDIR /sdmmc_test.ld) --gc-sections --nmagic
|
||||||
|
|
||||||
*startfile:
|
|
||||||
crti%O%s crtbegin%O%s
|
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
%rename link old_link
|
%rename link old_link
|
||||||
|
|
||||||
*link:
|
*link:
|
||||||
%(old_link) -T %:getenv(TOPDIR /warmboot.ld) --gc-sections --nmagic -nostdlib -nostartfiles
|
%(old_link) -T %:getenv(TOPDIR /warmboot.ld) --gc-sections --nmagic
|
||||||
|
|
||||||
*startfile:
|
|
||||||
crti%O%s crtbegin%O%s
|
|
||||||
@@ -46,6 +46,9 @@ CFLAGS := \
|
|||||||
-std=gnu11 \
|
-std=gnu11 \
|
||||||
-Werror \
|
-Werror \
|
||||||
-Wall \
|
-Wall \
|
||||||
|
-Wno-array-bounds \
|
||||||
|
-Wno-stringop-overflow \
|
||||||
|
-Wno-stringop-overread \
|
||||||
-fstrict-volatile-bitfields \
|
-fstrict-volatile-bitfields \
|
||||||
$(ARCH) $(DEFINES)
|
$(ARCH) $(DEFINES)
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ CFLAGS := \
|
|||||||
-std=gnu11 \
|
-std=gnu11 \
|
||||||
-Werror \
|
-Werror \
|
||||||
-Wall \
|
-Wall \
|
||||||
|
-Wno-array-bounds \
|
||||||
|
-Wno-stringop-overflow \
|
||||||
|
-Wno-stringop-overread \
|
||||||
-fstrict-volatile-bitfields \
|
-fstrict-volatile-bitfields \
|
||||||
$(ARCH) $(DEFINES)
|
$(ARCH) $(DEFINES)
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ CFLAGS := \
|
|||||||
-std=gnu11 \
|
-std=gnu11 \
|
||||||
-Werror \
|
-Werror \
|
||||||
-Wall \
|
-Wall \
|
||||||
|
-Wno-array-bounds \
|
||||||
|
-Wno-stringop-overflow \
|
||||||
|
-Wno-stringop-overread \
|
||||||
-fstrict-volatile-bitfields \
|
-fstrict-volatile-bitfields \
|
||||||
$(ARCH) $(DEFINES)
|
$(ARCH) $(DEFINES)
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ CFLAGS := \
|
|||||||
-std=gnu11 \
|
-std=gnu11 \
|
||||||
-Werror \
|
-Werror \
|
||||||
-Wall \
|
-Wall \
|
||||||
|
-Wno-array-bounds \
|
||||||
|
-Wno-stringop-overflow \
|
||||||
|
-Wno-stringop-overread \
|
||||||
-fstrict-volatile-bitfields \
|
-fstrict-volatile-bitfields \
|
||||||
$(ARCH) $(DEFINES)
|
$(ARCH) $(DEFINES)
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,9 @@ typedef enum {
|
|||||||
FS_VER_11_0_0,
|
FS_VER_11_0_0,
|
||||||
FS_VER_11_0_0_EXFAT,
|
FS_VER_11_0_0_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_12_0_0,
|
||||||
|
FS_VER_12_0_0_EXFAT,
|
||||||
|
|
||||||
FS_VER_MAX,
|
FS_VER_MAX,
|
||||||
} emummc_fs_ver_t;
|
} emummc_fs_ver_t;
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#define EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS (1 << 4u)
|
#define EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS (1 << 4u)
|
||||||
#define EXOSPHERE_FLAG_BLANK_PRODINFO (1 << 5u)
|
#define EXOSPHERE_FLAG_BLANK_PRODINFO (1 << 5u)
|
||||||
#define EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC (1 << 6u)
|
#define EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC (1 << 6u)
|
||||||
|
#define EXOSPHERE_FLAG_FORCE_ENABLE_USB_30 (1 << 7u)
|
||||||
|
|
||||||
#define EXOSPHERE_LOG_FLAG_INVERTED (1 << 0u)
|
#define EXOSPHERE_LOG_FLAG_INVERTED (1 << 0u)
|
||||||
|
|
||||||
|
|||||||
@@ -426,6 +426,9 @@ static const uint8_t g_fs_hashes[FS_VER_MAX][0x8] = {
|
|||||||
|
|
||||||
"\xE3\x99\x15\x6E\x84\x4E\xB0\xAA", /* FS_VER_11_0_0 */
|
"\xE3\x99\x15\x6E\x84\x4E\xB0\xAA", /* FS_VER_11_0_0 */
|
||||||
"\x0B\xA1\x5B\xB3\x04\xB5\x05\x63", /* FS_VER_11_0_0_EXFAT */
|
"\x0B\xA1\x5B\xB3\x04\xB5\x05\x63", /* FS_VER_11_0_0_EXFAT */
|
||||||
|
|
||||||
|
"\xDC\x2A\x08\x49\x96\xBB\x3C\x01", /* FS_VER_12_0_0 */
|
||||||
|
"\xD5\xA5\xBF\x36\x64\x0C\x49\xEA", /* FS_VER_12_0_0_EXFAT */
|
||||||
};
|
};
|
||||||
|
|
||||||
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver) {
|
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver) {
|
||||||
|
|||||||
@@ -568,6 +568,7 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, proc_id_recv)[] = {0xA9B
|
|||||||
*/
|
*/
|
||||||
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1100, proc_id_send)[] = {0xE0, 0x03, 0x15, 0xAA, 0xA8, 0x02, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0x88, 0x4A, 0x3C, 0x8B, 0x09, 0xFC, 0x60, 0xD3, 0x00, 0x25, 0x00, 0x29};
|
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1100, proc_id_send)[] = {0xE0, 0x03, 0x15, 0xAA, 0xA8, 0x02, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0x88, 0x4A, 0x3C, 0x8B, 0x09, 0xFC, 0x60, 0xD3, 0x00, 0x25, 0x00, 0x29};
|
||||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_send)[] = {0xA9BF2FEA, 0xF94043EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_send)[] = {0xA9BF2FEA, 0xF94043EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
stp x10, x11, [sp, #-0x10]!
|
stp x10, x11, [sp, #-0x10]!
|
||||||
ldr x11, [sp, #0xE0]
|
ldr x11, [sp, #0xE0]
|
||||||
@@ -596,6 +597,63 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_send)[] = {0xA9B
|
|||||||
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1100, proc_id_recv)[] = {0x08, 0x03, 0x40, 0xF9, 0xE0, 0x03, 0x18, 0xAA, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0xE8, 0x7F, 0x40, 0xF9, 0x09, 0xFC, 0x60, 0xD3, 0xEA, 0x5B, 0x40, 0xF9};
|
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1100, proc_id_recv)[] = {0x08, 0x03, 0x40, 0xF9, 0xE0, 0x03, 0x18, 0xAA, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0xE8, 0x7F, 0x40, 0xF9, 0x09, 0xFC, 0x60, 0xD3, 0xEA, 0x5B, 0x40, 0xF9};
|
||||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_recv)[] = {0xA9BF2FEA, 0xF94073EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_recv)[] = {0xA9BF2FEA, 0xF94073EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
|
||||||
|
|
||||||
|
/*
|
||||||
|
stp x10, x11, [sp, #-0x10]!
|
||||||
|
ldr x11, [sp, #0x98]
|
||||||
|
mov w10, #3
|
||||||
|
lsl x10, x10, #2
|
||||||
|
ldr x10, [x11, x10]
|
||||||
|
mov x9, #0x0000ffffffffffff
|
||||||
|
and x8, x10, x9
|
||||||
|
mov x9, #0xffff000000000000
|
||||||
|
and x10, x10, x9
|
||||||
|
mov x9, #0xfffe000000000000
|
||||||
|
cmp x10, x9
|
||||||
|
beq #0x20
|
||||||
|
|
||||||
|
stp x8, x9, [sp, #-0x10]!
|
||||||
|
ldr x8, [x22]
|
||||||
|
ldr x8, [x8, #0x38]
|
||||||
|
mov x0, x22
|
||||||
|
blr x8
|
||||||
|
ldp x8, x9, [sp],#0x10
|
||||||
|
mov x8, x0
|
||||||
|
|
||||||
|
ldp x10, x11, [sp],#0x10
|
||||||
|
mov x0, x8
|
||||||
|
*/
|
||||||
|
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1200, proc_id_send)[] = {0xE0, 0x03, 0x16, 0xAA, 0xC8, 0x02, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0xA8, 0x4A, 0x3B, 0x8B, 0x09, 0xFC, 0x60, 0xD3, 0x00, 0x25, 0x00, 0x29};
|
||||||
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(1200, proc_id_send)[] = {0xA9BF2FEA, 0xF9404FEB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002C8, 0xF9401D08, 0xAA1603E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
|
||||||
|
|
||||||
|
/*
|
||||||
|
stp x10, x11, [sp, #-0x10]!
|
||||||
|
ldr x11, [sp, #0xE0]
|
||||||
|
mov w10, #3
|
||||||
|
lsl x10, x10, #2
|
||||||
|
ldr x10, [x11, x10]
|
||||||
|
mov x9, #0x0000ffffffffffff
|
||||||
|
and x8, x10, x9
|
||||||
|
mov x9, #0xffff000000000000
|
||||||
|
and x10, x10, x9
|
||||||
|
mov x9, #0xfffe000000000000
|
||||||
|
cmp x10, x9
|
||||||
|
beq #0x20
|
||||||
|
|
||||||
|
stp x8, x9, [sp, #-0x10]!
|
||||||
|
ldr x8, [x28]
|
||||||
|
ldr x8, [x8, #0x38]
|
||||||
|
mov x0, x28
|
||||||
|
blr x8
|
||||||
|
ldp x8, x9, [sp],#0x10
|
||||||
|
mov x8, x0
|
||||||
|
|
||||||
|
ldp x10, x11, [sp],#0x10
|
||||||
|
mov x0, x8
|
||||||
|
*/
|
||||||
|
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1200, proc_id_recv)[] = {0x88, 0x03, 0x40, 0xF9, 0xE0, 0x03, 0x1C, 0xAA, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0x08, 0x4B, 0x3A, 0x8B, 0x09, 0xFC, 0x60, 0xD3, 0x00, 0x25, 0x00, 0x29};
|
||||||
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(1200, proc_id_recv)[] = {0xA9BF2FEA, 0xF94073EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400388, 0xF9401D08, 0xAA1C03E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
|
||||||
|
|
||||||
|
|
||||||
/* svcControlCodeMemory Patches */
|
/* svcControlCodeMemory Patches */
|
||||||
/* b.eq -> nop */
|
/* b.eq -> nop */
|
||||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, svc_control_codememory)[] = {MAKE_NOP};
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, svc_control_codememory)[] = {MAKE_NOP};
|
||||||
@@ -605,6 +663,7 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(800, svc_control_codememory)[
|
|||||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, svc_control_codememory)[] = {MAKE_NOP};
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, svc_control_codememory)[] = {MAKE_NOP};
|
||||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, svc_control_codememory)[] = {MAKE_NOP};
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, svc_control_codememory)[] = {MAKE_NOP};
|
||||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, svc_control_codememory)[] = {MAKE_NOP};
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, svc_control_codememory)[] = {MAKE_NOP};
|
||||||
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(1200, svc_control_codememory)[] = {MAKE_NOP};
|
||||||
|
|
||||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, system_memory_increase)[] = {0x52A3C008}; /* MOV W8, #0x1E000000 */
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, system_memory_increase)[] = {0x52A3C008}; /* MOV W8, #0x1E000000 */
|
||||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(600, system_memory_increase)[] = {0x52A3B008}; /* MOV W8, #0x1D800000 */
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(600, system_memory_increase)[] = {0x52A3B008}; /* MOV W8, #0x1D800000 */
|
||||||
@@ -613,6 +672,7 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(800, system_memory_increase)[
|
|||||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
|
||||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
|
||||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, system_memory_increase)[] = {0x52A3B015}; /* MOV W21, #0x1D800000 */
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, system_memory_increase)[] = {0x52A3B015}; /* MOV W21, #0x1D800000 */
|
||||||
|
static const instruction_t MAKE_KERNEL_PATCH_NAME(1200, system_memory_increase)[] = {0x52A3B015}; /* MOV W21, #0x1D800000 */
|
||||||
|
|
||||||
/* Hook Definitions. */
|
/* Hook Definitions. */
|
||||||
static const kernel_patch_t g_kernel_patches_100[] = {
|
static const kernel_patch_t g_kernel_patches_100[] = {
|
||||||
@@ -935,6 +995,35 @@ static const kernel_patch_t g_kernel_patches_1101[] = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const kernel_patch_t g_kernel_patches_1200[] = {
|
||||||
|
{ /* Send Message Process ID Patch. */
|
||||||
|
.pattern_size = 0x1C,
|
||||||
|
.pattern = MAKE_KERNEL_PATTERN_NAME(1200, proc_id_send),
|
||||||
|
.pattern_hook_offset = 0x0,
|
||||||
|
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1200, proc_id_send))/sizeof(instruction_t),
|
||||||
|
.branch_back_offset = 0x10,
|
||||||
|
.payload = MAKE_KERNEL_PATCH_NAME(1200, proc_id_send)
|
||||||
|
},
|
||||||
|
{ /* Receive Message Process ID Patch. */
|
||||||
|
.pattern_size = 0x1C,
|
||||||
|
.pattern = MAKE_KERNEL_PATTERN_NAME(1200, proc_id_recv),
|
||||||
|
.pattern_hook_offset = 0x0,
|
||||||
|
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1200, proc_id_recv))/sizeof(instruction_t),
|
||||||
|
.branch_back_offset = 0x10,
|
||||||
|
.payload = MAKE_KERNEL_PATCH_NAME(1200, proc_id_recv)
|
||||||
|
},
|
||||||
|
{ /* svcControlCodeMemory Patch. */
|
||||||
|
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1200, svc_control_codememory))/sizeof(instruction_t),
|
||||||
|
.payload = MAKE_KERNEL_PATCH_NAME(1200, svc_control_codememory),
|
||||||
|
.patch_offset = 0x2FCB4,
|
||||||
|
},
|
||||||
|
{ /* System Memory Increase Patch. */
|
||||||
|
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1200, system_memory_increase))/sizeof(instruction_t),
|
||||||
|
.payload = MAKE_KERNEL_PATCH_NAME(1200, system_memory_increase),
|
||||||
|
.patch_offset = 0x4809C,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#define KERNEL_PATCHES(vers) .num_patches = sizeof(g_kernel_patches_##vers)/sizeof(kernel_patch_t), .patches = g_kernel_patches_##vers,
|
#define KERNEL_PATCHES(vers) .num_patches = sizeof(g_kernel_patches_##vers)/sizeof(kernel_patch_t), .patches = g_kernel_patches_##vers,
|
||||||
|
|
||||||
/* Kernel Infos. */
|
/* Kernel Infos. */
|
||||||
@@ -1038,6 +1127,15 @@ static const kernel_info_t g_kernel_infos[] = {
|
|||||||
.embedded_ini_ptr = 0x180,
|
.embedded_ini_ptr = 0x180,
|
||||||
.free_code_space_offset = 0x49EE8,
|
.free_code_space_offset = 0x49EE8,
|
||||||
KERNEL_PATCHES(1101)
|
KERNEL_PATCHES(1101)
|
||||||
|
},
|
||||||
|
{ /* 12.0.0. */
|
||||||
|
.hash = {0x8D, 0x4A, 0x1E, 0xFC, 0xCC, 0x6C, 0xFE, 0x6C, 0x45, 0x14, 0x13, 0xA1, 0x7F, 0xF6, 0xDF, 0xFD, 0x7E, 0x5D, 0xD1, 0x38, 0xCE, 0x86, 0x11, 0x8B, 0x58, 0x5F, 0x89, 0x67, 0x84, 0x48, 0xA8, 0x17, },
|
||||||
|
.hash_offset = 0x1C4,
|
||||||
|
.hash_size = 0x68000 - 0x1C4,
|
||||||
|
.embedded_ini_offset = 0x68000,
|
||||||
|
.embedded_ini_ptr = 0x180,
|
||||||
|
.free_code_space_offset = 0x48810,
|
||||||
|
KERNEL_PATCHES(1200)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -256,6 +256,24 @@ static int stratosphere_ini_handler(void *user, const char *section, const char
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int system_settings_ini_handler(void *user, const char *section, const char *name, const char *value) {
|
||||||
|
uint32_t *flags = (uint32_t *)user;
|
||||||
|
if (strcmp(section, "usb") == 0) {
|
||||||
|
if (strcmp(name, "usb30_force_enabled") == 0) {
|
||||||
|
if (strcmp(value, "u8!0x1") == 0) {
|
||||||
|
*flags |= EXOSPHERE_FLAG_FORCE_ENABLE_USB_30;
|
||||||
|
} else if (strcmp(value, "u8!0x0") == 0) {
|
||||||
|
*flags &= ~(EXOSPHERE_FLAG_FORCE_ENABLE_USB_30);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_nca_present(const char *nca_name) {
|
static bool is_nca_present(const char *nca_name) {
|
||||||
char path[0x100];
|
char path[0x100];
|
||||||
snprintf(path, sizeof(path), "system:/contents/registered/%s.nca", nca_name);
|
snprintf(path, sizeof(path), "system:/contents/registered/%s.nca", nca_name);
|
||||||
@@ -267,7 +285,10 @@ static bool is_nca_present(const char *nca_name) {
|
|||||||
static uint32_t nxboot_get_specific_target_firmware(uint32_t target_firmware){
|
static uint32_t nxboot_get_specific_target_firmware(uint32_t target_firmware){
|
||||||
#define CHECK_NCA(NCA_ID, VERSION) do { if (is_nca_present(NCA_ID)) { return ATMOSPHERE_TARGET_FIRMWARE_##VERSION; } } while(0)
|
#define CHECK_NCA(NCA_ID, VERSION) do { if (is_nca_present(NCA_ID)) { return ATMOSPHERE_TARGET_FIRMWARE_##VERSION; } } while(0)
|
||||||
|
|
||||||
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_11_0_0) {
|
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_12_0_0) {
|
||||||
|
CHECK_NCA("e65114b456f9d0b566a80e53bade2d89", 12_0_1);
|
||||||
|
CHECK_NCA("bd4185843550fbba125b20787005d1d2", 12_0_0);
|
||||||
|
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_11_0_0) {
|
||||||
CHECK_NCA("56211c7a5ed20a5332f5cdda67121e37", 11_0_1);
|
CHECK_NCA("56211c7a5ed20a5332f5cdda67121e37", 11_0_1);
|
||||||
CHECK_NCA("594c90bcdbcccad6b062eadba0cd0e7e", 11_0_0);
|
CHECK_NCA("594c90bcdbcccad6b062eadba0cd0e7e", 11_0_0);
|
||||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0) {
|
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0) {
|
||||||
@@ -370,6 +391,8 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
|
|||||||
return ATMOSPHERE_TARGET_FIRMWARE_10_0_0;
|
return ATMOSPHERE_TARGET_FIRMWARE_10_0_0;
|
||||||
} else if (memcmp(package1loader_header->build_timestamp, "20201030", 8) == 0) {
|
} else if (memcmp(package1loader_header->build_timestamp, "20201030", 8) == 0) {
|
||||||
return ATMOSPHERE_TARGET_FIRMWARE_11_0_0;
|
return ATMOSPHERE_TARGET_FIRMWARE_11_0_0;
|
||||||
|
} else if (memcmp(package1loader_header->build_timestamp, "20210129", 8) == 0) {
|
||||||
|
return ATMOSPHERE_TARGET_FIRMWARE_12_0_0;
|
||||||
} else {
|
} else {
|
||||||
fatal_error("[NXBOOT] Unable to identify package1!\n");
|
fatal_error("[NXBOOT] Unable to identify package1!\n");
|
||||||
}
|
}
|
||||||
@@ -537,6 +560,15 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke
|
|||||||
/* Apply lcd vendor. */
|
/* Apply lcd vendor. */
|
||||||
exo_cfg.lcd_vendor = display_get_lcd_vendor();
|
exo_cfg.lcd_vendor = display_get_lcd_vendor();
|
||||||
|
|
||||||
|
/* Read and parse system settings.ini to determine usb 3.0 enable. */
|
||||||
|
char *settings_ini = calloc(1, 0x20000);
|
||||||
|
if (read_from_file(settings_ini, 0x1FFFF, "atmosphere/config/system_settings.ini")) {
|
||||||
|
if (ini_parse_string(settings_ini, system_settings_ini_handler, &exo_cfg.flags[0]) < 0) {
|
||||||
|
fatal_error("[NXBOOT] Failed to parse system_settings.ini!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(settings_ini);
|
||||||
|
|
||||||
if ((exo_cfg.target_firmware < ATMOSPHERE_TARGET_FIRMWARE_MIN) || (exo_cfg.target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX)) {
|
if ((exo_cfg.target_firmware < ATMOSPHERE_TARGET_FIRMWARE_MIN) || (exo_cfg.target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX)) {
|
||||||
fatal_error("[NXBOOT] Invalid Exosphere target firmware!\n");
|
fatal_error("[NXBOOT] Invalid Exosphere target firmware!\n");
|
||||||
}
|
}
|
||||||
@@ -568,6 +600,10 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
|
|||||||
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_11_0_0 && !(fuse_get_reserved_odm(7) & ~0x00001FFF)) {
|
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_11_0_0 && !(fuse_get_reserved_odm(7) & ~0x00001FFF)) {
|
||||||
kip_patches_set_enable_nogc();
|
kip_patches_set_enable_nogc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* NOTE: 12.0.0 added a new lotus firmware, but did not burn a fuse. */
|
||||||
|
/* This is literally undetectable using normal fuses.... */
|
||||||
|
/* C'est la vie. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
[subrepo]
|
[subrepo]
|
||||||
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
||||||
branch = master
|
branch = master
|
||||||
commit = 6c11c07e2a7f03952a4e70eb89b47bf528de39c6
|
commit = acee57e888aa87ba8976db889dfcf20701cb38a8
|
||||||
parent = 9e104bb83f1302e9f126542fbf57c7f666aae953
|
parent = dbcb1e15648ef7b050b9b59b40d413038b4888ec
|
||||||
method = merge
|
method = merge
|
||||||
cmdver = 0.4.1
|
cmdver = 0.4.1
|
||||||
|
|||||||
@@ -8,13 +8,19 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk
|
|||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64)
|
ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64)
|
||||||
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
||||||
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Wextra -Werror -fno-non-call-exceptions
|
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Wextra -Werror -fno-non-call-exceptions \
|
||||||
|
-Wno-array-bounds \
|
||||||
|
-Wno-stringop-overflow \
|
||||||
|
-Wno-stringop-overread
|
||||||
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||||
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
||||||
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
|
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
|
||||||
else ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm)
|
else ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm)
|
||||||
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
||||||
SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -fno-non-call-exceptions
|
SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -fno-non-call-exceptions \
|
||||||
|
-Wno-array-bounds \
|
||||||
|
-Wno-stringop-overflow \
|
||||||
|
-Wno-stringop-overread
|
||||||
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||||
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
||||||
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
|
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
|
|||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
||||||
SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Wextra -Werror -flto -fno-non-call-exceptions
|
SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Wextra -Werror -flto -fno-non-call-exceptions \
|
||||||
|
-Wno-array-bounds \
|
||||||
|
-Wno-stringop-overflow \
|
||||||
|
-Wno-stringop-overread
|
||||||
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||||
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
||||||
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
|
|||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
||||||
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Wextra -Werror -fno-non-call-exceptions
|
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Wextra -Werror -fno-non-call-exceptions \
|
||||||
|
-Wno-array-bounds \
|
||||||
|
-Wno-stringop-overflow \
|
||||||
|
-Wno-stringop-overread
|
||||||
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||||
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
||||||
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ namespace ams::fuse {
|
|||||||
DramId_IcosaSamsung4GB = 0,
|
DramId_IcosaSamsung4GB = 0,
|
||||||
DramId_IcosaHynix4GB = 1,
|
DramId_IcosaHynix4GB = 1,
|
||||||
DramId_IcosaMicron4GB = 2,
|
DramId_IcosaMicron4GB = 2,
|
||||||
DramId_AulaHynix1y4GB = 3,
|
DramId_IowaHynix1y4GB = 3,
|
||||||
DramId_IcosaSamsung6GB = 4,
|
DramId_IcosaSamsung6GB = 4,
|
||||||
DramId_CopperHynix4GB = 5,
|
DramId_HoagHynix1y4GB = 5,
|
||||||
DramId_CopperMicron4GB = 6,
|
DramId_CopperMicron4GB = 6,
|
||||||
DramId_IowaX1X2Samsung4GB = 7,
|
DramId_IowaX1X2Samsung4GB = 7,
|
||||||
DramId_IowaSansung4GB = 8,
|
DramId_IowaSansung4GB = 8,
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace ams::secmon {
|
|||||||
SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess = (1u << 4),
|
SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess = (1u << 4),
|
||||||
SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary = (1u << 5),
|
SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary = (1u << 5),
|
||||||
SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc = (1u << 6),
|
SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc = (1u << 6),
|
||||||
|
SecureMonitorConfigurationFlag_ForceEnableUsb30 = (1u << 7),
|
||||||
|
|
||||||
SecureMonitorConfigurationFlag_Default = SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel,
|
SecureMonitorConfigurationFlag_Default = SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel,
|
||||||
};
|
};
|
||||||
@@ -101,6 +102,7 @@ namespace ams::secmon {
|
|||||||
constexpr bool EnableUserModePerformanceCounterAccess() const { return (this->flags[0] & SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess) != 0; }
|
constexpr bool EnableUserModePerformanceCounterAccess() const { return (this->flags[0] & SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess) != 0; }
|
||||||
constexpr bool ShouldUseBlankCalibrationBinary() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary) != 0; }
|
constexpr bool ShouldUseBlankCalibrationBinary() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary) != 0; }
|
||||||
constexpr bool AllowWritingToCalibrationBinarySysmmc() const { return (this->flags[0] & SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc) != 0; }
|
constexpr bool AllowWritingToCalibrationBinarySysmmc() const { return (this->flags[0] & SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc) != 0; }
|
||||||
|
constexpr bool IsUsb30ForceEnabled() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ForceEnableUsb30) != 0; }
|
||||||
|
|
||||||
constexpr bool IsDevelopmentFunctionEnabled(bool for_kern) const { return for_kern ? this->IsDevelopmentFunctionEnabledForKernel() : this->IsDevelopmentFunctionEnabledForUser(); }
|
constexpr bool IsDevelopmentFunctionEnabled(bool for_kern) const { return for_kern ? this->IsDevelopmentFunctionEnabledForKernel() : this->IsDevelopmentFunctionEnabledForUser(); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -140,6 +140,8 @@ $(OFILES_SRC) : $(HFILES_BIN)
|
|||||||
|
|
||||||
kern_libc_generic.o: CFLAGS += -fno-builtin
|
kern_libc_generic.o: CFLAGS += -fno-builtin
|
||||||
|
|
||||||
|
kern_k_auto_object.o: CXXFLAGS += -fno-lto
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
%_bin.h %.bin.o : %.bin
|
%_bin.h %.bin.o : %.bin
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <mesosphere/kern_select_assembly_offsets.h>
|
||||||
|
|
||||||
namespace ams::kern::init {
|
namespace ams::kern::init {
|
||||||
|
|
||||||
@@ -31,5 +32,19 @@ namespace ams::kern::init {
|
|||||||
u64 setup_function;
|
u64 setup_function;
|
||||||
u64 exception_stack;
|
u64 exception_stack;
|
||||||
};
|
};
|
||||||
|
static_assert(sizeof(KInitArguments) == INIT_ARGUMENTS_SIZE);
|
||||||
|
|
||||||
|
static_assert(__builtin_offsetof(KInitArguments, ttbr0) == INIT_ARGUMENTS_TTBR0);
|
||||||
|
static_assert(__builtin_offsetof(KInitArguments, ttbr1) == INIT_ARGUMENTS_TTBR1);
|
||||||
|
static_assert(__builtin_offsetof(KInitArguments, tcr) == INIT_ARGUMENTS_TCR);
|
||||||
|
static_assert(__builtin_offsetof(KInitArguments, mair) == INIT_ARGUMENTS_MAIR);
|
||||||
|
static_assert(__builtin_offsetof(KInitArguments, cpuactlr) == INIT_ARGUMENTS_CPUACTLR);
|
||||||
|
static_assert(__builtin_offsetof(KInitArguments, cpuectlr) == INIT_ARGUMENTS_CPUECTLR);
|
||||||
|
static_assert(__builtin_offsetof(KInitArguments, sctlr) == INIT_ARGUMENTS_SCTLR);
|
||||||
|
static_assert(__builtin_offsetof(KInitArguments, sp) == INIT_ARGUMENTS_SP);
|
||||||
|
static_assert(__builtin_offsetof(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT);
|
||||||
|
static_assert(__builtin_offsetof(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT);
|
||||||
|
static_assert(__builtin_offsetof(KInitArguments, setup_function) == INIT_ARGUMENTS_SETUP_FUNCTION);
|
||||||
|
static_assert(__builtin_offsetof(KInitArguments, exception_stack) == INIT_ARGUMENTS_EXCEPTION_STACK);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -38,37 +38,67 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
public:
|
public:
|
||||||
class IPageAllocator {
|
class IPageAllocator {
|
||||||
public:
|
public:
|
||||||
virtual KPhysicalAddress Allocate() { return Null<KPhysicalAddress>; }
|
virtual KPhysicalAddress Allocate(size_t size) = 0;
|
||||||
virtual void Free(KPhysicalAddress phys_addr) { /* Nothing to do here. */ (void)(phys_addr); }
|
virtual void Free(KPhysicalAddress phys_addr, size_t size) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NoClear{};
|
|
||||||
private:
|
private:
|
||||||
KPhysicalAddress m_l1_table;
|
KPhysicalAddress m_l1_tables[2];
|
||||||
|
u32 m_num_entries[2];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr ALWAYS_INLINE KInitialPageTable(KPhysicalAddress l1, NoClear) : m_l1_table(l1) { /* ... */ }
|
KInitialPageTable(KVirtualAddress start_address, KVirtualAddress end_address, IPageAllocator &allocator) {
|
||||||
|
/* Set tables. */
|
||||||
|
m_l1_tables[0] = AllocateNewPageTable(allocator);
|
||||||
|
m_l1_tables[1] = AllocateNewPageTable(allocator);
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE KInitialPageTable(KPhysicalAddress l1) : KInitialPageTable(l1, NoClear{}) {
|
/* Set counts. */
|
||||||
ClearNewPageTable(m_l1_table);
|
m_num_entries[0] = MaxPageTableEntries;
|
||||||
|
m_num_entries[1] = ((end_address / L1BlockSize) & (MaxPageTableEntries - 1)) - ((start_address / L1BlockSize) & (MaxPageTableEntries - 1)) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE uintptr_t GetL1TableAddress() const {
|
KInitialPageTable() {
|
||||||
return GetInteger(m_l1_table);
|
/* Set tables. */
|
||||||
|
m_l1_tables[0] = util::AlignDown(cpu::GetTtbr0El1(), PageSize);
|
||||||
|
m_l1_tables[1] = util::AlignDown(cpu::GetTtbr1El1(), PageSize);
|
||||||
|
|
||||||
|
/* Set counts. */
|
||||||
|
cpu::TranslationControlRegisterAccessor tcr;
|
||||||
|
m_num_entries[0] = tcr.GetT0Size() / L1BlockSize;
|
||||||
|
m_num_entries[1] = tcr.GetT1Size() / L1BlockSize;
|
||||||
|
|
||||||
|
/* Check counts. */
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(0 < m_num_entries[0] && m_num_entries[0] <= MaxPageTableEntries);
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(0 < m_num_entries[1] && m_num_entries[1] <= MaxPageTableEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE uintptr_t GetTtbr0L1TableAddress() const {
|
||||||
|
return GetInteger(m_l1_tables[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE uintptr_t GetTtbr1L1TableAddress() const {
|
||||||
|
return GetInteger(m_l1_tables[1]);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
static constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KPhysicalAddress _l1_table, KVirtualAddress address) {
|
constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KVirtualAddress address) const {
|
||||||
L1PageTableEntry *l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(_l1_table));
|
const size_t index = (GetInteger(address) >> (BITSIZEOF(address) - 1)) & 1;
|
||||||
return l1_table + ((GetInteger(address) >> 30) & (MaxPageTableEntries - 1));
|
L1PageTableEntry *l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[index]));
|
||||||
|
return l1_table + ((GetInteger(address) / L1BlockSize) & (m_num_entries[index] - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KVirtualAddress address) {
|
static constexpr ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KVirtualAddress address) {
|
||||||
L2PageTableEntry *l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(entry->GetTable()));
|
L2PageTableEntry *l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(entry->GetTable()));
|
||||||
return l2_table + ((GetInteger(address) >> 21) & (MaxPageTableEntries - 1));
|
return l2_table + ((GetInteger(address) / L2BlockSize) & (MaxPageTableEntries - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KVirtualAddress address) {
|
static constexpr ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KVirtualAddress address) {
|
||||||
L3PageTableEntry *l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(entry->GetTable()));
|
L3PageTableEntry *l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(entry->GetTable()));
|
||||||
return l3_table + ((GetInteger(address) >> 12) & (MaxPageTableEntries - 1));
|
return l3_table + ((GetInteger(address) / L3BlockSize) & (MaxPageTableEntries - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(IPageAllocator &allocator) {
|
||||||
|
auto address = allocator.Allocate(PageSize);
|
||||||
|
ClearNewPageTable(address);
|
||||||
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address) {
|
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address) {
|
||||||
@@ -83,7 +113,7 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
const KVirtualAddress end_virt_addr = virt_addr + size;
|
const KVirtualAddress end_virt_addr = virt_addr + size;
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
while (virt_addr < end_virt_addr) {
|
while (virt_addr < end_virt_addr) {
|
||||||
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
|
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
||||||
|
|
||||||
/* If an L1 block is mapped or we're empty, advance by L1BlockSize. */
|
/* If an L1 block is mapped or we're empty, advance by L1BlockSize. */
|
||||||
if (l1_entry->IsBlock() || l1_entry->IsEmpty()) {
|
if (l1_entry->IsBlock() || l1_entry->IsEmpty()) {
|
||||||
@@ -137,7 +167,7 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
const KVirtualAddress end_virt_addr = virt_addr + size;
|
const KVirtualAddress end_virt_addr = virt_addr + size;
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
while (virt_addr < end_virt_addr) {
|
while (virt_addr < end_virt_addr) {
|
||||||
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
|
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
||||||
|
|
||||||
/* If an L1 block is mapped or we're empty, advance by L1BlockSize. */
|
/* If an L1 block is mapped or we're empty, advance by L1BlockSize. */
|
||||||
if (l1_entry->IsBlock() || l1_entry->IsEmpty()) {
|
if (l1_entry->IsBlock() || l1_entry->IsEmpty()) {
|
||||||
@@ -194,7 +224,7 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PageTableEntry *GetMappingEntry(KVirtualAddress virt_addr, size_t block_size) {
|
PageTableEntry *GetMappingEntry(KVirtualAddress virt_addr, size_t block_size) {
|
||||||
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
|
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
||||||
|
|
||||||
if (l1_entry->IsBlock()) {
|
if (l1_entry->IsBlock()) {
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(block_size == L1BlockSize);
|
MESOSPHERE_INIT_ABORT_UNLESS(block_size == L1BlockSize);
|
||||||
@@ -301,7 +331,7 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
|
|
||||||
/* Iteratively map pages until the requested region is mapped. */
|
/* Iteratively map pages until the requested region is mapped. */
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
|
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
||||||
|
|
||||||
/* Can we make an L1 block? */
|
/* Can we make an L1 block? */
|
||||||
if (util::IsAligned(GetInteger(virt_addr), L1BlockSize) && util::IsAligned(GetInteger(phys_addr), L1BlockSize) && size >= L1BlockSize) {
|
if (util::IsAligned(GetInteger(virt_addr), L1BlockSize) && util::IsAligned(GetInteger(phys_addr), L1BlockSize) && size >= L1BlockSize) {
|
||||||
@@ -316,7 +346,7 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
|
|
||||||
/* If we don't already have an L2 table, we need to make a new one. */
|
/* If we don't already have an L2 table, we need to make a new one. */
|
||||||
if (!l1_entry->IsTable()) {
|
if (!l1_entry->IsTable()) {
|
||||||
KPhysicalAddress new_table = allocator.Allocate();
|
KPhysicalAddress new_table = AllocateNewPageTable(allocator);
|
||||||
ClearNewPageTable(new_table);
|
ClearNewPageTable(new_table);
|
||||||
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
@@ -350,7 +380,7 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
|
|
||||||
/* If we don't already have an L3 table, we need to make a new one. */
|
/* If we don't already have an L3 table, we need to make a new one. */
|
||||||
if (!l2_entry->IsTable()) {
|
if (!l2_entry->IsTable()) {
|
||||||
KPhysicalAddress new_table = allocator.Allocate();
|
KPhysicalAddress new_table = AllocateNewPageTable(allocator);
|
||||||
ClearNewPageTable(new_table);
|
ClearNewPageTable(new_table);
|
||||||
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
@@ -382,7 +412,7 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
|
|
||||||
KPhysicalAddress GetPhysicalAddress(KVirtualAddress virt_addr) const {
|
KPhysicalAddress GetPhysicalAddress(KVirtualAddress virt_addr) const {
|
||||||
/* Get the L1 entry. */
|
/* Get the L1 entry. */
|
||||||
const L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
|
const L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
||||||
|
|
||||||
if (l1_entry->IsBlock()) {
|
if (l1_entry->IsBlock()) {
|
||||||
return l1_entry->GetBlock() + (GetInteger(virt_addr) & (L1BlockSize - 1));
|
return l1_entry->GetBlock() + (GetInteger(virt_addr) & (L1BlockSize - 1));
|
||||||
@@ -444,7 +474,7 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
};
|
};
|
||||||
|
|
||||||
while (virt_addr < end_virt_addr) {
|
while (virt_addr < end_virt_addr) {
|
||||||
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
|
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
||||||
|
|
||||||
/* If an L1 block is mapped, update. */
|
/* If an L1 block is mapped, update. */
|
||||||
if (l1_entry->IsBlock()) {
|
if (l1_entry->IsBlock()) {
|
||||||
@@ -485,7 +515,7 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
|
|
||||||
const KVirtualAddress end_virt_addr = virt_addr + size;
|
const KVirtualAddress end_virt_addr = virt_addr + size;
|
||||||
while (virt_addr < end_virt_addr) {
|
while (virt_addr < end_virt_addr) {
|
||||||
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
|
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
||||||
|
|
||||||
/* If an L1 block is mapped, the address isn't free. */
|
/* If an L1 block is mapped, the address isn't free. */
|
||||||
if (l1_entry->IsBlock()) {
|
if (l1_entry->IsBlock()) {
|
||||||
@@ -534,7 +564,7 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
|
|
||||||
/* Iteratively reprotect pages until the requested region is reprotected. */
|
/* Iteratively reprotect pages until the requested region is reprotected. */
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
|
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
||||||
|
|
||||||
/* Check if an L1 block is present. */
|
/* Check if an L1 block is present. */
|
||||||
if (l1_entry->IsBlock()) {
|
if (l1_entry->IsBlock()) {
|
||||||
@@ -673,11 +703,18 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class KInitialPageAllocator : public KInitialPageTable::IPageAllocator {
|
class KInitialPageAllocator final : public KInitialPageTable::IPageAllocator {
|
||||||
|
private:
|
||||||
|
static constexpr inline size_t FreeUnitSize = BITSIZEOF(u64) * PageSize;
|
||||||
|
struct FreeListEntry {
|
||||||
|
FreeListEntry *next;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
public:
|
public:
|
||||||
struct State {
|
struct State {
|
||||||
uintptr_t next_address;
|
uintptr_t start_address;
|
||||||
uintptr_t free_bitmap;
|
uintptr_t end_address;
|
||||||
|
FreeListEntry *free_head;
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
State m_state;
|
State m_state;
|
||||||
@@ -685,8 +722,8 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
constexpr ALWAYS_INLINE KInitialPageAllocator() : m_state{} { /* ... */ }
|
constexpr ALWAYS_INLINE KInitialPageAllocator() : m_state{} { /* ... */ }
|
||||||
|
|
||||||
ALWAYS_INLINE void Initialize(uintptr_t address) {
|
ALWAYS_INLINE void Initialize(uintptr_t address) {
|
||||||
m_state.next_address = address + BITSIZEOF(m_state.free_bitmap) * PageSize;
|
m_state.start_address = address;
|
||||||
m_state.free_bitmap = ~uintptr_t();
|
m_state.end_address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void InitializeFromState(uintptr_t state_val) {
|
ALWAYS_INLINE void InitializeFromState(uintptr_t state_val) {
|
||||||
@@ -697,28 +734,134 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
*out = m_state;
|
*out = m_state;
|
||||||
m_state = {};
|
m_state = {};
|
||||||
}
|
}
|
||||||
public:
|
private:
|
||||||
virtual KPhysicalAddress Allocate() override {
|
bool CanAllocate(size_t align, size_t size) const {
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(m_state.next_address != Null<uintptr_t>);
|
for (auto *cur = m_state.free_head; cur != nullptr; cur = cur->next) {
|
||||||
uintptr_t allocated = m_state.next_address;
|
const uintptr_t cur_last = reinterpret_cast<uintptr_t>(cur) + cur->size - 1;
|
||||||
if (m_state.free_bitmap != 0) {
|
const uintptr_t alloc_last = util::AlignUp(reinterpret_cast<uintptr_t>(cur), align) + size - 1;
|
||||||
u64 index;
|
if (alloc_last <= cur_last) {
|
||||||
uintptr_t mask;
|
return true;
|
||||||
do {
|
}
|
||||||
index = KSystemControl::Init::GenerateRandomRange(0, BITSIZEOF(m_state.free_bitmap) - 1);
|
|
||||||
mask = (static_cast<uintptr_t>(1) << index);
|
|
||||||
} while ((m_state.free_bitmap & mask) == 0);
|
|
||||||
m_state.free_bitmap &= ~mask;
|
|
||||||
allocated = m_state.next_address - ((BITSIZEOF(m_state.free_bitmap) - index) * PageSize);
|
|
||||||
} else {
|
|
||||||
m_state.next_address += PageSize;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
ClearPhysicalMemory(allocated, PageSize);
|
|
||||||
return allocated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No need to override free. The default does nothing, and so would we. */
|
bool TryAllocate(uintptr_t address, size_t size) {
|
||||||
|
/* Try to allocate the region. */
|
||||||
|
auto **prev_next = std::addressof(m_state.free_head);
|
||||||
|
for (auto *cur = m_state.free_head; cur != nullptr; prev_next = std::addressof(cur->next), cur = cur->next) {
|
||||||
|
const uintptr_t cur_start = reinterpret_cast<uintptr_t>(cur);
|
||||||
|
const uintptr_t cur_last = cur_start + cur->size - 1;
|
||||||
|
if (cur_start <= address && address + size - 1 <= cur_last) {
|
||||||
|
auto *alloc = reinterpret_cast<FreeListEntry *>(address);
|
||||||
|
|
||||||
|
/* Perform fragmentation at front. */
|
||||||
|
if (cur != alloc) {
|
||||||
|
prev_next = std::addressof(cur->next);
|
||||||
|
*alloc = {
|
||||||
|
.next = cur->next,
|
||||||
|
.size = cur_start + cur->size - address,
|
||||||
|
};
|
||||||
|
*cur = {
|
||||||
|
.next = alloc,
|
||||||
|
.size = address - cur_start,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform fragmentation at tail. */
|
||||||
|
if (alloc->size != size) {
|
||||||
|
auto *next = reinterpret_cast<FreeListEntry *>(address + size);
|
||||||
|
*next = {
|
||||||
|
.next = alloc->next,
|
||||||
|
.size = alloc->size - size,
|
||||||
|
};
|
||||||
|
*alloc = {
|
||||||
|
.next = next,
|
||||||
|
.size = size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
*prev_next = alloc->next;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
KPhysicalAddress Allocate(size_t align, size_t size) {
|
||||||
|
/* Ensure that the free list is non-empty. */
|
||||||
|
while (!this->CanAllocate(align, size)) {
|
||||||
|
this->Free(m_state.end_address, FreeUnitSize);
|
||||||
|
m_state.end_address += FreeUnitSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a random address. */
|
||||||
|
const uintptr_t aligned_start = util::AlignUp(m_state.start_address, align);
|
||||||
|
const uintptr_t aligned_end = util::AlignDown(m_state.end_address, align);
|
||||||
|
const size_t ind_max = ((aligned_end - aligned_start) / align) - 1;
|
||||||
|
while (true) {
|
||||||
|
if (const uintptr_t random_address = aligned_start + (KSystemControl::Init::GenerateRandomRange(0, ind_max) * align); this->TryAllocate(random_address, size)) {
|
||||||
|
return random_address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual KPhysicalAddress Allocate(size_t size) override {
|
||||||
|
return this->Allocate(size, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Free(KPhysicalAddress phys_addr, size_t size) override {
|
||||||
|
auto **prev_next = std::addressof(m_state.free_head);
|
||||||
|
auto *new_chunk = reinterpret_cast<FreeListEntry *>(GetInteger(phys_addr));
|
||||||
|
if (auto *cur = m_state.free_head; cur != nullptr) {
|
||||||
|
const uintptr_t new_start = reinterpret_cast<uintptr_t>(new_chunk);
|
||||||
|
const uintptr_t new_end = GetInteger(phys_addr) + size;
|
||||||
|
while (true) {
|
||||||
|
/* Attempt coalescing. */
|
||||||
|
const uintptr_t cur_start = reinterpret_cast<uintptr_t>(cur);
|
||||||
|
const uintptr_t cur_end = cur_start + cur->size;
|
||||||
|
if (new_start < new_end) {
|
||||||
|
if (new_end < cur_start) {
|
||||||
|
*new_chunk = {
|
||||||
|
.next = cur,
|
||||||
|
.size = size,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
} else if (new_end == cur_start) {
|
||||||
|
*new_chunk = {
|
||||||
|
.next = cur->next,
|
||||||
|
.size = cur->size + size,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (cur_end == new_start) {
|
||||||
|
cur->size += size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_next = std::addressof(cur->next);
|
||||||
|
if (cur->next != nullptr) {
|
||||||
|
cur = cur->next;
|
||||||
|
} else {
|
||||||
|
*new_chunk = {
|
||||||
|
.next = nullptr,
|
||||||
|
.size = size,
|
||||||
|
};
|
||||||
|
cur->next = new_chunk;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
*new_chunk = {
|
||||||
|
.next = nullptr,
|
||||||
|
.size = size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
*prev_next = new_chunk;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* TODO: Different header for this? */
|
||||||
|
#define AMS_KERN_NUM_SUPERVISOR_CALLS 0xC0
|
||||||
|
|
||||||
|
/* ams::kern::KThread::StackParameters, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp */
|
||||||
|
#define THREAD_STACK_PARAMETERS_SIZE 0x30
|
||||||
|
#define THREAD_STACK_PARAMETERS_SVC_PERMISSION 0x00
|
||||||
|
#define THREAD_STACK_PARAMETERS_CONTEXT 0x18
|
||||||
|
#define THREAD_STACK_PARAMETERS_CUR_THREAD 0x20
|
||||||
|
#define THREAD_STACK_PARAMETERS_DISABLE_COUNT 0x28
|
||||||
|
#define THREAD_STACK_PARAMETERS_DPC_FLAGS 0x2A
|
||||||
|
#define THREAD_STACK_PARAMETERS_CURRENT_SVC_ID 0x2B
|
||||||
|
#define THREAD_STACK_PARAMETERS_IS_CALLING_SVC 0x2C
|
||||||
|
#define THREAD_STACK_PARAMETERS_IS_IN_EXCEPTION_HANDLER 0x2D
|
||||||
|
#define THREAD_STACK_PARAMETERS_IS_PINNED 0x2E
|
||||||
|
|
||||||
|
/* ams::kern::arch::arm64::KThreadContext, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_thread_context.hpp */
|
||||||
|
#define THREAD_CONTEXT_SIZE 0x290
|
||||||
|
#define THREAD_CONTEXT_CPU_REGISTERS 0x000
|
||||||
|
#define THREAD_CONTEXT_X19 0x000
|
||||||
|
#define THREAD_CONTEXT_X20 0x008
|
||||||
|
#define THREAD_CONTEXT_X21 0x010
|
||||||
|
#define THREAD_CONTEXT_X22 0x018
|
||||||
|
#define THREAD_CONTEXT_X23 0x020
|
||||||
|
#define THREAD_CONTEXT_X24 0x028
|
||||||
|
#define THREAD_CONTEXT_X25 0x030
|
||||||
|
#define THREAD_CONTEXT_X26 0x038
|
||||||
|
#define THREAD_CONTEXT_X27 0x040
|
||||||
|
#define THREAD_CONTEXT_X28 0x048
|
||||||
|
#define THREAD_CONTEXT_X29 0x050
|
||||||
|
#define THREAD_CONTEXT_LR 0x058
|
||||||
|
#define THREAD_CONTEXT_SP 0x060
|
||||||
|
#define THREAD_CONTEXT_CPACR 0x068
|
||||||
|
#define THREAD_CONTEXT_FPCR 0x070
|
||||||
|
#define THREAD_CONTEXT_FPSR 0x078
|
||||||
|
#define THREAD_CONTEXT_FPU_REGISTERS 0x080
|
||||||
|
#define THREAD_CONTEXT_LOCKED 0x280
|
||||||
|
|
||||||
|
#define THREAD_CONTEXT_X19_X20 THREAD_CONTEXT_X19
|
||||||
|
#define THREAD_CONTEXT_X21_X22 THREAD_CONTEXT_X21
|
||||||
|
#define THREAD_CONTEXT_X23_X24 THREAD_CONTEXT_X23
|
||||||
|
#define THREAD_CONTEXT_X25_X26 THREAD_CONTEXT_X25
|
||||||
|
#define THREAD_CONTEXT_X27_X28 THREAD_CONTEXT_X27
|
||||||
|
#define THREAD_CONTEXT_X29_X30 THREAD_CONTEXT_X29
|
||||||
|
#define THREAD_CONTEXT_LR_SP THREAD_CONTEXT_LR
|
||||||
|
#define THREAD_CONTEXT_SP_CPACR THREAD_CONTEXT_SP
|
||||||
|
#define THREAD_CONTEXT_FPCR_FPSR THREAD_CONTEXT_FPCR
|
||||||
|
|
||||||
|
/* ams::kern::arch::arm64::KExceptionContext, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_exception_context.hpp */
|
||||||
|
#define EXCEPTION_CONTEXT_SIZE 0x120
|
||||||
|
#define EXCEPTION_CONTEXT_X0 0x000
|
||||||
|
#define EXCEPTION_CONTEXT_X1 0x008
|
||||||
|
#define EXCEPTION_CONTEXT_X2 0x010
|
||||||
|
#define EXCEPTION_CONTEXT_X3 0x018
|
||||||
|
#define EXCEPTION_CONTEXT_X4 0x020
|
||||||
|
#define EXCEPTION_CONTEXT_X5 0x028
|
||||||
|
#define EXCEPTION_CONTEXT_X6 0x030
|
||||||
|
#define EXCEPTION_CONTEXT_X7 0x038
|
||||||
|
#define EXCEPTION_CONTEXT_X8 0x040
|
||||||
|
#define EXCEPTION_CONTEXT_X9 0x048
|
||||||
|
#define EXCEPTION_CONTEXT_X10 0x050
|
||||||
|
#define EXCEPTION_CONTEXT_X11 0x058
|
||||||
|
#define EXCEPTION_CONTEXT_X12 0x060
|
||||||
|
#define EXCEPTION_CONTEXT_X13 0x068
|
||||||
|
#define EXCEPTION_CONTEXT_X14 0x070
|
||||||
|
#define EXCEPTION_CONTEXT_X15 0x078
|
||||||
|
#define EXCEPTION_CONTEXT_X16 0x080
|
||||||
|
#define EXCEPTION_CONTEXT_X17 0x088
|
||||||
|
#define EXCEPTION_CONTEXT_X18 0x090
|
||||||
|
#define EXCEPTION_CONTEXT_X19 0x098
|
||||||
|
#define EXCEPTION_CONTEXT_X20 0x0A0
|
||||||
|
#define EXCEPTION_CONTEXT_X21 0x0A8
|
||||||
|
#define EXCEPTION_CONTEXT_X22 0x0B0
|
||||||
|
#define EXCEPTION_CONTEXT_X23 0x0B8
|
||||||
|
#define EXCEPTION_CONTEXT_X24 0x0C0
|
||||||
|
#define EXCEPTION_CONTEXT_X25 0x0C8
|
||||||
|
#define EXCEPTION_CONTEXT_X26 0x0D0
|
||||||
|
#define EXCEPTION_CONTEXT_X27 0x0D8
|
||||||
|
#define EXCEPTION_CONTEXT_X28 0x0E0
|
||||||
|
#define EXCEPTION_CONTEXT_X29 0x0E8
|
||||||
|
#define EXCEPTION_CONTEXT_X30 0x0F0
|
||||||
|
#define EXCEPTION_CONTEXT_SP 0x0F8
|
||||||
|
#define EXCEPTION_CONTEXT_PC 0x100
|
||||||
|
#define EXCEPTION_CONTEXT_PSR 0x108
|
||||||
|
#define EXCEPTION_CONTEXT_TPIDR 0x110
|
||||||
|
|
||||||
|
#define EXCEPTION_CONTEXT_X0_X1 EXCEPTION_CONTEXT_X0
|
||||||
|
#define EXCEPTION_CONTEXT_X2_X3 EXCEPTION_CONTEXT_X2
|
||||||
|
#define EXCEPTION_CONTEXT_X4_X5 EXCEPTION_CONTEXT_X4
|
||||||
|
#define EXCEPTION_CONTEXT_X6_X7 EXCEPTION_CONTEXT_X6
|
||||||
|
#define EXCEPTION_CONTEXT_X8_X9 EXCEPTION_CONTEXT_X8
|
||||||
|
#define EXCEPTION_CONTEXT_X10_X11 EXCEPTION_CONTEXT_X10
|
||||||
|
#define EXCEPTION_CONTEXT_X12_X13 EXCEPTION_CONTEXT_X12
|
||||||
|
#define EXCEPTION_CONTEXT_X14_X15 EXCEPTION_CONTEXT_X14
|
||||||
|
#define EXCEPTION_CONTEXT_X16_X17 EXCEPTION_CONTEXT_X16
|
||||||
|
#define EXCEPTION_CONTEXT_X18_X19 EXCEPTION_CONTEXT_X18
|
||||||
|
#define EXCEPTION_CONTEXT_X20_X21 EXCEPTION_CONTEXT_X20
|
||||||
|
#define EXCEPTION_CONTEXT_X22_X23 EXCEPTION_CONTEXT_X22
|
||||||
|
#define EXCEPTION_CONTEXT_X24_X25 EXCEPTION_CONTEXT_X24
|
||||||
|
#define EXCEPTION_CONTEXT_X26_X27 EXCEPTION_CONTEXT_X26
|
||||||
|
#define EXCEPTION_CONTEXT_X28_X29 EXCEPTION_CONTEXT_X28
|
||||||
|
#define EXCEPTION_CONTEXT_X30_SP EXCEPTION_CONTEXT_X30
|
||||||
|
#define EXCEPTION_CONTEXT_PC_PSR EXCEPTION_CONTEXT_PC
|
||||||
|
|
||||||
|
#define EXCEPTION_CONTEXT_X9_X10 EXCEPTION_CONTEXT_X9
|
||||||
|
#define EXCEPTION_CONTEXT_X19_X20 EXCEPTION_CONTEXT_X19
|
||||||
|
#define EXCEPTION_CONTEXT_X21_X22 EXCEPTION_CONTEXT_X21
|
||||||
|
#define EXCEPTION_CONTEXT_X23_X24 EXCEPTION_CONTEXT_X23
|
||||||
|
#define EXCEPTION_CONTEXT_X25_X26 EXCEPTION_CONTEXT_X25
|
||||||
|
#define EXCEPTION_CONTEXT_X27_X28 EXCEPTION_CONTEXT_X27
|
||||||
|
#define EXCEPTION_CONTEXT_X29_X30 EXCEPTION_CONTEXT_X29
|
||||||
|
#define EXCEPTION_CONTEXT_SP_PC EXCEPTION_CONTEXT_SP
|
||||||
|
#define EXCEPTION_CONTEXT_PSR_TPIDR EXCEPTION_CONTEXT_PSR
|
||||||
|
|
||||||
|
/* ams::svc::arch::arm64::ThreadLocalRegion, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libvapours/include/vapours/svc/arch/arm64/svc_thread_local_region.hpp */
|
||||||
|
#define THREAD_LOCAL_REGION_MESSAGE_BUFFER 0x000
|
||||||
|
#define THREAD_LOCAL_REGION_DISABLE_COUNT 0x100
|
||||||
|
#define THREAD_LOCAL_REGION_INTERRUPT_FLAG 0x102
|
||||||
|
#define THREAD_LOCAL_REGION_SIZE 0x200
|
||||||
|
|
||||||
|
/* ams::kern::init::KInitArguments, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_arguments.hpp */
|
||||||
|
#define INIT_ARGUMENTS_SIZE 0x60
|
||||||
|
#define INIT_ARGUMENTS_TTBR0 0x00
|
||||||
|
#define INIT_ARGUMENTS_TTBR1 0x08
|
||||||
|
#define INIT_ARGUMENTS_TCR 0x10
|
||||||
|
#define INIT_ARGUMENTS_MAIR 0x18
|
||||||
|
#define INIT_ARGUMENTS_CPUACTLR 0x20
|
||||||
|
#define INIT_ARGUMENTS_CPUECTLR 0x28
|
||||||
|
#define INIT_ARGUMENTS_SCTLR 0x30
|
||||||
|
#define INIT_ARGUMENTS_SP 0x38
|
||||||
|
#define INIT_ARGUMENTS_ENTRYPOINT 0x40
|
||||||
|
#define INIT_ARGUMENTS_ARGUMENT 0x48
|
||||||
|
#define INIT_ARGUMENTS_SETUP_FUNCTION 0x50
|
||||||
|
#define INIT_ARGUMENTS_EXCEPTION_STACK 0x58
|
||||||
|
|
||||||
|
/* ams::kern::KScheduler (::SchedulingState), https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp */
|
||||||
|
/* NOTE: Due to constraints on ldarb relative offsets, KSCHEDULER_NEEDS_SCHEDULING cannot trivially be changed, and will require assembly edits. */
|
||||||
|
#define KSCHEDULER_NEEDS_SCHEDULING 0x00
|
||||||
|
#define KSCHEDULER_INTERRUPT_TASK_THREAD_RUNNABLE 0x01
|
||||||
|
#define KSCHEDULER_HIGHEST_PRIORITY_THREAD 0x10
|
||||||
|
#define KSCHEDULER_IDLE_THREAD_STACK 0x18
|
||||||
@@ -232,7 +232,7 @@ namespace ams::kern::arch::arm64::cpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void SetExceptionThreadStackTop(uintptr_t top) {
|
ALWAYS_INLINE void SetExceptionThreadStackTop(uintptr_t top) {
|
||||||
SetTpidrEl1(top);
|
cpu::SetCntvCvalEl0(top);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void SwitchThreadLocalRegion(uintptr_t tlr) {
|
ALWAYS_INLINE void SwitchThreadLocalRegion(uintptr_t tlr) {
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ namespace ams::kern::arch::arm64::cpu {
|
|||||||
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntkCtlEl1, cntkctl_el1)
|
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntkCtlEl1, cntkctl_el1)
|
||||||
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntpCtlEl0, cntp_ctl_el0)
|
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntpCtlEl0, cntp_ctl_el0)
|
||||||
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntpCvalEl0, cntp_cval_el0)
|
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntpCvalEl0, cntp_cval_el0)
|
||||||
|
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntvCvalEl0, cntv_cval_el0)
|
||||||
|
|
||||||
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Daif, daif)
|
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Daif, daif)
|
||||||
|
|
||||||
@@ -197,6 +198,11 @@ namespace ams::kern::arch::arm64::cpu {
|
|||||||
public:
|
public:
|
||||||
MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(TranslationControl, tcr_el1)
|
MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(TranslationControl, tcr_el1)
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE size_t GetT0Size() const {
|
||||||
|
const size_t shift_value = this->GetBits(0, 6);
|
||||||
|
return size_t(1) << (size_t(64) - shift_value);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE size_t GetT1Size() const {
|
constexpr ALWAYS_INLINE size_t GetT1Size() const {
|
||||||
const size_t shift_value = this->GetBits(16, 6);
|
const size_t shift_value = this->GetBits(16, 6);
|
||||||
return size_t(1) << (size_t(64) - shift_value);
|
return size_t(1) << (size_t(64) - shift_value);
|
||||||
|
|||||||
@@ -43,6 +43,42 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static_assert(sizeof(KExceptionContext) == 0x120);
|
static_assert(sizeof(KExceptionContext) == EXCEPTION_CONTEXT_SIZE);
|
||||||
|
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[ 0]) == EXCEPTION_CONTEXT_X0);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[ 1]) == EXCEPTION_CONTEXT_X1);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[ 2]) == EXCEPTION_CONTEXT_X2);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[ 3]) == EXCEPTION_CONTEXT_X3);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[ 4]) == EXCEPTION_CONTEXT_X4);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[ 5]) == EXCEPTION_CONTEXT_X5);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[ 6]) == EXCEPTION_CONTEXT_X6);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[ 7]) == EXCEPTION_CONTEXT_X7);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[ 8]) == EXCEPTION_CONTEXT_X8);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[ 9]) == EXCEPTION_CONTEXT_X9);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[10]) == EXCEPTION_CONTEXT_X10);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[11]) == EXCEPTION_CONTEXT_X11);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[12]) == EXCEPTION_CONTEXT_X12);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[13]) == EXCEPTION_CONTEXT_X13);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[14]) == EXCEPTION_CONTEXT_X14);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[15]) == EXCEPTION_CONTEXT_X15);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[16]) == EXCEPTION_CONTEXT_X16);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[17]) == EXCEPTION_CONTEXT_X17);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[18]) == EXCEPTION_CONTEXT_X18);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[19]) == EXCEPTION_CONTEXT_X19);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[20]) == EXCEPTION_CONTEXT_X20);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[21]) == EXCEPTION_CONTEXT_X21);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[22]) == EXCEPTION_CONTEXT_X22);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[23]) == EXCEPTION_CONTEXT_X23);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[24]) == EXCEPTION_CONTEXT_X24);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[25]) == EXCEPTION_CONTEXT_X25);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[26]) == EXCEPTION_CONTEXT_X26);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[27]) == EXCEPTION_CONTEXT_X27);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[28]) == EXCEPTION_CONTEXT_X28);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[29]) == EXCEPTION_CONTEXT_X29);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, x[30]) == EXCEPTION_CONTEXT_X30);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, sp) == EXCEPTION_CONTEXT_SP);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, pc) == EXCEPTION_CONTEXT_PC);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, psr) == EXCEPTION_CONTEXT_PSR);
|
||||||
|
static_assert(__builtin_offsetof(KExceptionContext, tpidr) == EXCEPTION_CONTEXT_TPIDR);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,6 @@ namespace ams::kern::arch::arm64 {
|
|||||||
NOINLINE Result BindHandler(KInterruptHandler *handler, s32 irq, s32 core_id, s32 priority, bool manual_clear, bool level);
|
NOINLINE Result BindHandler(KInterruptHandler *handler, s32 irq, s32 core_id, s32 priority, bool manual_clear, bool level);
|
||||||
NOINLINE Result UnbindHandler(s32 irq, s32 core);
|
NOINLINE Result UnbindHandler(s32 irq, s32 core);
|
||||||
|
|
||||||
NOINLINE Result ClearInterrupt(s32 irq);
|
|
||||||
NOINLINE Result ClearInterrupt(s32 irq, s32 core_id);
|
NOINLINE Result ClearInterrupt(s32 irq, s32 core_id);
|
||||||
|
|
||||||
ALWAYS_INLINE void SendInterProcessorInterrupt(s32 irq, u64 core_mask) {
|
ALWAYS_INLINE void SendInterProcessorInterrupt(s32 irq, u64 core_mask) {
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
|
NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
|
||||||
NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager);
|
NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit);
|
||||||
Result Finalize();
|
Result Finalize();
|
||||||
private:
|
private:
|
||||||
Result MapL1Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
Result MapL1Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
||||||
|
|||||||
@@ -30,12 +30,16 @@ namespace ams::kern::arch::arm64 {
|
|||||||
m_page_table.Activate(id);
|
m_page_table.Activate(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Initialize(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager) {
|
Result Initialize(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit) {
|
||||||
return m_page_table.InitializeForProcess(id, as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, mem_block_slab_manager, block_info_manager, pt_manager);
|
return m_page_table.InitializeForProcess(id, as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, mem_block_slab_manager, block_info_manager, pt_manager, resource_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Finalize() { m_page_table.Finalize(); }
|
void Finalize() { m_page_table.Finalize(); }
|
||||||
|
|
||||||
|
ALWAYS_INLINE KScopedLightLock AcquireDeviceMapLock() {
|
||||||
|
return m_page_table.AcquireDeviceMapLock();
|
||||||
|
}
|
||||||
|
|
||||||
Result SetMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission perm) {
|
Result SetMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission perm) {
|
||||||
return m_page_table.SetMemoryPermission(addr, size, perm);
|
return m_page_table.SetMemoryPermission(addr, size, perm);
|
||||||
}
|
}
|
||||||
@@ -136,26 +140,42 @@ namespace ams::kern::arch::arm64 {
|
|||||||
return m_page_table.ReadDebugMemory(buffer, address, size);
|
return m_page_table.ReadDebugMemory(buffer, address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size) {
|
||||||
|
return m_page_table.ReadDebugIoMemory(buffer, address, size);
|
||||||
|
}
|
||||||
|
|
||||||
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size) {
|
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size) {
|
||||||
return m_page_table.WriteDebugMemory(address, buffer, size);
|
return m_page_table.WriteDebugMemory(address, buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LockForDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
|
Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size) {
|
||||||
return m_page_table.LockForDeviceAddressSpace(out, address, size, perm, is_aligned);
|
return m_page_table.WriteDebugIoMemory(address, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LockForMapDeviceAddressSpace(KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
|
||||||
|
return m_page_table.LockForMapDeviceAddressSpace(address, size, perm, is_aligned);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size) {
|
||||||
|
return m_page_table.LockForUnmapDeviceAddressSpace(address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size) {
|
Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size) {
|
||||||
return m_page_table.UnlockForDeviceAddressSpace(address, size);
|
return m_page_table.UnlockForDeviceAddressSpace(address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MakePageGroupForUnmapDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size) {
|
|
||||||
return m_page_table.MakePageGroupForUnmapDeviceAddressSpace(out, address, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result UnlockForDeviceAddressSpacePartialMap(KProcessAddress address, size_t size, size_t mapped_size) {
|
Result UnlockForDeviceAddressSpacePartialMap(KProcessAddress address, size_t size, size_t mapped_size) {
|
||||||
return m_page_table.UnlockForDeviceAddressSpacePartialMap(address, size, mapped_size);
|
return m_page_table.UnlockForDeviceAddressSpacePartialMap(address, size, mapped_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result OpenMemoryRangeForMapDeviceAddressSpace(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
|
||||||
|
return m_page_table.OpenMemoryRangeForMapDeviceAddressSpace(out, address, size, perm, is_aligned);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result OpenMemoryRangeForUnmapDeviceAddressSpace(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size) {
|
||||||
|
return m_page_table.OpenMemoryRangeForUnmapDeviceAddressSpace(out, address, size);
|
||||||
|
}
|
||||||
|
|
||||||
Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size) {
|
Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size) {
|
||||||
return m_page_table.LockForIpcUserBuffer(out, address, size);
|
return m_page_table.LockForIpcUserBuffer(out, address, size);
|
||||||
}
|
}
|
||||||
@@ -180,6 +200,10 @@ namespace ams::kern::arch::arm64 {
|
|||||||
return m_page_table.UnlockForCodeMemory(address, size, pg);
|
return m_page_table.UnlockForCodeMemory(address, size, pg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result OpenMemoryRangeForProcessCacheOperation(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size) {
|
||||||
|
return m_page_table.OpenMemoryRangeForProcessCacheOperation(out, address, size);
|
||||||
|
}
|
||||||
|
|
||||||
Result CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) {
|
Result CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) {
|
||||||
return m_page_table.CopyMemoryFromLinearToUser(dst_addr, size, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr);
|
return m_page_table.CopyMemoryFromLinearToUser(dst_addr, size, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr);
|
||||||
}
|
}
|
||||||
@@ -208,8 +232,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
return m_page_table.SetupForIpc(out_dst_addr, size, src_addr, src_page_table.m_page_table, test_perm, dst_state, send);
|
return m_page_table.SetupForIpc(out_dst_addr, size, src_addr, src_page_table.m_page_table, test_perm, dst_state, send);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state, KProcess *server_process) {
|
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state) {
|
||||||
return m_page_table.CleanupForIpcServer(address, size, dst_state, server_process);
|
return m_page_table.CleanupForIpcServer(address, size, dst_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state) {
|
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state) {
|
||||||
@@ -232,6 +256,10 @@ namespace ams::kern::arch::arm64 {
|
|||||||
return m_page_table.UnmapPhysicalMemoryUnsafe(address, size);
|
return m_page_table.UnmapPhysicalMemoryUnsafe(address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result UnmapProcessMemory(KProcessAddress dst_address, size_t size, KProcessPageTable &src_page_table, KProcessAddress src_address) {
|
||||||
|
return m_page_table.UnmapProcessMemory(dst_address, size, src_page_table.m_page_table, src_address);
|
||||||
|
}
|
||||||
|
|
||||||
void DumpMemoryBlocks() const {
|
void DumpMemoryBlocks() const {
|
||||||
return m_page_table.DumpMemoryBlocks();
|
return m_page_table.DumpMemoryBlocks();
|
||||||
}
|
}
|
||||||
@@ -290,6 +318,10 @@ namespace ams::kern::arch::arm64 {
|
|||||||
KBlockInfoManager *GetBlockInfoManager() {
|
KBlockInfoManager *GetBlockInfoManager() {
|
||||||
return m_page_table.GetBlockInfoManager();
|
return m_page_table.GetBlockInfoManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KPageTableBase &GetBasePageTable() {
|
||||||
|
return m_page_table;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,8 +79,38 @@ namespace ams::kern::arch::arm64 {
|
|||||||
const u128 *GetFpuRegisters() const { return m_fpu_registers; }
|
const u128 *GetFpuRegisters() const { return m_fpu_registers; }
|
||||||
public:
|
public:
|
||||||
static void OnThreadTerminating(const KThread *thread);
|
static void OnThreadTerminating(const KThread *thread);
|
||||||
|
public:
|
||||||
|
static consteval bool ValidateOffsets();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
consteval bool KThreadContext::ValidateOffsets() {
|
||||||
|
static_assert(sizeof(KThreadContext) == THREAD_CONTEXT_SIZE);
|
||||||
|
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.registers) == THREAD_CONTEXT_CPU_REGISTERS);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x19) == THREAD_CONTEXT_X19);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x20) == THREAD_CONTEXT_X20);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x21) == THREAD_CONTEXT_X21);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x22) == THREAD_CONTEXT_X22);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x23) == THREAD_CONTEXT_X23);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x24) == THREAD_CONTEXT_X24);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x25) == THREAD_CONTEXT_X25);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x26) == THREAD_CONTEXT_X26);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x27) == THREAD_CONTEXT_X27);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x28) == THREAD_CONTEXT_X28);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x29) == THREAD_CONTEXT_X29);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_lr) == THREAD_CONTEXT_LR);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_sp) == THREAD_CONTEXT_SP);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_cpacr) == THREAD_CONTEXT_CPACR);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_fpcr) == THREAD_CONTEXT_FPCR);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_fpsr) == THREAD_CONTEXT_FPSR);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_fpu_registers) == THREAD_CONTEXT_FPU_REGISTERS);
|
||||||
|
static_assert(__builtin_offsetof(KThreadContext, m_locked) == THREAD_CONTEXT_LOCKED);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static_assert(KThreadContext::ValidateOffsets());
|
||||||
|
|
||||||
|
|
||||||
void GetUserContext(ams::svc::ThreadContext *out, const KThread *thread);
|
void GetUserContext(ams::svc::ThreadContext *out, const KThread *thread);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -69,8 +69,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
Result Attach(ams::svc::DeviceName device_name, u64 space_address, u64 space_size);
|
Result Attach(ams::svc::DeviceName device_name, u64 space_address, u64 space_size);
|
||||||
Result Detach(ams::svc::DeviceName device_name);
|
Result Detach(ams::svc::DeviceName device_name);
|
||||||
|
|
||||||
Result Map(size_t *out_mapped_size, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings);
|
Result Map(size_t *out_mapped_size, KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings);
|
||||||
Result Unmap(const KPageGroup &pg, KDeviceVirtualAddress device_address);
|
Result Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address);
|
||||||
|
|
||||||
void Unmap(KDeviceVirtualAddress device_address, size_t size) {
|
void Unmap(KDeviceVirtualAddress device_address, size_t size) {
|
||||||
return this->UnmapImpl(device_address, size, false);
|
return this->UnmapImpl(device_address, size, false);
|
||||||
@@ -78,12 +78,11 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
private:
|
private:
|
||||||
Result MapDevicePage(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, KPhysicalAddress phys_addr, u64 size, KDeviceVirtualAddress address, ams::svc::MemoryPermission device_perm);
|
Result MapDevicePage(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, KPhysicalAddress phys_addr, u64 size, KDeviceVirtualAddress address, ams::svc::MemoryPermission device_perm);
|
||||||
|
|
||||||
Result MapImpl(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm);
|
Result MapImpl(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned);
|
||||||
void UnmapImpl(KDeviceVirtualAddress address, u64 size, bool force);
|
void UnmapImpl(KDeviceVirtualAddress address, u64 size, bool force);
|
||||||
|
|
||||||
bool IsFree(KDeviceVirtualAddress address, u64 size) const;
|
bool IsFree(KDeviceVirtualAddress address, u64 size) const;
|
||||||
Result MakePageGroup(KPageGroup *out, KDeviceVirtualAddress address, u64 size) const;
|
bool Compare(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address) const;
|
||||||
bool Compare(const KPageGroup &pg, KDeviceVirtualAddress device_address) const;
|
|
||||||
public:
|
public:
|
||||||
static void Initialize();
|
static void Initialize();
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
/* Initialization. */
|
/* Initialization. */
|
||||||
static size_t GetIntendedMemorySize();
|
static size_t GetIntendedMemorySize();
|
||||||
static KPhysicalAddress GetKernelPhysicalBaseAddress(uintptr_t base_address);
|
static KPhysicalAddress GetKernelPhysicalBaseAddress(uintptr_t base_address);
|
||||||
|
static KPhysicalAddress GetInitialProcessBinaryPhysicalAddress();
|
||||||
static bool ShouldIncreaseThreadResourceLimit();
|
static bool ShouldIncreaseThreadResourceLimit();
|
||||||
static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
||||||
static size_t GetApplicationPoolSize();
|
static size_t GetApplicationPoolSize();
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace ams::kern::init {
|
|||||||
u32 rw_end_offset;
|
u32 rw_end_offset;
|
||||||
u32 bss_offset;
|
u32 bss_offset;
|
||||||
u32 bss_end_offset;
|
u32 bss_end_offset;
|
||||||
u32 ini_load_offset;
|
u32 resource_offset;
|
||||||
u32 dynamic_offset;
|
u32 dynamic_offset;
|
||||||
u32 init_array_offset;
|
u32 init_array_offset;
|
||||||
u32 init_array_end_offset;
|
u32 init_array_end_offset;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <vapours.hpp>
|
#include <vapours.hpp>
|
||||||
#include <mesosphere/kern_build_config.hpp>
|
#include <mesosphere/kern_build_config.hpp>
|
||||||
#include <mesosphere/svc/kern_svc_results.hpp>
|
#include <mesosphere/svc/kern_svc_results.hpp>
|
||||||
|
#include <mesosphere/kern_select_assembly_offsets.h>
|
||||||
|
|
||||||
namespace ams::kern {
|
namespace ams::kern {
|
||||||
|
|
||||||
|
|||||||
@@ -29,11 +29,14 @@ namespace ams::kern {
|
|||||||
u32 reserved;
|
u32 reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
NOINLINE void CopyInitialProcessBinaryToKernelMemory();
|
NOINLINE size_t CopyInitialProcessBinaryToKernelMemory();
|
||||||
NOINLINE void CreateAndRunInitialProcesses();
|
NOINLINE void CreateAndRunInitialProcesses();
|
||||||
|
|
||||||
u64 GetInitialProcessIdMin();
|
u64 GetInitialProcessIdMin();
|
||||||
u64 GetInitialProcessIdMax();
|
u64 GetInitialProcessIdMax();
|
||||||
|
KVirtualAddress GetInitialProcessBinaryAddress();
|
||||||
size_t GetInitialProcessesSecureMemorySize();
|
size_t GetInitialProcessesSecureMemorySize();
|
||||||
|
|
||||||
|
void LoadInitialProcessBinaryHeaderDeprecated(KPhysicalAddress pool_end);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,11 +69,12 @@ namespace ams::kern {
|
|||||||
private:
|
private:
|
||||||
MESOSPHERE_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
|
MESOSPHERE_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
|
||||||
private:
|
private:
|
||||||
|
KAutoObject *m_next_closed_object;
|
||||||
std::atomic<u32> m_ref_count;
|
std::atomic<u32> m_ref_count;
|
||||||
public:
|
public:
|
||||||
static KAutoObject *Create(KAutoObject *ptr);
|
static KAutoObject *Create(KAutoObject *ptr);
|
||||||
public:
|
public:
|
||||||
constexpr ALWAYS_INLINE explicit KAutoObject() : m_ref_count(0) { MESOSPHERE_ASSERT_THIS(); }
|
constexpr ALWAYS_INLINE explicit KAutoObject() : m_next_closed_object(nullptr), m_ref_count(0) { MESOSPHERE_ASSERT_THIS(); }
|
||||||
virtual ~KAutoObject() { MESOSPHERE_ASSERT_THIS(); }
|
virtual ~KAutoObject() { MESOSPHERE_ASSERT_THIS(); }
|
||||||
|
|
||||||
/* Destroy is responsible for destroying the auto object's resources when ref_count hits zero. */
|
/* Destroy is responsible for destroying the auto object's resources when ref_count hits zero. */
|
||||||
@@ -120,36 +121,16 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool Open() {
|
bool Open();
|
||||||
MESOSPHERE_ASSERT_THIS();
|
void Close();
|
||||||
|
private:
|
||||||
/* Atomically increment the reference count, only if it's positive. */
|
/* NOTE: This has to be defined *after* KThread is defined. */
|
||||||
u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire);
|
/* Nintendo seems to handle this by defining Open/Close() in a cpp, but we'd like them to remain in headers. */
|
||||||
do {
|
/* Implementation for this will be inside kern_k_thread.hpp, so it can be ALWAYS_INLINE. */
|
||||||
if (AMS_UNLIKELY(cur_ref_count == 0)) {
|
void ScheduleDestruction();
|
||||||
MESOSPHERE_AUDIT(cur_ref_count != 0);
|
public:
|
||||||
return false;
|
/* Getter, for KThread. */
|
||||||
}
|
ALWAYS_INLINE KAutoObject *GetNextClosedObject() { return m_next_closed_object; }
|
||||||
MESOSPHERE_ABORT_UNLESS(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
ALWAYS_INLINE void Close() {
|
|
||||||
MESOSPHERE_ASSERT_THIS();
|
|
||||||
|
|
||||||
/* Atomically decrement the reference count, not allowing it to become negative. */
|
|
||||||
u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire);
|
|
||||||
do {
|
|
||||||
MESOSPHERE_ABORT_UNLESS(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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class KAutoObjectWithListContainer;
|
class KAutoObjectWithListContainer;
|
||||||
@@ -198,7 +179,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~KScopedAutoObject() {
|
ALWAYS_INLINE ~KScopedAutoObject() {
|
||||||
if (m_obj != nullptr) {
|
if (m_obj != nullptr) {
|
||||||
m_obj->Close();
|
m_obj->Close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ namespace ams::kern {
|
|||||||
ALWAYS_INLINE s32 GetMaxSessions() const { return m_max_sessions; }
|
ALWAYS_INLINE s32 GetMaxSessions() const { return m_max_sessions; }
|
||||||
|
|
||||||
bool IsLight() const;
|
bool IsLight() const;
|
||||||
|
bool IsServerClosed() const;
|
||||||
|
|
||||||
/* Overridden virtual functions. */
|
/* Overridden virtual functions. */
|
||||||
virtual void Destroy() override;
|
virtual void Destroy() override;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace ams::kern {
|
|||||||
class KCodeMemory final : public KAutoObjectWithSlabHeapAndContainer<KCodeMemory, KAutoObjectWithList> {
|
class KCodeMemory final : public KAutoObjectWithSlabHeapAndContainer<KCodeMemory, KAutoObjectWithList> {
|
||||||
MESOSPHERE_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject);
|
MESOSPHERE_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject);
|
||||||
private:
|
private:
|
||||||
TYPED_STORAGE(KPageGroup) m_page_group;
|
util::TypedStorage<KPageGroup> m_page_group;
|
||||||
KProcess *m_owner;
|
KProcess *m_owner;
|
||||||
KProcessAddress m_address;
|
KProcessAddress m_address;
|
||||||
KLightLock m_lock;
|
KLightLock m_lock;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace ams::kern {
|
|||||||
void Signal(uintptr_t cv_key, s32 count);
|
void Signal(uintptr_t cv_key, s32 count);
|
||||||
Result Wait(KProcessAddress addr, uintptr_t key, u32 value, s64 timeout);
|
Result Wait(KProcessAddress addr, uintptr_t key, u32 value, s64 timeout);
|
||||||
private:
|
private:
|
||||||
KThread *SignalImpl(KThread *thread);
|
void SignalImpl(KThread *thread);
|
||||||
};
|
};
|
||||||
|
|
||||||
ALWAYS_INLINE void BeforeUpdatePriority(KConditionVariable::ThreadTree *tree, KThread *thread) {
|
ALWAYS_INLINE void BeforeUpdatePriority(KConditionVariable::ThreadTree *tree, KThread *thread) {
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
if (AMS_LIKELY(allocated != nullptr)) {
|
if (AMS_LIKELY(allocated != nullptr)) {
|
||||||
/* Construct the object. */
|
/* Construct the object. */
|
||||||
new (allocated) T();
|
std::construct_at(allocated);
|
||||||
|
|
||||||
/* Update our tracking. */
|
/* Update our tracking. */
|
||||||
size_t used = m_used.fetch_add(1) + 1;
|
size_t used = m_used.fetch_add(1) + 1;
|
||||||
|
|||||||
@@ -53,46 +53,29 @@ namespace ams::kern {
|
|||||||
return pack.Get<HandleEncoded>();
|
return pack.Get<HandleEncoded>();
|
||||||
}
|
}
|
||||||
|
|
||||||
class Entry {
|
union EntryInfo {
|
||||||
private:
|
struct {
|
||||||
union {
|
u16 linear_id;
|
||||||
struct {
|
u16 type;
|
||||||
u16 linear_id;
|
} info;
|
||||||
u16 type;
|
s32 next_free_index;
|
||||||
} info;
|
|
||||||
Entry *next_free_entry;
|
|
||||||
} m_meta;
|
|
||||||
KAutoObject *m_object;
|
|
||||||
public:
|
|
||||||
constexpr Entry() : m_meta(), m_object(nullptr) { /* ... */ }
|
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE void SetFree(Entry *next) {
|
constexpr ALWAYS_INLINE u16 GetLinearId() const { return info.linear_id; }
|
||||||
m_object = nullptr;
|
constexpr ALWAYS_INLINE u16 GetType() const { return info.type; }
|
||||||
m_meta.next_free_entry = next;
|
constexpr ALWAYS_INLINE s32 GetNextFreeIndex() const { return next_free_index; }
|
||||||
}
|
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE void SetUsed(KAutoObject *obj, u16 linear_id, u16 type) {
|
|
||||||
m_object = obj;
|
|
||||||
m_meta.info = { linear_id, type };
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE KAutoObject *GetObject() const { return m_object; }
|
|
||||||
constexpr ALWAYS_INLINE Entry *GetNextFreeEntry() const { return m_meta.next_free_entry; }
|
|
||||||
constexpr ALWAYS_INLINE u16 GetLinearId() const { return m_meta.info.linear_id; }
|
|
||||||
constexpr ALWAYS_INLINE u16 GetType() const { return m_meta.info.type; }
|
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
mutable KSpinLock m_lock;
|
EntryInfo m_entry_infos[MaxTableSize];
|
||||||
Entry *m_table;
|
KAutoObject *m_objects[MaxTableSize];
|
||||||
Entry *m_free_head;
|
s32 m_free_head_index;
|
||||||
Entry m_entries[MaxTableSize];
|
|
||||||
u16 m_table_size;
|
u16 m_table_size;
|
||||||
u16 m_max_count;
|
u16 m_max_count;
|
||||||
u16 m_next_linear_id;
|
u16 m_next_linear_id;
|
||||||
u16 m_count;
|
u16 m_count;
|
||||||
|
mutable KSpinLock m_lock;
|
||||||
public:
|
public:
|
||||||
constexpr KHandleTable() :
|
constexpr KHandleTable() :
|
||||||
m_lock(), m_table(nullptr), m_free_head(nullptr), m_entries(), m_table_size(0), m_max_count(0), m_next_linear_id(MinLinearId), m_count(0)
|
m_entry_infos(), m_objects(), m_free_head_index(-1), m_table_size(0), m_max_count(0), m_next_linear_id(MinLinearId), m_count(0), m_lock()
|
||||||
{ MESOSPHERE_ASSERT_THIS(); }
|
{ MESOSPHERE_ASSERT_THIS(); }
|
||||||
|
|
||||||
constexpr NOINLINE Result Initialize(s32 size) {
|
constexpr NOINLINE Result Initialize(s32 size) {
|
||||||
@@ -101,19 +84,18 @@ namespace ams::kern {
|
|||||||
R_UNLESS(size <= static_cast<s32>(MaxTableSize), svc::ResultOutOfMemory());
|
R_UNLESS(size <= static_cast<s32>(MaxTableSize), svc::ResultOutOfMemory());
|
||||||
|
|
||||||
/* Initialize all fields. */
|
/* Initialize all fields. */
|
||||||
m_table = m_entries;
|
m_max_count = 0;
|
||||||
m_table_size = (size <= 0) ? MaxTableSize : size;
|
m_table_size = (size <= 0) ? MaxTableSize : size;
|
||||||
m_next_linear_id = MinLinearId;
|
m_next_linear_id = MinLinearId;
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
m_max_count = 0;
|
m_free_head_index = -1;
|
||||||
|
|
||||||
/* Free all entries. */
|
/* Free all entries. */
|
||||||
for (size_t i = 0; i < static_cast<size_t>(m_table_size - 1); i++) {
|
for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
|
||||||
m_entries[i].SetFree(std::addressof(m_entries[i + 1]));
|
m_objects[i] = nullptr;
|
||||||
|
m_entry_infos[i].next_free_index = i - 1;
|
||||||
|
m_free_head_index = i;
|
||||||
}
|
}
|
||||||
m_entries[m_table_size - 1].SetFree(nullptr);
|
|
||||||
|
|
||||||
m_free_head = std::addressof(m_entries[0]);
|
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
@@ -134,7 +116,7 @@ namespace ams::kern {
|
|||||||
if constexpr (std::is_same<T, KAutoObject>::value) {
|
if constexpr (std::is_same<T, KAutoObject>::value) {
|
||||||
return this->GetObjectImpl(handle);
|
return this->GetObjectImpl(handle);
|
||||||
} else {
|
} else {
|
||||||
if (auto *obj = this->GetObjectImpl(handle); obj != nullptr) {
|
if (auto *obj = this->GetObjectImpl(handle); AMS_LIKELY(obj != nullptr)) {
|
||||||
return obj->DynamicCast<T*>();
|
return obj->DynamicCast<T*>();
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -149,11 +131,15 @@ namespace ams::kern {
|
|||||||
/* Handle pseudo-handles. */
|
/* Handle pseudo-handles. */
|
||||||
if constexpr (std::derived_from<KProcess, T>) {
|
if constexpr (std::derived_from<KProcess, T>) {
|
||||||
if (handle == ams::svc::PseudoHandle::CurrentProcess) {
|
if (handle == ams::svc::PseudoHandle::CurrentProcess) {
|
||||||
return GetCurrentProcessPointer();
|
auto * const cur_process = GetCurrentProcessPointer();
|
||||||
|
AMS_ASSUME(cur_process != nullptr);
|
||||||
|
return cur_process;
|
||||||
}
|
}
|
||||||
} else if constexpr (std::derived_from<KThread, T>) {
|
} else if constexpr (std::derived_from<KThread, T>) {
|
||||||
if (handle == ams::svc::PseudoHandle::CurrentThread) {
|
if (handle == ams::svc::PseudoHandle::CurrentThread) {
|
||||||
return GetCurrentThreadPointer();
|
auto * const cur_thread = GetCurrentThreadPointer();
|
||||||
|
AMS_ASSUME(cur_thread != nullptr);
|
||||||
|
return cur_thread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,8 +163,11 @@ namespace ams::kern {
|
|||||||
|
|
||||||
ALWAYS_INLINE KScopedAutoObject<KAutoObject> GetObjectForIpc(ams::svc::Handle handle, KThread *cur_thread) const {
|
ALWAYS_INLINE KScopedAutoObject<KAutoObject> GetObjectForIpc(ams::svc::Handle handle, KThread *cur_thread) const {
|
||||||
/* Handle pseudo-handles. */
|
/* Handle pseudo-handles. */
|
||||||
|
AMS_ASSUME(cur_thread != nullptr);
|
||||||
if (handle == ams::svc::PseudoHandle::CurrentProcess) {
|
if (handle == ams::svc::PseudoHandle::CurrentProcess) {
|
||||||
return static_cast<KAutoObject *>(static_cast<void *>(cur_thread->GetOwnerProcess()));
|
auto * const cur_process = static_cast<KAutoObject *>(static_cast<void *>(cur_thread->GetOwnerProcess()));
|
||||||
|
AMS_ASSUME(cur_process != nullptr);
|
||||||
|
return cur_process;
|
||||||
}
|
}
|
||||||
if (handle == ams::svc::PseudoHandle::CurrentThread) {
|
if (handle == ams::svc::PseudoHandle::CurrentThread) {
|
||||||
return static_cast<KAutoObject *>(cur_thread);
|
return static_cast<KAutoObject *>(cur_thread);
|
||||||
@@ -256,27 +245,29 @@ namespace ams::kern {
|
|||||||
NOINLINE Result Add(ams::svc::Handle *out_handle, KAutoObject *obj, u16 type);
|
NOINLINE Result Add(ams::svc::Handle *out_handle, KAutoObject *obj, u16 type);
|
||||||
NOINLINE void Register(ams::svc::Handle handle, KAutoObject *obj, u16 type);
|
NOINLINE void Register(ams::svc::Handle handle, KAutoObject *obj, u16 type);
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE Entry *AllocateEntry() {
|
constexpr ALWAYS_INLINE s32 AllocateEntry() {
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
MESOSPHERE_ASSERT(m_count < m_table_size);
|
MESOSPHERE_ASSERT(m_count < m_table_size);
|
||||||
|
|
||||||
Entry *entry = m_free_head;
|
const auto index = m_free_head_index;
|
||||||
m_free_head = entry->GetNextFreeEntry();
|
|
||||||
|
|
||||||
m_count++;
|
m_free_head_index = m_entry_infos[index].GetNextFreeIndex();
|
||||||
m_max_count = std::max(m_max_count, m_count);
|
|
||||||
|
|
||||||
return entry;
|
m_max_count = std::max(m_max_count, ++m_count);
|
||||||
|
|
||||||
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE void FreeEntry(Entry *entry) {
|
constexpr ALWAYS_INLINE void FreeEntry(s32 index) {
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
MESOSPHERE_ASSERT(m_count > 0);
|
MESOSPHERE_ASSERT(m_count > 0);
|
||||||
|
|
||||||
entry->SetFree(m_free_head);
|
m_objects[index] = nullptr;
|
||||||
m_free_head = entry;
|
m_entry_infos[index].next_free_index = m_free_head_index;
|
||||||
|
|
||||||
m_count--;
|
m_free_head_index = index;
|
||||||
|
|
||||||
|
--m_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE u16 AllocateLinearId() {
|
constexpr ALWAYS_INLINE u16 AllocateLinearId() {
|
||||||
@@ -287,13 +278,7 @@ namespace ams::kern {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE size_t GetEntryIndex(Entry *entry) {
|
constexpr ALWAYS_INLINE bool IsValidHandle(ams::svc::Handle handle) const {
|
||||||
const size_t index = entry - m_table;
|
|
||||||
MESOSPHERE_ASSERT(index < m_table_size);
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE Entry *FindEntry(ams::svc::Handle handle) const {
|
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
|
||||||
/* Unpack the handle. */
|
/* Unpack the handle. */
|
||||||
@@ -306,38 +291,38 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_UNUSED(reserved);
|
MESOSPHERE_UNUSED(reserved);
|
||||||
|
|
||||||
/* Validate our indexing information. */
|
/* Validate our indexing information. */
|
||||||
if (raw_value == 0) {
|
if (AMS_UNLIKELY(raw_value == 0)) {
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
if (linear_id == 0) {
|
if (AMS_UNLIKELY(linear_id == 0)) {
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
if (index >= m_table_size) {
|
if (AMS_UNLIKELY(index >= m_table_size)) {
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the entry, and ensure our serial id is correct. */
|
/* Check that there's an object, and our serial id is correct. */
|
||||||
Entry *entry = std::addressof(m_table[index]);
|
if (AMS_UNLIKELY(m_objects[index] == nullptr)) {
|
||||||
if (entry->GetObject() == nullptr) {
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
if (entry->GetLinearId() != linear_id) {
|
if (AMS_UNLIKELY(m_entry_infos[index].GetLinearId() != linear_id)) {
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE KAutoObject *GetObjectImpl(ams::svc::Handle handle) const {
|
constexpr NOINLINE KAutoObject *GetObjectImpl(ams::svc::Handle handle) const {
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
|
||||||
/* Handles must not have reserved bits set. */
|
/* Handles must not have reserved bits set. */
|
||||||
if (GetHandleBitPack(handle).Get<HandleReserved>() != 0) {
|
const auto handle_pack = GetHandleBitPack(handle);
|
||||||
|
if (AMS_UNLIKELY(handle_pack.Get<HandleReserved>() != 0)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Entry *entry = this->FindEntry(handle); entry != nullptr) {
|
if (AMS_LIKELY(this->IsValidHandle(handle))) {
|
||||||
return entry->GetObject();
|
return m_objects[handle_pack.Get<HandleIndex>()];
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -347,18 +332,17 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
|
||||||
/* Index must be in bounds. */
|
/* Index must be in bounds. */
|
||||||
if (index >= m_table_size || m_table == nullptr) {
|
if (AMS_UNLIKELY(index >= m_table_size)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure entry has an object. */
|
/* Ensure entry has an object. */
|
||||||
Entry *entry = std::addressof(m_table[index]);
|
if (KAutoObject *obj = m_objects[index]; obj != nullptr) {
|
||||||
if (entry->GetObject() == nullptr) {
|
*out_handle = EncodeHandle(index, m_entry_infos[index].GetLinearId());
|
||||||
|
return obj;
|
||||||
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_handle = EncodeHandle(index, entry->GetLinearId());
|
|
||||||
return entry->GetObject();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ namespace ams::kern {
|
|||||||
constexpr bool Is64Bit() const { return (m_flags & (1 << 3)); }
|
constexpr bool Is64Bit() const { return (m_flags & (1 << 3)); }
|
||||||
constexpr bool Is64BitAddressSpace() const { return (m_flags & (1 << 4)); }
|
constexpr bool Is64BitAddressSpace() const { return (m_flags & (1 << 4)); }
|
||||||
constexpr bool UsesSecureMemory() const { return (m_flags & (1 << 5)); }
|
constexpr bool UsesSecureMemory() const { return (m_flags & (1 << 5)); }
|
||||||
|
constexpr bool IsImmortal() const { return (m_flags & (1 << 6)); }
|
||||||
|
|
||||||
constexpr u32 GetRxAddress() const { return m_rx_address; }
|
constexpr u32 GetRxAddress() const { return m_rx_address; }
|
||||||
constexpr u32 GetRxSize() const { return m_rx_size; }
|
constexpr u32 GetRxSize() const { return m_rx_size; }
|
||||||
@@ -90,45 +91,49 @@ namespace ams::kern {
|
|||||||
|
|
||||||
class KInitialProcessReader {
|
class KInitialProcessReader {
|
||||||
private:
|
private:
|
||||||
KInitialProcessHeader *m_kip_header;
|
KInitialProcessHeader m_kip_header;
|
||||||
public:
|
public:
|
||||||
constexpr KInitialProcessReader() : m_kip_header() { /* ... */ }
|
constexpr KInitialProcessReader() : m_kip_header() { /* ... */ }
|
||||||
|
|
||||||
constexpr const u32 *GetCapabilities() const { return m_kip_header->GetCapabilities(); }
|
constexpr const u32 *GetCapabilities() const { return m_kip_header.GetCapabilities(); }
|
||||||
constexpr size_t GetNumCapabilities() const { return m_kip_header->GetNumCapabilities(); }
|
constexpr size_t GetNumCapabilities() const { return m_kip_header.GetNumCapabilities(); }
|
||||||
|
|
||||||
constexpr size_t GetBinarySize() const {
|
constexpr size_t GetBinarySize() const {
|
||||||
return sizeof(*m_kip_header) + m_kip_header->GetRxCompressedSize() + m_kip_header->GetRoCompressedSize() + m_kip_header->GetRwCompressedSize();
|
return m_kip_header.GetRxCompressedSize() + m_kip_header.GetRoCompressedSize() + m_kip_header.GetRwCompressedSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr size_t GetSize() const {
|
constexpr size_t GetSize() const {
|
||||||
if (const size_t bss_size = m_kip_header->GetBssSize(); bss_size != 0) {
|
if (const size_t bss_size = m_kip_header.GetBssSize(); bss_size != 0) {
|
||||||
return m_kip_header->GetBssAddress() + m_kip_header->GetBssSize();
|
return util::AlignUp(m_kip_header.GetBssAddress() + m_kip_header.GetBssSize(), PageSize);
|
||||||
} else {
|
} else {
|
||||||
return m_kip_header->GetRwAddress() + m_kip_header->GetRwSize();
|
return util::AlignUp(m_kip_header.GetRwAddress() + m_kip_header.GetRwSize(), PageSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u8 GetPriority() const { return m_kip_header->GetPriority(); }
|
constexpr u8 GetPriority() const { return m_kip_header.GetPriority(); }
|
||||||
constexpr u8 GetIdealCoreId() const { return m_kip_header->GetIdealCoreId(); }
|
constexpr u8 GetIdealCoreId() const { return m_kip_header.GetIdealCoreId(); }
|
||||||
constexpr u32 GetAffinityMask() const { return m_kip_header->GetAffinityMask(); }
|
constexpr u32 GetAffinityMask() const { return m_kip_header.GetAffinityMask(); }
|
||||||
constexpr u32 GetStackSize() const { return m_kip_header->GetStackSize(); }
|
constexpr u32 GetStackSize() const { return m_kip_header.GetStackSize(); }
|
||||||
|
|
||||||
constexpr bool Is64Bit() const { return m_kip_header->Is64Bit(); }
|
constexpr bool Is64Bit() const { return m_kip_header.Is64Bit(); }
|
||||||
constexpr bool Is64BitAddressSpace() const { return m_kip_header->Is64BitAddressSpace(); }
|
constexpr bool Is64BitAddressSpace() const { return m_kip_header.Is64BitAddressSpace(); }
|
||||||
constexpr bool UsesSecureMemory() const { return m_kip_header->UsesSecureMemory(); }
|
constexpr bool UsesSecureMemory() const { return m_kip_header.UsesSecureMemory(); }
|
||||||
|
constexpr bool IsImmortal() const { return m_kip_header.IsImmortal(); }
|
||||||
|
|
||||||
bool Attach(u8 *bin) {
|
KVirtualAddress Attach(KVirtualAddress bin) {
|
||||||
if (KInitialProcessHeader *header = reinterpret_cast<KInitialProcessHeader *>(bin); header->IsValid()) {
|
/* Copy the header. */
|
||||||
m_kip_header = header;
|
m_kip_header = *GetPointer<const KInitialProcessHeader>(bin);
|
||||||
return true;
|
|
||||||
|
/* Check that it's valid. */
|
||||||
|
if (m_kip_header.IsValid()) {
|
||||||
|
return bin + sizeof(KInitialProcessHeader);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return Null<KVirtualAddress>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const;
|
Result MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const;
|
||||||
Result Load(KProcessAddress address, const ams::svc::CreateProcessParameter ¶ms) const;
|
Result Load(KProcessAddress address, const ams::svc::CreateProcessParameter ¶ms, KProcessAddress src) const;
|
||||||
Result SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter ¶ms) const;
|
Result SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter ¶ms) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,10 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_AUTOOBJECT_TRAITS(KInterruptEvent, KReadableEvent);
|
MESOSPHERE_AUTOOBJECT_TRAITS(KInterruptEvent, KReadableEvent);
|
||||||
private:
|
private:
|
||||||
s32 m_interrupt_id;
|
s32 m_interrupt_id;
|
||||||
|
s32 m_core_id;
|
||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
public:
|
public:
|
||||||
constexpr KInterruptEvent() : m_interrupt_id(-1), m_is_initialized(false) { /* ... */ }
|
constexpr KInterruptEvent() : m_interrupt_id(-1), m_core_id(-1), m_is_initialized(false) { /* ... */ }
|
||||||
virtual ~KInterruptEvent() { /* ... */ }
|
virtual ~KInterruptEvent() { /* ... */ }
|
||||||
|
|
||||||
Result Initialize(int32_t interrupt_name, ams::svc::InterruptType type);
|
Result Initialize(int32_t interrupt_name, ams::svc::InterruptType type);
|
||||||
@@ -58,9 +59,9 @@ namespace ams::kern {
|
|||||||
virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override;
|
virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override;
|
||||||
virtual void DoTask() override;
|
virtual void DoTask() override;
|
||||||
|
|
||||||
void Unregister(s32 interrupt_id);
|
void Unregister(s32 interrupt_id, s32 core_id);
|
||||||
public:
|
public:
|
||||||
static Result Register(s32 interrupt_id, bool level, KInterruptEvent *event);
|
static Result Register(s32 interrupt_id, s32 core_id, bool level, KInterruptEvent *event);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,40 +24,59 @@ namespace ams::kern {
|
|||||||
|
|
||||||
class KLightConditionVariable {
|
class KLightConditionVariable {
|
||||||
private:
|
private:
|
||||||
KThreadQueue m_thread_queue;
|
KThread::WaiterList m_wait_list;
|
||||||
public:
|
public:
|
||||||
constexpr ALWAYS_INLINE KLightConditionVariable() : m_thread_queue() { /* ... */ }
|
constexpr ALWAYS_INLINE KLightConditionVariable() : m_wait_list() { /* ... */ }
|
||||||
private:
|
private:
|
||||||
void WaitImpl(KLightLock *lock, s64 timeout) {
|
void WaitImpl(KLightLock *lock, s64 timeout, bool allow_terminating_thread) {
|
||||||
KThread *owner = GetCurrentThreadPointer();
|
KThread *owner = GetCurrentThreadPointer();
|
||||||
KHardwareTimer *timer;
|
KHardwareTimer *timer;
|
||||||
|
|
||||||
/* Sleep the thread. */
|
/* Sleep the thread. */
|
||||||
{
|
{
|
||||||
KScopedSchedulerLockAndSleep lk(&timer, owner, timeout);
|
KScopedSchedulerLockAndSleep lk(&timer, owner, timeout);
|
||||||
lock->Unlock();
|
|
||||||
|
|
||||||
if (!m_thread_queue.SleepThread(owner)) {
|
if (!allow_terminating_thread && owner->IsTerminationRequested()) {
|
||||||
lk.CancelSleep();
|
lk.CancelSleep();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock->Unlock();
|
||||||
|
|
||||||
|
|
||||||
|
/* Set the thread as waiting. */
|
||||||
|
GetCurrentThread().SetState(KThread::ThreadState_Waiting);
|
||||||
|
|
||||||
|
/* Add the thread to the queue. */
|
||||||
|
m_wait_list.push_back(GetCurrentThread());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the thread from the wait list. */
|
||||||
|
{
|
||||||
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
|
m_wait_list.erase(m_wait_list.iterator_to(GetCurrentThread()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cancel the task that the sleep setup. */
|
/* Cancel the task that the sleep setup. */
|
||||||
if (timer != nullptr) {
|
if (timer != nullptr) {
|
||||||
timer->CancelTask(owner);
|
timer->CancelTask(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Re-acquire the lock. */
|
||||||
|
lock->Lock();
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
void Wait(KLightLock *lock, s64 timeout = -1ll) {
|
void Wait(KLightLock *lock, s64 timeout = -1ll, bool allow_terminating_thread = true) {
|
||||||
this->WaitImpl(lock, timeout);
|
this->WaitImpl(lock, timeout, allow_terminating_thread);
|
||||||
lock->Lock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Broadcast() {
|
void Broadcast() {
|
||||||
KScopedSchedulerLock lk;
|
KScopedSchedulerLock lk;
|
||||||
while (m_thread_queue.WakeupFrontThread() != nullptr) {
|
|
||||||
/* We want to signal all threads, and so should continue waking up until there's nothing to wake. */
|
/* Signal all threads. */
|
||||||
|
for (auto &thread : m_wait_list) {
|
||||||
|
thread.SetState(KThread::ThreadState_Runnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,236 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include <mesosphere/kern_common.hpp>
|
|
||||||
#include <mesosphere/kern_k_typed_address.hpp>
|
|
||||||
#include <mesosphere/kern_slab_helpers.hpp>
|
|
||||||
|
|
||||||
namespace ams::kern {
|
|
||||||
|
|
||||||
class KLinkedListNode : public util::IntrusiveListBaseNode<KLinkedListNode>, public KSlabAllocated<KLinkedListNode> {
|
|
||||||
private:
|
|
||||||
void *m_item;
|
|
||||||
public:
|
|
||||||
constexpr KLinkedListNode() : util::IntrusiveListBaseNode<KLinkedListNode>(), m_item(nullptr) { MESOSPHERE_ASSERT_THIS(); }
|
|
||||||
|
|
||||||
constexpr void Initialize(void *it) {
|
|
||||||
MESOSPHERE_ASSERT_THIS();
|
|
||||||
m_item = it;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void *GetItem() const {
|
|
||||||
return m_item;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
static_assert(sizeof(KLinkedListNode) == sizeof(util::IntrusiveListNode) + sizeof(void *));
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class KLinkedList : private util::IntrusiveListBaseTraits<KLinkedListNode>::ListType {
|
|
||||||
private:
|
|
||||||
using BaseList = util::IntrusiveListBaseTraits<KLinkedListNode>::ListType;
|
|
||||||
public:
|
|
||||||
template<bool Const>
|
|
||||||
class Iterator;
|
|
||||||
|
|
||||||
using value_type = T;
|
|
||||||
using size_type = size_t;
|
|
||||||
using difference_type = ptrdiff_t;
|
|
||||||
using pointer = value_type *;
|
|
||||||
using const_pointer = const value_type *;
|
|
||||||
using reference = value_type &;
|
|
||||||
using const_reference = const value_type &;
|
|
||||||
using iterator = Iterator<false>;
|
|
||||||
using const_iterator = Iterator<true>;
|
|
||||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
|
||||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
|
||||||
|
|
||||||
template<bool Const>
|
|
||||||
class Iterator {
|
|
||||||
private:
|
|
||||||
using BaseIterator = BaseList::Iterator<Const>;
|
|
||||||
friend class KLinkedList;
|
|
||||||
public:
|
|
||||||
using iterator_category = std::bidirectional_iterator_tag;
|
|
||||||
using value_type = typename KLinkedList::value_type;
|
|
||||||
using difference_type = typename KLinkedList::difference_type;
|
|
||||||
using pointer = typename std::conditional<Const, KLinkedList::const_pointer, KLinkedList::pointer>::type;
|
|
||||||
using reference = typename std::conditional<Const, KLinkedList::const_reference, KLinkedList::reference>::type;
|
|
||||||
private:
|
|
||||||
BaseIterator m_base_it;
|
|
||||||
public:
|
|
||||||
explicit Iterator(BaseIterator it) : m_base_it(it) { /* ... */ }
|
|
||||||
|
|
||||||
pointer GetItem() const {
|
|
||||||
return static_cast<pointer>(m_base_it->GetItem());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const Iterator &rhs) const {
|
|
||||||
return m_base_it == rhs.m_base_it;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const Iterator &rhs) const {
|
|
||||||
return !(*this == rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
pointer operator->() const {
|
|
||||||
return this->GetItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
reference operator*() const {
|
|
||||||
return *this->GetItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator &operator++() {
|
|
||||||
++m_base_it;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator &operator--() {
|
|
||||||
--m_base_it;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator operator++(int) {
|
|
||||||
const Iterator it{*this};
|
|
||||||
++(*this);
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator operator--(int) {
|
|
||||||
const Iterator it{*this};
|
|
||||||
--(*this);
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator Iterator<true>() const {
|
|
||||||
return Iterator<true>(m_base_it);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
constexpr KLinkedList() : BaseList() { /* ... */ }
|
|
||||||
|
|
||||||
~KLinkedList() {
|
|
||||||
/* Erase all elements. */
|
|
||||||
for (auto it = this->begin(); it != this->end(); it = this->erase(it)) {
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure we succeeded. */
|
|
||||||
MESOSPHERE_ASSERT(this->empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Iterator accessors. */
|
|
||||||
iterator begin() {
|
|
||||||
return iterator(BaseList::begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator begin() const {
|
|
||||||
return const_iterator(BaseList::begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator end() {
|
|
||||||
return iterator(BaseList::end());
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator end() const {
|
|
||||||
return const_iterator(BaseList::end());
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator cbegin() const {
|
|
||||||
return this->begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator cend() const {
|
|
||||||
return this->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse_iterator rbegin() {
|
|
||||||
return reverse_iterator(this->end());
|
|
||||||
}
|
|
||||||
|
|
||||||
const_reverse_iterator rbegin() const {
|
|
||||||
return const_reverse_iterator(this->end());
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse_iterator rend() {
|
|
||||||
return reverse_iterator(this->begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
const_reverse_iterator rend() const {
|
|
||||||
return const_reverse_iterator(this->begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
const_reverse_iterator crbegin() const {
|
|
||||||
return this->rbegin();
|
|
||||||
}
|
|
||||||
|
|
||||||
const_reverse_iterator crend() const {
|
|
||||||
return this->rend();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Content management. */
|
|
||||||
using BaseList::empty;
|
|
||||||
using BaseList::size;
|
|
||||||
|
|
||||||
reference back() {
|
|
||||||
return *(--this->end());
|
|
||||||
}
|
|
||||||
|
|
||||||
const_reference back() const {
|
|
||||||
return *(--this->end());
|
|
||||||
}
|
|
||||||
|
|
||||||
reference front() {
|
|
||||||
return *this->begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
const_reference front() const {
|
|
||||||
return *this->begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator insert(const_iterator pos, reference ref) {
|
|
||||||
KLinkedListNode *node = KLinkedListNode::Allocate();
|
|
||||||
MESOSPHERE_ABORT_UNLESS(node != nullptr);
|
|
||||||
node->Initialize(std::addressof(ref));
|
|
||||||
return iterator(BaseList::insert(pos.m_base_it, *node));
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_back(reference ref) {
|
|
||||||
this->insert(this->end(), ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_front(reference ref) {
|
|
||||||
this->insert(this->begin(), ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop_back() {
|
|
||||||
this->erase(--this->end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop_front() {
|
|
||||||
this->erase(this->begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator erase(const iterator pos) {
|
|
||||||
KLinkedListNode *freed_node = std::addressof(*pos.m_base_it);
|
|
||||||
iterator ret = iterator(BaseList::erase(pos.m_base_it));
|
|
||||||
KLinkedListNode::Free(freed_node);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -160,7 +160,7 @@ namespace ams::kern {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constexpr KMemoryPermission ConvertToKMemoryPermission(ams::svc::MemoryPermission perm) {
|
constexpr KMemoryPermission ConvertToKMemoryPermission(ams::svc::MemoryPermission perm) {
|
||||||
return static_cast<KMemoryPermission>((perm & KMemoryPermission_UserMask) | KMemoryPermission_KernelRead | ((perm & KMemoryPermission_UserWrite) << KMemoryPermission_KernelShift) | (perm == ams::svc::MemoryPermission_None ? KMemoryPermission_NotMapped : KMemoryPermission_None));
|
return static_cast<KMemoryPermission>((util::ToUnderlying(perm) & KMemoryPermission_UserMask) | KMemoryPermission_KernelRead | ((util::ToUnderlying(perm) & KMemoryPermission_UserWrite) << KMemoryPermission_KernelShift) | (perm == ams::svc::MemoryPermission_None ? KMemoryPermission_NotMapped : KMemoryPermission_None));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum KMemoryAttribute : u8 {
|
enum KMemoryAttribute : u8 {
|
||||||
|
|||||||
@@ -27,18 +27,8 @@ namespace ams::kern {
|
|||||||
KMemoryBlock *m_blocks[MaxBlocks];
|
KMemoryBlock *m_blocks[MaxBlocks];
|
||||||
size_t m_index;
|
size_t m_index;
|
||||||
KMemoryBlockSlabManager *m_slab_manager;
|
KMemoryBlockSlabManager *m_slab_manager;
|
||||||
public:
|
private:
|
||||||
constexpr explicit KMemoryBlockManagerUpdateAllocator(KMemoryBlockSlabManager *sm) : m_blocks(), m_index(MaxBlocks), m_slab_manager(sm) { /* ... */ }
|
ALWAYS_INLINE Result Initialize(size_t num_blocks) {
|
||||||
|
|
||||||
~KMemoryBlockManagerUpdateAllocator() {
|
|
||||||
for (const auto &block : m_blocks) {
|
|
||||||
if (block != nullptr) {
|
|
||||||
m_slab_manager->Free(block);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Initialize(size_t num_blocks) {
|
|
||||||
/* Check num blocks. */
|
/* Check num blocks. */
|
||||||
MESOSPHERE_ASSERT(num_blocks <= MaxBlocks);
|
MESOSPHERE_ASSERT(num_blocks <= MaxBlocks);
|
||||||
|
|
||||||
@@ -53,6 +43,18 @@ namespace ams::kern {
|
|||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
KMemoryBlockManagerUpdateAllocator(Result *out_result, KMemoryBlockSlabManager *sm, size_t num_blocks = MaxBlocks) : m_blocks(), m_index(MaxBlocks), m_slab_manager(sm) {
|
||||||
|
*out_result = this->Initialize(num_blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
~KMemoryBlockManagerUpdateAllocator() {
|
||||||
|
for (const auto &block : m_blocks) {
|
||||||
|
if (block != nullptr) {
|
||||||
|
m_slab_manager->Free(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
KMemoryBlock *Allocate() {
|
KMemoryBlock *Allocate() {
|
||||||
MESOSPHERE_ABORT_UNLESS(m_index < MaxBlocks);
|
MESOSPHERE_ABORT_UNLESS(m_index < MaxBlocks);
|
||||||
|
|||||||
@@ -44,9 +44,8 @@ namespace ams::kern {
|
|||||||
constexpr size_t KernelInitialPageHeapSize = 128_KB;
|
constexpr size_t KernelInitialPageHeapSize = 128_KB;
|
||||||
|
|
||||||
constexpr size_t KernelSlabHeapDataSize = 5_MB;
|
constexpr size_t KernelSlabHeapDataSize = 5_MB;
|
||||||
constexpr size_t KernelSlabHeapGapsSize = 2_MB - 64_KB;
|
constexpr size_t KernelSlabHeapGapsSizeMax = 2_MB - 64_KB;
|
||||||
constexpr size_t KernelSlabHeapGapsSizeDeprecated = 2_MB;
|
constexpr size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSizeMax;
|
||||||
constexpr size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSize;
|
|
||||||
|
|
||||||
/* NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860. */
|
/* NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860. */
|
||||||
constexpr size_t KernelSlabHeapAdditionalSize = 0x68000;
|
constexpr size_t KernelSlabHeapAdditionalSize = 0x68000;
|
||||||
@@ -176,7 +175,14 @@ namespace ams::kern {
|
|||||||
return std::make_tuple(total_size, kernel_size);
|
return std::make_tuple(total_size, kernel_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitializeLinearMemoryRegionTrees(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start);
|
static void InitializeLinearMemoryAddresses(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start) {
|
||||||
|
/* Set static differences. */
|
||||||
|
s_linear_phys_to_virt_diff = GetInteger(linear_virtual_start) - GetInteger(aligned_linear_phys_start);
|
||||||
|
s_linear_virt_to_phys_diff = GetInteger(aligned_linear_phys_start) - GetInteger(linear_virtual_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InitializeLinearMemoryRegionTrees();
|
||||||
|
|
||||||
static size_t GetResourceRegionSizeForInit();
|
static size_t GetResourceRegionSizeForInit();
|
||||||
|
|
||||||
static NOINLINE auto GetKernelRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel); }
|
static NOINLINE auto GetKernelRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel); }
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace ams::kern {
|
|||||||
KVirtualAddress AllocateBlock(s32 index, bool random) { return m_heap.AllocateBlock(index, random); }
|
KVirtualAddress AllocateBlock(s32 index, bool random) { return m_heap.AllocateBlock(index, random); }
|
||||||
void Free(KVirtualAddress addr, size_t num_pages) { m_heap.Free(addr, num_pages); }
|
void Free(KVirtualAddress addr, size_t num_pages) { m_heap.Free(addr, num_pages); }
|
||||||
|
|
||||||
void UpdateUsedHeapSize() { m_heap.UpdateUsedSize(); }
|
void SetInitialUsedHeapSize(size_t reserved_size) { m_heap.SetInitialUsedSize(reserved_size); }
|
||||||
|
|
||||||
void InitializeOptimizedMemory() { std::memset(GetVoidPointer(m_management_region), 0, CalculateOptimizedProcessOverheadSize(m_heap.GetSize())); }
|
void InitializeOptimizedMemory() { std::memset(GetVoidPointer(m_management_region), 0, CalculateOptimizedProcessOverheadSize(m_heap.GetSize())); }
|
||||||
|
|
||||||
@@ -168,6 +168,10 @@ namespace ams::kern {
|
|||||||
return m_managers[KMemoryLayout::GetVirtualLinearRegion(address).GetAttributes()];
|
return m_managers[KMemoryLayout::GetVirtualLinearRegion(address).GetAttributes()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Impl &GetManager(KVirtualAddress address) const {
|
||||||
|
return m_managers[KMemoryLayout::GetVirtualLinearRegion(address).GetAttributes()];
|
||||||
|
}
|
||||||
|
|
||||||
constexpr Impl *GetFirstManager(Pool pool, Direction dir) {
|
constexpr Impl *GetFirstManager(Pool pool, Direction dir) {
|
||||||
return dir == Direction_FromBack ? m_pool_managers_tail[pool] : m_pool_managers_head[pool];
|
return dir == Direction_FromBack ? m_pool_managers_tail[pool] : m_pool_managers_head[pool];
|
||||||
}
|
}
|
||||||
@@ -197,6 +201,10 @@ namespace ams::kern {
|
|||||||
NOINLINE Result AllocateAndOpen(KPageGroup *out, size_t num_pages, u32 option);
|
NOINLINE Result AllocateAndOpen(KPageGroup *out, size_t num_pages, u32 option);
|
||||||
NOINLINE Result AllocateAndOpenForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern);
|
NOINLINE Result AllocateAndOpenForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern);
|
||||||
|
|
||||||
|
Pool GetPool(KVirtualAddress address) const {
|
||||||
|
return this->GetManager(address).GetPool();
|
||||||
|
}
|
||||||
|
|
||||||
void Open(KVirtualAddress address, size_t num_pages) {
|
void Open(KVirtualAddress address, size_t num_pages) {
|
||||||
/* Repeatedly open references until we've done so for all pages. */
|
/* Repeatedly open references until we've done so for all pages. */
|
||||||
while (num_pages) {
|
while (num_pages) {
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ namespace ams::kern {
|
|||||||
enum KMemoryRegionType : u32 {};
|
enum KMemoryRegionType : u32 {};
|
||||||
|
|
||||||
enum KMemoryRegionAttr : typename std::underlying_type<KMemoryRegionType>::type {
|
enum KMemoryRegionAttr : typename std::underlying_type<KMemoryRegionType>::type {
|
||||||
KMemoryRegionAttr_CarveoutProtected = 0x04000000,
|
KMemoryRegionAttr_CarveoutProtected = 0x02000000,
|
||||||
|
KMemoryRegionAttr_Uncached = 0x04000000,
|
||||||
KMemoryRegionAttr_DidKernelMap = 0x08000000,
|
KMemoryRegionAttr_DidKernelMap = 0x08000000,
|
||||||
KMemoryRegionAttr_ShouldKernelMap = 0x10000000,
|
KMemoryRegionAttr_ShouldKernelMap = 0x10000000,
|
||||||
KMemoryRegionAttr_UserReadOnly = 0x20000000,
|
KMemoryRegionAttr_UserReadOnly = 0x20000000,
|
||||||
@@ -65,11 +66,41 @@ namespace ams::kern {
|
|||||||
consteval operator KMemoryRegionType() const { return static_cast<KMemoryRegionType>(m_value); }
|
consteval operator KMemoryRegionType() const { return static_cast<KMemoryRegionType>(m_value); }
|
||||||
consteval ValueType GetValue() const { return m_value; }
|
consteval ValueType GetValue() const { return m_value; }
|
||||||
|
|
||||||
consteval const KMemoryRegionTypeValue &Finalize() { m_finalized = true; return *this; }
|
consteval const KMemoryRegionTypeValue Finalize() {
|
||||||
consteval const KMemoryRegionTypeValue &SetSparseOnly() { m_sparse_only = true; return *this; }
|
AMS_ASSUME(!m_finalized);
|
||||||
consteval const KMemoryRegionTypeValue &SetDenseOnly() { m_dense_only = true; return *this; }
|
|
||||||
|
|
||||||
consteval KMemoryRegionTypeValue &SetAttribute(KMemoryRegionAttr attr) { AMS_ASSUME(!m_finalized); m_value |= attr; return *this; }
|
KMemoryRegionTypeValue new_type = *this;
|
||||||
|
new_type.m_finalized = true;
|
||||||
|
return new_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
consteval const KMemoryRegionTypeValue SetSparseOnly() {
|
||||||
|
AMS_ASSUME(!m_finalized);
|
||||||
|
AMS_ASSUME(!m_sparse_only);
|
||||||
|
AMS_ASSUME(!m_dense_only);
|
||||||
|
|
||||||
|
KMemoryRegionTypeValue new_type = *this;
|
||||||
|
new_type.m_sparse_only = true;
|
||||||
|
return new_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
consteval const KMemoryRegionTypeValue SetDenseOnly() {
|
||||||
|
AMS_ASSUME(!m_finalized);
|
||||||
|
AMS_ASSUME(!m_sparse_only);
|
||||||
|
AMS_ASSUME(!m_dense_only);
|
||||||
|
|
||||||
|
KMemoryRegionTypeValue new_type = *this;
|
||||||
|
new_type.m_dense_only = true;
|
||||||
|
return new_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
consteval KMemoryRegionTypeValue SetAttribute(KMemoryRegionAttr attr) {
|
||||||
|
AMS_ASSUME(!m_finalized);
|
||||||
|
|
||||||
|
KMemoryRegionTypeValue new_type = *this;
|
||||||
|
new_type.m_value |= attr;
|
||||||
|
return new_type;
|
||||||
|
}
|
||||||
|
|
||||||
consteval KMemoryRegionTypeValue DeriveInitial(size_t i, size_t next = BITSIZEOF(ValueType)) const {
|
consteval KMemoryRegionTypeValue DeriveInitial(size_t i, size_t next = BITSIZEOF(ValueType)) const {
|
||||||
AMS_ASSUME(!m_finalized);
|
AMS_ASSUME(!m_finalized);
|
||||||
@@ -216,6 +247,10 @@ namespace ams::kern {
|
|||||||
static_assert(KMemoryRegionType_VirtualDramKernelPtHeap .GetValue() == 0x2A);
|
static_assert(KMemoryRegionType_VirtualDramKernelPtHeap .GetValue() == 0x2A);
|
||||||
static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
|
static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
|
||||||
|
|
||||||
|
/* UNUSED: .DeriveSparse(2, 2, 0); */
|
||||||
|
constexpr inline const auto KMemoryRegionType_VirtualDramUnknownDebug = KMemoryRegionType_Dram.DeriveSparse(2, 2, 1);
|
||||||
|
static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x52));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelInitPt = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
|
constexpr inline const auto KMemoryRegionType_VirtualDramKernelInitPt = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramPoolManagement = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
|
constexpr inline const auto KMemoryRegionType_VirtualDramPoolManagement = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramUserPool = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
|
constexpr inline const auto KMemoryRegionType_VirtualDramUserPool = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
|
||||||
@@ -292,6 +327,8 @@ namespace ams::kern {
|
|||||||
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
|
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
|
||||||
} else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
|
} else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
|
||||||
return KMemoryRegionType_VirtualDramKernelPtHeap;
|
return KMemoryRegionType_VirtualDramKernelPtHeap;
|
||||||
|
} else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) {
|
||||||
|
return KMemoryRegionType_VirtualDramUnknownDebug;
|
||||||
} else {
|
} else {
|
||||||
return KMemoryRegionType_Dram;
|
return KMemoryRegionType_Dram;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ namespace ams::kern {
|
|||||||
Derived *derived = obj->DynamicCast<Derived *>();
|
Derived *derived = obj->DynamicCast<Derived *>();
|
||||||
R_UNLESS(derived != nullptr, svc::ResultNotFound());
|
R_UNLESS(derived != nullptr, svc::ResultNotFound());
|
||||||
|
|
||||||
|
/* Check that the object is closed. */
|
||||||
|
R_UNLESS(derived->IsServerClosed(), svc::ResultInvalidState());
|
||||||
|
|
||||||
return Delete(obj.GetPointerUnsafe(), name);
|
return Delete(obj.GetPointerUnsafe(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ namespace ams::kern {
|
|||||||
private:
|
private:
|
||||||
KVirtualAddress m_heap_address;
|
KVirtualAddress m_heap_address;
|
||||||
size_t m_heap_size;
|
size_t m_heap_size;
|
||||||
size_t m_used_size;
|
size_t m_initial_used_size;
|
||||||
size_t m_num_blocks;
|
size_t m_num_blocks;
|
||||||
Block m_blocks[NumMemoryBlockPageShifts];
|
Block m_blocks[NumMemoryBlockPageShifts];
|
||||||
private:
|
private:
|
||||||
@@ -134,7 +134,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
void FreeBlock(KVirtualAddress block, s32 index);
|
void FreeBlock(KVirtualAddress block, s32 index);
|
||||||
public:
|
public:
|
||||||
KPageHeap() : m_heap_address(), m_heap_size(), m_used_size(), m_num_blocks(), m_blocks() { /* ... */ }
|
KPageHeap() : m_heap_address(), m_heap_size(), m_initial_used_size(), m_num_blocks(), m_blocks() { /* ... */ }
|
||||||
|
|
||||||
constexpr KVirtualAddress GetAddress() const { return m_heap_address; }
|
constexpr KVirtualAddress GetAddress() const { return m_heap_address; }
|
||||||
constexpr size_t GetSize() const { return m_heap_size; }
|
constexpr size_t GetSize() const { return m_heap_size; }
|
||||||
@@ -149,8 +149,13 @@ namespace ams::kern {
|
|||||||
size_t GetFreeSize() const { return this->GetNumFreePages() * PageSize; }
|
size_t GetFreeSize() const { return this->GetNumFreePages() * PageSize; }
|
||||||
void DumpFreeList() const;
|
void DumpFreeList() const;
|
||||||
|
|
||||||
void UpdateUsedSize() {
|
void SetInitialUsedSize(size_t reserved_size) {
|
||||||
m_used_size = m_heap_size - (this->GetNumFreePages() * PageSize);
|
/* Check that the reserved size is valid. */
|
||||||
|
const size_t free_size = this->GetNumFreePages() * PageSize;
|
||||||
|
MESOSPHERE_ABORT_UNLESS(m_heap_size >= free_size + reserved_size);
|
||||||
|
|
||||||
|
/* Set the initial used size. */
|
||||||
|
m_initial_used_size = m_heap_size - free_size - reserved_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
KVirtualAddress AllocateBlock(s32 index, bool random);
|
KVirtualAddress AllocateBlock(s32 index, bool random);
|
||||||
|
|||||||
@@ -47,12 +47,21 @@ namespace ams::kern {
|
|||||||
static_assert(std::is_trivial<KPageProperties>::value);
|
static_assert(std::is_trivial<KPageProperties>::value);
|
||||||
static_assert(sizeof(KPageProperties) == sizeof(u32));
|
static_assert(sizeof(KPageProperties) == sizeof(u32));
|
||||||
|
|
||||||
|
class KResourceLimit;
|
||||||
|
|
||||||
class KPageTableBase {
|
class KPageTableBase {
|
||||||
NON_COPYABLE(KPageTableBase);
|
NON_COPYABLE(KPageTableBase);
|
||||||
NON_MOVEABLE(KPageTableBase);
|
NON_MOVEABLE(KPageTableBase);
|
||||||
public:
|
public:
|
||||||
using TraversalEntry = KPageTableImpl::TraversalEntry;
|
using TraversalEntry = KPageTableImpl::TraversalEntry;
|
||||||
using TraversalContext = KPageTableImpl::TraversalContext;
|
using TraversalContext = KPageTableImpl::TraversalContext;
|
||||||
|
|
||||||
|
struct MemoryRange {
|
||||||
|
KVirtualAddress address;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
void Close();
|
||||||
|
};
|
||||||
protected:
|
protected:
|
||||||
enum MemoryFillValue {
|
enum MemoryFillValue {
|
||||||
MemoryFillValue_Zero = 0,
|
MemoryFillValue_Zero = 0,
|
||||||
@@ -150,8 +159,10 @@ namespace ams::kern {
|
|||||||
size_t m_max_heap_size{};
|
size_t m_max_heap_size{};
|
||||||
size_t m_mapped_physical_memory_size{};
|
size_t m_mapped_physical_memory_size{};
|
||||||
size_t m_mapped_unsafe_physical_memory{};
|
size_t m_mapped_unsafe_physical_memory{};
|
||||||
|
size_t m_mapped_ipc_server_memory{};
|
||||||
mutable KLightLock m_general_lock{};
|
mutable KLightLock m_general_lock{};
|
||||||
mutable KLightLock m_map_physical_memory_lock{};
|
mutable KLightLock m_map_physical_memory_lock{};
|
||||||
|
KLightLock m_device_map_lock{};
|
||||||
KPageTableImpl m_impl{};
|
KPageTableImpl m_impl{};
|
||||||
KMemoryBlockManager m_memory_block_manager{};
|
KMemoryBlockManager m_memory_block_manager{};
|
||||||
u32 m_allocate_option{};
|
u32 m_allocate_option{};
|
||||||
@@ -161,6 +172,7 @@ namespace ams::kern {
|
|||||||
bool m_enable_device_address_space_merge{};
|
bool m_enable_device_address_space_merge{};
|
||||||
KMemoryBlockSlabManager *m_memory_block_slab_manager{};
|
KMemoryBlockSlabManager *m_memory_block_slab_manager{};
|
||||||
KBlockInfoManager *m_block_info_manager{};
|
KBlockInfoManager *m_block_info_manager{};
|
||||||
|
KResourceLimit *m_resource_limit{};
|
||||||
const KMemoryRegion *m_cached_physical_linear_region{};
|
const KMemoryRegion *m_cached_physical_linear_region{};
|
||||||
const KMemoryRegion *m_cached_physical_heap_region{};
|
const KMemoryRegion *m_cached_physical_heap_region{};
|
||||||
const KMemoryRegion *m_cached_virtual_heap_region{};
|
const KMemoryRegion *m_cached_virtual_heap_region{};
|
||||||
@@ -171,7 +183,7 @@ namespace ams::kern {
|
|||||||
constexpr KPageTableBase() { /* ... */ }
|
constexpr KPageTableBase() { /* ... */ }
|
||||||
|
|
||||||
NOINLINE Result InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end);
|
NOINLINE Result InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end);
|
||||||
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager);
|
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KResourceLimit *resource_limit);
|
||||||
|
|
||||||
void Finalize();
|
void Finalize();
|
||||||
|
|
||||||
@@ -195,6 +207,10 @@ namespace ams::kern {
|
|||||||
return this->CanContain(addr, size, KMemoryState_AliasCode);
|
return this->CanContain(addr, size, KMemoryState_AliasCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE KScopedLightLock AcquireDeviceMapLock() {
|
||||||
|
return KScopedLightLock(m_device_map_lock);
|
||||||
|
}
|
||||||
|
|
||||||
KProcessAddress GetRegionAddress(KMemoryState state) const;
|
KProcessAddress GetRegionAddress(KMemoryState state) const;
|
||||||
size_t GetRegionSize(KMemoryState state) const;
|
size_t GetRegionSize(KMemoryState state) const;
|
||||||
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const;
|
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const;
|
||||||
@@ -286,16 +302,35 @@ namespace ams::kern {
|
|||||||
Result MakePageGroup(KPageGroup &pg, KProcessAddress addr, size_t num_pages);
|
Result MakePageGroup(KPageGroup &pg, KProcessAddress addr, size_t num_pages);
|
||||||
bool IsValidPageGroup(const KPageGroup &pg, KProcessAddress addr, size_t num_pages);
|
bool IsValidPageGroup(const KPageGroup &pg, KProcessAddress addr, size_t num_pages);
|
||||||
|
|
||||||
|
Result GetContiguousMemoryRangeWithState(MemoryRange *out, KProcessAddress address, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr);
|
||||||
|
|
||||||
NOINLINE Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
|
NOINLINE Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
|
||||||
|
|
||||||
|
Result MapIoImpl(KProcessAddress *out, PageLinkedList *page_list, KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
||||||
|
Result ReadIoMemoryImpl(void *buffer, KPhysicalAddress phys_addr, size_t size);
|
||||||
|
Result WriteIoMemoryImpl(KPhysicalAddress phys_addr, const void *buffer, size_t size);
|
||||||
|
|
||||||
Result SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state);
|
Result SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state);
|
||||||
Result SetupForIpcServer(KProcessAddress *out_addr, size_t size, KProcessAddress src_addr, KMemoryPermission test_perm, KMemoryState dst_state, KPageTableBase &src_page_table, bool send);
|
Result SetupForIpcServer(KProcessAddress *out_addr, size_t size, KProcessAddress src_addr, KMemoryPermission test_perm, KMemoryState dst_state, KPageTableBase &src_page_table, bool send);
|
||||||
void CleanupForIpcClientOnServerSetupFailure(PageLinkedList *page_list, KProcessAddress address, size_t size, KMemoryPermission prot_perm);
|
void CleanupForIpcClientOnServerSetupFailure(PageLinkedList *page_list, KProcessAddress address, size_t size, KMemoryPermission prot_perm);
|
||||||
|
|
||||||
size_t GetSize(KMemoryState state) const;
|
size_t GetSize(KMemoryState state) const;
|
||||||
|
|
||||||
|
ALWAYS_INLINE bool GetPhysicalAddressLocked(KPhysicalAddress *out, KProcessAddress virt_addr) const {
|
||||||
|
/* Validate pre-conditions. */
|
||||||
|
MESOSPHERE_AUDIT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
|
return this->GetImpl().GetPhysicalAddress(out, virt_addr);
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const {
|
bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const {
|
||||||
return this->GetImpl().GetPhysicalAddress(out, virt_addr);
|
/* Validate pre-conditions. */
|
||||||
|
MESOSPHERE_AUDIT(!this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
|
/* Acquire exclusive access to the table while doing address translation. */
|
||||||
|
KScopedLightLock lk(m_general_lock);
|
||||||
|
|
||||||
|
return this->GetPhysicalAddressLocked(out, virt_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
KBlockInfoManager *GetBlockInfoManager() const { return m_block_info_manager; }
|
KBlockInfoManager *GetBlockInfoManager() const { return m_block_info_manager; }
|
||||||
@@ -341,14 +376,20 @@ namespace ams::kern {
|
|||||||
Result InvalidateProcessDataCache(KProcessAddress address, size_t size);
|
Result InvalidateProcessDataCache(KProcessAddress address, size_t size);
|
||||||
|
|
||||||
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size);
|
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size);
|
||||||
|
Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size);
|
||||||
|
|
||||||
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size);
|
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size);
|
||||||
|
Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size);
|
||||||
|
|
||||||
|
Result LockForMapDeviceAddressSpace(KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned);
|
||||||
|
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size);
|
||||||
|
|
||||||
Result LockForDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned);
|
|
||||||
Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size);
|
Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size);
|
||||||
|
|
||||||
Result MakePageGroupForUnmapDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size);
|
|
||||||
Result UnlockForDeviceAddressSpacePartialMap(KProcessAddress address, size_t size, size_t mapped_size);
|
Result UnlockForDeviceAddressSpacePartialMap(KProcessAddress address, size_t size, size_t mapped_size);
|
||||||
|
|
||||||
|
Result OpenMemoryRangeForMapDeviceAddressSpace(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned);
|
||||||
|
Result OpenMemoryRangeForUnmapDeviceAddressSpace(MemoryRange *out, KProcessAddress address, size_t size);
|
||||||
|
|
||||||
Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size);
|
Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size);
|
||||||
Result UnlockForIpcUserBuffer(KProcessAddress address, size_t size);
|
Result UnlockForIpcUserBuffer(KProcessAddress address, size_t size);
|
||||||
|
|
||||||
@@ -357,6 +398,8 @@ namespace ams::kern {
|
|||||||
Result LockForCodeMemory(KPageGroup *out, KProcessAddress address, size_t size);
|
Result LockForCodeMemory(KPageGroup *out, KProcessAddress address, size_t size);
|
||||||
Result UnlockForCodeMemory(KProcessAddress address, size_t size, const KPageGroup &pg);
|
Result UnlockForCodeMemory(KProcessAddress address, size_t size, const KPageGroup &pg);
|
||||||
|
|
||||||
|
Result OpenMemoryRangeForProcessCacheOperation(MemoryRange *out, KProcessAddress address, size_t size);
|
||||||
|
|
||||||
Result CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
|
Result CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
|
||||||
Result CopyMemoryFromLinearToKernel(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
|
Result CopyMemoryFromLinearToKernel(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
|
||||||
Result CopyMemoryFromUserToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr);
|
Result CopyMemoryFromUserToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr);
|
||||||
@@ -365,7 +408,7 @@ namespace ams::kern {
|
|||||||
Result CopyMemoryFromHeapToHeapWithoutCheckDestination(KPageTableBase &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
|
Result CopyMemoryFromHeapToHeapWithoutCheckDestination(KPageTableBase &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
|
||||||
|
|
||||||
Result SetupForIpc(KProcessAddress *out_dst_addr, size_t size, KProcessAddress src_addr, KPageTableBase &src_page_table, KMemoryPermission test_perm, KMemoryState dst_state, bool send);
|
Result SetupForIpc(KProcessAddress *out_dst_addr, size_t size, KProcessAddress src_addr, KPageTableBase &src_page_table, KMemoryPermission test_perm, KMemoryState dst_state, bool send);
|
||||||
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state, KProcess *server_process);
|
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state);
|
||||||
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state);
|
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state);
|
||||||
|
|
||||||
Result MapPhysicalMemory(KProcessAddress address, size_t size);
|
Result MapPhysicalMemory(KProcessAddress address, size_t size);
|
||||||
@@ -374,6 +417,8 @@ namespace ams::kern {
|
|||||||
Result MapPhysicalMemoryUnsafe(KProcessAddress address, size_t size);
|
Result MapPhysicalMemoryUnsafe(KProcessAddress address, size_t size);
|
||||||
Result UnmapPhysicalMemoryUnsafe(KProcessAddress address, size_t size);
|
Result UnmapPhysicalMemoryUnsafe(KProcessAddress address, size_t size);
|
||||||
|
|
||||||
|
Result UnmapProcessMemory(KProcessAddress dst_address, size_t size, KPageTableBase &src_pt, KProcessAddress src_address);
|
||||||
|
|
||||||
void DumpMemoryBlocksLocked() const {
|
void DumpMemoryBlocksLocked() const {
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
m_memory_block_manager.DumpBlocks();
|
m_memory_block_manager.DumpBlocks();
|
||||||
|
|||||||
@@ -53,6 +53,11 @@ namespace ams::kern {
|
|||||||
uintptr_t GetName() const { return m_name; }
|
uintptr_t GetName() const { return m_name; }
|
||||||
bool IsLight() const { return m_is_light; }
|
bool IsLight() const { return m_is_light; }
|
||||||
|
|
||||||
|
bool IsServerClosed() const {
|
||||||
|
KScopedSchedulerLock sl;
|
||||||
|
return m_state == State::ServerClosed;
|
||||||
|
}
|
||||||
|
|
||||||
Result EnqueueSession(KServerSession *session);
|
Result EnqueueSession(KServerSession *session);
|
||||||
Result EnqueueSession(KLightServerSession *session);
|
Result EnqueueSession(KLightServerSession *session);
|
||||||
|
|
||||||
|
|||||||
@@ -77,8 +77,7 @@ namespace ams::kern {
|
|||||||
bool m_is_initialized{};
|
bool m_is_initialized{};
|
||||||
bool m_is_application{};
|
bool m_is_application{};
|
||||||
char m_name[13]{};
|
char m_name[13]{};
|
||||||
std::atomic<u16> m_num_threads{};
|
std::atomic<u16> m_num_running_threads{};
|
||||||
u16 m_peak_num_threads{};
|
|
||||||
u32 m_flags{};
|
u32 m_flags{};
|
||||||
KMemoryManager::Pool m_memory_pool{};
|
KMemoryManager::Pool m_memory_pool{};
|
||||||
s64 m_schedule_count{};
|
s64 m_schedule_count{};
|
||||||
@@ -99,7 +98,9 @@ namespace ams::kern {
|
|||||||
SharedMemoryInfoList m_shared_memory_list{};
|
SharedMemoryInfoList m_shared_memory_list{};
|
||||||
BetaList m_beta_list{};
|
BetaList m_beta_list{};
|
||||||
bool m_is_suspended{};
|
bool m_is_suspended{};
|
||||||
|
bool m_is_immortal{};
|
||||||
bool m_is_jit_debug{};
|
bool m_is_jit_debug{};
|
||||||
|
bool m_is_handle_table_initialized{};
|
||||||
ams::svc::DebugEvent m_jit_debug_event_type{};
|
ams::svc::DebugEvent m_jit_debug_event_type{};
|
||||||
ams::svc::DebugException m_jit_debug_exception_type{};
|
ams::svc::DebugException m_jit_debug_exception_type{};
|
||||||
uintptr_t m_jit_debug_params[4]{};
|
uintptr_t m_jit_debug_params[4]{};
|
||||||
@@ -108,7 +109,6 @@ namespace ams::kern {
|
|||||||
KThread *m_running_threads[cpu::NumCores]{};
|
KThread *m_running_threads[cpu::NumCores]{};
|
||||||
u64 m_running_thread_idle_counts[cpu::NumCores]{};
|
u64 m_running_thread_idle_counts[cpu::NumCores]{};
|
||||||
KThread *m_pinned_threads[cpu::NumCores]{};
|
KThread *m_pinned_threads[cpu::NumCores]{};
|
||||||
std::atomic<s32> m_num_created_threads{};
|
|
||||||
std::atomic<s64> m_cpu_time{};
|
std::atomic<s64> m_cpu_time{};
|
||||||
std::atomic<s64> m_num_process_switches{};
|
std::atomic<s64> m_num_process_switches{};
|
||||||
std::atomic<s64> m_num_thread_switches{};
|
std::atomic<s64> m_num_thread_switches{};
|
||||||
@@ -124,17 +124,17 @@ namespace ams::kern {
|
|||||||
private:
|
private:
|
||||||
Result Initialize(const ams::svc::CreateProcessParameter ¶ms);
|
Result Initialize(const ams::svc::CreateProcessParameter ¶ms);
|
||||||
|
|
||||||
void StartTermination();
|
Result StartTermination();
|
||||||
void FinishTermination();
|
void FinishTermination();
|
||||||
|
|
||||||
void PinThread(s32 core_id, KThread *thread) {
|
ALWAYS_INLINE void PinThread(s32 core_id, KThread *thread) {
|
||||||
MESOSPHERE_ASSERT(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores));
|
MESOSPHERE_ASSERT(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores));
|
||||||
MESOSPHERE_ASSERT(thread != nullptr);
|
MESOSPHERE_ASSERT(thread != nullptr);
|
||||||
MESOSPHERE_ASSERT(m_pinned_threads[core_id] == nullptr);
|
MESOSPHERE_ASSERT(m_pinned_threads[core_id] == nullptr);
|
||||||
m_pinned_threads[core_id] = thread;
|
m_pinned_threads[core_id] = thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnpinThread(s32 core_id, KThread *thread) {
|
ALWAYS_INLINE void UnpinThread(s32 core_id, KThread *thread) {
|
||||||
MESOSPHERE_UNUSED(thread);
|
MESOSPHERE_UNUSED(thread);
|
||||||
MESOSPHERE_ASSERT(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores));
|
MESOSPHERE_ASSERT(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores));
|
||||||
MESOSPHERE_ASSERT(thread != nullptr);
|
MESOSPHERE_ASSERT(thread != nullptr);
|
||||||
@@ -145,7 +145,7 @@ namespace ams::kern {
|
|||||||
KProcess() { /* ... */ }
|
KProcess() { /* ... */ }
|
||||||
virtual ~KProcess() { /* ... */ }
|
virtual ~KProcess() { /* ... */ }
|
||||||
|
|
||||||
Result Initialize(const ams::svc::CreateProcessParameter ¶ms, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool);
|
Result Initialize(const ams::svc::CreateProcessParameter ¶ms, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool, bool immortal);
|
||||||
Result Initialize(const ams::svc::CreateProcessParameter ¶ms, svc::KUserPointer<const u32 *> caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool);
|
Result Initialize(const ams::svc::CreateProcessParameter ¶ms, svc::KUserPointer<const u32 *> caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool);
|
||||||
void Exit();
|
void Exit();
|
||||||
|
|
||||||
@@ -285,8 +285,8 @@ namespace ams::kern {
|
|||||||
constexpr s64 GetScheduledCount() const { return m_schedule_count; }
|
constexpr s64 GetScheduledCount() const { return m_schedule_count; }
|
||||||
void IncrementScheduledCount() { ++m_schedule_count; }
|
void IncrementScheduledCount() { ++m_schedule_count; }
|
||||||
|
|
||||||
void IncrementThreadCount();
|
void IncrementRunningThreadCount();
|
||||||
void DecrementThreadCount();
|
void DecrementRunningThreadCount();
|
||||||
|
|
||||||
size_t GetTotalSystemResourceSize() const { return m_system_resource_num_pages * PageSize; }
|
size_t GetTotalSystemResourceSize() const { return m_system_resource_num_pages * PageSize; }
|
||||||
size_t GetUsedSystemResourceSize() const {
|
size_t GetUsedSystemResourceSize() const {
|
||||||
@@ -340,6 +340,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
void PinCurrentThread();
|
void PinCurrentThread();
|
||||||
void UnpinCurrentThread();
|
void UnpinCurrentThread();
|
||||||
|
void UnpinThread(KThread *thread);
|
||||||
|
|
||||||
Result SignalToAddress(KProcessAddress address) {
|
Result SignalToAddress(KProcessAddress address) {
|
||||||
return m_cond_var.SignalToAddress(address);
|
return m_cond_var.SignalToAddress(address);
|
||||||
@@ -405,6 +406,23 @@ namespace ams::kern {
|
|||||||
this->NotifyAvailable();
|
this->NotifyAvailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE Result InitializeHandleTable(s32 size) {
|
||||||
|
/* Try to initialize the handle table. */
|
||||||
|
R_TRY(m_handle_table.Initialize(size));
|
||||||
|
|
||||||
|
/* We succeeded, so note that we did. */
|
||||||
|
m_is_handle_table_initialized = true;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void FinalizeHandleTable() {
|
||||||
|
/* Finalize the table. */
|
||||||
|
m_handle_table.Finalize();
|
||||||
|
|
||||||
|
/* Note that the table is finalized. */
|
||||||
|
m_is_handle_table_initialized = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,8 +194,20 @@ namespace ams::kern {
|
|||||||
static bool s_scheduler_update_needed;
|
static bool s_scheduler_update_needed;
|
||||||
static KSchedulerPriorityQueue s_priority_queue;
|
static KSchedulerPriorityQueue s_priority_queue;
|
||||||
static LockType s_scheduler_lock;
|
static LockType s_scheduler_lock;
|
||||||
|
public:
|
||||||
|
static consteval bool ValidateAssemblyOffsets();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
consteval bool KScheduler::ValidateAssemblyOffsets() {
|
||||||
|
static_assert(__builtin_offsetof(KScheduler, m_state.needs_scheduling) == KSCHEDULER_NEEDS_SCHEDULING);
|
||||||
|
static_assert(__builtin_offsetof(KScheduler, m_state.interrupt_task_thread_runnable) == KSCHEDULER_INTERRUPT_TASK_THREAD_RUNNABLE);
|
||||||
|
static_assert(__builtin_offsetof(KScheduler, m_state.highest_priority_thread) == KSCHEDULER_HIGHEST_PRIORITY_THREAD);
|
||||||
|
static_assert(__builtin_offsetof(KScheduler, m_state.idle_thread_stack) == KSCHEDULER_IDLE_THREAD_STACK);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static_assert(KScheduler::ValidateAssemblyOffsets());
|
||||||
|
|
||||||
class KScopedSchedulerLock : KScopedLock<KScheduler::LockType> {
|
class KScopedSchedulerLock : KScopedLock<KScheduler::LockType> {
|
||||||
public:
|
public:
|
||||||
explicit ALWAYS_INLINE KScopedSchedulerLock() : KScopedLock(KScheduler::s_scheduler_lock) { /* ... */ }
|
explicit ALWAYS_INLINE KScopedSchedulerLock() : KScopedLock(KScheduler::s_scheduler_lock) { /* ... */ }
|
||||||
|
|||||||
@@ -37,14 +37,22 @@ namespace ams::kern {
|
|||||||
private:
|
private:
|
||||||
KServerSession m_server;
|
KServerSession m_server;
|
||||||
KClientSession m_client;
|
KClientSession m_client;
|
||||||
State m_state;
|
std::atomic<std::underlying_type<State>::type> m_atomic_state;
|
||||||
KClientPort *m_port;
|
KClientPort *m_port;
|
||||||
uintptr_t m_name;
|
uintptr_t m_name;
|
||||||
KProcess *m_process;
|
KProcess *m_process;
|
||||||
bool m_initialized;
|
bool m_initialized;
|
||||||
|
private:
|
||||||
|
ALWAYS_INLINE void SetState(State state) {
|
||||||
|
m_atomic_state = static_cast<u8>(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE State GetState() const {
|
||||||
|
return static_cast<State>(m_atomic_state.load());
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
constexpr KSession()
|
constexpr KSession()
|
||||||
: m_server(), m_client(), m_state(State::Invalid), m_port(), m_name(), m_process(), m_initialized()
|
: m_server(), m_client(), m_atomic_state(static_cast<std::underlying_type<State>::type>(State::Invalid)), m_port(), m_name(), m_process(), m_initialized()
|
||||||
{
|
{
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
@@ -62,8 +70,8 @@ namespace ams::kern {
|
|||||||
void OnServerClosed();
|
void OnServerClosed();
|
||||||
void OnClientClosed();
|
void OnClientClosed();
|
||||||
|
|
||||||
bool IsServerClosed() const { return m_state != State::Normal; }
|
bool IsServerClosed() const { return this->GetState() != State::Normal; }
|
||||||
bool IsClientClosed() const { return m_state != State::Normal; }
|
bool IsClientClosed() const { return this->GetState() != State::Normal; }
|
||||||
|
|
||||||
Result OnRequest(KSessionRequest *request) { return m_server.OnRequest(request); }
|
Result OnRequest(KSessionRequest *request) { return m_server.OnRequest(request); }
|
||||||
|
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ namespace ams::kern {
|
|||||||
T *Allocate() {
|
T *Allocate() {
|
||||||
T *obj = reinterpret_cast<T *>(this->AllocateImpl());
|
T *obj = reinterpret_cast<T *>(this->AllocateImpl());
|
||||||
if (AMS_LIKELY(obj != nullptr)) {
|
if (AMS_LIKELY(obj != nullptr)) {
|
||||||
new (obj) T();
|
std::construct_at(obj);
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <mesosphere/kern_k_auto_object.hpp>
|
#include <mesosphere/kern_k_auto_object.hpp>
|
||||||
#include <mesosphere/kern_slab_helpers.hpp>
|
#include <mesosphere/kern_slab_helpers.hpp>
|
||||||
#include <mesosphere/kern_k_linked_list.hpp>
|
|
||||||
|
|
||||||
namespace ams::kern {
|
namespace ams::kern {
|
||||||
|
|
||||||
@@ -46,7 +45,7 @@ namespace ams::kern {
|
|||||||
static Result Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout);
|
static Result Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout);
|
||||||
public:
|
public:
|
||||||
virtual void Finalize() override;
|
virtual void Finalize() override;
|
||||||
virtual bool IsSignaled() const = 0;
|
virtual bool IsSignaled() const { AMS_INFINITE_LOOP(); }
|
||||||
virtual void DumpWaiters();
|
virtual void DumpWaiters();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -77,22 +77,34 @@ namespace ams::kern {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum DpcFlag : u32 {
|
enum DpcFlag : u32 {
|
||||||
DpcFlag_Terminating = (1 << 0),
|
DpcFlag_Terminating = (1 << 0),
|
||||||
DpcFlag_Terminated = (1 << 1),
|
DpcFlag_Terminated = (1 << 1),
|
||||||
|
DpcFlag_PerformDestruction = (1 << 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StackParameters {
|
struct StackParameters {
|
||||||
alignas(0x10) u8 svc_permission[0x10];
|
alignas(0x10) u8 svc_permission[0x18];
|
||||||
|
KThreadContext *context;
|
||||||
|
KThread *cur_thread;
|
||||||
|
s16 disable_count;
|
||||||
std::atomic<u8> dpc_flags;
|
std::atomic<u8> dpc_flags;
|
||||||
u8 current_svc_id;
|
u8 current_svc_id;
|
||||||
bool is_calling_svc;
|
bool is_calling_svc;
|
||||||
bool is_in_exception_handler;
|
bool is_in_exception_handler;
|
||||||
bool is_pinned;
|
bool is_pinned;
|
||||||
s32 disable_count;
|
|
||||||
KThreadContext *context;
|
|
||||||
KThread *cur_thread;
|
|
||||||
};
|
};
|
||||||
static_assert(alignof(StackParameters) == 0x10);
|
static_assert(alignof(StackParameters) == 0x10);
|
||||||
|
static_assert(sizeof(StackParameters) == THREAD_STACK_PARAMETERS_SIZE);
|
||||||
|
|
||||||
|
static_assert(__builtin_offsetof(StackParameters, svc_permission) == THREAD_STACK_PARAMETERS_SVC_PERMISSION);
|
||||||
|
static_assert(__builtin_offsetof(StackParameters, context) == THREAD_STACK_PARAMETERS_CONTEXT);
|
||||||
|
static_assert(__builtin_offsetof(StackParameters, cur_thread) == THREAD_STACK_PARAMETERS_CUR_THREAD);
|
||||||
|
static_assert(__builtin_offsetof(StackParameters, disable_count) == THREAD_STACK_PARAMETERS_DISABLE_COUNT);
|
||||||
|
static_assert(__builtin_offsetof(StackParameters, dpc_flags) == THREAD_STACK_PARAMETERS_DPC_FLAGS);
|
||||||
|
static_assert(__builtin_offsetof(StackParameters, current_svc_id) == THREAD_STACK_PARAMETERS_CURRENT_SVC_ID);
|
||||||
|
static_assert(__builtin_offsetof(StackParameters, is_calling_svc) == THREAD_STACK_PARAMETERS_IS_CALLING_SVC);
|
||||||
|
static_assert(__builtin_offsetof(StackParameters, is_in_exception_handler) == THREAD_STACK_PARAMETERS_IS_IN_EXCEPTION_HANDLER);
|
||||||
|
static_assert(__builtin_offsetof(StackParameters, is_pinned) == THREAD_STACK_PARAMETERS_IS_PINNED);
|
||||||
|
|
||||||
struct QueueEntry {
|
struct QueueEntry {
|
||||||
private:
|
private:
|
||||||
@@ -124,7 +136,7 @@ namespace ams::kern {
|
|||||||
static_assert(sizeof(SyncObjectBuffer::m_sync_objects) == sizeof(SyncObjectBuffer::m_handles));
|
static_assert(sizeof(SyncObjectBuffer::m_sync_objects) == sizeof(SyncObjectBuffer::m_handles));
|
||||||
|
|
||||||
struct ConditionVariableComparator {
|
struct ConditionVariableComparator {
|
||||||
struct LightCompareType {
|
struct RedBlackKeyType {
|
||||||
uintptr_t m_cv_key;
|
uintptr_t m_cv_key;
|
||||||
s32 m_priority;
|
s32 m_priority;
|
||||||
|
|
||||||
@@ -137,7 +149,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T> requires (std::same_as<T, KThread> || std::same_as<T, LightCompareType>)
|
template<typename T> requires (std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>)
|
||||||
static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KThread &rhs) {
|
static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KThread &rhs) {
|
||||||
const uintptr_t l_key = lhs.GetConditionVariableKey();
|
const uintptr_t l_key = lhs.GetConditionVariableKey();
|
||||||
const uintptr_t r_key = rhs.GetConditionVariableKey();
|
const uintptr_t r_key = rhs.GetConditionVariableKey();
|
||||||
@@ -153,8 +165,8 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static_assert(ams::util::HasLightCompareType<ConditionVariableComparator>);
|
static_assert(ams::util::HasRedBlackKeyType<ConditionVariableComparator>);
|
||||||
static_assert(std::same_as<ams::util::LightCompareType<ConditionVariableComparator, void>, ConditionVariableComparator::LightCompareType>);
|
static_assert(std::same_as<ams::util::RedBlackKeyType<ConditionVariableComparator, void>, ConditionVariableComparator::RedBlackKeyType>);
|
||||||
private:
|
private:
|
||||||
static inline std::atomic<u64> s_next_thread_id = 0;
|
static inline std::atomic<u64> s_next_thread_id = 0;
|
||||||
private:
|
private:
|
||||||
@@ -192,12 +204,14 @@ namespace ams::kern {
|
|||||||
WaiterList m_pinned_waiter_list{};
|
WaiterList m_pinned_waiter_list{};
|
||||||
KThread *m_lock_owner{};
|
KThread *m_lock_owner{};
|
||||||
uintptr_t m_debug_params[3]{};
|
uintptr_t m_debug_params[3]{};
|
||||||
|
KAutoObject *m_closed_object{};
|
||||||
u32 m_address_key_value{};
|
u32 m_address_key_value{};
|
||||||
u32 m_suspend_request_flags{};
|
u32 m_suspend_request_flags{};
|
||||||
u32 m_suspend_allowed_flags{};
|
u32 m_suspend_allowed_flags{};
|
||||||
Result m_wait_result;
|
Result m_wait_result;
|
||||||
Result m_debug_exception_result;
|
Result m_debug_exception_result;
|
||||||
s32 m_base_priority{};
|
s32 m_base_priority{};
|
||||||
|
s32 m_base_priority_on_unpin{};
|
||||||
s32 m_physical_ideal_core_id{};
|
s32 m_physical_ideal_core_id{};
|
||||||
s32 m_virtual_ideal_core_id{};
|
s32 m_virtual_ideal_core_id{};
|
||||||
s32 m_num_kernel_waiters{};
|
s32 m_num_kernel_waiters{};
|
||||||
@@ -251,7 +265,7 @@ namespace ams::kern {
|
|||||||
return *(reinterpret_cast<StackParameters *>(m_kernel_stack_top) - 1);
|
return *(reinterpret_cast<StackParameters *>(m_kernel_stack_top) - 1);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
ALWAYS_INLINE s32 GetDisableDispatchCount() const {
|
ALWAYS_INLINE s16 GetDisableDispatchCount() const {
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
return this->GetStackParameters().disable_count;
|
return this->GetStackParameters().disable_count;
|
||||||
}
|
}
|
||||||
@@ -312,15 +326,15 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void RegisterDpc(DpcFlag flag) {
|
ALWAYS_INLINE void RegisterDpc(DpcFlag flag) {
|
||||||
this->GetStackParameters().dpc_flags |= flag;
|
this->GetStackParameters().dpc_flags.fetch_or(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void ClearDpc(DpcFlag flag) {
|
ALWAYS_INLINE void ClearDpc(DpcFlag flag) {
|
||||||
this->GetStackParameters().dpc_flags &= ~flag;
|
this->GetStackParameters().dpc_flags.fetch_and(~flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE u8 GetDpc() const {
|
ALWAYS_INLINE u8 GetDpc() const {
|
||||||
return this->GetStackParameters().dpc_flags;
|
return this->GetStackParameters().dpc_flags.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool HasDpc() const {
|
ALWAYS_INLINE bool HasDpc() const {
|
||||||
@@ -328,13 +342,15 @@ namespace ams::kern {
|
|||||||
return this->GetDpc() != 0;
|
return this->GetDpc() != 0;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
void Suspend();
|
void UpdateState();
|
||||||
ALWAYS_INLINE void AddWaiterImpl(KThread *thread);
|
ALWAYS_INLINE void AddWaiterImpl(KThread *thread);
|
||||||
ALWAYS_INLINE void RemoveWaiterImpl(KThread *thread);
|
ALWAYS_INLINE void RemoveWaiterImpl(KThread *thread);
|
||||||
ALWAYS_INLINE static void RestorePriority(KThread *thread);
|
ALWAYS_INLINE static void RestorePriority(KThread *thread);
|
||||||
|
|
||||||
void StartTermination();
|
void StartTermination();
|
||||||
void FinishTermination();
|
void FinishTermination();
|
||||||
|
|
||||||
|
void IncreaseBasePriority(s32 priority);
|
||||||
public:
|
public:
|
||||||
constexpr u64 GetThreadId() const { return m_thread_id; }
|
constexpr u64 GetThreadId() const { return m_thread_id; }
|
||||||
|
|
||||||
@@ -471,12 +487,45 @@ namespace ams::kern {
|
|||||||
constexpr void *GetThreadLocalRegionHeapAddress() const { return m_tls_heap_address; }
|
constexpr void *GetThreadLocalRegionHeapAddress() const { return m_tls_heap_address; }
|
||||||
|
|
||||||
constexpr KSynchronizationObject **GetSynchronizationObjectBuffer() { return std::addressof(m_sync_object_buffer.m_sync_objects[0]); }
|
constexpr KSynchronizationObject **GetSynchronizationObjectBuffer() { return std::addressof(m_sync_object_buffer.m_sync_objects[0]); }
|
||||||
constexpr ams::svc::Handle *GetHandleBuffer() { return std::addressof(m_sync_object_buffer.m_handles[sizeof(m_sync_object_buffer.m_sync_objects) / sizeof(ams::svc::Handle) - ams::svc::ArgumentHandleCountMax]); }
|
constexpr ams::svc::Handle *GetHandleBuffer() { return std::addressof(m_sync_object_buffer.m_handles[sizeof(m_sync_object_buffer.m_sync_objects) / (sizeof(ams::svc::Handle)) - ams::svc::ArgumentHandleCountMax]); }
|
||||||
|
|
||||||
u16 GetUserDisableCount() const { return static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->disable_count; }
|
u16 GetUserDisableCount() const { return static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->disable_count; }
|
||||||
void SetInterruptFlag() const { static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->interrupt_flag = 1; }
|
void SetInterruptFlag() const { static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->interrupt_flag = 1; }
|
||||||
void ClearInterruptFlag() const { static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->interrupt_flag = 0; }
|
void ClearInterruptFlag() const { static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->interrupt_flag = 0; }
|
||||||
|
|
||||||
|
ALWAYS_INLINE KAutoObject *GetClosedObject() { return m_closed_object; }
|
||||||
|
|
||||||
|
ALWAYS_INLINE void SetClosedObject(KAutoObject *object) {
|
||||||
|
MESOSPHERE_ASSERT(object != nullptr);
|
||||||
|
|
||||||
|
/* Set the object to destroy. */
|
||||||
|
m_closed_object = object;
|
||||||
|
|
||||||
|
/* Schedule destruction DPC. */
|
||||||
|
if ((this->GetStackParameters().dpc_flags.load(std::memory_order_relaxed) & DpcFlag_PerformDestruction) == 0) {
|
||||||
|
this->RegisterDpc(DpcFlag_PerformDestruction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void DestroyClosedObjects() {
|
||||||
|
/* Destroy all objects that have been closed. */
|
||||||
|
if (KAutoObject *cur = m_closed_object; cur != nullptr) {
|
||||||
|
do {
|
||||||
|
/* Set our closed object as the next to close. */
|
||||||
|
m_closed_object = cur->GetNextClosedObject();
|
||||||
|
|
||||||
|
/* Destroy the current object. */
|
||||||
|
cur->Destroy();
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
cur = m_closed_object;
|
||||||
|
} while (cur != nullptr);
|
||||||
|
|
||||||
|
/* Clear the pending DPC. */
|
||||||
|
this->ClearDpc(DpcFlag_PerformDestruction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr void SetDebugAttached() { m_debug_attached = true; }
|
constexpr void SetDebugAttached() { m_debug_attached = true; }
|
||||||
constexpr bool IsAttachedToDebugger() const { return m_debug_attached; }
|
constexpr bool IsAttachedToDebugger() const { return m_debug_attached; }
|
||||||
|
|
||||||
@@ -497,7 +546,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
constexpr u32 GetSuspendFlags() const { return m_suspend_allowed_flags & m_suspend_request_flags; }
|
constexpr u32 GetSuspendFlags() const { return m_suspend_allowed_flags & m_suspend_request_flags; }
|
||||||
constexpr bool IsSuspended() const { return this->GetSuspendFlags() != 0; }
|
constexpr bool IsSuspended() const { return this->GetSuspendFlags() != 0; }
|
||||||
constexpr bool IsSuspendRequested(SuspendType type) const { return (m_suspend_request_flags & (1u << (ThreadState_SuspendShift + type))) != 0; }
|
constexpr bool IsSuspendRequested(SuspendType type) const { return (m_suspend_request_flags & (1u << (util::ToUnderlying(ThreadState_SuspendShift) + util::ToUnderlying(type)))) != 0; }
|
||||||
constexpr bool IsSuspendRequested() const { return m_suspend_request_flags != 0; }
|
constexpr bool IsSuspendRequested() const { return m_suspend_request_flags != 0; }
|
||||||
void RequestSuspend(SuspendType type);
|
void RequestSuspend(SuspendType type);
|
||||||
void Resume(SuspendType type);
|
void Resume(SuspendType type);
|
||||||
@@ -521,7 +570,7 @@ namespace ams::kern {
|
|||||||
Result Run();
|
Result Run();
|
||||||
void Exit();
|
void Exit();
|
||||||
|
|
||||||
void Terminate();
|
Result Terminate();
|
||||||
ThreadState RequestTerminate();
|
ThreadState RequestTerminate();
|
||||||
|
|
||||||
Result Sleep(s64 timeout);
|
Result Sleep(s64 timeout);
|
||||||
@@ -589,4 +638,14 @@ namespace ams::kern {
|
|||||||
return GetCurrentThread().GetCurrentCore();
|
return GetCurrentThread().GetCurrentCore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void KAutoObject::ScheduleDestruction() {
|
||||||
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
|
||||||
|
/* Set our object to destroy. */
|
||||||
|
m_next_closed_object = GetCurrentThread().GetClosedObject();
|
||||||
|
|
||||||
|
/* Set ourselves as the thread's next object to destroy. */
|
||||||
|
GetCurrentThread().SetClosedObject(this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,4 +105,10 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Miscellaneous sanity checking. */
|
||||||
|
static_assert(ams::svc::ThreadLocalRegionSize == THREAD_LOCAL_REGION_SIZE);
|
||||||
|
static_assert(__builtin_offsetof(ams::svc::ThreadLocalRegion, message_buffer) == THREAD_LOCAL_REGION_MESSAGE_BUFFER);
|
||||||
|
static_assert(__builtin_offsetof(ams::svc::ThreadLocalRegion, disable_count) == THREAD_LOCAL_REGION_DISABLE_COUNT);
|
||||||
|
static_assert(__builtin_offsetof(ams::svc::ThreadLocalRegion, interrupt_flag) == THREAD_LOCAL_REGION_INTERRUPT_FLAG);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace ams::kern {
|
|||||||
class KTransferMemory final : public KAutoObjectWithSlabHeapAndContainer<KTransferMemory, KAutoObjectWithList> {
|
class KTransferMemory final : public KAutoObjectWithSlabHeapAndContainer<KTransferMemory, KAutoObjectWithList> {
|
||||||
MESOSPHERE_AUTOOBJECT_TRAITS(KTransferMemory, KAutoObject);
|
MESOSPHERE_AUTOOBJECT_TRAITS(KTransferMemory, KAutoObject);
|
||||||
private:
|
private:
|
||||||
TYPED_STORAGE(KPageGroup) m_page_group;
|
util::TypedStorage<KPageGroup> m_page_group;
|
||||||
KProcess *m_owner;
|
KProcess *m_owner;
|
||||||
KProcessAddress m_address;
|
KProcessAddress m_address;
|
||||||
KLightLock m_lock;
|
KLightLock m_lock;
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ATMOSPHERE_ARCH_ARM64
|
||||||
|
|
||||||
|
#include <mesosphere/arch/arm64/kern_assembly_offsets.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error "Unknown architecture for CPU"
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -45,7 +45,21 @@
|
|||||||
|
|
||||||
namespace ams::kern {
|
namespace ams::kern {
|
||||||
|
|
||||||
static_assert(cpu::NumCores <= static_cast<s32>(BITSIZEOF(u64)));
|
namespace cpu {
|
||||||
static_assert(util::size(cpu::VirtualToPhysicalCoreMap) == BITSIZEOF(u64));
|
|
||||||
|
static constexpr inline size_t NumVirtualCores = BITSIZEOF(u64);
|
||||||
|
|
||||||
|
static constexpr inline u64 VirtualCoreMask = [] {
|
||||||
|
u64 mask = 0;
|
||||||
|
for (size_t i = 0; i < NumVirtualCores; ++i) {
|
||||||
|
mask |= (UINT64_C(1) << i);
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(cpu::NumCores <= cpu::NumVirtualCores);
|
||||||
|
static_assert(util::size(cpu::VirtualToPhysicalCoreMap) == cpu::NumVirtualCores);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
namespace ams::kern::svc {
|
namespace ams::kern::svc {
|
||||||
|
|
||||||
static constexpr size_t NumSupervisorCalls = 0x80;
|
static constexpr size_t NumSupervisorCalls = AMS_KERN_NUM_SUPERVISOR_CALLS;
|
||||||
|
|
||||||
#define AMS_KERN_SVC_DECLARE_ENUM_ID(ID, RETURN_TYPE, NAME, ...) \
|
#define AMS_KERN_SVC_DECLARE_ENUM_ID(ID, RETURN_TYPE, NAME, ...) \
|
||||||
SvcId_##NAME = ID,
|
SvcId_##NAME = ID,
|
||||||
|
|||||||
@@ -283,6 +283,16 @@ namespace ams::kern::arch::arm64::cpu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StoreDataCacheBySetWay(int level) {
|
||||||
|
PerformCacheOperationBySetWayImpl<false>(level, StoreDataCacheLineBySetWayImpl);
|
||||||
|
cpu::DataSynchronizationBarrier();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushDataCacheBySetWay(int level) {
|
||||||
|
PerformCacheOperationBySetWayImpl<false>(level, FlushDataCacheLineBySetWayImpl);
|
||||||
|
cpu::DataSynchronizationBarrier();
|
||||||
|
}
|
||||||
|
|
||||||
void KCacheHelperInterruptHandler::ProcessOperation() {
|
void KCacheHelperInterruptHandler::ProcessOperation() {
|
||||||
switch (m_operation) {
|
switch (m_operation) {
|
||||||
case Operation::Idle:
|
case Operation::Idle:
|
||||||
@@ -291,12 +301,10 @@ namespace ams::kern::arch::arm64::cpu {
|
|||||||
InstructionMemoryBarrier();
|
InstructionMemoryBarrier();
|
||||||
break;
|
break;
|
||||||
case Operation::StoreDataCache:
|
case Operation::StoreDataCache:
|
||||||
PerformCacheOperationBySetWayLocal<false>(StoreDataCacheLineBySetWayImpl);
|
StoreDataCacheBySetWay(0);
|
||||||
DataSynchronizationBarrier();
|
|
||||||
break;
|
break;
|
||||||
case Operation::FlushDataCache:
|
case Operation::FlushDataCache:
|
||||||
PerformCacheOperationBySetWayLocal<false>(FlushDataCacheLineBySetWayImpl);
|
FlushDataCacheBySetWay(0);
|
||||||
DataSynchronizationBarrier();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,7 +382,20 @@ namespace ams::kern::arch::arm64::cpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FlushEntireDataCache() {
|
void FlushEntireDataCache() {
|
||||||
return PerformCacheOperationBySetWayShared<false>(FlushDataCacheLineBySetWayImpl);
|
KScopedCoreMigrationDisable dm;
|
||||||
|
|
||||||
|
CacheLineIdRegisterAccessor clidr_el1;
|
||||||
|
const int levels_of_coherency = clidr_el1.GetLevelsOfCoherency();
|
||||||
|
|
||||||
|
/* Store cache from L2 up to the level of coherence (if there's an L3 cache or greater). */
|
||||||
|
for (int level = 2; level < levels_of_coherency; ++level) {
|
||||||
|
StoreDataCacheBySetWay(level - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush cache from the level of coherence down to L2. */
|
||||||
|
for (int level = levels_of_coherency; level > 1; --level) {
|
||||||
|
FlushDataCacheBySetWay(level - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result InvalidateDataCache(void *addr, size_t size) {
|
Result InvalidateDataCache(void *addr, size_t size) {
|
||||||
|
|||||||
@@ -521,6 +521,11 @@ namespace ams::kern::arch::arm64 {
|
|||||||
{
|
{
|
||||||
KScopedInterruptEnable ei;
|
KScopedInterruptEnable ei;
|
||||||
|
|
||||||
|
/* Terminate the thread, if we should. */
|
||||||
|
if (GetCurrentThread().IsTerminationRequested()) {
|
||||||
|
GetCurrentThread().Exit();
|
||||||
|
}
|
||||||
|
|
||||||
HandleUserException(context, esr, far, afsr0, afsr1, data);
|
HandleUserException(context, esr, far, afsr0, afsr1, data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -239,14 +239,6 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KInterruptManager::ClearInterrupt(s32 irq) {
|
|
||||||
R_UNLESS(KInterruptController::IsGlobal(irq), svc::ResultOutOfRange());
|
|
||||||
|
|
||||||
KScopedInterruptDisable di;
|
|
||||||
KScopedSpinLock lk(this->GetGlobalInterruptLock());
|
|
||||||
return this->ClearGlobal(irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result KInterruptManager::ClearInterrupt(s32 irq, s32 core_id) {
|
Result KInterruptManager::ClearInterrupt(s32 irq, s32 core_id) {
|
||||||
MESOSPHERE_UNUSED(core_id);
|
MESOSPHERE_UNUSED(core_id);
|
||||||
|
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager) {
|
Result KPageTable::InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit) {
|
||||||
/* The input ID isn't actually used. */
|
/* The input ID isn't actually used. */
|
||||||
MESOSPHERE_UNUSED(id);
|
MESOSPHERE_UNUSED(id);
|
||||||
|
|
||||||
@@ -202,7 +202,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
const size_t as_width = GetAddressSpaceWidth(as_type);
|
const size_t as_width = GetAddressSpaceWidth(as_type);
|
||||||
const KProcessAddress as_start = 0;
|
const KProcessAddress as_start = 0;
|
||||||
const KProcessAddress as_end = (1ul << as_width);
|
const KProcessAddress as_end = (1ul << as_width);
|
||||||
R_TRY(KPageTableBase::InitializeForProcess(as_type, enable_aslr, enable_das_merge, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, mem_block_slab_manager, block_info_manager));
|
R_TRY(KPageTableBase::InitializeForProcess(as_type, enable_aslr, enable_das_merge, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, mem_block_slab_manager, block_info_manager, resource_limit));
|
||||||
|
|
||||||
/* We succeeded! */
|
/* We succeeded! */
|
||||||
table_guard.Cancel();
|
table_guard.Cancel();
|
||||||
@@ -556,13 +556,13 @@ namespace ams::kern::arch::arm64 {
|
|||||||
/* If we're not forcing an unmap, separate pages immediately. */
|
/* If we're not forcing an unmap, separate pages immediately. */
|
||||||
if (!force) {
|
if (!force) {
|
||||||
const size_t size = num_pages * PageSize;
|
const size_t size = num_pages * PageSize;
|
||||||
R_TRY(this->SeparatePages(virt_addr, std::min(GetInteger(virt_addr) & -GetInteger(virt_addr), size), page_list, reuse_ll));
|
R_TRY(this->SeparatePages(virt_addr, std::min(util::GetAlignment(GetInteger(virt_addr)), size), page_list, reuse_ll));
|
||||||
if (num_pages > 1) {
|
if (num_pages > 1) {
|
||||||
const auto end_page = virt_addr + size;
|
const auto end_page = virt_addr + size;
|
||||||
const auto last_page = end_page - PageSize;
|
const auto last_page = end_page - PageSize;
|
||||||
|
|
||||||
auto merge_guard = SCOPE_GUARD { this->MergePages(virt_addr, page_list); };
|
auto merge_guard = SCOPE_GUARD { this->MergePages(virt_addr, page_list); };
|
||||||
R_TRY(this->SeparatePages(last_page, std::min(GetInteger(end_page) & -GetInteger(end_page), size), page_list, reuse_ll));
|
R_TRY(this->SeparatePages(last_page, std::min(util::GetAlignment(GetInteger(end_page)), size), page_list, reuse_ll));
|
||||||
merge_guard.Cancel();
|
merge_guard.Cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1194,13 +1194,13 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
/* Separate pages before we change permissions. */
|
/* Separate pages before we change permissions. */
|
||||||
const size_t size = num_pages * PageSize;
|
const size_t size = num_pages * PageSize;
|
||||||
R_TRY(this->SeparatePages(virt_addr, std::min(GetInteger(virt_addr) & -GetInteger(virt_addr), size), page_list, reuse_ll));
|
R_TRY(this->SeparatePages(virt_addr, std::min(util::GetAlignment(GetInteger(virt_addr)), size), page_list, reuse_ll));
|
||||||
if (num_pages > 1) {
|
if (num_pages > 1) {
|
||||||
const auto end_page = virt_addr + size;
|
const auto end_page = virt_addr + size;
|
||||||
const auto last_page = end_page - PageSize;
|
const auto last_page = end_page - PageSize;
|
||||||
|
|
||||||
auto merge_guard = SCOPE_GUARD { this->MergePages(virt_addr, page_list); };
|
auto merge_guard = SCOPE_GUARD { this->MergePages(virt_addr, page_list); };
|
||||||
R_TRY(this->SeparatePages(last_page, std::min(GetInteger(end_page) & -GetInteger(end_page), size), page_list, reuse_ll));
|
R_TRY(this->SeparatePages(last_page, std::min(util::GetAlignment(GetInteger(end_page)), size), page_list, reuse_ll));
|
||||||
merge_guard.Cancel();
|
merge_guard.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <mesosphere/kern_build_config.hpp>
|
#include <mesosphere/kern_build_config.hpp>
|
||||||
|
#include <mesosphere/kern_select_assembly_offsets.h>
|
||||||
|
|
||||||
#if defined(MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP)
|
#if defined(MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP)
|
||||||
|
|
||||||
@@ -32,28 +33,28 @@
|
|||||||
\
|
\
|
||||||
/* Save x0/x1/sp to the context. */ \
|
/* Save x0/x1/sp to the context. */ \
|
||||||
ldr x1, [sp, #(8 * 0)]; \
|
ldr x1, [sp, #(8 * 0)]; \
|
||||||
str x1, [x0, #(8 * 0)]; \
|
str x1, [x0, #(EXCEPTION_CONTEXT_X0)]; \
|
||||||
ldr x1, [sp, #(8 * 1)]; \
|
ldr x1, [sp, #(8 * 1)]; \
|
||||||
str x1, [x0, #(8 * 1)]; \
|
str x1, [x0, #(EXCEPTION_CONTEXT_X1)]; \
|
||||||
\
|
\
|
||||||
/* Save all other registers to the context. */ \
|
/* Save all other registers to the context. */ \
|
||||||
stp x2, x3, [x0, #(8 * 2)]; \
|
stp x2, x3, [x0, #(EXCEPTION_CONTEXT_X2_X3)]; \
|
||||||
stp x4, x5, [x0, #(8 * 4)]; \
|
stp x4, x5, [x0, #(EXCEPTION_CONTEXT_X4_X5)]; \
|
||||||
stp x6, x7, [x0, #(8 * 6)]; \
|
stp x6, x7, [x0, #(EXCEPTION_CONTEXT_X6_X7)]; \
|
||||||
stp x8, x9, [x0, #(8 * 8)]; \
|
stp x8, x9, [x0, #(EXCEPTION_CONTEXT_X8_X9)]; \
|
||||||
stp x10, x11, [x0, #(8 * 10)]; \
|
stp x10, x11, [x0, #(EXCEPTION_CONTEXT_X10_X11)]; \
|
||||||
stp x12, x13, [x0, #(8 * 12)]; \
|
stp x12, x13, [x0, #(EXCEPTION_CONTEXT_X12_X13)]; \
|
||||||
stp x14, x15, [x0, #(8 * 14)]; \
|
stp x14, x15, [x0, #(EXCEPTION_CONTEXT_X14_X15)]; \
|
||||||
stp x16, x17, [x0, #(8 * 16)]; \
|
stp x16, x17, [x0, #(EXCEPTION_CONTEXT_X16_X17)]; \
|
||||||
stp x18, x19, [x0, #(8 * 18)]; \
|
stp x18, x19, [x0, #(EXCEPTION_CONTEXT_X18_X19)]; \
|
||||||
stp x20, x21, [x0, #(8 * 20)]; \
|
stp x20, x21, [x0, #(EXCEPTION_CONTEXT_X20_X21)]; \
|
||||||
stp x22, x23, [x0, #(8 * 22)]; \
|
stp x22, x23, [x0, #(EXCEPTION_CONTEXT_X22_X23)]; \
|
||||||
stp x24, x25, [x0, #(8 * 24)]; \
|
stp x24, x25, [x0, #(EXCEPTION_CONTEXT_X24_X25)]; \
|
||||||
stp x26, x27, [x0, #(8 * 26)]; \
|
stp x26, x27, [x0, #(EXCEPTION_CONTEXT_X26_X27)]; \
|
||||||
stp x28, x29, [x0, #(8 * 28)]; \
|
stp x28, x29, [x0, #(EXCEPTION_CONTEXT_X28_X29)]; \
|
||||||
\
|
\
|
||||||
add x1, sp, #16; \
|
add x1, sp, #16; \
|
||||||
stp x30, x1, [x0, #(8 * 30)]; \
|
stp x30, x1, [x0, #(EXCEPTION_CONTEXT_X30_SP)]; \
|
||||||
\
|
\
|
||||||
/* Restore x0/x1. */ \
|
/* Restore x0/x1. */ \
|
||||||
ldp x0, x1, [sp], #16;
|
ldp x0, x1, [sp], #16;
|
||||||
|
|||||||
@@ -758,7 +758,6 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory32BitEPvPKvm:
|
|||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
1: /* Read the word from normal memory. */
|
1: /* Read the word from normal memory. */
|
||||||
mov x30, x8
|
|
||||||
ldtr w9, [x5]
|
ldtr w9, [x5]
|
||||||
|
|
||||||
/* Set our return address so that on read failure we continue. */
|
/* Set our return address so that on read failure we continue. */
|
||||||
@@ -769,7 +768,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory32BitEPvPKvm:
|
|||||||
dsb sy
|
dsb sy
|
||||||
|
|
||||||
2: /* Continue. */
|
2: /* Continue. */
|
||||||
nop
|
mov x30, x8
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
add x4, x4, #4
|
add x4, x4, #4
|
||||||
@@ -801,7 +800,6 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory16BitEPvPKvm:
|
|||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
1: /* Read the word from normal memory. */
|
1: /* Read the word from normal memory. */
|
||||||
mov x30, x8
|
|
||||||
ldtrh w9, [x5]
|
ldtrh w9, [x5]
|
||||||
|
|
||||||
/* Set our return address so that on read failure we continue. */
|
/* Set our return address so that on read failure we continue. */
|
||||||
@@ -812,7 +810,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory16BitEPvPKvm:
|
|||||||
dsb sy
|
dsb sy
|
||||||
|
|
||||||
2: /* Continue. */
|
2: /* Continue. */
|
||||||
nop
|
mov x30, x8
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
add x4, x4, #2
|
add x4, x4, #2
|
||||||
@@ -844,7 +842,6 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17WriteIoMemory8BitEPvPKvm:
|
|||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
1: /* Read the word from normal memory. */
|
1: /* Read the word from normal memory. */
|
||||||
mov x30, x8
|
|
||||||
ldtrb w9, [x5]
|
ldtrb w9, [x5]
|
||||||
|
|
||||||
/* Set our return address so that on read failure we continue. */
|
/* Set our return address so that on read failure we continue. */
|
||||||
@@ -855,7 +852,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17WriteIoMemory8BitEPvPKvm:
|
|||||||
dsb sy
|
dsb sy
|
||||||
|
|
||||||
2: /* Continue. */
|
2: /* Continue. */
|
||||||
nop
|
mov x30, x8
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
add x4, x4, #1
|
add x4, x4, #1
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#include <mesosphere/kern_select_assembly_offsets.h>
|
||||||
|
|
||||||
/* ams::kern::svc::CallReturnFromException64(Result result) */
|
/* ams::kern::svc::CallReturnFromException64(Result result) */
|
||||||
.section .text._ZN3ams4kern3svc25CallReturnFromException64Ev, "ax", %progbits
|
.section .text._ZN3ams4kern3svc25CallReturnFromException64Ev, "ax", %progbits
|
||||||
@@ -20,15 +21,15 @@
|
|||||||
.type _ZN3ams4kern3svc25CallReturnFromException64Ev, %function
|
.type _ZN3ams4kern3svc25CallReturnFromException64Ev, %function
|
||||||
_ZN3ams4kern3svc25CallReturnFromException64Ev:
|
_ZN3ams4kern3svc25CallReturnFromException64Ev:
|
||||||
/* Save registers the SVC entry handler didn't. */
|
/* Save registers the SVC entry handler didn't. */
|
||||||
stp x12, x13, [sp, #(8 * 12)]
|
stp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
|
||||||
stp x14, x15, [sp, #(8 * 14)]
|
stp x14, x15, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
|
||||||
stp x16, x17, [sp, #(8 * 16)]
|
stp x16, x17, [sp, #(EXCEPTION_CONTEXT_X16_X17)]
|
||||||
str x19, [sp, #(8 * 19)]
|
str x19, [sp, #(EXCEPTION_CONTEXT_X19)]
|
||||||
stp x20, x21, [sp, #(8 * 20)]
|
stp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)]
|
||||||
stp x22, x23, [sp, #(8 * 22)]
|
stp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)]
|
||||||
stp x24, x25, [sp, #(8 * 24)]
|
stp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)]
|
||||||
stp x26, x26, [sp, #(8 * 26)]
|
stp x26, x26, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
|
||||||
stp x28, x29, [sp, #(8 * 28)]
|
stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
|
||||||
|
|
||||||
/* Call ams::kern::arch::arm64::ReturnFromException(result). */
|
/* Call ams::kern::arch::arm64::ReturnFromException(result). */
|
||||||
bl _ZN3ams4kern4arch5arm6419ReturnFromExceptionENS_6ResultE
|
bl _ZN3ams4kern4arch5arm6419ReturnFromExceptionENS_6ResultE
|
||||||
@@ -62,7 +63,7 @@ _ZN3ams4kern3svc14RestoreContextEm:
|
|||||||
|
|
||||||
0: /* We should handle DPC. */
|
0: /* We should handle DPC. */
|
||||||
/* Check the dpc flags. */
|
/* Check the dpc flags. */
|
||||||
ldrb w8, [sp, #(0x120 + 0x10)]
|
ldrb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_DPC_FLAGS)]
|
||||||
cbz w8, 1f
|
cbz w8, 1f
|
||||||
|
|
||||||
/* We have DPC to do! */
|
/* We have DPC to do! */
|
||||||
@@ -82,32 +83,32 @@ _ZN3ams4kern3svc14RestoreContextEm:
|
|||||||
|
|
||||||
1: /* We're done with DPC, and should return from the svc. */
|
1: /* We're done with DPC, and should return from the svc. */
|
||||||
/* Clear our in-SVC note. */
|
/* Clear our in-SVC note. */
|
||||||
strb wzr, [sp, #(0x120 + 0x12)]
|
strb wzr, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_CALLING_SVC)]
|
||||||
|
|
||||||
/* Restore registers. */
|
/* Restore registers. */
|
||||||
ldp x30, x8, [sp, #(8 * 30)]
|
ldp x30, x8, [sp, #(EXCEPTION_CONTEXT_X30_SP)]
|
||||||
ldp x9, x10, [sp, #(8 * 32)]
|
ldp x9, x10, [sp, #(EXCEPTION_CONTEXT_PC_PSR)]
|
||||||
ldr x11, [sp, #(8 * 34)]
|
ldr x11, [sp, #(EXCEPTION_CONTEXT_TPIDR)]
|
||||||
msr sp_el0, x8
|
msr sp_el0, x8
|
||||||
msr elr_el1, x9
|
msr elr_el1, x9
|
||||||
msr spsr_el1, x10
|
msr spsr_el1, x10
|
||||||
msr tpidr_el0, x11
|
msr tpidr_el0, x11
|
||||||
ldp x0, x1, [sp, #(8 * 0)]
|
ldp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
|
||||||
ldp x2, x3, [sp, #(8 * 2)]
|
ldp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
|
||||||
ldp x4, x5, [sp, #(8 * 4)]
|
ldp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
|
||||||
ldp x6, x7, [sp, #(8 * 6)]
|
ldp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
|
||||||
ldp x8, x9, [sp, #(8 * 8)]
|
ldp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)]
|
||||||
ldp x10, x11, [sp, #(8 * 10)]
|
ldp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)]
|
||||||
ldp x12, x13, [sp, #(8 * 12)]
|
ldp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
|
||||||
ldp x14, x15, [sp, #(8 * 14)]
|
ldp x14, x15, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
|
||||||
ldp x16, x17, [sp, #(8 * 16)]
|
ldp x16, x17, [sp, #(EXCEPTION_CONTEXT_X16_X17)]
|
||||||
ldp x18, x19, [sp, #(8 * 18)]
|
ldp x18, x19, [sp, #(EXCEPTION_CONTEXT_X18_X19)]
|
||||||
ldp x20, x21, [sp, #(8 * 20)]
|
ldp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)]
|
||||||
ldp x22, x23, [sp, #(8 * 22)]
|
ldp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)]
|
||||||
ldp x24, x25, [sp, #(8 * 24)]
|
ldp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)]
|
||||||
ldp x26, x27, [sp, #(8 * 26)]
|
ldp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
|
||||||
ldp x28, x29, [sp, #(8 * 28)]
|
ldp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
|
||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #0x120
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
eret
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <mesosphere/kern_build_config.hpp>
|
#include <mesosphere/kern_build_config.hpp>
|
||||||
|
#include <mesosphere/kern_select_assembly_offsets.h>
|
||||||
|
|
||||||
/* ams::kern::arch::arm64::SvcHandler64() */
|
/* ams::kern::arch::arm64::SvcHandler64() */
|
||||||
.section .text._ZN3ams4kern4arch5arm6412SvcHandler64Ev, "ax", %progbits
|
.section .text._ZN3ams4kern4arch5arm6412SvcHandler64Ev, "ax", %progbits
|
||||||
@@ -21,45 +22,45 @@
|
|||||||
.type _ZN3ams4kern4arch5arm6412SvcHandler64Ev, %function
|
.type _ZN3ams4kern4arch5arm6412SvcHandler64Ev, %function
|
||||||
_ZN3ams4kern4arch5arm6412SvcHandler64Ev:
|
_ZN3ams4kern4arch5arm6412SvcHandler64Ev:
|
||||||
/* Create a KExceptionContext for the exception. */
|
/* Create a KExceptionContext for the exception. */
|
||||||
sub sp, sp, #0x120
|
sub sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
|
|
||||||
/* Save registers needed for ReturnFromException */
|
/* Save registers needed for ReturnFromException */
|
||||||
stp x9, x10, [sp, #(8 * 9)]
|
stp x9, x10, [sp, #(EXCEPTION_CONTEXT_X9_X10)]
|
||||||
str x11, [sp, #(8 * 11)]
|
str x11, [sp, #(EXCEPTION_CONTEXT_X11)]
|
||||||
str x18, [sp, #(8 * 18)]
|
str x18, [sp, #(EXCEPTION_CONTEXT_X18)]
|
||||||
|
|
||||||
mrs x8, sp_el0
|
mrs x8, sp_el0
|
||||||
mrs x9, elr_el1
|
mrs x9, elr_el1
|
||||||
mrs x10, spsr_el1
|
mrs x10, spsr_el1
|
||||||
mrs x11, tpidr_el0
|
mrs x11, tpidr_el0
|
||||||
ldr x18, [sp, #(0x120 + 0x28)]
|
ldr x18, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CUR_THREAD)]
|
||||||
|
|
||||||
/* Save callee-saved registers. */
|
/* Save callee-saved registers. */
|
||||||
stp x19, x20, [sp, #(8 * 19)]
|
stp x19, x20, [sp, #(EXCEPTION_CONTEXT_X19_X20)]
|
||||||
stp x21, x22, [sp, #(8 * 21)]
|
stp x21, x22, [sp, #(EXCEPTION_CONTEXT_X21_X22)]
|
||||||
stp x23, x24, [sp, #(8 * 23)]
|
stp x23, x24, [sp, #(EXCEPTION_CONTEXT_X23_X24)]
|
||||||
stp x25, x26, [sp, #(8 * 25)]
|
stp x25, x26, [sp, #(EXCEPTION_CONTEXT_X25_X26)]
|
||||||
stp x27, x28, [sp, #(8 * 27)]
|
stp x27, x28, [sp, #(EXCEPTION_CONTEXT_X27_X28)]
|
||||||
|
|
||||||
/* Save miscellaneous registers. */
|
/* Save miscellaneous registers. */
|
||||||
stp x0, x1, [sp, #(8 * 0)]
|
stp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
|
||||||
stp x2, x3, [sp, #(8 * 2)]
|
stp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
|
||||||
stp x4, x5, [sp, #(8 * 4)]
|
stp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
|
||||||
stp x6, x7, [sp, #(8 * 6)]
|
stp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
|
||||||
stp x29, x30, [sp, #(8 * 29)]
|
stp x29, x30, [sp, #(EXCEPTION_CONTEXT_X29_X30)]
|
||||||
stp x8, x9, [sp, #(8 * 31)]
|
stp x8, x9, [sp, #(EXCEPTION_CONTEXT_SP_PC)]
|
||||||
stp x10, x11, [sp, #(8 * 33)]
|
stp x10, x11, [sp, #(EXCEPTION_CONTEXT_PSR_TPIDR)]
|
||||||
|
|
||||||
/* Check if the SVC index is out of range. */
|
/* Check if the SVC index is out of range. */
|
||||||
mrs x8, esr_el1
|
mrs x8, esr_el1
|
||||||
and x8, x8, #0xFF
|
and x8, x8, #0xFF
|
||||||
cmp x8, #0x80
|
cmp x8, #(AMS_KERN_NUM_SUPERVISOR_CALLS)
|
||||||
b.ge 3f
|
b.ge 3f
|
||||||
|
|
||||||
/* Check the specific SVC permission bit for allowal. */
|
/* Check the specific SVC permission bit for allowal. */
|
||||||
mov x9, sp
|
mov x9, sp
|
||||||
add x9, x9, x8, lsr#3
|
add x9, x9, x8, lsr#3
|
||||||
ldrb w9, [x9, #0x120]
|
ldrb w9, [x9, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_SVC_PERMISSION)]
|
||||||
and x10, x8, #0x7
|
and x10, x8, #0x7
|
||||||
lsr x10, x9, x10
|
lsr x10, x9, x10
|
||||||
tst x10, #1
|
tst x10, #1
|
||||||
@@ -67,11 +68,11 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
|
|||||||
|
|
||||||
/* Check if our disable count allows us to call SVCs. */
|
/* Check if our disable count allows us to call SVCs. */
|
||||||
mrs x10, tpidrro_el0
|
mrs x10, tpidrro_el0
|
||||||
ldrh w10, [x10, #0x100]
|
ldrh w10, [x10, #(THREAD_LOCAL_REGION_DISABLE_COUNT)]
|
||||||
cbz w10, 1f
|
cbz w10, 1f
|
||||||
|
|
||||||
/* It might not, so check the stack params to see if we must not allow the SVC. */
|
/* It might not, so check the stack params to see if we must not allow the SVC. */
|
||||||
ldrb w10, [sp, #(0x120 + 0x14)]
|
ldrb w10, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_PINNED)]
|
||||||
cbz w10, 3f
|
cbz w10, 3f
|
||||||
|
|
||||||
1: /* We can call the SVC. */
|
1: /* We can call the SVC. */
|
||||||
@@ -81,8 +82,8 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
|
|||||||
|
|
||||||
/* Note that we're calling the SVC. */
|
/* Note that we're calling the SVC. */
|
||||||
mov w10, #1
|
mov w10, #1
|
||||||
strb w10, [sp, #(0x120 + 0x12)]
|
strb w10, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_CALLING_SVC)]
|
||||||
strb w8, [sp, #(0x120 + 0x11)]
|
strb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CURRENT_SVC_ID)]
|
||||||
|
|
||||||
/* If we should, trace the svc entry. */
|
/* If we should, trace the svc entry. */
|
||||||
#if defined(MESOSPHERE_BUILD_FOR_TRACING)
|
#if defined(MESOSPHERE_BUILD_FOR_TRACING)
|
||||||
@@ -109,7 +110,7 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
|
|||||||
|
|
||||||
2: /* We completed the SVC, and we should handle DPC. */
|
2: /* We completed the SVC, and we should handle DPC. */
|
||||||
/* Check the dpc flags. */
|
/* Check the dpc flags. */
|
||||||
ldrb w8, [sp, #(0x120 + 0x10)]
|
ldrb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_DPC_FLAGS)]
|
||||||
cbz w8, 4f
|
cbz w8, 4f
|
||||||
|
|
||||||
/* We have DPC to do! */
|
/* We have DPC to do! */
|
||||||
@@ -129,57 +130,57 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
|
|||||||
|
|
||||||
3: /* Invalid SVC. */
|
3: /* Invalid SVC. */
|
||||||
/* Setup the context to call into HandleException. */
|
/* Setup the context to call into HandleException. */
|
||||||
stp x0, x1, [sp, #(8 * 0)]
|
stp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
|
||||||
stp x2, x3, [sp, #(8 * 2)]
|
stp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
|
||||||
stp x4, x5, [sp, #(8 * 4)]
|
stp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
|
||||||
stp x6, x7, [sp, #(8 * 6)]
|
stp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
|
||||||
stp xzr, xzr, [sp, #(8 * 8)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X8_X9)]
|
||||||
stp xzr, xzr, [sp, #(8 * 10)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X10_X11)]
|
||||||
stp xzr, xzr, [sp, #(8 * 12)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
|
||||||
stp xzr, xzr, [sp, #(8 * 14)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
|
||||||
stp xzr, xzr, [sp, #(8 * 16)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X16_X17)]
|
||||||
str x19, [sp, #(8 * 19)]
|
str x19, [sp, #(EXCEPTION_CONTEXT_X19)]
|
||||||
stp x20, x21, [sp, #(8 * 20)]
|
stp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)]
|
||||||
stp x22, x23, [sp, #(8 * 22)]
|
stp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)]
|
||||||
stp x24, x25, [sp, #(8 * 24)]
|
stp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)]
|
||||||
stp x26, x27, [sp, #(8 * 26)]
|
stp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
|
||||||
stp x28, x29, [sp, #(8 * 28)]
|
stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
|
||||||
|
|
||||||
/* Call ams::kern::arch::arm64::HandleException(ams::kern::arch::arm64::KExceptionContext *) */
|
/* Call ams::kern::arch::arm64::HandleException(ams::kern::arch::arm64::KExceptionContext *) */
|
||||||
mov x0, sp
|
mov x0, sp
|
||||||
bl _ZN3ams4kern4arch5arm6415HandleExceptionEPNS2_17KExceptionContextE
|
bl _ZN3ams4kern4arch5arm6415HandleExceptionEPNS2_17KExceptionContextE
|
||||||
|
|
||||||
/* Restore registers. */
|
/* Restore registers. */
|
||||||
ldp x30, x8, [sp, #(8 * 30)]
|
ldp x30, x8, [sp, #(EXCEPTION_CONTEXT_X30_SP)]
|
||||||
ldp x9, x10, [sp, #(8 * 32)]
|
ldp x9, x10, [sp, #(EXCEPTION_CONTEXT_PC_PSR)]
|
||||||
ldr x11, [sp, #(8 * 34)]
|
ldr x11, [sp, #(EXCEPTION_CONTEXT_TPIDR)]
|
||||||
msr sp_el0, x8
|
msr sp_el0, x8
|
||||||
msr elr_el1, x9
|
msr elr_el1, x9
|
||||||
msr spsr_el1, x10
|
msr spsr_el1, x10
|
||||||
msr tpidr_el0, x11
|
msr tpidr_el0, x11
|
||||||
ldp x0, x1, [sp, #(8 * 0)]
|
ldp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
|
||||||
ldp x2, x3, [sp, #(8 * 2)]
|
ldp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
|
||||||
ldp x4, x5, [sp, #(8 * 4)]
|
ldp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
|
||||||
ldp x6, x7, [sp, #(8 * 6)]
|
ldp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
|
||||||
ldp x8, x9, [sp, #(8 * 8)]
|
ldp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)]
|
||||||
ldp x10, x11, [sp, #(8 * 10)]
|
ldp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)]
|
||||||
ldp x12, x13, [sp, #(8 * 12)]
|
ldp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
|
||||||
ldp x14, x15, [sp, #(8 * 14)]
|
ldp x14, x15, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
|
||||||
ldp x16, x17, [sp, #(8 * 16)]
|
ldp x16, x17, [sp, #(EXCEPTION_CONTEXT_X16_X17)]
|
||||||
ldp x18, x19, [sp, #(8 * 18)]
|
ldp x18, x19, [sp, #(EXCEPTION_CONTEXT_X18_X19)]
|
||||||
ldp x20, x21, [sp, #(8 * 20)]
|
ldp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)]
|
||||||
ldp x22, x23, [sp, #(8 * 22)]
|
ldp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)]
|
||||||
ldp x24, x25, [sp, #(8 * 24)]
|
ldp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)]
|
||||||
ldp x26, x27, [sp, #(8 * 26)]
|
ldp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
|
||||||
ldp x28, x29, [sp, #(8 * 28)]
|
ldp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
|
||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #0x120
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
eret
|
||||||
|
|
||||||
4: /* Return from SVC. */
|
4: /* Return from SVC. */
|
||||||
/* Clear our in-SVC note. */
|
/* Clear our in-SVC note. */
|
||||||
strb wzr, [sp, #(0x120 + 0x12)]
|
strb wzr, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_CALLING_SVC)]
|
||||||
|
|
||||||
/* If we should, trace the svc exit. */
|
/* If we should, trace the svc exit. */
|
||||||
#if defined(MESOSPHERE_BUILD_FOR_TRACING)
|
#if defined(MESOSPHERE_BUILD_FOR_TRACING)
|
||||||
@@ -198,10 +199,10 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Restore registers. */
|
/* Restore registers. */
|
||||||
ldp x30, x8, [sp, #(8 * 30)]
|
ldp x30, x8, [sp, #(EXCEPTION_CONTEXT_X30_SP)]
|
||||||
ldp x9, x10, [sp, #(8 * 32)]
|
ldp x9, x10, [sp, #(EXCEPTION_CONTEXT_PC_PSR)]
|
||||||
ldr x11, [sp, #(8 * 34)]
|
ldr x11, [sp, #(EXCEPTION_CONTEXT_TPIDR)]
|
||||||
ldr x18, [sp, #(8 * 18)]
|
ldr x18, [sp, #(EXCEPTION_CONTEXT_X18)]
|
||||||
msr sp_el0, x8
|
msr sp_el0, x8
|
||||||
msr elr_el1, x9
|
msr elr_el1, x9
|
||||||
msr spsr_el1, x10
|
msr spsr_el1, x10
|
||||||
@@ -220,7 +221,7 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
|
|||||||
mov x17, xzr
|
mov x17, xzr
|
||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #0x120
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
eret
|
||||||
|
|
||||||
/* ams::kern::arch::arm64::SvcHandler32() */
|
/* ams::kern::arch::arm64::SvcHandler32() */
|
||||||
@@ -239,36 +240,36 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
|
|||||||
mov w7, w7
|
mov w7, w7
|
||||||
|
|
||||||
/* Create a KExceptionContext for the exception. */
|
/* Create a KExceptionContext for the exception. */
|
||||||
sub sp, sp, #0x120
|
sub sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
|
|
||||||
/* Save system registers */
|
/* Save system registers */
|
||||||
mrs x17, elr_el1
|
mrs x17, elr_el1
|
||||||
mrs x20, spsr_el1
|
mrs x20, spsr_el1
|
||||||
mrs x19, tpidr_el0
|
mrs x19, tpidr_el0
|
||||||
ldr x18, [sp, #(0x120 + 0x28)]
|
ldr x18, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CUR_THREAD)]
|
||||||
stp x17, x20, [sp, #(8 * 32)]
|
stp x17, x20, [sp, #(EXCEPTION_CONTEXT_PC_PSR)]
|
||||||
str x19, [sp, #(8 * 34)]
|
str x19, [sp, #(EXCEPTION_CONTEXT_TPIDR)]
|
||||||
|
|
||||||
/* Save registers. */
|
/* Save registers. */
|
||||||
stp x0, x1, [sp, #(8 * 0)]
|
stp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
|
||||||
stp x2, x3, [sp, #(8 * 2)]
|
stp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
|
||||||
stp x4, x5, [sp, #(8 * 4)]
|
stp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
|
||||||
stp x6, x7, [sp, #(8 * 6)]
|
stp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
|
||||||
stp x8, x9, [sp, #(8 * 8)]
|
stp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)]
|
||||||
stp x10, x11, [sp, #(8 * 10)]
|
stp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)]
|
||||||
stp x12, x13, [sp, #(8 * 12)]
|
stp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
|
||||||
stp x14, xzr, [sp, #(8 * 14)]
|
stp x14, xzr, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
|
||||||
|
|
||||||
/* Check if the SVC index is out of range. */
|
/* Check if the SVC index is out of range. */
|
||||||
mrs x16, esr_el1
|
mrs x16, esr_el1
|
||||||
and x16, x16, #0xFF
|
and x16, x16, #0xFF
|
||||||
cmp x16, #0x80
|
cmp x16, #(AMS_KERN_NUM_SUPERVISOR_CALLS)
|
||||||
b.ge 3f
|
b.ge 3f
|
||||||
|
|
||||||
/* Check the specific SVC permission bit for allowal. */
|
/* Check the specific SVC permission bit for allowal. */
|
||||||
mov x20, sp
|
mov x20, sp
|
||||||
add x20, x20, x16, lsr#3
|
add x20, x20, x16, lsr#3
|
||||||
ldrb w20, [x20, #0x120]
|
ldrb w20, [x20, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_SVC_PERMISSION)]
|
||||||
and x17, x16, #0x7
|
and x17, x16, #0x7
|
||||||
lsr x17, x20, x17
|
lsr x17, x20, x17
|
||||||
tst x17, #1
|
tst x17, #1
|
||||||
@@ -276,11 +277,11 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
|
|||||||
|
|
||||||
/* Check if our disable count allows us to call SVCs. */
|
/* Check if our disable count allows us to call SVCs. */
|
||||||
mrs x15, tpidrro_el0
|
mrs x15, tpidrro_el0
|
||||||
ldrh w15, [x15, #0x100]
|
ldrh w15, [x15, #(THREAD_LOCAL_REGION_DISABLE_COUNT)]
|
||||||
cbz w15, 1f
|
cbz w15, 1f
|
||||||
|
|
||||||
/* It might not, so check the stack params to see if we must not allow the SVC. */
|
/* It might not, so check the stack params to see if we must not allow the SVC. */
|
||||||
ldrb w15, [sp, #(0x120 + 0x14)]
|
ldrb w15, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_PINNED)]
|
||||||
cbz w15, 3f
|
cbz w15, 3f
|
||||||
|
|
||||||
1: /* We can call the SVC. */
|
1: /* We can call the SVC. */
|
||||||
@@ -290,8 +291,8 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
|
|||||||
|
|
||||||
/* Note that we're calling the SVC. */
|
/* Note that we're calling the SVC. */
|
||||||
mov w15, #1
|
mov w15, #1
|
||||||
strb w15, [sp, #(0x120 + 0x12)]
|
strb w15, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_CALLING_SVC)]
|
||||||
strb w16, [sp, #(0x120 + 0x11)]
|
strb w16, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CURRENT_SVC_ID)]
|
||||||
|
|
||||||
/* If we should, trace the svc entry. */
|
/* If we should, trace the svc entry. */
|
||||||
#if defined(MESOSPHERE_BUILD_FOR_TRACING)
|
#if defined(MESOSPHERE_BUILD_FOR_TRACING)
|
||||||
@@ -318,7 +319,7 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
|
|||||||
|
|
||||||
2: /* We completed the SVC, and we should handle DPC. */
|
2: /* We completed the SVC, and we should handle DPC. */
|
||||||
/* Check the dpc flags. */
|
/* Check the dpc flags. */
|
||||||
ldrb w16, [sp, #(0x120 + 0x10)]
|
ldrb w16, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_DPC_FLAGS)]
|
||||||
cbz w16, 4f
|
cbz w16, 4f
|
||||||
|
|
||||||
/* We have DPC to do! */
|
/* We have DPC to do! */
|
||||||
@@ -338,45 +339,45 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
|
|||||||
|
|
||||||
3: /* Invalid SVC. */
|
3: /* Invalid SVC. */
|
||||||
/* Setup the context to call into HandleException. */
|
/* Setup the context to call into HandleException. */
|
||||||
stp x0, x1, [sp, #(8 * 0)]
|
stp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
|
||||||
stp x2, x3, [sp, #(8 * 2)]
|
stp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
|
||||||
stp x4, x5, [sp, #(8 * 4)]
|
stp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
|
||||||
stp x6, x7, [sp, #(8 * 6)]
|
stp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
|
||||||
stp xzr, xzr, [sp, #(8 * 16)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X16_X17)]
|
||||||
stp xzr, xzr, [sp, #(8 * 18)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X18_X19)]
|
||||||
stp xzr, xzr, [sp, #(8 * 20)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X20_X21)]
|
||||||
stp xzr, xzr, [sp, #(8 * 22)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X22_X23)]
|
||||||
stp xzr, xzr, [sp, #(8 * 24)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X24_X25)]
|
||||||
stp xzr, xzr, [sp, #(8 * 26)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
|
||||||
stp xzr, xzr, [sp, #(8 * 28)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
|
||||||
stp xzr, xzr, [sp, #(8 * 30)]
|
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X30_SP)]
|
||||||
|
|
||||||
/* Call ams::kern::arch::arm64::HandleException(ams::kern::arch::arm64::KExceptionContext *) */
|
/* Call ams::kern::arch::arm64::HandleException(ams::kern::arch::arm64::KExceptionContext *) */
|
||||||
mov x0, sp
|
mov x0, sp
|
||||||
bl _ZN3ams4kern4arch5arm6415HandleExceptionEPNS2_17KExceptionContextE
|
bl _ZN3ams4kern4arch5arm6415HandleExceptionEPNS2_17KExceptionContextE
|
||||||
|
|
||||||
/* Restore registers. */
|
/* Restore registers. */
|
||||||
ldp x17, x20, [sp, #(8 * 32)]
|
ldp x17, x20, [sp, #(EXCEPTION_CONTEXT_PC_PSR)]
|
||||||
ldr x19, [sp, #(8 * 34)]
|
ldr x19, [sp, #(EXCEPTION_CONTEXT_TPIDR)]
|
||||||
msr elr_el1, x17
|
msr elr_el1, x17
|
||||||
msr spsr_el1, x20
|
msr spsr_el1, x20
|
||||||
msr tpidr_el0, x19
|
msr tpidr_el0, x19
|
||||||
ldp x0, x1, [sp, #(8 * 0)]
|
ldp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
|
||||||
ldp x2, x3, [sp, #(8 * 2)]
|
ldp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
|
||||||
ldp x4, x5, [sp, #(8 * 4)]
|
ldp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
|
||||||
ldp x6, x7, [sp, #(8 * 6)]
|
ldp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
|
||||||
ldp x8, x9, [sp, #(8 * 8)]
|
ldp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)]
|
||||||
ldp x10, x11, [sp, #(8 * 10)]
|
ldp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)]
|
||||||
ldp x12, x13, [sp, #(8 * 12)]
|
ldp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
|
||||||
ldp x14, x15, [sp, #(8 * 14)]
|
ldp x14, x15, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
|
||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #0x120
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
eret
|
||||||
|
|
||||||
4: /* Return from SVC. */
|
4: /* Return from SVC. */
|
||||||
/* Clear our in-SVC note. */
|
/* Clear our in-SVC note. */
|
||||||
strb wzr, [sp, #(0x120 + 0x12)]
|
strb wzr, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_CALLING_SVC)]
|
||||||
|
|
||||||
/* If we should, trace the svc exit. */
|
/* If we should, trace the svc exit. */
|
||||||
#if defined(MESOSPHERE_BUILD_FOR_TRACING)
|
#if defined(MESOSPHERE_BUILD_FOR_TRACING)
|
||||||
@@ -395,16 +396,16 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Restore registers. */
|
/* Restore registers. */
|
||||||
ldp x8, x9, [sp, #(8 * 8)]
|
ldp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)]
|
||||||
ldp x10, x11, [sp, #(8 * 10)]
|
ldp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)]
|
||||||
ldp x12, x13, [sp, #(8 * 12)]
|
ldp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
|
||||||
ldp x14, xzr, [sp, #(8 * 14)]
|
ldp x14, xzr, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
|
||||||
ldp x17, x20, [sp, #(8 * 32)]
|
ldp x17, x20, [sp, #(EXCEPTION_CONTEXT_PC_PSR)]
|
||||||
ldr x19, [sp, #(8 * 34)]
|
ldr x19, [sp, #(EXCEPTION_CONTEXT_TPIDR)]
|
||||||
msr elr_el1, x17
|
msr elr_el1, x17
|
||||||
msr spsr_el1, x20
|
msr spsr_el1, x20
|
||||||
msr tpidr_el0, x19
|
msr tpidr_el0, x19
|
||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #0x120
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
eret
|
||||||
|
|||||||
@@ -216,6 +216,12 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
return (m_value & (1u << n));
|
return (m_value & (1u << n));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<Bit... Bits>
|
||||||
|
constexpr ALWAYS_INLINE u32 SelectBits() const {
|
||||||
|
constexpr u32 Mask = ((1u << Bits) | ...);
|
||||||
|
return m_value & Mask;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE bool GetBit(Bit n) const {
|
constexpr ALWAYS_INLINE bool GetBit(Bit n) const {
|
||||||
return this->SelectBit(n) != 0;
|
return this->SelectBit(n) != 0;
|
||||||
}
|
}
|
||||||
@@ -242,12 +248,14 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBit(Bit_NonSecure); }
|
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBit(Bit_NonSecure); }
|
||||||
constexpr ALWAYS_INLINE bool IsWriteable() const { return this->GetBit(Bit_Writeable); }
|
constexpr ALWAYS_INLINE bool IsWriteable() const { return this->GetBit(Bit_Writeable); }
|
||||||
constexpr ALWAYS_INLINE bool IsReadable() const { return this->GetBit(Bit_Readable); }
|
constexpr ALWAYS_INLINE bool IsReadable() const { return this->GetBit(Bit_Readable); }
|
||||||
constexpr ALWAYS_INLINE bool IsValid() const { return this->IsWriteable() || this->IsReadable(); }
|
constexpr ALWAYS_INLINE bool IsValid() const { return this->SelectBits<Bit_Readable, Bit_Writeable>(); }
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE u32 GetAttributes() const { return this->SelectBit(Bit_NonSecure) | this->SelectBit(Bit_Writeable) | this->SelectBit(Bit_Readable); }
|
constexpr ALWAYS_INLINE u32 GetAttributes() const { return this->SelectBits<Bit_Readable, Bit_Writeable, Bit_NonSecure>(); }
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE KPhysicalAddress GetPhysicalAddress() const { return (static_cast<u64>(m_value) << DevicePageBits) & PhysicalAddressMask; }
|
constexpr ALWAYS_INLINE KPhysicalAddress GetPhysicalAddress() const { return (static_cast<u64>(m_value) << DevicePageBits) & PhysicalAddressMask; }
|
||||||
|
|
||||||
|
|
||||||
|
ALWAYS_INLINE void InvalidateAttributes() { this->SetValue(m_value & ~(0xCu << 28)); }
|
||||||
ALWAYS_INLINE void Invalidate() { this->SetValue(0); }
|
ALWAYS_INLINE void Invalidate() { this->SetValue(0); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -526,7 +534,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
#if defined(MESOSPHERE_ENABLE_MEMORY_CONTROLLER_INTERRUPT)
|
#if defined(MESOSPHERE_ENABLE_MEMORY_CONTROLLER_INTERRUPT)
|
||||||
{
|
{
|
||||||
/* Clear the interrupt when we're done. */
|
/* Clear the interrupt when we're done. */
|
||||||
ON_SCOPE_EXIT { Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_MemoryController); };
|
ON_SCOPE_EXIT { Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_MemoryController, GetCurrentCoreId()); };
|
||||||
|
|
||||||
/* Get and clear the interrupt status. */
|
/* Get and clear the interrupt status. */
|
||||||
u32 int_status, err_status, err_adr;
|
u32 int_status, err_status, err_adr;
|
||||||
@@ -847,7 +855,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Forcibly unmap all pages. */
|
/* Forcibly unmap all pages. */
|
||||||
this->UnmapImpl(0, (1ul << DeviceVirtualAddressBits), true);
|
this->UnmapImpl(0, (1ul << DeviceVirtualAddressBits), false);
|
||||||
|
|
||||||
/* Release all asids. */
|
/* Release all asids. */
|
||||||
for (size_t i = 0; i < TableCount; ++i) {
|
for (size_t i = 0; i < TableCount; ++i) {
|
||||||
@@ -1117,12 +1125,11 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KDevicePageTable::MapImpl(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm) {
|
Result KDevicePageTable::MapImpl(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned) {
|
||||||
/* Clear the output size. */
|
/* Clear the output size. */
|
||||||
*out_mapped_size = 0;
|
*out_mapped_size = 0;
|
||||||
|
|
||||||
/* Get the size, and validate the address. */
|
/* Get the size, and validate the address. */
|
||||||
const u64 size = pg.GetNumPages() * PageSize;
|
|
||||||
MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0);
|
MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0);
|
||||||
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
|
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
|
||||||
|
|
||||||
@@ -1130,28 +1137,33 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
R_UNLESS(this->IsFree(device_address, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(this->IsFree(device_address, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
/* Ensure that if we fail, we unmap anything we mapped. */
|
/* Ensure that if we fail, we unmap anything we mapped. */
|
||||||
auto unmap_guard = SCOPE_GUARD { this->UnmapImpl(device_address, size, true); };
|
auto unmap_guard = SCOPE_GUARD { this->UnmapImpl(device_address, size, false); };
|
||||||
|
|
||||||
/* Iterate, mapping device pages. */
|
/* Iterate, mapping device pages. */
|
||||||
KDeviceVirtualAddress cur_addr = device_address;
|
KDeviceVirtualAddress cur_addr = device_address;
|
||||||
for (auto it = pg.begin(); it != pg.end(); ++it) {
|
while (true) {
|
||||||
/* Require that we be able to map the device page. */
|
/* Get the current contiguous range. */
|
||||||
R_UNLESS(IsHeapVirtualAddress(it->GetAddress()), svc::ResultInvalidCurrentMemory());
|
KPageTableBase::MemoryRange contig_range = {};
|
||||||
|
R_TRY(page_table->OpenMemoryRangeForMapDeviceAddressSpace(std::addressof(contig_range), process_address + *out_mapped_size, size - *out_mapped_size, ConvertToKMemoryPermission(device_perm), is_aligned));
|
||||||
|
|
||||||
/* Get the physical address for the page. */
|
/* Ensure we close the range when we're done. */
|
||||||
const KPhysicalAddress phys_addr = GetHeapPhysicalAddress(it->GetAddress());
|
ON_SCOPE_EXIT { contig_range.Close(); };
|
||||||
|
|
||||||
/* Map the device page. */
|
/* Map the device page. */
|
||||||
const u64 block_size = it->GetSize();
|
|
||||||
size_t mapped_size = 0;
|
size_t mapped_size = 0;
|
||||||
R_TRY(this->MapDevicePage(std::addressof(mapped_size), num_pt, max_pt, phys_addr, block_size, cur_addr, device_perm));
|
R_TRY(this->MapDevicePage(std::addressof(mapped_size), num_pt, max_pt, GetHeapPhysicalAddress(contig_range.address), contig_range.size, cur_addr, device_perm));
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
cur_addr += block_size;
|
cur_addr += contig_range.size;
|
||||||
*out_mapped_size += mapped_size;
|
*out_mapped_size += mapped_size;
|
||||||
|
|
||||||
/* If we didn't map as much as we wanted, break. */
|
/* If we didn't map as much as we wanted, break. */
|
||||||
if (mapped_size < block_size) {
|
if (mapped_size < contig_range.size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Similarly, if we're done, break. */
|
||||||
|
if (*out_mapped_size >= size) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1186,8 +1198,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
/* Check if there's nothing mapped at l1. */
|
/* Check if there's nothing mapped at l1. */
|
||||||
if (l1 == nullptr || !l1[l1_index].IsValid()) {
|
if (l1 == nullptr || !l1[l1_index].IsValid()) {
|
||||||
MESOSPHERE_ASSERT(force);
|
|
||||||
|
|
||||||
const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index;
|
const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index;
|
||||||
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize);
|
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize);
|
||||||
|
|
||||||
@@ -1201,30 +1211,12 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index;
|
const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index;
|
||||||
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize);
|
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize);
|
||||||
size_t num_closed = 0;
|
size_t num_closed = 0;
|
||||||
bool invalidated_tlb = false;
|
|
||||||
|
|
||||||
|
/* Invalidate the attributes of all entries. */
|
||||||
for (size_t i = 0; i < map_count; ++i) {
|
for (size_t i = 0; i < map_count; ++i) {
|
||||||
if (l2[l2_index + i].IsValid()) {
|
if (l2[l2_index + i].IsValid()) {
|
||||||
/* Get the physical address. */
|
l2[l2_index + i].InvalidateAttributes();
|
||||||
const KPhysicalAddress phys_addr = l2[l2_index + i].GetPhysicalAddress();
|
|
||||||
MESOSPHERE_ASSERT(IsHeapPhysicalAddress(phys_addr));
|
|
||||||
|
|
||||||
/* Invalidate the entry. */
|
|
||||||
l2[l2_index + i].Invalidate();
|
|
||||||
++num_closed;
|
++num_closed;
|
||||||
|
|
||||||
/* Try to add the page to the group. */
|
|
||||||
if (R_FAILED(pg.AddBlock(GetHeapVirtualAddress(phys_addr), DevicePageSize / PageSize))) {
|
|
||||||
/* If we can't add it for deferred close, close it now. */
|
|
||||||
cpu::StoreDataCache(std::addressof(l2[l2_index + i]), sizeof(PageTableEntry));
|
|
||||||
InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l2[l2_index + i]))));
|
|
||||||
SmmuSynchronizationBarrier();
|
|
||||||
|
|
||||||
/* Close the page's reference. */
|
|
||||||
mm.Close(GetHeapVirtualAddress(phys_addr), 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
MESOSPHERE_ASSERT(force);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cpu::StoreDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry));
|
cpu::StoreDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry));
|
||||||
@@ -1235,6 +1227,38 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
}
|
}
|
||||||
SmmuSynchronizationBarrier();
|
SmmuSynchronizationBarrier();
|
||||||
|
|
||||||
|
/* Close the memory manager's references to the pages. */
|
||||||
|
{
|
||||||
|
KPhysicalAddress contig_phys_addr = Null<KPhysicalAddress>;
|
||||||
|
size_t contig_count = 0;
|
||||||
|
for (size_t i = 0; i < map_count; ++i) {
|
||||||
|
/* Get the physical address. */
|
||||||
|
const KPhysicalAddress phys_addr = l2[l2_index + i].GetPhysicalAddress();
|
||||||
|
MESOSPHERE_ASSERT(IsHeapPhysicalAddress(phys_addr));
|
||||||
|
|
||||||
|
/* Fully invalidate the entry. */
|
||||||
|
l2[l2_index + i].Invalidate();
|
||||||
|
|
||||||
|
if (contig_count == 0) {
|
||||||
|
/* Ensure that our address/count is valid. */
|
||||||
|
contig_phys_addr = phys_addr;
|
||||||
|
contig_count = contig_phys_addr != Null<KPhysicalAddress> ? 1 : 0;
|
||||||
|
} else if (phys_addr == Null<KPhysicalAddress> || phys_addr != (contig_phys_addr + (contig_count * DevicePageSize))) {
|
||||||
|
/* If we're no longer contiguous, close the range we've been building. */
|
||||||
|
mm.Close(GetHeapVirtualAddress(contig_phys_addr), (contig_count * DevicePageSize) / PageSize);
|
||||||
|
|
||||||
|
contig_phys_addr = phys_addr;
|
||||||
|
contig_count = contig_phys_addr != Null<KPhysicalAddress> ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
++contig_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contig_count > 0) {
|
||||||
|
mm.Close(GetHeapVirtualAddress(contig_phys_addr), (contig_count * DevicePageSize) / PageSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Close the pages. */
|
/* Close the pages. */
|
||||||
if (ptm.Close(KVirtualAddress(l2), num_closed)) {
|
if (ptm.Close(KVirtualAddress(l2), num_closed)) {
|
||||||
/* Invalidate the l1 entry. */
|
/* Invalidate the l1 entry. */
|
||||||
@@ -1243,22 +1267,12 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
/* Synchronize. */
|
/* Synchronize. */
|
||||||
InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l1[l1_index]))));
|
InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l1[l1_index]))));
|
||||||
InvalidateTlbSection(m_table_asids[l0_index], address);
|
|
||||||
SmmuSynchronizationBarrier();
|
SmmuSynchronizationBarrier();
|
||||||
|
|
||||||
/* We invalidated the tlb. */
|
|
||||||
invalidated_tlb = true;
|
|
||||||
|
|
||||||
/* Free the l2 page. */
|
/* Free the l2 page. */
|
||||||
ptm.Free(KVirtualAddress(l2));
|
ptm.Free(KVirtualAddress(l2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invalidate the tlb if we haven't already. */
|
|
||||||
if (!invalidated_tlb) {
|
|
||||||
InvalidateTlbSection(m_table_asids[l0_index], address);
|
|
||||||
SmmuSynchronizationBarrier();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
address += map_count * DevicePageSize;
|
address += map_count * DevicePageSize;
|
||||||
remaining -= map_count * DevicePageSize;
|
remaining -= map_count * DevicePageSize;
|
||||||
@@ -1287,114 +1301,158 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
remaining -= DeviceLargePageSize;
|
remaining -= DeviceLargePageSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close references to the pages in the group. */
|
|
||||||
pg.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KDevicePageTable::MakePageGroup(KPageGroup *out, KDeviceVirtualAddress address, u64 size) const {
|
bool KDevicePageTable::Compare(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address) const {
|
||||||
MESOSPHERE_ASSERT((address & ~DeviceVirtualAddressMask) == 0);
|
MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0);
|
||||||
MESOSPHERE_ASSERT(((address + size - 1) & ~DeviceVirtualAddressMask) == 0);
|
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
|
||||||
|
|
||||||
|
/* We need to traverse the ranges that make up our mapping, to make sure they're all good. Start by getting a contiguous range. */
|
||||||
|
KPageTableBase::MemoryRange contig_range = {};
|
||||||
|
if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), process_address, size))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that we close the range when we're done. */
|
||||||
|
bool range_open = true;
|
||||||
|
ON_SCOPE_EXIT { if (range_open) { contig_range.Close(); } };
|
||||||
|
|
||||||
/* Walk the directory. */
|
/* Walk the directory. */
|
||||||
u64 remaining = size;
|
KProcessAddress cur_process_address = process_address;
|
||||||
bool first = true;
|
size_t remaining_size = size;
|
||||||
u32 attr = 0;
|
KPhysicalAddress cur_phys_address = GetHeapPhysicalAddress(contig_range.address);
|
||||||
while (remaining > 0) {
|
size_t remaining_in_range = contig_range.size;
|
||||||
const size_t l0_index = (address / DeviceRegionSize);
|
bool first = true;
|
||||||
const size_t l1_index = (address % DeviceRegionSize) / DeviceLargePageSize;
|
u32 first_attr = 0;
|
||||||
const size_t l2_index = (address % DeviceLargePageSize) / DevicePageSize;
|
while (remaining_size > 0) {
|
||||||
|
/* Convert the device address to a series of indices. */
|
||||||
|
const size_t l0_index = (device_address / DeviceRegionSize);
|
||||||
|
const size_t l1_index = (device_address % DeviceRegionSize) / DeviceLargePageSize;
|
||||||
|
const size_t l2_index = (device_address % DeviceLargePageSize) / DevicePageSize;
|
||||||
|
|
||||||
/* Get and validate l1. */
|
/* Get and validate l1. */
|
||||||
const PageDirectoryEntry *l1 = GetPointer<PageDirectoryEntry>(m_tables[l0_index]);
|
const PageDirectoryEntry *l1 = GetPointer<PageDirectoryEntry>(m_tables[l0_index]);
|
||||||
R_UNLESS(l1 != nullptr, svc::ResultInvalidCurrentMemory());
|
if (!(l1 != nullptr && l1[l1_index].IsValid())) {
|
||||||
R_UNLESS(l1[l1_index].IsValid(), svc::ResultInvalidCurrentMemory());
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (l1[l1_index].IsTable()) {
|
if (l1[l1_index].IsTable()) {
|
||||||
/* We're acting on an l2 entry. */
|
/* We're acting on an l2 entry. */
|
||||||
const PageTableEntry *l2 = GetPointer<PageTableEntry>(GetPageTableVirtualAddress(l1[l1_index].GetPhysicalAddress()));
|
const PageTableEntry *l2 = GetPointer<PageTableEntry>(GetPageTableVirtualAddress(l1[l1_index].GetPhysicalAddress()));
|
||||||
|
|
||||||
|
/* Determine the number of pages to check. */
|
||||||
const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index;
|
const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index;
|
||||||
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize);
|
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining_size / DevicePageSize);
|
||||||
|
|
||||||
|
/* Check each page. */
|
||||||
for (size_t i = 0; i < map_count; ++i) {
|
for (size_t i = 0; i < map_count; ++i) {
|
||||||
/* Ensure the l2 entry is valid. */
|
/* Ensure the l2 entry is valid. */
|
||||||
R_UNLESS(l2[l2_index + i].IsValid(), svc::ResultInvalidCurrentMemory());
|
if (!l2[l2_index + i].IsValid()) {
|
||||||
|
return false;
|
||||||
/* Get the physical address. */
|
|
||||||
const KPhysicalAddress phys_addr = l2[l2_index + i].GetPhysicalAddress();
|
|
||||||
MESOSPHERE_ASSERT(IsHeapPhysicalAddress(phys_addr));
|
|
||||||
|
|
||||||
/* Add to the group. */
|
|
||||||
R_TRY(out->AddBlock(GetHeapVirtualAddress(phys_addr), DevicePageSize / PageSize));
|
|
||||||
|
|
||||||
/* If this is our first entry, get the attribute. */
|
|
||||||
if (first) {
|
|
||||||
attr = l2[l2_index + i].GetAttributes();
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
/* Validate the attributes match the first entry. */
|
|
||||||
R_UNLESS(l2[l2_index + i].GetAttributes() == attr, svc::ResultInvalidCurrentMemory());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check that the attributes match the first attributes we encountered. */
|
||||||
|
const u32 cur_attr = l2[l2_index + i].GetAttributes();
|
||||||
|
if (!first && cur_attr != first_attr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there's nothing remaining in the range, refresh the range. */
|
||||||
|
if (remaining_in_range == 0) {
|
||||||
|
contig_range.Close();
|
||||||
|
|
||||||
|
range_open = false;
|
||||||
|
if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), cur_process_address, remaining_size))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
range_open = true;
|
||||||
|
|
||||||
|
cur_phys_address = GetHeapPhysicalAddress(contig_range.address);
|
||||||
|
remaining_in_range = contig_range.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the physical address is expected. */
|
||||||
|
if (l2[l2_index + i].GetPhysicalAddress() != cur_phys_address) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
cur_phys_address += DevicePageSize;
|
||||||
|
cur_process_address += DevicePageSize;
|
||||||
|
remaining_size -= DevicePageSize;
|
||||||
|
remaining_in_range -= DevicePageSize;
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
first_attr = cur_attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance the device address. */
|
||||||
address += DevicePageSize * map_count;
|
device_address += map_count * DevicePageSize;
|
||||||
remaining -= DevicePageSize * map_count;
|
|
||||||
} else {
|
} else {
|
||||||
/* We're acting on an l1 entry. */
|
/* We're acting on an l1 entry. */
|
||||||
R_UNLESS(l2_index == 0, svc::ResultInvalidCurrentMemory());
|
if (!(l2_index == 0 && remaining_size >= DeviceLargePageSize)) {
|
||||||
R_UNLESS(remaining >= DeviceLargePageSize, svc::ResultInvalidCurrentMemory());
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the physical address. */
|
/* Check that the attributes match the first attributes we encountered. */
|
||||||
const KPhysicalAddress phys_addr = l1[l1_index].GetPhysicalAddress();
|
const u32 cur_attr = l1[l1_index].GetAttributes();
|
||||||
MESOSPHERE_ASSERT(IsHeapPhysicalAddress(phys_addr));
|
if (!first && cur_attr != first_attr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Add to the group. */
|
/* If there's nothing remaining in the range, refresh the range. */
|
||||||
R_TRY(out->AddBlock(GetHeapVirtualAddress(phys_addr), DeviceLargePageSize / PageSize));
|
if (remaining_in_range == 0) {
|
||||||
|
contig_range.Close();
|
||||||
|
|
||||||
/* If this is our first entry, get the attribute. */
|
range_open = false;
|
||||||
if (first) {
|
if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), cur_process_address, remaining_size))) {
|
||||||
attr = l1[l1_index].GetAttributes();
|
return false;
|
||||||
first = false;
|
}
|
||||||
} else {
|
range_open = true;
|
||||||
/* Validate the attributes match the first entry. */
|
|
||||||
R_UNLESS(l1[l1_index].GetAttributes() == attr, svc::ResultInvalidCurrentMemory());
|
cur_phys_address = GetHeapPhysicalAddress(contig_range.address);
|
||||||
|
remaining_in_range = contig_range.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the physical address is expected, and there's enough in the range. */
|
||||||
|
if (remaining_in_range < DeviceLargePageSize || l1[l1_index].GetPhysicalAddress() != cur_phys_address) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
address += DeviceLargePageSize;
|
cur_phys_address += DeviceLargePageSize;
|
||||||
remaining -= DeviceLargePageSize;
|
cur_process_address += DeviceLargePageSize;
|
||||||
|
remaining_size -= DeviceLargePageSize;
|
||||||
|
remaining_in_range -= DeviceLargePageSize;
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
first_attr = cur_attr;
|
||||||
|
|
||||||
|
/* Advance the device address. */
|
||||||
|
device_address += DeviceLargePageSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess();
|
/* The range is valid! */
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KDevicePageTable::Compare(const KPageGroup &compare_pg, KDeviceVirtualAddress device_address) const {
|
Result KDevicePageTable::Map(size_t *out_mapped_size, KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings) {
|
||||||
/* Check whether the page group we expect for the virtual address matches the page group we're validating. */
|
|
||||||
KPageGroup calc_pg(std::addressof(Kernel::GetBlockInfoManager()));
|
|
||||||
return (R_SUCCEEDED(this->MakePageGroup(std::addressof(calc_pg), device_address, compare_pg.GetNumPages() * PageSize))) &&
|
|
||||||
calc_pg.IsEquivalentTo(compare_pg);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result KDevicePageTable::Map(size_t *out_mapped_size, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings) {
|
|
||||||
/* Clear the output size. */
|
/* Clear the output size. */
|
||||||
*out_mapped_size = 0;
|
*out_mapped_size = 0;
|
||||||
|
|
||||||
/* Map the pages. */
|
/* Map the pages. */
|
||||||
s32 num_pt = 0;
|
s32 num_pt = 0;
|
||||||
return this->MapImpl(out_mapped_size, num_pt, refresh_mappings ? 1 : std::numeric_limits<s32>::max(), pg, device_address, device_perm);
|
return this->MapImpl(out_mapped_size, num_pt, refresh_mappings ? 1 : std::numeric_limits<s32>::max(), page_table, process_address, size, device_address, device_perm, refresh_mappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KDevicePageTable::Unmap(const KPageGroup &pg, KDeviceVirtualAddress device_address) {
|
Result KDevicePageTable::Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address) {
|
||||||
/* Validate address/size. */
|
/* Validate address/size. */
|
||||||
const size_t size = pg.GetNumPages() * PageSize;
|
|
||||||
MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0);
|
MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0);
|
||||||
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
|
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
|
||||||
|
|
||||||
/* Ensure the page group is correct. */
|
/* Ensure the page group is correct. */
|
||||||
R_UNLESS(this->Compare(pg, device_address), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(this->Compare(page_table, process_address, size, device_address), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
/* Unmap the pages. */
|
/* Unmap the pages. */
|
||||||
this->UnmapImpl(device_address, size, false);
|
this->UnmapImpl(device_address, size, false);
|
||||||
|
|||||||
@@ -492,7 +492,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
/* Wait for a request. */
|
/* Wait for a request. */
|
||||||
{
|
{
|
||||||
KScopedLightLock lk(g_cv_lock);
|
KScopedLightLock lk(g_cv_lock);
|
||||||
while (!(g_sleep_target_cores & target_core_mask)) {
|
while ((g_sleep_target_cores & target_core_mask) == 0) {
|
||||||
g_cv.Wait(std::addressof(g_cv_lock));
|
g_cv.Wait(std::addressof(g_cv_lock));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */
|
/* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */
|
||||||
#define cpuactlr_el1 s3_1_c15_c2_0
|
#define cpuactlr_el1 s3_1_c15_c2_0
|
||||||
#define cpuectlr_el1 s3_1_c15_c2_1
|
#define cpuectlr_el1 s3_1_c15_c2_1
|
||||||
@@ -95,9 +94,10 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
|
|||||||
mrs x2, tpidr_el1
|
mrs x2, tpidr_el1
|
||||||
stp x1, x2, [x0], #0x10
|
stp x1, x2, [x0], #0x10
|
||||||
|
|
||||||
/* Save the virtual resumption entrypoint. */
|
/* Save the virtual resumption entrypoint and cntv_cval_el0. */
|
||||||
adr x1, 77f
|
adr x1, 77f
|
||||||
stp x1, xzr, [x0], #0x10
|
mrs x2, cntv_cval_el0
|
||||||
|
stp x1, x2, [x0], #0x10
|
||||||
|
|
||||||
/* Get the current core id. */
|
/* Get the current core id. */
|
||||||
mrs x0, mpidr_el1
|
mrs x0, mpidr_el1
|
||||||
@@ -245,12 +245,13 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm:
|
|||||||
msr tcr_el1, x1
|
msr tcr_el1, x1
|
||||||
msr mair_el1, x2
|
msr mair_el1, x2
|
||||||
|
|
||||||
/* Get sctlr, tpidr, and the entrypoint. */
|
/* Get sctlr, tpidr, the entrypoint, and cntv_cval_el0. */
|
||||||
ldp x1, x2, [x0], #0x10
|
ldp x1, x2, [x0], #0x10
|
||||||
ldp x3, xzr, [x0], #0x10
|
ldp x3, x4, [x0], #0x10
|
||||||
|
|
||||||
/* Set the global context back into x18/tpidr. */
|
/* Set the global context back into x18/tpidr. */
|
||||||
msr tpidr_el1, x2
|
msr tpidr_el1, x2
|
||||||
|
msr cntv_cval_el0, x4
|
||||||
dsb sy
|
dsb sy
|
||||||
isb
|
isb
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr size_t SecureAlignment = 128_KB;
|
constexpr uintptr_t DramPhysicalAddress = 0x80000000;
|
||||||
|
constexpr size_t SecureAlignment = 128_KB;
|
||||||
|
|
||||||
/* Global variables for panic. */
|
/* Global variables for panic. */
|
||||||
constinit bool g_call_smc_on_panic;
|
constinit bool g_call_smc_on_panic;
|
||||||
@@ -41,8 +42,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
/* Nintendo uses std::mt19937_t for randomness. */
|
/* Nintendo uses std::mt19937_t for randomness. */
|
||||||
/* To save space (and because mt19337_t isn't secure anyway), */
|
/* To save space (and because mt19337_t isn't secure anyway), */
|
||||||
/* We will use TinyMT. */
|
/* We will use TinyMT. */
|
||||||
bool g_initialized_random_generator;
|
constinit bool g_initialized_random_generator;
|
||||||
util::TinyMT g_random_generator;
|
constinit util::TinyMT g_random_generator;
|
||||||
constinit KSpinLock g_random_lock;
|
constinit KSpinLock g_random_lock;
|
||||||
|
|
||||||
ALWAYS_INLINE size_t GetRealMemorySizeForInit() {
|
ALWAYS_INLINE size_t GetRealMemorySizeForInit() {
|
||||||
@@ -89,13 +90,10 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnsureRandomGeneratorInitialized() {
|
ALWAYS_INLINE u64 GenerateRandomU64FromSmc() {
|
||||||
if (AMS_UNLIKELY(!g_initialized_random_generator)) {
|
u64 value;
|
||||||
u64 seed;
|
smc::GenerateRandomBytes(std::addressof(value), sizeof(value));
|
||||||
smc::GenerateRandomBytes(&seed, sizeof(seed));
|
return value;
|
||||||
g_random_generator.Initialize(reinterpret_cast<u32*>(&seed), sizeof(seed) / sizeof(u32));
|
|
||||||
g_initialized_random_generator = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE u64 GenerateRandomU64FromGenerator() {
|
ALWAYS_INLINE u64 GenerateRandomU64FromGenerator() {
|
||||||
@@ -314,12 +312,12 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
g_secure_applet_memory_used = false;
|
g_secure_applet_memory_used = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetVersionIdentifier() {
|
u32 GetVersionIdentifier() {
|
||||||
u64 value = kern::GetTargetFirmware();
|
u32 value = 0;
|
||||||
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO) << 32;
|
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO) << 0;
|
||||||
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR) << 40;
|
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR) << 8;
|
||||||
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR) << 48;
|
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR) << 16;
|
||||||
value |= static_cast<u64>('M') << 56;
|
value |= static_cast<u64>('M') << 24;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,6 +346,10 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KPhysicalAddress KSystemControl::Init::GetInitialProcessBinaryPhysicalAddress() {
|
||||||
|
return GetKernelPhysicalBaseAddress(DramPhysicalAddress) + GetIntendedMemorySize() - KTraceBufferSize - InitialProcessBinarySizeMax;
|
||||||
|
}
|
||||||
|
|
||||||
bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() {
|
bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() {
|
||||||
return GetKernelConfigurationForInit().Get<smc::KernelConfiguration::IncreaseThreadResourceLimit>();
|
return GetKernelConfigurationForInit().Get<smc::KernelConfiguration::IncreaseThreadResourceLimit>();
|
||||||
}
|
}
|
||||||
@@ -368,7 +370,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
case smc::MemoryArrangement_6GBForAppletDev:
|
case smc::MemoryArrangement_6GBForAppletDev:
|
||||||
return 3285_MB;
|
return 3285_MB;
|
||||||
case smc::MemoryArrangement_8GB:
|
case smc::MemoryArrangement_8GB:
|
||||||
return 4916_MB;
|
return 6964_MB;
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
@@ -392,12 +394,12 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
case smc::MemoryArrangement_6GBForAppletDev:
|
case smc::MemoryArrangement_6GBForAppletDev:
|
||||||
return 2193_MB;
|
return 2193_MB;
|
||||||
case smc::MemoryArrangement_8GB:
|
case smc::MemoryArrangement_8GB:
|
||||||
return 2193_MB;
|
return 562_MB;
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
/* Return (possibly) adjusted size. */
|
/* Return (possibly) adjusted size. */
|
||||||
constexpr size_t ExtraSystemMemoryForAtmosphere = 33_MB;
|
constexpr size_t ExtraSystemMemoryForAtmosphere = 40_MB;
|
||||||
return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
|
return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,6 +436,14 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
/* System Initialization. */
|
/* System Initialization. */
|
||||||
void KSystemControl::InitializePhase1() {
|
void KSystemControl::InitializePhase1() {
|
||||||
|
/* Initialize our random generator. */
|
||||||
|
{
|
||||||
|
u64 seed;
|
||||||
|
smc::GenerateRandomBytes(std::addressof(seed), sizeof(seed));
|
||||||
|
g_random_generator.Initialize(reinterpret_cast<u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
|
||||||
|
g_initialized_random_generator = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set IsDebugMode. */
|
/* Set IsDebugMode. */
|
||||||
{
|
{
|
||||||
KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
|
KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
|
||||||
@@ -539,18 +549,23 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
KScopedInterruptDisable intr_disable;
|
KScopedInterruptDisable intr_disable;
|
||||||
KScopedSpinLock lk(g_random_lock);
|
KScopedSpinLock lk(g_random_lock);
|
||||||
|
|
||||||
EnsureRandomGeneratorInitialized();
|
|
||||||
|
|
||||||
return GenerateUniformRange(min, max, GenerateRandomU64FromGenerator);
|
if (AMS_LIKELY(g_initialized_random_generator)) {
|
||||||
|
return GenerateUniformRange(min, max, GenerateRandomU64FromGenerator);
|
||||||
|
} else {
|
||||||
|
return GenerateUniformRange(min, max, GenerateRandomU64FromSmc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 KSystemControl::GenerateRandomU64() {
|
u64 KSystemControl::GenerateRandomU64() {
|
||||||
KScopedInterruptDisable intr_disable;
|
KScopedInterruptDisable intr_disable;
|
||||||
KScopedSpinLock lk(g_random_lock);
|
KScopedSpinLock lk(g_random_lock);
|
||||||
|
|
||||||
EnsureRandomGeneratorInitialized();
|
if (AMS_LIKELY(g_initialized_random_generator)) {
|
||||||
|
return GenerateRandomU64FromGenerator();
|
||||||
return GenerateRandomU64FromGenerator();
|
} else {
|
||||||
|
return GenerateRandomU64FromSmc();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KSystemControl::SleepSystem() {
|
void KSystemControl::SleepSystem() {
|
||||||
@@ -584,8 +599,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
f_ctx->module_base = KMemoryLayout::GetKernelCodeRegionExtents().GetAddress();
|
f_ctx->module_base = KMemoryLayout::GetKernelCodeRegionExtents().GetAddress();
|
||||||
|
|
||||||
/* Set afsr1. */
|
/* Set afsr1. */
|
||||||
f_ctx->afsr0 = 0;
|
f_ctx->afsr0 = GetVersionIdentifier();
|
||||||
f_ctx->afsr1 = GetVersionIdentifier();
|
f_ctx->afsr1 = static_cast<u32>(kern::GetTargetFirmware());
|
||||||
|
|
||||||
/* Set efsr/far. */
|
/* Set efsr/far. */
|
||||||
f_ctx->far = cpu::GetFarEl1();
|
f_ctx->far = cpu::GetFarEl1();
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ namespace ams::kern::init {
|
|||||||
#define FOREACH_SLAB_TYPE(HANDLER, ...) \
|
#define FOREACH_SLAB_TYPE(HANDLER, ...) \
|
||||||
HANDLER(KProcess, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \
|
HANDLER(KProcess, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \
|
||||||
HANDLER(KThread, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \
|
HANDLER(KThread, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \
|
||||||
HANDLER(KLinkedListNode, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \
|
|
||||||
HANDLER(KEvent, (SLAB_COUNT(KEvent)), ## __VA_ARGS__) \
|
HANDLER(KEvent, (SLAB_COUNT(KEvent)), ## __VA_ARGS__) \
|
||||||
HANDLER(KInterruptEvent, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \
|
HANDLER(KInterruptEvent, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \
|
||||||
HANDLER(KInterruptEventTask, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \
|
HANDLER(KInterruptEventTask, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \
|
||||||
@@ -58,14 +57,14 @@ namespace ams::kern::init {
|
|||||||
/* Constexpr counts. */
|
/* Constexpr counts. */
|
||||||
constexpr size_t SlabCountKProcess = 80;
|
constexpr size_t SlabCountKProcess = 80;
|
||||||
constexpr size_t SlabCountKThread = 800;
|
constexpr size_t SlabCountKThread = 800;
|
||||||
constexpr size_t SlabCountKEvent = 700;
|
constexpr size_t SlabCountKEvent = 900;
|
||||||
constexpr size_t SlabCountKInterruptEvent = 100;
|
constexpr size_t SlabCountKInterruptEvent = 100;
|
||||||
constexpr size_t SlabCountKPort = 256;
|
constexpr size_t SlabCountKPort = 256 + 0x20 /* Extra 0x20 ports over Nintendo for homebrew. */;
|
||||||
constexpr size_t SlabCountKSharedMemory = 80;
|
constexpr size_t SlabCountKSharedMemory = 80;
|
||||||
constexpr size_t SlabCountKTransferMemory = 200;
|
constexpr size_t SlabCountKTransferMemory = 200;
|
||||||
constexpr size_t SlabCountKCodeMemory = 10;
|
constexpr size_t SlabCountKCodeMemory = 10;
|
||||||
constexpr size_t SlabCountKDeviceAddressSpace = 300;
|
constexpr size_t SlabCountKDeviceAddressSpace = 300;
|
||||||
constexpr size_t SlabCountKSession = 933;
|
constexpr size_t SlabCountKSession = 1133;
|
||||||
constexpr size_t SlabCountKLightSession = 100;
|
constexpr size_t SlabCountKLightSession = 100;
|
||||||
constexpr size_t SlabCountKObjectName = 7;
|
constexpr size_t SlabCountKObjectName = 7;
|
||||||
constexpr size_t SlabCountKResourceLimit = 5;
|
constexpr size_t SlabCountKResourceLimit = 5;
|
||||||
@@ -77,13 +76,13 @@ namespace ams::kern::init {
|
|||||||
|
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
constexpr size_t RequiredSizeForExtraThreadCount = SlabCountExtraKThread * (sizeof(KThread) + sizeof(KLinkedListNode) + (sizeof(KThreadLocalPage) / 8) + sizeof(KEventInfo));
|
constexpr size_t RequiredSizeForExtraThreadCount = SlabCountExtraKThread * (sizeof(KThread) + (sizeof(KThreadLocalPage) / 8) + sizeof(KEventInfo));
|
||||||
static_assert(RequiredSizeForExtraThreadCount <= KernelSlabHeapAdditionalSize);
|
static_assert(RequiredSizeForExtraThreadCount <= KernelSlabHeapAdditionalSize);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Global to hold our resource counts. */
|
/* Global to hold our resource counts. */
|
||||||
KSlabResourceCounts g_slab_resource_counts = {
|
constinit KSlabResourceCounts g_slab_resource_counts = {
|
||||||
.num_KProcess = SlabCountKProcess,
|
.num_KProcess = SlabCountKProcess,
|
||||||
.num_KThread = SlabCountKThread,
|
.num_KThread = SlabCountKThread,
|
||||||
.num_KEvent = SlabCountKEvent,
|
.num_KEvent = SlabCountKEvent,
|
||||||
@@ -132,7 +131,9 @@ namespace ams::kern::init {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t CalculateSlabHeapGapSize() {
|
size_t CalculateSlabHeapGapSize() {
|
||||||
return (kern::GetTargetFirmware() >= TargetFirmware_10_0_0) ? KernelSlabHeapGapsSize : KernelSlabHeapGapsSizeDeprecated;
|
constexpr size_t KernelSlabHeapGapSize = 2_MB - 296_KB;
|
||||||
|
static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax);
|
||||||
|
return KernelSlabHeapGapSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t CalculateTotalSlabHeapSize() {
|
size_t CalculateTotalSlabHeapSize() {
|
||||||
|
|||||||
@@ -25,101 +25,225 @@ namespace ams::kern {
|
|||||||
s32 priority;
|
s32 priority;
|
||||||
};
|
};
|
||||||
|
|
||||||
KVirtualAddress GetInitialProcessBinaryAddress() {
|
constinit KVirtualAddress g_initial_process_binary_address = Null<KVirtualAddress>;
|
||||||
const uintptr_t end_address = KMemoryLayout::GetPageTableHeapRegion().GetEndAddress();
|
constinit InitialProcessBinaryHeader g_initial_process_binary_header = {};
|
||||||
MESOSPHERE_ABORT_UNLESS(end_address != 0);
|
constinit size_t g_initial_process_secure_memory_size = 0;
|
||||||
return end_address - InitialProcessBinarySizeMax;
|
constinit u64 g_initial_process_id_min = std::numeric_limits<u64>::max();
|
||||||
}
|
constinit u64 g_initial_process_id_max = std::numeric_limits<u64>::min();
|
||||||
|
|
||||||
void LoadInitialProcessBinaryHeader(InitialProcessBinaryHeader *header) {
|
void LoadInitialProcessBinaryHeader(KVirtualAddress virt_addr = Null<KVirtualAddress>) {
|
||||||
if (header->magic != InitialProcessBinaryMagic) {
|
if (g_initial_process_binary_header.magic != InitialProcessBinaryMagic) {
|
||||||
*header = *GetPointer<InitialProcessBinaryHeader>(GetInitialProcessBinaryAddress());
|
/* Get the virtual address, if it's not overridden. */
|
||||||
}
|
if (virt_addr == Null<KVirtualAddress>) {
|
||||||
|
virt_addr = GetInitialProcessBinaryAddress();
|
||||||
MESOSPHERE_ABORT_UNLESS(header->magic == InitialProcessBinaryMagic);
|
|
||||||
MESOSPHERE_ABORT_UNLESS(header->num_processes <= init::GetSlabResourceCounts().num_KProcess);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t GetProcessesSecureMemorySize(KVirtualAddress binary_address, const InitialProcessBinaryHeader &header) {
|
|
||||||
u8 *current = GetPointer<u8>(binary_address + sizeof(InitialProcessBinaryHeader));
|
|
||||||
const u8 * const end = GetPointer<u8>(binary_address + header.size - sizeof(KInitialProcessHeader));
|
|
||||||
|
|
||||||
size_t size = 0;
|
|
||||||
const size_t num_processes = header.num_processes;
|
|
||||||
for (size_t i = 0; i < num_processes; i++) {
|
|
||||||
/* Validate that we can read the current KIP. */
|
|
||||||
MESOSPHERE_ABORT_UNLESS(current <= end);
|
|
||||||
KInitialProcessReader reader;
|
|
||||||
MESOSPHERE_ABORT_UNLESS(reader.Attach(current));
|
|
||||||
|
|
||||||
/* If the process uses secure memory, account for that. */
|
|
||||||
if (reader.UsesSecureMemory()) {
|
|
||||||
size += util::AlignUp(reader.GetSize(), PageSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advance the reader. */
|
/* Copy and validate the header. */
|
||||||
current += reader.GetBinarySize();
|
g_initial_process_binary_header = *GetPointer<InitialProcessBinaryHeader>(virt_addr);
|
||||||
}
|
MESOSPHERE_ABORT_UNLESS(g_initial_process_binary_header.magic == InitialProcessBinaryMagic);
|
||||||
|
MESOSPHERE_ABORT_UNLESS(g_initial_process_binary_header.num_processes <= init::GetSlabResourceCounts().num_KProcess);
|
||||||
|
|
||||||
return size;
|
/* Set the image address. */
|
||||||
|
g_initial_process_binary_address = virt_addr;
|
||||||
|
|
||||||
|
/* Process/calculate the secure memory size. */
|
||||||
|
KVirtualAddress current = g_initial_process_binary_address + sizeof(InitialProcessBinaryHeader);
|
||||||
|
const KVirtualAddress end = g_initial_process_binary_address + g_initial_process_binary_header.size;
|
||||||
|
const size_t num_processes = g_initial_process_binary_header.num_processes;
|
||||||
|
for (size_t i = 0; i < num_processes; ++i) {
|
||||||
|
/* Validate that we can read the current KIP. */
|
||||||
|
MESOSPHERE_ABORT_UNLESS(current <= end - sizeof(KInitialProcessHeader));
|
||||||
|
|
||||||
|
/* Attach to the current KIP. */
|
||||||
|
KInitialProcessReader reader;
|
||||||
|
KVirtualAddress data = reader.Attach(current);
|
||||||
|
MESOSPHERE_ABORT_UNLESS(data != Null<KVirtualAddress>);
|
||||||
|
|
||||||
|
/* If the process uses secure memory, account for that. */
|
||||||
|
if (reader.UsesSecureMemory()) {
|
||||||
|
g_initial_process_secure_memory_size += reader.GetSize() + util::AlignUp(reader.GetStackSize(), PageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance to the next KIP. */
|
||||||
|
current = data + reader.GetBinarySize();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateProcesses(InitialProcessInfo *infos, KVirtualAddress binary_address, const InitialProcessBinaryHeader &header) {
|
void CreateProcesses(InitialProcessInfo *infos) {
|
||||||
u8 *current = GetPointer<u8>(binary_address + sizeof(InitialProcessBinaryHeader));
|
/* Determine process image extents. */
|
||||||
const u8 * const end = GetPointer<u8>(binary_address + header.size - sizeof(KInitialProcessHeader));
|
KVirtualAddress current = g_initial_process_binary_address + sizeof(InitialProcessBinaryHeader);
|
||||||
|
KVirtualAddress end = g_initial_process_binary_address + g_initial_process_binary_header.size;
|
||||||
|
|
||||||
/* Decide on pools to use. */
|
/* Decide on pools to use. */
|
||||||
const auto unsafe_pool = static_cast<KMemoryManager::Pool>(KSystemControl::GetCreateProcessMemoryPool());
|
const auto unsafe_pool = static_cast<KMemoryManager::Pool>(KSystemControl::GetCreateProcessMemoryPool());
|
||||||
const auto secure_pool = (GetTargetFirmware() >= TargetFirmware_2_0_0) ? KMemoryManager::Pool_Secure : unsafe_pool;
|
const auto secure_pool = (GetTargetFirmware() >= TargetFirmware_2_0_0) ? KMemoryManager::Pool_Secure : unsafe_pool;
|
||||||
|
|
||||||
const size_t num_processes = header.num_processes;
|
const size_t num_processes = g_initial_process_binary_header.num_processes;
|
||||||
for (size_t i = 0; i < num_processes; i++) {
|
for (size_t i = 0; i < num_processes; ++i) {
|
||||||
/* Validate that we can read the current KIP. */
|
/* Validate that we can read the current KIP header. */
|
||||||
MESOSPHERE_ABORT_UNLESS(current <= end);
|
MESOSPHERE_ABORT_UNLESS(current <= end - sizeof(KInitialProcessHeader));
|
||||||
KInitialProcessReader reader;
|
|
||||||
MESOSPHERE_ABORT_UNLESS(reader.Attach(current));
|
|
||||||
|
|
||||||
/* Parse process parameters and reserve memory. */
|
/* Attach to the current kip. */
|
||||||
|
KInitialProcessReader reader;
|
||||||
|
KVirtualAddress data = reader.Attach(current);
|
||||||
|
MESOSPHERE_ABORT_UNLESS(data != Null<KVirtualAddress>);
|
||||||
|
|
||||||
|
/* Ensure that the remainder of our parse is page aligned. */
|
||||||
|
if (!util::IsAligned(GetInteger(data), PageSize)) {
|
||||||
|
const KVirtualAddress aligned_data = util::AlignDown(GetInteger(data), PageSize);
|
||||||
|
std::memmove(GetVoidPointer(aligned_data), GetVoidPointer(data), end - data);
|
||||||
|
|
||||||
|
data = aligned_data;
|
||||||
|
end -= (data - aligned_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we crossed a page boundary, free the pages we're done using. */
|
||||||
|
if (KVirtualAddress aligned_current = util::AlignDown(GetInteger(current), PageSize); aligned_current != data) {
|
||||||
|
const size_t freed_size = data - aligned_current;
|
||||||
|
Kernel::GetMemoryManager().Close(aligned_current, freed_size / PageSize);
|
||||||
|
Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_PhysicalMemoryMax, freed_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse process parameters. */
|
||||||
ams::svc::CreateProcessParameter params;
|
ams::svc::CreateProcessParameter params;
|
||||||
MESOSPHERE_R_ABORT_UNLESS(reader.MakeCreateProcessParameter(std::addressof(params), true));
|
MESOSPHERE_R_ABORT_UNLESS(reader.MakeCreateProcessParameter(std::addressof(params), true));
|
||||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, params.code_num_pages * PageSize));
|
|
||||||
|
/* Get the binary size for the kip. */
|
||||||
|
const size_t binary_size = reader.GetBinarySize();
|
||||||
|
const size_t binary_pages = binary_size / PageSize;
|
||||||
|
|
||||||
|
/* Get the pool for both the current (compressed) image, and the decompressed process. */
|
||||||
|
const auto src_pool = Kernel::GetMemoryManager().GetPool(data);
|
||||||
|
const auto dst_pool = reader.UsesSecureMemory() ? secure_pool : unsafe_pool;
|
||||||
|
|
||||||
|
/* Determine the process size, and how much memory isn't already reserved. */
|
||||||
|
const size_t process_size = params.code_num_pages * PageSize;
|
||||||
|
const size_t unreserved_size = process_size - (src_pool == dst_pool ? util::AlignDown(binary_size, PageSize) : 0);
|
||||||
|
|
||||||
|
/* Reserve however much memory we need to reserve. */
|
||||||
|
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, unreserved_size));
|
||||||
|
|
||||||
/* Create the process. */
|
/* Create the process. */
|
||||||
KProcess *new_process = nullptr;
|
KProcess *new_process = nullptr;
|
||||||
{
|
{
|
||||||
/* Declare page group to use for process memory. */
|
/* Make page groups to represent the data. */
|
||||||
KPageGroup pg(std::addressof(Kernel::GetBlockInfoManager()));
|
KPageGroup pg(std::addressof(Kernel::GetBlockInfoManager()));
|
||||||
|
KPageGroup workaround_pg(std::addressof(Kernel::GetBlockInfoManager()));
|
||||||
|
|
||||||
/* Allocate memory for the process. */
|
/* Populate the page group to represent the data. */
|
||||||
auto &mm = Kernel::GetMemoryManager();
|
|
||||||
const auto pool = reader.UsesSecureMemory() ? secure_pool : unsafe_pool;
|
|
||||||
MESOSPHERE_R_ABORT_UNLESS(mm.AllocateAndOpen(std::addressof(pg), params.code_num_pages, KMemoryManager::EncodeOption(pool, KMemoryManager::Direction_FromFront)));
|
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Ensure that we do not leak pages. */
|
/* Allocate the previously unreserved pages. */
|
||||||
ON_SCOPE_EXIT { pg.Close(); };
|
KPageGroup unreserve_pg(std::addressof(Kernel::GetBlockInfoManager()));
|
||||||
|
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(unreserve_pg), unreserved_size / PageSize, KMemoryManager::EncodeOption(dst_pool, KMemoryManager::Direction_FromFront)));
|
||||||
|
|
||||||
/* Get the temporary region. */
|
/* Add the previously reserved pages. */
|
||||||
const auto &temp_region = KMemoryLayout::GetTempRegion();
|
if (src_pool == dst_pool && binary_pages != 0) {
|
||||||
MESOSPHERE_ABORT_UNLESS(temp_region.GetEndAddress() != 0);
|
/* NOTE: Nintendo does not check the result of this operation. */
|
||||||
|
pg.AddBlock(data, binary_pages);
|
||||||
|
}
|
||||||
|
|
||||||
/* Map the process's memory into the temporary region. */
|
/* Add the previously unreserved pages. */
|
||||||
KProcessAddress temp_address = Null<KProcessAddress>;
|
for (const auto &block : unreserve_pg) {
|
||||||
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().MapPageGroup(std::addressof(temp_address), pg, temp_region.GetAddress(), temp_region.GetSize() / PageSize, KMemoryState_Kernel, KMemoryPermission_KernelReadWrite));
|
/* NOTE: Nintendo does not check the result of this operation. */
|
||||||
|
pg.AddBlock(block.GetAddress(), block.GetNumPages());
|
||||||
/* Load the process. */
|
}
|
||||||
MESOSPHERE_R_ABORT_UNLESS(reader.Load(temp_address, params));
|
|
||||||
|
|
||||||
/* Unmap the temporary mapping. */
|
|
||||||
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().UnmapPageGroup(temp_address, pg, KMemoryState_Kernel));
|
|
||||||
|
|
||||||
/* Create a KProcess object. */
|
|
||||||
new_process = KProcess::Create();
|
|
||||||
MESOSPHERE_ABORT_UNLESS(new_process != nullptr);
|
|
||||||
|
|
||||||
/* Initialize the process. */
|
|
||||||
MESOSPHERE_R_ABORT_UNLESS(new_process->Initialize(params, pg, reader.GetCapabilities(), reader.GetNumCapabilities(), std::addressof(Kernel::GetSystemResourceLimit()), pool));
|
|
||||||
}
|
}
|
||||||
|
MESOSPHERE_ABORT_UNLESS(pg.GetNumPages() == static_cast<size_t>(params.code_num_pages));
|
||||||
|
|
||||||
|
/* Ensure that we do not leak pages. */
|
||||||
|
KPageGroup *process_pg = std::addressof(pg);
|
||||||
|
ON_SCOPE_EXIT { process_pg->Close(); };
|
||||||
|
|
||||||
|
/* Get the temporary region. */
|
||||||
|
const auto &temp_region = KMemoryLayout::GetTempRegion();
|
||||||
|
MESOSPHERE_ABORT_UNLESS(temp_region.GetEndAddress() != 0);
|
||||||
|
|
||||||
|
/* Map the process's memory into the temporary region. */
|
||||||
|
KProcessAddress temp_address = Null<KProcessAddress>;
|
||||||
|
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().MapPageGroup(std::addressof(temp_address), pg, temp_region.GetAddress(), temp_region.GetSize() / PageSize, KMemoryState_Kernel, KMemoryPermission_KernelReadWrite));
|
||||||
|
|
||||||
|
/* Setup the new page group's memory, so that we can load the process. */
|
||||||
|
{
|
||||||
|
/* Copy the unaligned ending of the compressed binary. */
|
||||||
|
if (const size_t unaligned_size = binary_size - util::AlignDown(binary_size, PageSize); unaligned_size != 0) {
|
||||||
|
std::memcpy(GetVoidPointer(temp_address + process_size - unaligned_size), GetVoidPointer(data + binary_size - unaligned_size), unaligned_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the aligned part of the compressed binary. */
|
||||||
|
if (const size_t aligned_size = util::AlignDown(binary_size, PageSize); aligned_size != 0 && src_pool == dst_pool) {
|
||||||
|
std::memmove(GetVoidPointer(temp_address + process_size - binary_size), GetVoidPointer(temp_address), aligned_size);
|
||||||
|
} else {
|
||||||
|
if (src_pool != dst_pool) {
|
||||||
|
std::memcpy(GetVoidPointer(temp_address + process_size - binary_size), GetVoidPointer(data), aligned_size);
|
||||||
|
Kernel::GetMemoryManager().Close(data, aligned_size / PageSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the first part of the memory. */
|
||||||
|
std::memset(GetVoidPointer(temp_address), 0, process_size - binary_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load the process. */
|
||||||
|
MESOSPHERE_R_ABORT_UNLESS(reader.Load(temp_address, params, temp_address + process_size - binary_size));
|
||||||
|
|
||||||
|
/* Unmap the temporary mapping. */
|
||||||
|
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().UnmapPageGroup(temp_address, pg, KMemoryState_Kernel));
|
||||||
|
|
||||||
|
/* Create a KProcess object. */
|
||||||
|
new_process = KProcess::Create();
|
||||||
|
MESOSPHERE_ABORT_UNLESS(new_process != nullptr);
|
||||||
|
|
||||||
|
/* Ensure the page group is usable for the process. */
|
||||||
|
/* If the pool is the same, we need to use the workaround page group. */
|
||||||
|
if (src_pool == dst_pool) {
|
||||||
|
/* Allocate a new, usable group for the process. */
|
||||||
|
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(workaround_pg), static_cast<size_t>(params.code_num_pages), KMemoryManager::EncodeOption(dst_pool, KMemoryManager::Direction_FromFront)));
|
||||||
|
|
||||||
|
/* Copy data from the working page group to the usable one. */
|
||||||
|
auto work_it = pg.begin();
|
||||||
|
MESOSPHERE_ABORT_UNLESS(work_it != pg.end());
|
||||||
|
{
|
||||||
|
auto work_address = work_it->GetAddress();
|
||||||
|
auto work_remaining = work_it->GetNumPages();
|
||||||
|
for (const auto &block : workaround_pg) {
|
||||||
|
auto block_address = block.GetAddress();
|
||||||
|
auto block_remaining = block.GetNumPages();
|
||||||
|
while (block_remaining > 0) {
|
||||||
|
if (work_remaining == 0) {
|
||||||
|
++work_it;
|
||||||
|
work_address = work_it->GetAddress();
|
||||||
|
work_remaining = work_it->GetNumPages();
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t cur_pages = std::min(block_remaining, work_remaining);
|
||||||
|
const size_t cur_size = cur_pages * PageSize;
|
||||||
|
std::memcpy(GetVoidPointer(block_address), GetVoidPointer(work_address), cur_size);
|
||||||
|
|
||||||
|
block_address += cur_size;
|
||||||
|
work_address += cur_size;
|
||||||
|
|
||||||
|
block_remaining -= cur_pages;
|
||||||
|
work_remaining -= cur_pages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++work_it;
|
||||||
|
}
|
||||||
|
MESOSPHERE_ABORT_UNLESS(work_it == pg.end());
|
||||||
|
|
||||||
|
/* We want to use the new page group. */
|
||||||
|
process_pg = std::addressof(workaround_pg);
|
||||||
|
pg.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the process. */
|
||||||
|
MESOSPHERE_R_ABORT_UNLESS(new_process->Initialize(params, *process_pg, reader.GetCapabilities(), reader.GetNumCapabilities(), std::addressof(Kernel::GetSystemResourceLimit()), dst_pool, reader.IsImmortal()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the memory that was previously reserved. */
|
||||||
|
if (const size_t aligned_bin_size = util::AlignDown(binary_size, PageSize); aligned_bin_size != 0 && src_pool != dst_pool) {
|
||||||
|
Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_PhysicalMemoryMax, aligned_bin_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the process's memory permissions. */
|
/* Set the process's memory permissions. */
|
||||||
@@ -137,14 +261,21 @@ namespace ams::kern {
|
|||||||
infos[i].priority = reader.GetPriority();
|
infos[i].priority = reader.GetPriority();
|
||||||
|
|
||||||
/* Advance the reader. */
|
/* Advance the reader. */
|
||||||
current += reader.GetBinarySize();
|
current = data + binary_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release remaining memory used by the image. */
|
||||||
|
{
|
||||||
|
const size_t remaining_size = util::AlignUp(GetInteger(g_initial_process_binary_address) + g_initial_process_binary_header.size, PageSize) - util::AlignDown(GetInteger(current), PageSize);
|
||||||
|
const size_t remaining_pages = remaining_size / PageSize;
|
||||||
|
Kernel::GetMemoryManager().Close(util::AlignDown(GetInteger(current), PageSize), remaining_pages);
|
||||||
|
Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_PhysicalMemoryMax, remaining_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constinit KVirtualAddress g_initial_process_binary_address = Null<KVirtualAddress>;
|
ALWAYS_INLINE KVirtualAddress GetInitialProcessBinaryAddress(KVirtualAddress pool_end) {
|
||||||
constinit InitialProcessBinaryHeader g_initial_process_binary_header = {};
|
return pool_end - InitialProcessBinarySizeMax;
|
||||||
constinit u64 g_initial_process_id_min = std::numeric_limits<u64>::max();
|
}
|
||||||
constinit u64 g_initial_process_id_max = std::numeric_limits<u64>::min();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,49 +287,50 @@ namespace ams::kern {
|
|||||||
return g_initial_process_id_max;
|
return g_initial_process_id_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetInitialProcessesSecureMemorySize() {
|
KVirtualAddress GetInitialProcessBinaryAddress() {
|
||||||
LoadInitialProcessBinaryHeader(&g_initial_process_binary_header);
|
/* Get, validate the pool region. */
|
||||||
|
const auto *pool_region = KMemoryLayout::GetVirtualMemoryRegionTree().FindLastDerived(KMemoryRegionType_VirtualDramUserPool);
|
||||||
return GetProcessesSecureMemorySize(g_initial_process_binary_address != Null<KVirtualAddress> ? g_initial_process_binary_address : GetInitialProcessBinaryAddress(), g_initial_process_binary_header);
|
MESOSPHERE_INIT_ABORT_UNLESS(pool_region != nullptr);
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(pool_region->GetEndAddress() != 0);
|
||||||
|
MESOSPHERE_ABORT_UNLESS(pool_region->GetSize() >= InitialProcessBinarySizeMax);
|
||||||
|
return GetInitialProcessBinaryAddress(pool_region->GetEndAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyInitialProcessBinaryToKernelMemory() {
|
size_t GetInitialProcessesSecureMemorySize() {
|
||||||
LoadInitialProcessBinaryHeader(&g_initial_process_binary_header);
|
LoadInitialProcessBinaryHeader();
|
||||||
|
|
||||||
|
return g_initial_process_secure_memory_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CopyInitialProcessBinaryToKernelMemory() {
|
||||||
|
LoadInitialProcessBinaryHeader();
|
||||||
|
|
||||||
if (g_initial_process_binary_header.num_processes > 0) {
|
if (g_initial_process_binary_header.num_processes > 0) {
|
||||||
/* Reserve pages for the initial process binary from the system resource limit. */
|
/* Reserve pages for the initial process binary from the system resource limit. */
|
||||||
auto &mm = Kernel::GetMemoryManager();
|
|
||||||
const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize);
|
const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize);
|
||||||
const size_t num_pages = total_size / PageSize;
|
|
||||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, total_size));
|
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, total_size));
|
||||||
|
|
||||||
/* Allocate memory for the image. */
|
/* The initial process binary is potentially over-allocated, so free any extra pages. */
|
||||||
const KMemoryManager::Pool pool = static_cast<KMemoryManager::Pool>(KSystemControl::GetCreateProcessMemoryPool());
|
if (total_size < InitialProcessBinarySizeMax) {
|
||||||
const auto allocate_option = KMemoryManager::EncodeOption(pool, KMemoryManager::Direction_FromFront);
|
Kernel::GetMemoryManager().Close(g_initial_process_binary_address + total_size, (InitialProcessBinarySizeMax - total_size) / PageSize);
|
||||||
KVirtualAddress allocated_memory = mm.AllocateAndOpenContinuous(num_pages, 1, allocate_option);
|
}
|
||||||
MESOSPHERE_ABORT_UNLESS(allocated_memory != Null<KVirtualAddress>);
|
|
||||||
|
|
||||||
/* Relocate the image. */
|
return total_size;
|
||||||
std::memmove(GetVoidPointer(allocated_memory), GetVoidPointer(GetInitialProcessBinaryAddress()), g_initial_process_binary_header.size);
|
} else {
|
||||||
std::memset(GetVoidPointer(GetInitialProcessBinaryAddress()), 0, g_initial_process_binary_header.size);
|
return 0;
|
||||||
g_initial_process_binary_address = allocated_memory;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoadInitialProcessBinaryHeaderDeprecated(KPhysicalAddress pool_end) {
|
||||||
|
LoadInitialProcessBinaryHeader(GetInitialProcessBinaryAddress(KMemoryLayout::GetLinearVirtualAddress(pool_end)));
|
||||||
|
}
|
||||||
|
|
||||||
void CreateAndRunInitialProcesses() {
|
void CreateAndRunInitialProcesses() {
|
||||||
/* Allocate space for the processes. */
|
/* Allocate space for the processes. */
|
||||||
InitialProcessInfo *infos = static_cast<InitialProcessInfo *>(__builtin_alloca(sizeof(InitialProcessInfo) * g_initial_process_binary_header.num_processes));
|
InitialProcessInfo *infos = static_cast<InitialProcessInfo *>(__builtin_alloca(sizeof(InitialProcessInfo) * g_initial_process_binary_header.num_processes));
|
||||||
|
|
||||||
/* Create the processes. */
|
/* Create the processes. */
|
||||||
CreateProcesses(infos, g_initial_process_binary_address, g_initial_process_binary_header);
|
CreateProcesses(infos);
|
||||||
|
|
||||||
/* Release the memory used by the image. */
|
|
||||||
{
|
|
||||||
const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize);
|
|
||||||
const size_t num_pages = total_size / PageSize;
|
|
||||||
Kernel::GetMemoryManager().Close(g_initial_process_binary_address, num_pages);
|
|
||||||
Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_PhysicalMemoryMax, total_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine the initial process id range. */
|
/* Determine the initial process id range. */
|
||||||
for (size_t i = 0; i < g_initial_process_binary_header.num_processes; i++) {
|
for (size_t i = 0; i < g_initial_process_binary_header.num_processes; i++) {
|
||||||
@@ -210,6 +342,7 @@ namespace ams::kern {
|
|||||||
/* Run the processes. */
|
/* Run the processes. */
|
||||||
for (size_t i = 0; i < g_initial_process_binary_header.num_processes; i++) {
|
for (size_t i = 0; i < g_initial_process_binary_header.num_processes; i++) {
|
||||||
MESOSPHERE_R_ABORT_UNLESS(infos[i].process->Run(infos[i].priority, infos[i].stack_size));
|
MESOSPHERE_R_ABORT_UNLESS(infos[i].process->Run(infos[i].priority, infos[i].stack_size));
|
||||||
|
infos[i].process->Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace ams::kern {
|
|||||||
{
|
{
|
||||||
KScopedSchedulerLock sl;
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
auto it = m_tree.nfind_light({ addr, -1 });
|
auto it = m_tree.nfind_key({ addr, -1 });
|
||||||
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) {
|
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) {
|
||||||
KThread *target_thread = std::addressof(*it);
|
KThread *target_thread = std::addressof(*it);
|
||||||
target_thread->SetSyncedObject(nullptr, ResultSuccess());
|
target_thread->SetSyncedObject(nullptr, ResultSuccess());
|
||||||
@@ -78,7 +78,7 @@ namespace ams::kern {
|
|||||||
R_UNLESS(UpdateIfEqual(std::addressof(user_value), addr, value, value + 1), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(UpdateIfEqual(std::addressof(user_value), addr, value, value + 1), svc::ResultInvalidCurrentMemory());
|
||||||
R_UNLESS(user_value == value, svc::ResultInvalidState());
|
R_UNLESS(user_value == value, svc::ResultInvalidState());
|
||||||
|
|
||||||
auto it = m_tree.nfind_light({ addr, -1 });
|
auto it = m_tree.nfind_key({ addr, -1 });
|
||||||
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) {
|
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) {
|
||||||
KThread *target_thread = std::addressof(*it);
|
KThread *target_thread = std::addressof(*it);
|
||||||
target_thread->SetSyncedObject(nullptr, ResultSuccess());
|
target_thread->SetSyncedObject(nullptr, ResultSuccess());
|
||||||
@@ -100,7 +100,7 @@ namespace ams::kern {
|
|||||||
{
|
{
|
||||||
KScopedSchedulerLock sl;
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
auto it = m_tree.nfind_light({ addr, -1 });
|
auto it = m_tree.nfind_key({ addr, -1 });
|
||||||
/* Determine the updated value. */
|
/* Determine the updated value. */
|
||||||
s32 new_value;
|
s32 new_value;
|
||||||
if (GetTargetFirmware() >= TargetFirmware_7_0_0) {
|
if (GetTargetFirmware() >= TargetFirmware_7_0_0) {
|
||||||
|
|||||||
@@ -22,19 +22,19 @@ namespace ams::kern {
|
|||||||
constexpr uintptr_t Invalid = std::numeric_limits<uintptr_t>::max();
|
constexpr uintptr_t Invalid = std::numeric_limits<uintptr_t>::max();
|
||||||
|
|
||||||
constexpr KAddressSpaceInfo AddressSpaceInfos[] = {
|
constexpr KAddressSpaceInfo AddressSpaceInfos[] = {
|
||||||
{ .bit_width = 32, .address = 2_MB, .size = 1_GB - 2_MB, .type = KAddressSpaceInfo::Type_MapSmall, },
|
{ 32, 2_MB, 1_GB - 2_MB, KAddressSpaceInfo::Type_MapSmall, },
|
||||||
{ .bit_width = 32, .address = 1_GB, .size = 4_GB - 1_GB, .type = KAddressSpaceInfo::Type_MapLarge, },
|
{ 32, 1_GB, 4_GB - 1_GB, KAddressSpaceInfo::Type_MapLarge, },
|
||||||
{ .bit_width = 32, .address = Invalid, .size = 1_GB, .type = KAddressSpaceInfo::Type_Heap, },
|
{ 32, Invalid, 1_GB, KAddressSpaceInfo::Type_Heap, },
|
||||||
{ .bit_width = 32, .address = Invalid, .size = 1_GB, .type = KAddressSpaceInfo::Type_Alias, },
|
{ 32, Invalid, 1_GB, KAddressSpaceInfo::Type_Alias, },
|
||||||
{ .bit_width = 36, .address = 128_MB, .size = 2_GB - 128_MB, .type = KAddressSpaceInfo::Type_MapSmall, },
|
{ 36, 128_MB, 2_GB - 128_MB, KAddressSpaceInfo::Type_MapSmall, },
|
||||||
{ .bit_width = 36, .address = 2_GB, .size = 64_GB - 2_GB, .type = KAddressSpaceInfo::Type_MapLarge, },
|
{ 36, 2_GB, 64_GB - 2_GB, KAddressSpaceInfo::Type_MapLarge, },
|
||||||
{ .bit_width = 36, .address = Invalid, .size = 6_GB, .type = KAddressSpaceInfo::Type_Heap, },
|
{ 36, Invalid, 6_GB, KAddressSpaceInfo::Type_Heap, },
|
||||||
{ .bit_width = 36, .address = Invalid, .size = 6_GB, .type = KAddressSpaceInfo::Type_Alias, },
|
{ 36, Invalid, 6_GB, KAddressSpaceInfo::Type_Alias, },
|
||||||
{ .bit_width = 39, .address = 128_MB, .size = 512_GB - 128_MB, .type = KAddressSpaceInfo::Type_Map39Bit, },
|
{ 39, 128_MB, 512_GB - 128_MB, KAddressSpaceInfo::Type_Map39Bit, },
|
||||||
{ .bit_width = 39, .address = Invalid, .size = 64_GB, .type = KAddressSpaceInfo::Type_MapSmall, },
|
{ 39, Invalid, 64_GB, KAddressSpaceInfo::Type_MapSmall, },
|
||||||
{ .bit_width = 39, .address = Invalid, .size = 6_GB, .type = KAddressSpaceInfo::Type_Heap, },
|
{ 39, Invalid, 6_GB, KAddressSpaceInfo::Type_Heap, },
|
||||||
{ .bit_width = 39, .address = Invalid, .size = 64_GB, .type = KAddressSpaceInfo::Type_Alias, },
|
{ 39, Invalid, 64_GB, KAddressSpaceInfo::Type_Alias, },
|
||||||
{ .bit_width = 39, .address = Invalid, .size = 2_GB, .type = KAddressSpaceInfo::Type_Stack, },
|
{ 39, Invalid, 2_GB, KAddressSpaceInfo::Type_Stack, },
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr bool IsAllowedIndexForAddress(size_t index) {
|
constexpr bool IsAllowedIndexForAddress(size_t index) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user