Compare commits
242 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39c201e37f | ||
|
|
ab5cc75684 | ||
|
|
1e3349e99a | ||
|
|
76628e273a | ||
|
|
257ac2bd33 | ||
|
|
9eb92f37db | ||
|
|
5b135d12ca | ||
|
|
c41a6b80d7 | ||
|
|
05fde7b764 | ||
|
|
1609f804f2 | ||
|
|
f35c94810c | ||
|
|
548b48b2a6 | ||
|
|
35d93a7c41 | ||
|
|
410f23035e | ||
|
|
29cc13543a | ||
|
|
31ad4eec1d | ||
|
|
3ccb0ae02b | ||
|
|
4f7db6e60e | ||
|
|
a325e18cb5 | ||
|
|
af41272591 | ||
|
|
551821e7e2 | ||
|
|
b081762657 | ||
|
|
d2c2a94c5e | ||
|
|
4ff9278d11 | ||
|
|
21c85c6a4f | ||
|
|
05090005b7 | ||
|
|
c0487ad384 | ||
|
|
ecbe5cd406 | ||
|
|
4fe139ea52 | ||
|
|
6922eae3e7 | ||
|
|
952188fc73 | ||
|
|
c0a4fc30a8 | ||
|
|
0b04c89a84 | ||
|
|
217dd1260a | ||
|
|
8aa62a54d8 | ||
|
|
25bae14064 | ||
|
|
900913fe3b | ||
|
|
7562f807fd | ||
|
|
cf5895e04f | ||
|
|
1f37fbed1d | ||
|
|
9701d5b2ab | ||
|
|
c8c76bf8f8 | ||
|
|
0220f67085 | ||
|
|
615f8a3ef3 | ||
|
|
000e382c42 | ||
|
|
3627356d4b | ||
|
|
72b0fe6c1c | ||
|
|
e919b80fa2 | ||
|
|
fc16f28d0c | ||
|
|
e09ba765a1 | ||
|
|
3217df147e | ||
|
|
1fa41c3e2a | ||
|
|
db3dc4ebd2 | ||
|
|
742fd16080 | ||
|
|
812b2aeb4c | ||
|
|
46a4357882 | ||
|
|
872c18c501 | ||
|
|
afc0e14556 | ||
|
|
f7bf379cfe | ||
|
|
9f26419b1a | ||
|
|
1b057d48c6 | ||
|
|
0c3afff4d3 | ||
|
|
274f6b63f2 | ||
|
|
2ed8450446 | ||
|
|
60974a5f4e | ||
|
|
fa384fd920 | ||
|
|
3f19db0d96 | ||
|
|
a84f725e21 | ||
|
|
7f61dfdb8d | ||
|
|
c44da84869 | ||
|
|
7f4450f930 | ||
|
|
edb4e2ea56 | ||
|
|
183f3e0d7e | ||
|
|
7650c5eb96 | ||
|
|
0ff197b300 | ||
|
|
d9fff85bc4 | ||
|
|
c866c15856 | ||
|
|
e8ac23e2ee | ||
|
|
3a8cffef57 | ||
|
|
13411902c9 | ||
|
|
693fb423cb | ||
|
|
8a9eb85e05 | ||
|
|
d389ef639e | ||
|
|
719858ad18 | ||
|
|
e4d08ae0c5 | ||
|
|
0c063db926 | ||
|
|
02e987819b | ||
|
|
2ec3e141c7 | ||
|
|
71d0274884 | ||
|
|
05259b7519 | ||
|
|
59a24fa646 | ||
|
|
f5b2eab4a8 | ||
|
|
e96e1063e2 | ||
|
|
aa170a72a9 | ||
|
|
9d4cb685a7 | ||
|
|
c95741142e | ||
|
|
ef9b111bbf | ||
|
|
114b82284d | ||
|
|
c5d7ca5159 | ||
|
|
6d0bf70783 | ||
|
|
aba6ca7329 | ||
|
|
06a840e550 | ||
|
|
11c02e22e0 | ||
|
|
f93aea4c06 | ||
|
|
4ddfb6183c | ||
|
|
3737151a2f | ||
|
|
2a4d68f916 | ||
|
|
7b523cfc8d | ||
|
|
39a95d4023 | ||
|
|
2c5002ce50 | ||
|
|
b7384a8667 | ||
|
|
85b5f20395 | ||
|
|
ad5bd81d3f | ||
|
|
777b6d285c | ||
|
|
ae2c25e9c8 | ||
|
|
3b8f65d502 | ||
|
|
cfd2d5b012 | ||
|
|
c72ba35684 | ||
|
|
ec96203cb7 | ||
|
|
1491a7b159 | ||
|
|
0daef4a6e8 | ||
|
|
4ca3c44e5f | ||
|
|
add4b3fdc3 | ||
|
|
159f8d384b | ||
|
|
92a8c8eb88 | ||
|
|
9e0daff46e | ||
|
|
6b72dbd22d | ||
|
|
ba91f070e8 | ||
|
|
4fe9a89ab8 | ||
|
|
de73f6c5bb | ||
|
|
e488b6ee47 | ||
|
|
99810dc091 | ||
|
|
e54957285f | ||
|
|
fca213460b | ||
|
|
4e6bd19fcd | ||
|
|
8b88351cb4 | ||
|
|
63ea152349 | ||
|
|
3cb54e2b4b | ||
|
|
e9de11a746 | ||
|
|
b979b5aa36 | ||
|
|
f2ee44da74 | ||
|
|
85c23b5781 | ||
|
|
8e042f2262 | ||
|
|
81e9154a52 | ||
|
|
e9b9dbc2aa | ||
|
|
7e6c849ca4 | ||
|
|
8ec7c096d0 | ||
|
|
6e5b901a9b | ||
|
|
b800953d66 | ||
|
|
f0240db75a | ||
|
|
1f5ec68a5c | ||
|
|
ed9e60acb9 | ||
|
|
a7300b0fa4 | ||
|
|
8e2eca2004 | ||
|
|
9f83b3c838 | ||
|
|
434c8cefc4 | ||
|
|
d8aed7de6d | ||
|
|
a346014dc7 | ||
|
|
4b3c801e9f | ||
|
|
90db1223f6 | ||
|
|
fa64a6ff4d | ||
|
|
0c6a06a0cf | ||
|
|
5efb4a2a98 | ||
|
|
3b662122f9 | ||
|
|
e9b28ab4b1 | ||
|
|
1afb184c14 | ||
|
|
5e070600a9 | ||
|
|
8274081e39 | ||
|
|
f1ad26ce84 | ||
|
|
e4c314146e | ||
|
|
52f00731d9 | ||
|
|
476d658a79 | ||
|
|
7263022bac | ||
|
|
e0e7aa1e2f | ||
|
|
bd9d8fff46 | ||
|
|
61e3f0b391 | ||
|
|
cd9b173318 | ||
|
|
a8df400825 | ||
|
|
68040e2922 | ||
|
|
8da4d14e15 | ||
|
|
e2ebf9c0ff | ||
|
|
5fb6f52b9e | ||
|
|
982389dceb | ||
|
|
f636596ee2 | ||
|
|
0a2440522f | ||
|
|
3292ea5970 | ||
|
|
33d42f4831 | ||
|
|
46094cfb3e | ||
|
|
618691a500 | ||
|
|
356d89244f | ||
|
|
1ce3611695 | ||
|
|
1ab8b23444 | ||
|
|
06b4738d54 | ||
|
|
b92c614347 | ||
|
|
99175c1149 | ||
|
|
8876eedfb0 | ||
|
|
bbcee8c77c | ||
|
|
f7915c2c05 | ||
|
|
668cabd4a2 | ||
|
|
d64ab354ad | ||
|
|
59b518783d | ||
|
|
6462101b6f | ||
|
|
0ea5dbcfbb | ||
|
|
bb6446aada | ||
|
|
e46e7e0eb1 | ||
|
|
cb89c66bd8 | ||
|
|
e85a512cf4 | ||
|
|
7d9fea01c3 | ||
|
|
406320f6ec | ||
|
|
aad2be0a01 | ||
|
|
25383db524 | ||
|
|
48f4c526f3 | ||
|
|
1279d236f3 | ||
|
|
008eb974d4 | ||
|
|
035cebef9d | ||
|
|
8db22967bf | ||
|
|
db510f96c3 | ||
|
|
6e2dd791b2 | ||
|
|
bff61c68ab | ||
|
|
ca7734ffaf | ||
|
|
ed22f802ee | ||
|
|
8ffc177b44 | ||
|
|
c058376b3b | ||
|
|
d5ebf13094 | ||
|
|
695c125721 | ||
|
|
e7e3e7b374 | ||
|
|
3a5f406c5f | ||
|
|
8176f085f1 | ||
|
|
7a69f2f062 | ||
|
|
32b590e7ab | ||
|
|
590f22933d | ||
|
|
0dd071b279 | ||
|
|
f1132fbf5a | ||
|
|
9cd57b6c61 | ||
|
|
bf66e40a7b | ||
|
|
77cc53227a | ||
|
|
59a295db79 | ||
|
|
e4b9930bf3 | ||
|
|
04c9004e05 | ||
|
|
1f8798ace7 | ||
|
|
ff7a80e592 | ||
|
|
e3ace4be15 |
@@ -3,7 +3,7 @@
|
|||||||
=====
|
=====
|
||||||
|
|
||||||

|

|
||||||
[](https://discordapp.com/invite/ZdqEhed)
|
[](https://discordapp.com/invite/ZdqEhed)
|
||||||
|
|
||||||
Atmosphère is a work-in-progress customized firmware for the Nintendo Switch.
|
Atmosphère is a work-in-progress customized firmware for the Nintendo Switch.
|
||||||
|
|
||||||
@@ -27,7 +27,6 @@ This software is licensed under the terms of the GPLv2, with exemptions for spec
|
|||||||
You can find a copy of the license in the [LICENSE file](LICENSE).
|
You can find a copy of the license in the [LICENSE file](LICENSE).
|
||||||
|
|
||||||
Exemptions:
|
Exemptions:
|
||||||
* The [yuzu Nintendo Switch emulator](https://github.com/yuzu-emu/yuzu) and the [Ryujinx Team and Contributors](https://github.com/orgs/Ryujinx) are exempt from GPLv2 licensing. They are permitted, each at their individual discretion, to instead license any source code authored for the Atmosphère project as either GPLv2 or later or the [MIT license](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/licensing_exemptions/MIT_LICENSE). In doing so, they may alter, supplement, or entirely remove the copyright notice for each file they choose to relicense. Neither the Atmosphère project nor its individual contributors shall assert their moral rights against any of the aforementioned projects.
|
|
||||||
* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the Atmosphère project under the Zero-Clause BSD license.
|
* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the Atmosphère project under the Zero-Clause BSD license.
|
||||||
|
|
||||||
Credits
|
Credits
|
||||||
@@ -38,7 +37,7 @@ In no particular order, we credit the following for their invaluable contributio
|
|||||||
|
|
||||||
* __switchbrew__ for the [libnx](https://github.com/switchbrew/libnx) project and the extensive [documentation, research and tool development](http://switchbrew.org) pertaining to the Nintendo Switch.
|
* __switchbrew__ for the [libnx](https://github.com/switchbrew/libnx) project and the extensive [documentation, research and tool development](http://switchbrew.org) pertaining to the Nintendo Switch.
|
||||||
* __devkitPro__ for the [devkitA64](https://devkitpro.org/) toolchain and libnx support.
|
* __devkitPro__ for the [devkitA64](https://devkitpro.org/) toolchain and libnx support.
|
||||||
* __ReSwitched Team__ for additional [documentation, research and tool development](https://reswitched.team/) pertaining to the Nintendo Switch.
|
* __ReSwitched Team__ for additional [documentation, research and tool development](https://reswitched.github.io/) pertaining to the Nintendo Switch.
|
||||||
* __ChaN__ for the [FatFs](http://elm-chan.org/fsw/ff/00index_e.html) module.
|
* __ChaN__ for the [FatFs](http://elm-chan.org/fsw/ff/00index_e.html) module.
|
||||||
* __Marcus Geelnard__ for the [bcl-1.2.0](https://sourceforge.net/projects/bcl/files/bcl/bcl-1.2.0) library.
|
* __Marcus Geelnard__ for the [bcl-1.2.0](https://sourceforge.net/projects/bcl/files/bcl/bcl-1.2.0) library.
|
||||||
* __naehrwert__ and __st4rk__ for the original [hekate](https://github.com/nwert/hekate) project and its hwinit code base.
|
* __naehrwert__ and __st4rk__ for the original [hekate](https://github.com/nwert/hekate) project and its hwinit code base.
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ dist: dist-no-debug
|
|||||||
cp $(CURRENT_DIRECTORY)/stratosphere/spl/$(ATMOSPHERE_OUT_DIR)/spl.elf $(DIST_DIR)/spl.elf
|
cp $(CURRENT_DIRECTORY)/stratosphere/spl/$(ATMOSPHERE_OUT_DIR)/spl.elf $(DIST_DIR)/spl.elf
|
||||||
cp $(CURRENT_DIRECTORY)/stratosphere/TioServer/$(ATMOSPHERE_OUT_DIR)/TioServer.elf $(DIST_DIR)/TioServer.elf
|
cp $(CURRENT_DIRECTORY)/stratosphere/TioServer/$(ATMOSPHERE_OUT_DIR)/TioServer.elf $(DIST_DIR)/TioServer.elf
|
||||||
cp $(CURRENT_DIRECTORY)/troposphere/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf
|
cp $(CURRENT_DIRECTORY)/troposphere/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf
|
||||||
|
cp $(CURRENT_DIRECTORY)/troposphere/haze/haze.elf $(DIST_DIR)/haze.elf
|
||||||
|
cp $(CURRENT_DIRECTORY)/troposphere/reboot_to_payload/reboot_to_payload.elf $(DIST_DIR)/reboot_to_payload.elf
|
||||||
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../;
|
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../;
|
||||||
rm -rf $(DIST_DIR)
|
rm -rf $(DIST_DIR)
|
||||||
|
|
||||||
@@ -82,7 +84,7 @@ dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
|
|||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000034
|
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000034
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000036
|
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000036
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000037
|
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000037
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003c
|
#mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003c
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042
|
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420
|
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000b240
|
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000b240
|
||||||
@@ -96,7 +98,7 @@ dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
|
|||||||
cp stratosphere/fatal/$(ATMOSPHERE_OUT_DIR)/fatal.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000034/exefs.nsp
|
cp stratosphere/fatal/$(ATMOSPHERE_OUT_DIR)/fatal.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000034/exefs.nsp
|
||||||
cp stratosphere/creport/$(ATMOSPHERE_OUT_DIR)/creport.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000036/exefs.nsp
|
cp stratosphere/creport/$(ATMOSPHERE_OUT_DIR)/creport.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000036/exefs.nsp
|
||||||
cp stratosphere/ro/$(ATMOSPHERE_OUT_DIR)/ro.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000037/exefs.nsp
|
cp stratosphere/ro/$(ATMOSPHERE_OUT_DIR)/ro.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000037/exefs.nsp
|
||||||
cp stratosphere/jpegdec/$(ATMOSPHERE_OUT_DIR)/jpegdec.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003c/exefs.nsp
|
#cp stratosphere/jpegdec/$(ATMOSPHERE_OUT_DIR)/jpegdec.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003c/exefs.nsp
|
||||||
cp stratosphere/pgl/$(ATMOSPHERE_OUT_DIR)/pgl.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp
|
cp stratosphere/pgl/$(ATMOSPHERE_OUT_DIR)/pgl.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp
|
||||||
cp stratosphere/LogManager/$(ATMOSPHERE_OUT_DIR)/LogManager.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp
|
cp stratosphere/LogManager/$(ATMOSPHERE_OUT_DIR)/LogManager.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp
|
||||||
cp stratosphere/htc/$(ATMOSPHERE_OUT_DIR)/htc.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000b240/exefs.nsp
|
cp stratosphere/htc/$(ATMOSPHERE_OUT_DIR)/htc.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000b240/exefs.nsp
|
||||||
@@ -106,6 +108,7 @@ dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
|
|||||||
rm -r $(DIST_DIR)/stratosphere_romfs
|
rm -r $(DIST_DIR)/stratosphere_romfs
|
||||||
cp troposphere/reboot_to_payload/reboot_to_payload.nro $(DIST_DIR)/switch/reboot_to_payload.nro
|
cp troposphere/reboot_to_payload/reboot_to_payload.nro $(DIST_DIR)/switch/reboot_to_payload.nro
|
||||||
cp troposphere/daybreak/daybreak.nro $(DIST_DIR)/switch/daybreak.nro
|
cp troposphere/daybreak/daybreak.nro $(DIST_DIR)/switch/daybreak.nro
|
||||||
|
cp troposphere/haze/haze.nro $(DIST_DIR)/switch/haze.nro
|
||||||
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION).zip ./*; cd ../;
|
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION).zip ./*; cd ../;
|
||||||
rm -rf $(DIST_DIR)
|
rm -rf $(DIST_DIR)
|
||||||
cp fusee/$(ATMOSPHERE_BOOT_OUT_DIR)/fusee.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin
|
cp fusee/$(ATMOSPHERE_BOOT_OUT_DIR)/fusee.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin
|
||||||
|
|||||||
@@ -67,6 +67,10 @@
|
|||||||
; Note that this setting is ignored (and treated as 1) when htc is enabled.
|
; Note that this setting is ignored (and treated as 1) when htc is enabled.
|
||||||
; 0 = Disabled, 1 = Enabled
|
; 0 = Disabled, 1 = Enabled
|
||||||
; enable_log_manager = u8!0x0
|
; enable_log_manager = u8!0x0
|
||||||
|
; Controls whether the bluetooth pairing database is redirected to the SD card (shared across sysmmc/all emummcs)
|
||||||
|
; NOTE: On <13.0.0, the database size was 10 instead of 20; booting pre-13.0.0 will truncate the database.
|
||||||
|
; 0 = Disabled, 1 = Enabled
|
||||||
|
; enable_external_bluetooth_db = 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,8 +1,136 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
## 1.7.1
|
||||||
|
+ Support was added for 18.1.0.
|
||||||
|
+ Atmosphère was updated to use GCC 14/newlib (latest devkitA64/devkitARM releases).
|
||||||
|
+ Further changes were for 18.0.0:
|
||||||
|
+ `loader` was updated to reflect the latest official behavior.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.7.0
|
||||||
|
+ Basic support was added for 18.0.0.
|
||||||
|
+ The console should boot and atmosphère should be fully functional. However, not all modules have been fully updated to reflect the latest changes.
|
||||||
|
+ There shouldn't be anything user visible resulting from this, but it will be addressed in a future atmosphère update, once I am not traveling so much.
|
||||||
|
+ `exosphère` was updated to reflect the latest official secure monitor behavior.
|
||||||
|
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
||||||
|
+ `spl` was updated to reflect the latest official behavior.
|
||||||
|
+ `fusee`'s no longer supports applying IPS patches to KIPs.
|
||||||
|
+ The only KIPs that are ever present are a) atmosphère modules, b) custom system modules, or c) FS.
|
||||||
|
+ The IPS subsystem was originally designed to make nogc patches work for FS, but these are now internal, and it appears the literal only kip patches that exist are for piracy.
|
||||||
|
+ I could not find any kip patches posted anywhere made for any other purpose.
|
||||||
|
+ It fundamentally does not make sense to slow down boot for every normal user for a feature that has no actual use-case, especially when `fusee` seeks to be a minimal bootloader.
|
||||||
|
+ Minor improvements were made to atmosphere's gdbstub, including:
|
||||||
|
+ Support was added for QStartNoAckMode.
|
||||||
|
+ An issue was fixed that could cause a fatal error when creating too many breakpoints.
|
||||||
|
+ A number of minor issues were fixed and improvements were made, including:
|
||||||
|
+ `pt-BR` (`PortugueseBr`) is now accepted as a valid language when overriding game locales.
|
||||||
|
+ A bug was fixed that could cause atmosphere to incorrectly serialize output object IDs over IPC when using domain objects.
|
||||||
|
+ A bug was fixed in `pm`'s resource limit boost logic that could potentially cause legitimate boosts to fail in certain circumstances.
|
||||||
|
+ `loader`/`ro` will now throw a fatal error when using invalid IPS patches that go out of bounds, instead of corrupting memory.
|
||||||
|
+ Support was fixed for booting using a memory configuration of half of the true available memory (e.g. forcing a 4GB configuration on an 8GB board).
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.6.2
|
||||||
|
+ Support was finished for 17.0.0.
|
||||||
|
+ `erpt` was updated to support the latest official behavior.
|
||||||
|
+ `jpegdec` was updated to support the latest official behavior.
|
||||||
|
+ `pm` was updated to support the latest official behavior.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.6.1
|
||||||
|
+ An improved solution to [the problem that would cause consoles which had previously re-built their SYSTEM partition to brick on update-to-17.0.0](https://gist.github.com/SciresM/2ddb708c812ed585c4d99f54e25205ff) was added.
|
||||||
|
+ In particular, booting atmosphère will now automatically detect the problem and unbrick any consoles which have fallen into this state.
|
||||||
|
+ Some improvements were made to `haze`, including:
|
||||||
|
+ Performance was greatly improved:
|
||||||
|
+ Support was added for GetObjectPropList, which decreases the amount of requests made by ~8x.
|
||||||
|
+ Haze now performs rendering on the GPU, freeing up the CPU to respond to requests in a more timely manner.
|
||||||
|
+ An issue was fixed with how `haze` configures `bMaxPacketSize0` which improves support for USB3.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.6.0
|
||||||
|
+ Basic support was added for 17.0.0.
|
||||||
|
+ The console should boot and atmosphère should be fully functional. However, not all modules have been fully updated to reflect the latest changes.
|
||||||
|
+ There shouldn't be anything user visible resulting from this, but it will be addressed in a soon-to-come atmosphère update.
|
||||||
|
+ `exosphère` was updated to reflect the latest official secure monitor behavior.
|
||||||
|
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
||||||
|
+ `ncm` was updated to reflect the latest official behavior.
|
||||||
|
+ `erpt` was partially updated to support the latest official behavior.
|
||||||
|
+ Atmosphere's gdbstub now supports waiting to attach to a specific program id on launch (as opposed to any application).
|
||||||
|
+ The monitor command for this is `monitor wait <hex program id>`, where program id can optionally have an `0x` prefix.
|
||||||
|
+ Support was added to `haze` for editing files in-place and performing 64-bit transfers (files larger than 4 GB).
|
||||||
|
+ `bpc.mitm` was enabled on Mariko units, and now triggers pmic-based shutdowns/reboots (thanks @CTCaer).
|
||||||
|
+ This should cause the console to no longer wake ~15 seconds after shutdown on Mariko.
|
||||||
|
+ A number of minor issues were fixed and improvements were made, including:
|
||||||
|
+ A workaround was added for a change in 17.0.0 that would cause consoles which had previously re-built their SYSTEM partition to brick on update-to-17.0.0.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.5.5
|
||||||
|
+ Support was added for 16.1.0.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.5.4
|
||||||
|
+ Experimental new functionality was implemented to prevent crashing when building romfs for certain games with obscene file counts.
|
||||||
|
+ This includes both Fire Emblem: Engage (~190000 files), and The Legend of Zelda: Tears of the Kingdom (~300000) files.
|
||||||
|
+ The solution involved adding functionality to ams.mitm/pm to dynamically steal memory from the application (and system) pool as needed when the games have romfs mods.
|
||||||
|
+ No memory is taken, and there is no cost to this functionality when playing without mods (or with overrides disabled).
|
||||||
|
+ The Legend of Zelda: Tears of the Kingdom is currently the absolute worst case game, requiring ~48 MB of memory to build a romfs image to play with mods.
|
||||||
|
+ Right now, the memory is sourced as follows: 32 MB (base ams.mitm heap), 10 MB (stolen from application pool), 8 MB (dynamically stolen from system pool).
|
||||||
|
+ This is 50 MB, which allows a little overhead in the worst case (prevents crashing due to exhausting the heap for other allocations in ams.mitm).
|
||||||
|
+ Zelda is remarkably sensitive to memory being stolen from the application pool, tolerating no more than 16 MB on 1.0.0 and 12 MB on 1.1.0. I have chosen to steal 10 MB, to be safe, for now.
|
||||||
|
+ This may break on a future game update, but I will fix it if and when that happens. There is no perfect solution; the game simply requires too much memory to support mods flawlessly, and I am forced to compromise.
|
||||||
|
+ As usual, if you encounter a game that exhausts ams.mitm's memory (crashing it) when loading layeredfs mods, please contact `SciresM#0524`.
|
||||||
|
"I am jinxing myself by saying this, but it's really hard to imagine any game being worse than The Legend of Zelda: Tears of the Kingdom, but if it happens again I will drop everything to fix it as usual".
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.5.3
|
||||||
|
+ Support was added for 16.0.3.
|
||||||
|
+ Atmosphère was updated to use GCC 13/newlib (latest devkitA64/devkitARM releases).
|
||||||
|
+ **Please note**: This introduces a known issue, which is currently being worked on.
|
||||||
|
+ As you may recall from the 1.4.1 changelog, Fire Emblem: Engage requires enormous amounts of memory to support using layeredfs mods with the game.
|
||||||
|
+ Latest GCC/newlib slightly increases malloc overhead size, which makes the previous memory increase insufficient.
|
||||||
|
+ A general-case solution to this is in the works, which should hopefully fix the problem in a way that doesn't jinx me for the future.
|
||||||
|
+ A number of minor issues were fixed and improvements were made, including:
|
||||||
|
+ An issue was fixed that caused system font replacement to not work on 16.0.0+.
|
||||||
|
+ An minor accuracy issue was addressed in mesosphere's management of certain memory ranges; this issue would have had zero visible impact to the end-user.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.5.2
|
||||||
|
+ A homebrew application (`haze`) was added for performing USB file transfer (with thanks to @liamwhite for both design and implementation).
|
||||||
|
+ `haze` is included with atmosphère, and provides access to the SD card via the PTP/MTP protocol.
|
||||||
|
+ **Please note**: haze will show inside the homebrew menu under the name "USB File Transfer".
|
||||||
|
+ **Please note**: Atmosphère cannot be updated at runtime, and trying to install an atmosphère update via haze will fail as usual.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.5.1
|
||||||
|
+ `fatal` was updated to reduce memory footprint.
|
||||||
|
+ Starting in 16.0.0, official `fatal` has no framebuffer or rendering logic, and instead calls other system service commands to draw the screen.
|
||||||
|
+ However, these commands aren't usable by atmosphère (too small rendering window, bad color support).
|
||||||
|
+ To reduce the relative memory footprint differential between atmosphère and official code, the framebuffer (2 MB) is now dynamically allocated when needed.
|
||||||
|
+ This will try to allocate from multiple pools (preferring System > System_NonSecure > Application).
|
||||||
|
+ This technically requires that 2 MB be available in at least one of these pools for the fatal screen to render (otherwise, a reboot-to-black-and-white-fatal will occur), but this should be a non-issue in almost all cases.
|
||||||
|
+ A feature was added to optionally mirror the bluetooth pairing database to the SD card (thanks @ndeadly).
|
||||||
|
+ This allows device pairings to be automatically kept in-sync across sysmmc/all emummcs.
|
||||||
|
+ This is opt-in, and can be controlled by setting `atmosphere!enable_external_bluetooth_db = u8!0x1`.
|
||||||
|
+ When enabled, the pairing database will be synchronized to `/atmosphere/bluetooth_devices.db`.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.5.0
|
||||||
|
+ Support was added for 16.0.0
|
||||||
|
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
||||||
|
+ `ncm` was updated to reflect the latest official behavior.
|
||||||
|
+ Many FS apis were updated under the hood to reflect the latest official behavior.
|
||||||
|
+ **Please Note**: 16.0.0 made breaking changes to a number of system APIs, including in FS/NCM/Shared Font commands that some homebrew programs may use.
|
||||||
|
+ These programs may encounter strange errors, and may need to be recompiled with a libnx updated to support 16.0.0's changes to function properly.
|
||||||
|
+ A number of minor issues were fixed and improvements were made, including:
|
||||||
|
+ An issue was fixed that could cause GPIO outputs to be misconfigured under certain circumstances.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.4.1
|
||||||
|
+ A number of minor issues were fixed and improvements were made, including:
|
||||||
|
+ `dmnt` cheat toggle files are no longer ignored when they are missing a trailing newline.
|
||||||
|
+ The mechanism for automatically cleaning up `erpt_reports` added in 1.3.0 was fixed.
|
||||||
|
+ This was actually just very fundamentally broken and has never worked, but it is verified working now.
|
||||||
|
+ Minor fixes were made in `mesosphère` to match official kernel behavior (spin lock assembly was corrected, wrong result on failure in in GetProcessId was corrected).
|
||||||
|
+ A missing call to GetSdStatus when initializing SD cards at non uhs-i mode was added in the sdmmc driver.
|
||||||
|
+ `ams.mitm`'s memory usage was increased by 16 MB, to prevent crashing when building romfs for games with obscene file counts.
|
||||||
|
+ To quote the changelog for 1.2.3: "Animal Crossing's 2.0.0 update contains >99000 files [...] It's really hard to imagine any game being worse than Animal Crossing".
|
||||||
|
+ As it turns out, Fire Emblem: Engage has ~186000 files, and is approximately twice as bad as animal crossing.
|
||||||
|
+ The additional memory here is taken from the applet pool; no issues are expected to arise from this, but please report anything you may run into.
|
||||||
|
+ As usual, if you encounter a game that exhausts ams.mitm's memory (crashing it) when loading layeredfs mods, please contact `SciresM#0524`.
|
||||||
|
+ I am jinxing myself by saying this, but it's really hard to imagine any game being worse than Fire Emblem: Engage, but if it happens again I will drop everything to fix it as usual.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
## 1.4.0
|
## 1.4.0
|
||||||
+ Support was added for 15.0.0.
|
+ Support was added for 15.0.0.
|
||||||
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
||||||
+ `ncm` was updated to reflect the latest official kernel behavior.
|
+ `ncm` was updated to reflect the latest official behavior.
|
||||||
+ A number of minor issues were fixed and improvements were made, including:
|
+ A number of minor issues were fixed and improvements were made, including:
|
||||||
+ The capacity limit on registered add-on contents was fixed in NCM to reflect the increase that occurred in 12.0.0.
|
+ The capacity limit on registered add-on contents was fixed in NCM to reflect the increase that occurred in 12.0.0.
|
||||||
+ An off-by-one was fixed in mesosphere when computing the new value for an address arbiter signaled with ModifyByWaitingCountIfEqual.
|
+ An off-by-one was fixed in mesosphere when computing the new value for an address arbiter signaled with ModifyByWaitingCountIfEqual.
|
||||||
|
|||||||
18
docs/faq.md
Normal file
18
docs/faq.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Frequently Asked Questions
|
||||||
|
|
||||||
|
This document serves as a place to store answers for common questions received about Atmosphère.
|
||||||
|
|
||||||
|
## What does "June 15th" mean?
|
||||||
|
When Atmosphère began development in February 2018, "June 15" was given as the estimate/target date for a first release, to coincide with the planned disclosure of a vulnerability.
|
||||||
|
|
||||||
|
This deadline was missed, hard.
|
||||||
|
|
||||||
|
People made rather a lot of fun of me (SciresM) for this.
|
||||||
|
|
||||||
|
Several months later, when the first Atmosphère release occurred, I captioned it "Happy June 15th!" and pretended like I hadn't missed the first deadline.
|
||||||
|
|
||||||
|
This amused me a lot, and so the practice has been kept up for every single release since.
|
||||||
|
|
||||||
|
Depending on who you ask, you may be told that this is a dumb joke and it is not funny.
|
||||||
|
|
||||||
|
This is incorrect. It is definitely a dumb joke, but it is also hilarious.
|
||||||
@@ -27,3 +27,6 @@ A list of planned features for Atmosphère can be found [here](roadmap.md).
|
|||||||
|
|
||||||
## Release History
|
## Release History
|
||||||
A changelog of previous versions of Atmosphère can be found [here](changelog.md).
|
A changelog of previous versions of Atmosphère can be found [here](changelog.md).
|
||||||
|
|
||||||
|
## Frequently Asked Questions
|
||||||
|
Answers to one or more frequently asked questions may be found [here](faq.md).
|
||||||
|
|||||||
4
emummc/.gitrepo
vendored
4
emummc/.gitrepo
vendored
@@ -6,7 +6,7 @@
|
|||||||
[subrepo]
|
[subrepo]
|
||||||
remote = https://github.com/m4xw/emummc
|
remote = https://github.com/m4xw/emummc
|
||||||
branch = develop
|
branch = develop
|
||||||
commit = 4714b2df9eaf68fb85516b35f7f4265ab0413825
|
commit = f23f943d4092ca9490dbcebbdd117abc3740abcf
|
||||||
parent = 99f6a96845b6097d50f5059eea9245d27876f26a
|
parent = 1e3349e99a023517269b3fc1bc32fd84e5b3caa9
|
||||||
method = merge
|
method = merge
|
||||||
cmdver = 0.4.1
|
cmdver = 0.4.1
|
||||||
|
|||||||
2
emummc/README.md
vendored
2
emummc/README.md
vendored
@@ -2,7 +2,7 @@
|
|||||||
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
|
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
|
||||||
|
|
||||||
### Supported Horizon Versions
|
### Supported Horizon Versions
|
||||||
**1.0.0 - 15.0.0**
|
**1.0.0 - 18.1.0**
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Arbitrary SDMMC backend selection
|
* Arbitrary SDMMC backend selection
|
||||||
|
|||||||
40
emummc/source/FS/FS_offsets.c
vendored
40
emummc/source/FS/FS_offsets.c
vendored
@@ -63,6 +63,16 @@
|
|||||||
#include "offsets/1400_exfat.h"
|
#include "offsets/1400_exfat.h"
|
||||||
#include "offsets/1500.h"
|
#include "offsets/1500.h"
|
||||||
#include "offsets/1500_exfat.h"
|
#include "offsets/1500_exfat.h"
|
||||||
|
#include "offsets/1600.h"
|
||||||
|
#include "offsets/1600_exfat.h"
|
||||||
|
#include "offsets/1603.h"
|
||||||
|
#include "offsets/1603_exfat.h"
|
||||||
|
#include "offsets/1700.h"
|
||||||
|
#include "offsets/1700_exfat.h"
|
||||||
|
#include "offsets/1800.h"
|
||||||
|
#include "offsets/1800_exfat.h"
|
||||||
|
#include "offsets/1810.h"
|
||||||
|
#include "offsets/1810_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
|
||||||
@@ -137,6 +147,16 @@ DEFINE_OFFSET_STRUCT(_1400);
|
|||||||
DEFINE_OFFSET_STRUCT(_1400_EXFAT);
|
DEFINE_OFFSET_STRUCT(_1400_EXFAT);
|
||||||
DEFINE_OFFSET_STRUCT(_1500);
|
DEFINE_OFFSET_STRUCT(_1500);
|
||||||
DEFINE_OFFSET_STRUCT(_1500_EXFAT);
|
DEFINE_OFFSET_STRUCT(_1500_EXFAT);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1600);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1600_EXFAT);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1603);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1603_EXFAT);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1700);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1700_EXFAT);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1800);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1800_EXFAT);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1810);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1810_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) {
|
||||||
@@ -234,6 +254,26 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
|||||||
return &(GET_OFFSET_STRUCT_NAME(_1500));
|
return &(GET_OFFSET_STRUCT_NAME(_1500));
|
||||||
case FS_VER_15_0_0_EXFAT:
|
case FS_VER_15_0_0_EXFAT:
|
||||||
return &(GET_OFFSET_STRUCT_NAME(_1500_EXFAT));
|
return &(GET_OFFSET_STRUCT_NAME(_1500_EXFAT));
|
||||||
|
case FS_VER_16_0_0:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1600));
|
||||||
|
case FS_VER_16_0_0_EXFAT:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1600_EXFAT));
|
||||||
|
case FS_VER_16_0_3:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1603));
|
||||||
|
case FS_VER_16_0_3_EXFAT:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1603_EXFAT));
|
||||||
|
case FS_VER_17_0_0:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1700));
|
||||||
|
case FS_VER_17_0_0_EXFAT:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1700_EXFAT));
|
||||||
|
case FS_VER_18_0_0:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1800));
|
||||||
|
case FS_VER_18_0_0_EXFAT:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1800_EXFAT));
|
||||||
|
case FS_VER_18_1_0:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1810));
|
||||||
|
case FS_VER_18_1_0_EXFAT:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1810_EXFAT));
|
||||||
default:
|
default:
|
||||||
fatal_abort(Fatal_UnknownVersion);
|
fatal_abort(Fatal_UnknownVersion);
|
||||||
}
|
}
|
||||||
|
|||||||
15
emummc/source/FS/FS_versions.h
vendored
15
emummc/source/FS/FS_versions.h
vendored
@@ -92,6 +92,21 @@ enum FS_VER
|
|||||||
FS_VER_15_0_0,
|
FS_VER_15_0_0,
|
||||||
FS_VER_15_0_0_EXFAT,
|
FS_VER_15_0_0_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_16_0_0,
|
||||||
|
FS_VER_16_0_0_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_16_0_3,
|
||||||
|
FS_VER_16_0_3_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_17_0_0,
|
||||||
|
FS_VER_17_0_0_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_18_0_0,
|
||||||
|
FS_VER_18_0_0_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_18_1_0,
|
||||||
|
FS_VER_18_1_0_EXFAT,
|
||||||
|
|
||||||
FS_VER_MAX,
|
FS_VER_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
59
emummc/source/FS/offsets/1600.h
vendored
Normal file
59
emummc/source/FS/offsets/1600.h
vendored
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_1600_H__
|
||||||
|
#define __FS_1600_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1600_SDMMC_ACCESSOR_GC 0x1862A0
|
||||||
|
#define FS_OFFSET_1600_SDMMC_ACCESSOR_SD 0x187F20
|
||||||
|
#define FS_OFFSET_1600_SDMMC_ACCESSOR_NAND 0x186760
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1600_SDMMC_WRAPPER_READ 0x1821F0
|
||||||
|
#define FS_OFFSET_1600_SDMMC_WRAPPER_WRITE 0x182250
|
||||||
|
#define FS_OFFSET_1600_RTLD 0x269B0
|
||||||
|
#define FS_OFFSET_1600_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1600_CLKRST_SET_MIN_V_CLK_RATE 0x1A2D30
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1600_LOCK_MUTEX 0x17B730
|
||||||
|
#define FS_OFFSET_1600_UNLOCK_MUTEX 0x17B780
|
||||||
|
|
||||||
|
#define FS_OFFSET_1600_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1821B0
|
||||||
|
#define FS_OFFSET_1600_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1821D0
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1600_SD_MUTEX 0xFFB3F0
|
||||||
|
#define FS_OFFSET_1600_NAND_MUTEX 0xFF6B58
|
||||||
|
#define FS_OFFSET_1600_ACTIVE_PARTITION 0xFF6B98
|
||||||
|
#define FS_OFFSET_1600_SDMMC_DAS_HANDLE 0xFDC8B0
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1600_SD_DAS_INIT 0x258D4
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1600_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00063B48, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00070D6C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007790C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0008A754, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1600_H__
|
||||||
59
emummc/source/FS/offsets/1600_exfat.h
vendored
Normal file
59
emummc/source/FS/offsets/1600_exfat.h
vendored
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_1600_EXFAT_H__
|
||||||
|
#define __FS_1600_EXFAT_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_ACCESSOR_GC 0x190F80
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_ACCESSOR_SD 0x192C00
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_ACCESSOR_NAND 0x191440
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_READ 0x18CED0
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_WRITE 0x18CF30
|
||||||
|
#define FS_OFFSET_1600_EXFAT_RTLD 0x269B0
|
||||||
|
#define FS_OFFSET_1600_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1600_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1ADA10
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1600_EXFAT_LOCK_MUTEX 0x186410
|
||||||
|
#define FS_OFFSET_1600_EXFAT_UNLOCK_MUTEX 0x186460
|
||||||
|
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x18CE90
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x18CEB0
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SD_MUTEX 0x100D3F0
|
||||||
|
#define FS_OFFSET_1600_EXFAT_NAND_MUTEX 0x1008B58
|
||||||
|
#define FS_OFFSET_1600_EXFAT_ACTIVE_PARTITION 0x1008B98
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_DAS_HANDLE 0xFE98B0
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SD_DAS_INIT 0x258D4
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1600_EXFAT_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00063B48, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00070D6C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007790C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0008A754, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1600_EXFAT_H__
|
||||||
59
emummc/source/FS/offsets/1603.h
vendored
Normal file
59
emummc/source/FS/offsets/1603.h
vendored
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_1603_H__
|
||||||
|
#define __FS_1603_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1603_SDMMC_ACCESSOR_GC 0x1862F0
|
||||||
|
#define FS_OFFSET_1603_SDMMC_ACCESSOR_SD 0x187F70
|
||||||
|
#define FS_OFFSET_1603_SDMMC_ACCESSOR_NAND 0x1867B0
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1603_SDMMC_WRAPPER_READ 0x182240
|
||||||
|
#define FS_OFFSET_1603_SDMMC_WRAPPER_WRITE 0x1822A0
|
||||||
|
#define FS_OFFSET_1603_RTLD 0x269B0
|
||||||
|
#define FS_OFFSET_1603_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1603_CLKRST_SET_MIN_V_CLK_RATE 0x1A2D80
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1603_LOCK_MUTEX 0x17B780
|
||||||
|
#define FS_OFFSET_1603_UNLOCK_MUTEX 0x17B7D0
|
||||||
|
|
||||||
|
#define FS_OFFSET_1603_SDMMC_WRAPPER_CONTROLLER_OPEN 0x182200
|
||||||
|
#define FS_OFFSET_1603_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x182220
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1603_SD_MUTEX 0xFFB3F0
|
||||||
|
#define FS_OFFSET_1603_NAND_MUTEX 0xFF6B58
|
||||||
|
#define FS_OFFSET_1603_ACTIVE_PARTITION 0xFF6B98
|
||||||
|
#define FS_OFFSET_1603_SDMMC_DAS_HANDLE 0xFDC8B0
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1603_SD_DAS_INIT 0x258D4
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1603_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00063B98, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00070DBC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007795C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0008A7A4, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1603_H__
|
||||||
59
emummc/source/FS/offsets/1603_exfat.h
vendored
Normal file
59
emummc/source/FS/offsets/1603_exfat.h
vendored
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_1603_EXFAT_H__
|
||||||
|
#define __FS_1603_EXFAT_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_ACCESSOR_GC 0x190FD0
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_ACCESSOR_SD 0x192C50
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_ACCESSOR_NAND 0x191490
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_READ 0x18CF20
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_WRITE 0x18CF80
|
||||||
|
#define FS_OFFSET_1603_EXFAT_RTLD 0x269B0
|
||||||
|
#define FS_OFFSET_1603_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1603_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1ADA60
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1603_EXFAT_LOCK_MUTEX 0x186460
|
||||||
|
#define FS_OFFSET_1603_EXFAT_UNLOCK_MUTEX 0x1864B0
|
||||||
|
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x18CEE0
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x18CF00
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SD_MUTEX 0x100D3F0
|
||||||
|
#define FS_OFFSET_1603_EXFAT_NAND_MUTEX 0x1008B58
|
||||||
|
#define FS_OFFSET_1603_EXFAT_ACTIVE_PARTITION 0x1008B98
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_DAS_HANDLE 0xFE98B0
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SD_DAS_INIT 0x258D4
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1603_EXFAT_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00063B98, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00070DBC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007795C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0008A7A4, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1603_EXFAT_H__
|
||||||
59
emummc/source/FS/offsets/1700.h
vendored
Normal file
59
emummc/source/FS/offsets/1700.h
vendored
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_1700_H__
|
||||||
|
#define __FS_1700_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1700_SDMMC_ACCESSOR_GC 0x18AD00
|
||||||
|
#define FS_OFFSET_1700_SDMMC_ACCESSOR_SD 0x18C9D0
|
||||||
|
#define FS_OFFSET_1700_SDMMC_ACCESSOR_NAND 0x18B1D0
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1700_SDMMC_WRAPPER_READ 0x186BC0
|
||||||
|
#define FS_OFFSET_1700_SDMMC_WRAPPER_WRITE 0x186C20
|
||||||
|
#define FS_OFFSET_1700_RTLD 0x29D10
|
||||||
|
#define FS_OFFSET_1700_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1700_CLKRST_SET_MIN_V_CLK_RATE 0x1A7B60
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1700_LOCK_MUTEX 0x17FEA0
|
||||||
|
#define FS_OFFSET_1700_UNLOCK_MUTEX 0x17FEF0
|
||||||
|
|
||||||
|
#define FS_OFFSET_1700_SDMMC_WRAPPER_CONTROLLER_OPEN 0x186B80
|
||||||
|
#define FS_OFFSET_1700_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x186BA0
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1700_SD_MUTEX 0xFCE3F0
|
||||||
|
#define FS_OFFSET_1700_NAND_MUTEX 0xFC9B78
|
||||||
|
#define FS_OFFSET_1700_ACTIVE_PARTITION 0xFC9BB8
|
||||||
|
#define FS_OFFSET_1700_SDMMC_DAS_HANDLE 0xFAF840
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1700_SD_DAS_INIT 0x28C64
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1700_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00068068, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x0007510C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007BEAC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0008F674, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1700_H__
|
||||||
59
emummc/source/FS/offsets/1700_exfat.h
vendored
Normal file
59
emummc/source/FS/offsets/1700_exfat.h
vendored
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_1700_EXFAT_H__
|
||||||
|
#define __FS_1700_EXFAT_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1700_EXFAT_SDMMC_ACCESSOR_GC 0x195B60
|
||||||
|
#define FS_OFFSET_1700_EXFAT_SDMMC_ACCESSOR_SD 0x197830
|
||||||
|
#define FS_OFFSET_1700_EXFAT_SDMMC_ACCESSOR_NAND 0x196030
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1700_EXFAT_SDMMC_WRAPPER_READ 0x191A20
|
||||||
|
#define FS_OFFSET_1700_EXFAT_SDMMC_WRAPPER_WRITE 0x191A80
|
||||||
|
#define FS_OFFSET_1700_EXFAT_RTLD 0x29D10
|
||||||
|
#define FS_OFFSET_1700_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1700_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1B29C0
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1700_EXFAT_LOCK_MUTEX 0x18AD00
|
||||||
|
#define FS_OFFSET_1700_EXFAT_UNLOCK_MUTEX 0x18AD50
|
||||||
|
|
||||||
|
#define FS_OFFSET_1700_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1919E0
|
||||||
|
#define FS_OFFSET_1700_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x191A00
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1700_EXFAT_SD_MUTEX 0xFE03F0
|
||||||
|
#define FS_OFFSET_1700_EXFAT_NAND_MUTEX 0xFDBB78
|
||||||
|
#define FS_OFFSET_1700_EXFAT_ACTIVE_PARTITION 0xFDBBB8
|
||||||
|
#define FS_OFFSET_1700_EXFAT_SDMMC_DAS_HANDLE 0xFBC840
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1700_EXFAT_SD_DAS_INIT 0x28C64
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1700_EXFAT_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00068068, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x0007510C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007BEAC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0008F674, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1700_EXFAT_H__
|
||||||
59
emummc/source/FS/offsets/1800.h
vendored
Normal file
59
emummc/source/FS/offsets/1800.h
vendored
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_1800_H__
|
||||||
|
#define __FS_1800_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1800_SDMMC_ACCESSOR_GC 0x18AB00
|
||||||
|
#define FS_OFFSET_1800_SDMMC_ACCESSOR_SD 0x18C800
|
||||||
|
#define FS_OFFSET_1800_SDMMC_ACCESSOR_NAND 0x18AFE0
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1800_SDMMC_WRAPPER_READ 0x186A50
|
||||||
|
#define FS_OFFSET_1800_SDMMC_WRAPPER_WRITE 0x186AB0
|
||||||
|
#define FS_OFFSET_1800_RTLD 0x2A3A4
|
||||||
|
#define FS_OFFSET_1800_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x44)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1800_CLKRST_SET_MIN_V_CLK_RATE 0x1A77D0
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1800_LOCK_MUTEX 0x17FCC0
|
||||||
|
#define FS_OFFSET_1800_UNLOCK_MUTEX 0x17FD10
|
||||||
|
|
||||||
|
#define FS_OFFSET_1800_SDMMC_WRAPPER_CONTROLLER_OPEN 0x186A10
|
||||||
|
#define FS_OFFSET_1800_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x186A30
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1800_SD_MUTEX 0xFD13F0
|
||||||
|
#define FS_OFFSET_1800_NAND_MUTEX 0xFCCB28
|
||||||
|
#define FS_OFFSET_1800_ACTIVE_PARTITION 0xFCCB68
|
||||||
|
#define FS_OFFSET_1800_SDMMC_DAS_HANDLE 0xFB1950
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1800_SD_DAS_INIT 0x28F24
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1800_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00068B08, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x000758DC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007C77C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x000905C4, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1800_H__
|
||||||
59
emummc/source/FS/offsets/1800_exfat.h
vendored
Normal file
59
emummc/source/FS/offsets/1800_exfat.h
vendored
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_1800_EXFAT_H__
|
||||||
|
#define __FS_1800_EXFAT_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_ACCESSOR_GC 0x195B90
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_ACCESSOR_SD 0x197890
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_ACCESSOR_NAND 0x196070
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_WRAPPER_READ 0x191AE0
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_WRAPPER_WRITE 0x191B40
|
||||||
|
#define FS_OFFSET_1800_EXFAT_RTLD 0x2A3A4
|
||||||
|
#define FS_OFFSET_1800_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x44)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1800_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1B2860
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1800_EXFAT_LOCK_MUTEX 0x18AD50
|
||||||
|
#define FS_OFFSET_1800_EXFAT_UNLOCK_MUTEX 0x18ADA0
|
||||||
|
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x191AA0
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x191AC0
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SD_MUTEX 0xFE33F0
|
||||||
|
#define FS_OFFSET_1800_EXFAT_NAND_MUTEX 0xFDEB28
|
||||||
|
#define FS_OFFSET_1800_EXFAT_ACTIVE_PARTITION 0xFDEB68
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_DAS_HANDLE 0xFBE950
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SD_DAS_INIT 0x28F24
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1800_EXFAT_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00068B08, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x000758DC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007C77C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x000905C4, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1800_EXFAT_H__
|
||||||
59
emummc/source/FS/offsets/1810.h
vendored
Normal file
59
emummc/source/FS/offsets/1810.h
vendored
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_1810_H__
|
||||||
|
#define __FS_1810_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1810_SDMMC_ACCESSOR_GC 0x18AB00
|
||||||
|
#define FS_OFFSET_1810_SDMMC_ACCESSOR_SD 0x18C800
|
||||||
|
#define FS_OFFSET_1810_SDMMC_ACCESSOR_NAND 0x18AFE0
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1810_SDMMC_WRAPPER_READ 0x186A50
|
||||||
|
#define FS_OFFSET_1810_SDMMC_WRAPPER_WRITE 0x186AB0
|
||||||
|
#define FS_OFFSET_1810_RTLD 0x2A3A4
|
||||||
|
#define FS_OFFSET_1810_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x44)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1810_CLKRST_SET_MIN_V_CLK_RATE 0x1A77D0
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1810_LOCK_MUTEX 0x17FCC0
|
||||||
|
#define FS_OFFSET_1810_UNLOCK_MUTEX 0x17FD10
|
||||||
|
|
||||||
|
#define FS_OFFSET_1810_SDMMC_WRAPPER_CONTROLLER_OPEN 0x186A10
|
||||||
|
#define FS_OFFSET_1810_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x186A30
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1810_SD_MUTEX 0xFD13F0
|
||||||
|
#define FS_OFFSET_1810_NAND_MUTEX 0xFCCB28
|
||||||
|
#define FS_OFFSET_1810_ACTIVE_PARTITION 0xFCCB68
|
||||||
|
#define FS_OFFSET_1810_SDMMC_DAS_HANDLE 0xFB1950
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1810_SD_DAS_INIT 0x28F24
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1810_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00068B08, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x000758DC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007C77C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x000905C4, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1810_H__
|
||||||
59
emummc/source/FS/offsets/1810_exfat.h
vendored
Normal file
59
emummc/source/FS/offsets/1810_exfat.h
vendored
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_1810_EXFAT_H__
|
||||||
|
#define __FS_1810_EXFAT_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1810_EXFAT_SDMMC_ACCESSOR_GC 0x195B90
|
||||||
|
#define FS_OFFSET_1810_EXFAT_SDMMC_ACCESSOR_SD 0x197890
|
||||||
|
#define FS_OFFSET_1810_EXFAT_SDMMC_ACCESSOR_NAND 0x196070
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1810_EXFAT_SDMMC_WRAPPER_READ 0x191AE0
|
||||||
|
#define FS_OFFSET_1810_EXFAT_SDMMC_WRAPPER_WRITE 0x191B40
|
||||||
|
#define FS_OFFSET_1810_EXFAT_RTLD 0x2A3A4
|
||||||
|
#define FS_OFFSET_1810_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x44)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1810_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1B2860
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1810_EXFAT_LOCK_MUTEX 0x18AD50
|
||||||
|
#define FS_OFFSET_1810_EXFAT_UNLOCK_MUTEX 0x18ADA0
|
||||||
|
|
||||||
|
#define FS_OFFSET_1810_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x191AA0
|
||||||
|
#define FS_OFFSET_1810_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x191AC0
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1810_EXFAT_SD_MUTEX 0xFE33F0
|
||||||
|
#define FS_OFFSET_1810_EXFAT_NAND_MUTEX 0xFDEB28
|
||||||
|
#define FS_OFFSET_1810_EXFAT_ACTIVE_PARTITION 0xFDEB68
|
||||||
|
#define FS_OFFSET_1810_EXFAT_SDMMC_DAS_HANDLE 0xFBE950
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1810_EXFAT_SD_DAS_INIT 0x28F24
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1810_EXFAT_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00068B08, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x000758DC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007C77C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x000905C4, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1810_EXFAT_H__
|
||||||
@@ -85,10 +85,10 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||||||
/* We can get away with only including latest because exosphere supports newer-than-expected master key in engine. */
|
/* We can get away with only including latest because exosphere supports newer-than-expected master key in engine. */
|
||||||
/* TODO: Update on next change of keys. */
|
/* TODO: Update on next change of keys. */
|
||||||
/* Mariko Development Master Kek Source. */
|
/* Mariko Development Master Kek Source. */
|
||||||
.byte 0x18, 0xA5, 0x6F, 0xEF, 0x72, 0x11, 0x62, 0xC5, 0x1A, 0x14, 0xF1, 0x8C, 0x21, 0x83, 0x27, 0xB7
|
.byte 0xE4, 0x45, 0xD0, 0x14, 0xA0, 0xE5, 0xE9, 0x4B, 0xFE, 0x76, 0xF4, 0x29, 0x41, 0xBB, 0x64, 0xED
|
||||||
|
|
||||||
/* Mariko Production Master Kek Source. */
|
/* Mariko Production Master Kek Source. */
|
||||||
.byte 0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D
|
.byte 0x4F, 0x41, 0x3C, 0x3B, 0xFB, 0x6A, 0x01, 0x2A, 0x68, 0x9F, 0x83, 0xE9, 0x53, 0xBD, 0x16, 0xD2
|
||||||
|
|
||||||
/* Development Master Key Vectors. */
|
/* Development Master Key Vectors. */
|
||||||
.byte 0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE /* Zeroes encrypted with Master Key 00. */
|
.byte 0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE /* Zeroes encrypted with Master Key 00. */
|
||||||
@@ -106,6 +106,9 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||||||
.byte 0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15 /* Master key 0B encrypted with Master key 0C. */
|
.byte 0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15 /* Master key 0B encrypted with Master key 0C. */
|
||||||
.byte 0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12 /* Master key 0C encrypted with Master key 0D. */
|
.byte 0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12 /* Master key 0C encrypted with Master key 0D. */
|
||||||
.byte 0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D /* Master key 0D encrypted with Master key 0E. */
|
.byte 0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D /* Master key 0D encrypted with Master key 0E. */
|
||||||
|
.byte 0x78, 0x66, 0x19, 0xBD, 0x86, 0xE7, 0xC1, 0x09, 0x9B, 0x6F, 0x92, 0xB2, 0x58, 0x7D, 0xCF, 0x26 /* Master key 0E encrypted with Master key 0F. */
|
||||||
|
.byte 0x39, 0x1E, 0x7E, 0xF8, 0x7E, 0x73, 0xEA, 0x6F, 0xAF, 0x00, 0x3A, 0xB4, 0xAA, 0xB8, 0xB7, 0x59 /* Master key 0F encrypted with Master key 10. */
|
||||||
|
.byte 0x0C, 0x75, 0x39, 0x15, 0x53, 0xEA, 0x81, 0x11, 0xA3, 0xE0, 0xDC, 0x3D, 0x0E, 0x76, 0xC6, 0xB8 /* Master key 10 encrypted with Master key 11. */
|
||||||
|
|
||||||
/* Production Master Key Vectors. */
|
/* Production Master Key Vectors. */
|
||||||
.byte 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D /* Zeroes encrypted with Master Key 00. */
|
.byte 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D /* Zeroes encrypted with Master Key 00. */
|
||||||
@@ -123,6 +126,9 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||||||
.byte 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 /* Master key 0B encrypted with Master key 0C. */
|
.byte 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 /* Master key 0B encrypted with Master key 0C. */
|
||||||
.byte 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 /* Master key 0C encrypted with Master key 0D. */
|
.byte 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 /* Master key 0C encrypted with Master key 0D. */
|
||||||
.byte 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 /* Master key 0D encrypted with Master key 0E. */
|
.byte 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 /* Master key 0D encrypted with Master key 0E. */
|
||||||
|
.byte 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 /* Master key 0E encrypted with Master key 0F. */
|
||||||
|
.byte 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD /* Master key 0F encrypted with Master key 10. */
|
||||||
|
.byte 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 /* Master key 10 encrypted with Master key 11. */
|
||||||
|
|
||||||
/* Device Master Key Source Sources. */
|
/* Device Master Key Source Sources. */
|
||||||
.byte 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D /* 4.0.0 Device Master Key Source Source. */
|
.byte 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D /* 4.0.0 Device Master Key Source Source. */
|
||||||
@@ -137,6 +143,9 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||||||
.byte 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F /* 13.0.0 Device Master Key Source Source. */
|
.byte 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F /* 13.0.0 Device Master Key Source Source. */
|
||||||
.byte 0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D /* 14.0.0 Device Master Key Source Source. */
|
.byte 0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D /* 14.0.0 Device Master Key Source Source. */
|
||||||
.byte 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 /* 15.0.0 Device Master Key Source Source. */
|
.byte 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 /* 15.0.0 Device Master Key Source Source. */
|
||||||
|
.byte 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C /* 16.0.0 Device Master Key Source Source. */
|
||||||
|
.byte 0xDA, 0xB9, 0xD6, 0x77, 0x52, 0x2D, 0x1F, 0x78, 0x73, 0xC9, 0x98, 0x5B, 0x06, 0xFE, 0xA0, 0x52 /* 17.0.0 Device Master Key Source Source. */
|
||||||
|
.byte 0x14, 0xF5, 0xA5, 0xD0, 0x73, 0x6D, 0x44, 0x80, 0x5F, 0x31, 0x5A, 0x8F, 0x1E, 0xD4, 0x0D, 0x63 /* 18.0.0 Device Master Key Source Source. */
|
||||||
|
|
||||||
/* Development Device Master Kek Sources. */
|
/* Development Device Master Kek Sources. */
|
||||||
.byte 0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34 /* 4.0.0 Device Master Kek Source. */
|
.byte 0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34 /* 4.0.0 Device Master Kek Source. */
|
||||||
@@ -151,6 +160,9 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||||||
.byte 0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F /* 13.0.0 Device Master Kek Source. */
|
.byte 0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F /* 13.0.0 Device Master Kek Source. */
|
||||||
.byte 0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA /* 14.0.0 Device Master Kek Source. */
|
.byte 0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA /* 14.0.0 Device Master Kek Source. */
|
||||||
.byte 0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E /* 15.0.0 Device Master Kek Source. */
|
.byte 0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E /* 15.0.0 Device Master Kek Source. */
|
||||||
|
.byte 0xFF, 0xF6, 0x4B, 0x0F, 0xFF, 0x0D, 0xC0, 0x4F, 0x56, 0x8A, 0x40, 0x74, 0x67, 0xC5, 0xFE, 0x9F /* 16.0.0 Device Master Kek Source. */
|
||||||
|
.byte 0x4E, 0xCE, 0x7B, 0x2A, 0xEA, 0x2E, 0x3D, 0x16, 0xD5, 0x2A, 0xDE, 0xF6, 0xF8, 0x6A, 0x7D, 0x43 /* 17.0.0 Device Master Kek Source. */
|
||||||
|
.byte 0x3B, 0x00, 0x89, 0xD7, 0xA9, 0x9E, 0xB7, 0x70, 0x86, 0x00, 0xC3, 0x49, 0x52, 0x8C, 0xA4, 0xAF /* 18.0.0 Device Master Kek Source. */
|
||||||
|
|
||||||
/* Production Device Master Kek Sources. */
|
/* Production Device Master Kek Sources. */
|
||||||
.byte 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D /* 4.0.0 Device Master Kek Source. */
|
.byte 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D /* 4.0.0 Device Master Kek Source. */
|
||||||
@@ -165,3 +177,6 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||||||
.byte 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 /* 13.0.0 Device Master Kek Source. */
|
.byte 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 /* 13.0.0 Device Master Kek Source. */
|
||||||
.byte 0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2 /* 14.0.0 Device Master Kek Source. */
|
.byte 0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2 /* 14.0.0 Device Master Kek Source. */
|
||||||
.byte 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 /* 15.0.0 Device Master Kek Source. */
|
.byte 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 /* 15.0.0 Device Master Kek Source. */
|
||||||
|
.byte 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F /* 16.0.0 Device Master Kek Source. */
|
||||||
|
.byte 0x21, 0xD6, 0x35, 0xF1, 0x0F, 0x7A, 0xF0, 0x5D, 0xDF, 0x79, 0x1C, 0x7A, 0xE4, 0x32, 0x82, 0x9E /* 17.0.0 Device Master Kek Source. */
|
||||||
|
.byte 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B /* 18.0.0 Device Master Kek Source. */
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ namespace ams::secmon::boot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the key generation is one that we can use. */
|
/* Check that the key generation is one that we can use. */
|
||||||
static_assert(pkg1::KeyGeneration_Count == 15);
|
static_assert(pkg1::KeyGeneration_Count == 18);
|
||||||
if (key_generation >= pkg1::KeyGeneration_Count) {
|
if (key_generation >= pkg1::KeyGeneration_Count) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,15 @@ namespace ams::secmon {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PerformUserRebootByPmic() {
|
||||||
|
/* Ensure that i2c-5 is usable for communicating with the pmic. */
|
||||||
|
clkrst::EnableI2c5Clock();
|
||||||
|
i2c::Initialize(i2c::Port_5);
|
||||||
|
|
||||||
|
/* Reboot. */
|
||||||
|
pmic::ShutdownSystem(true);
|
||||||
|
}
|
||||||
|
|
||||||
void PerformUserRebootToRcm() {
|
void PerformUserRebootToRcm() {
|
||||||
/* Configure the bootrom to boot to rcm. */
|
/* Configure the bootrom to boot to rcm. */
|
||||||
reg::Write(PMC + APBDEV_PMC_SCRATCH0, 0x2);
|
reg::Write(PMC + APBDEV_PMC_SCRATCH0, 0x2);
|
||||||
@@ -100,11 +109,20 @@ namespace ams::secmon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PerformUserShutDown() {
|
void PerformUserShutDown() {
|
||||||
/* Load our reboot stub to iram. */
|
if (fuse::GetSocType() == fuse::SocType_Mariko) {
|
||||||
LoadRebootStub(RebootStubAction_ShutDown);
|
/* Ensure that i2c-5 is usable for communicating with the pmic. */
|
||||||
|
clkrst::EnableI2c5Clock();
|
||||||
|
i2c::Initialize(i2c::Port_5);
|
||||||
|
|
||||||
/* Reboot. */
|
/* On Mariko shutdown via pmic. */
|
||||||
PerformPmcReboot();
|
pmic::ShutdownSystem(false);
|
||||||
|
} else /* if (fuse::GetSocType() == fuse::SocType_Erista) */ {
|
||||||
|
/* Load our reboot stub to iram. */
|
||||||
|
LoadRebootStub(RebootStubAction_ShutDown);
|
||||||
|
|
||||||
|
/* Reboot. */
|
||||||
|
PerformPmcReboot();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,11 +23,13 @@ namespace ams::secmon {
|
|||||||
UserRebootType_ToRcm = 1,
|
UserRebootType_ToRcm = 1,
|
||||||
UserRebootType_ToPayload = 2,
|
UserRebootType_ToPayload = 2,
|
||||||
UserRebootType_ToFatalError = 3,
|
UserRebootType_ToFatalError = 3,
|
||||||
|
UserRebootType_ByPmic = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
void PerformUserRebootToRcm();
|
void PerformUserRebootToRcm();
|
||||||
void PerformUserRebootToPayload();
|
void PerformUserRebootToPayload();
|
||||||
void PerformUserRebootToFatalError();
|
void PerformUserRebootToFatalError();
|
||||||
|
void PerformUserRebootByPmic();
|
||||||
void PerformUserShutDown();
|
void PerformUserShutDown();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ namespace ams::secmon::smc {
|
|||||||
constexpr const u8 EsCommonKeySources[EsCommonKeyType_Count][AesKeySize] = {
|
constexpr const u8 EsCommonKeySources[EsCommonKeyType_Count][AesKeySize] = {
|
||||||
[EsCommonKeyType_TitleKey] = { 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B },
|
[EsCommonKeyType_TitleKey] = { 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B },
|
||||||
[EsCommonKeyType_ArchiveKey] = { 0x3B, 0x78, 0xF2, 0x61, 0x0F, 0x9D, 0x5A, 0xE2, 0x7B, 0x4E, 0x45, 0xAF, 0xCB, 0x0B, 0x67, 0x4D },
|
[EsCommonKeyType_ArchiveKey] = { 0x3B, 0x78, 0xF2, 0x61, 0x0F, 0x9D, 0x5A, 0xE2, 0x7B, 0x4E, 0x45, 0xAF, 0xCB, 0x0B, 0x67, 0x4D },
|
||||||
|
[EsCommonKeyType_Unknown2] = { 0x42, 0x64, 0x0B, 0xE3, 0x5F, 0xC6, 0xBE, 0x47, 0xC7, 0xB4, 0x84, 0xC5, 0xEB, 0x63, 0xAA, 0x02 },
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr const u8 EsSealKeySource[AesKeySize] = {
|
constexpr const u8 EsSealKeySource[AesKeySize] = {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace ams::secmon::smc {
|
|||||||
enum EsCommonKeyType {
|
enum EsCommonKeyType {
|
||||||
EsCommonKeyType_TitleKey = 0,
|
EsCommonKeyType_TitleKey = 0,
|
||||||
EsCommonKeyType_ArchiveKey = 1,
|
EsCommonKeyType_ArchiveKey = 1,
|
||||||
|
EsCommonKeyType_Unknown2 = 2,
|
||||||
|
|
||||||
EsCommonKeyType_Count,
|
EsCommonKeyType_Count,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -357,6 +357,9 @@ namespace ams::secmon::smc {
|
|||||||
case UserRebootType_ToFatalError:
|
case UserRebootType_ToFatalError:
|
||||||
PerformUserRebootToFatalError();
|
PerformUserRebootToFatalError();
|
||||||
break;
|
break;
|
||||||
|
case UserRebootType_ByPmic:
|
||||||
|
PerformUserRebootByPmic();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return SmcResult::InvalidArgument;
|
return SmcResult::InvalidArgument;
|
||||||
}
|
}
|
||||||
@@ -365,18 +368,17 @@ namespace ams::secmon::smc {
|
|||||||
case UserRebootType_ToFatalError:
|
case UserRebootType_ToFatalError:
|
||||||
PerformUserRebootToFatalError();
|
PerformUserRebootToFatalError();
|
||||||
break;
|
break;
|
||||||
|
case UserRebootType_ByPmic:
|
||||||
|
PerformUserRebootByPmic();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return SmcResult::InvalidArgument;
|
return SmcResult::InvalidArgument;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ConfigItem::ExosphereNeedsShutdown:
|
case ConfigItem::ExosphereNeedsShutdown:
|
||||||
if (soc_type == fuse::SocType_Erista) {
|
if (args.r[3] != 0) {
|
||||||
if (args.r[3] != 0) {
|
PerformUserShutDown();
|
||||||
PerformUserShutDown();
|
|
||||||
}
|
|
||||||
} else /* if (soc_type == fuse::SocType_Mariko) */ {
|
|
||||||
return SmcResult::NotSupported;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ConfigItem::ExospherePayloadAddress:
|
case ConfigItem::ExospherePayloadAddress:
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ namespace ams::secmon::smc {
|
|||||||
|
|
||||||
struct PrepareEsDeviceUniqueKeyOption {
|
struct PrepareEsDeviceUniqueKeyOption {
|
||||||
using KeyGeneration = util::BitPack32::Field<0, 6, int>;
|
using KeyGeneration = util::BitPack32::Field<0, 6, int>;
|
||||||
using Type = util::BitPack32::Field<6, 1, EsCommonKeyType>;
|
using Type = util::BitPack32::Field<6, 2, EsCommonKeyType>;
|
||||||
using Reserved = util::BitPack32::Field<7, 25, u32>;
|
using Reserved = util::BitPack32::Field<8, 24, u32>;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr const u8 ModularExponentiateByStorageKeyTable[] = {
|
constexpr const u8 ModularExponentiateByStorageKeyTable[] = {
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ namespace ams::nxboot::loader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Uncompress(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
void Uncompress(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||||
/* Create an execute a decompressor. */
|
/* Create and execute a decompressor. */
|
||||||
Lz4Uncompressor(dst, dst_size, src, src_size).Uncompress();
|
Lz4Uncompressor(dst, dst_size, src, src_size).Uncompress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,17 +23,17 @@ namespace ams::nxboot {
|
|||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSource[se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSource[se::AesBlockSize] = {
|
||||||
/* TODO: Update on next change of keys. */
|
/* TODO: Update on next change of keys. */
|
||||||
0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D
|
0x4F, 0x41, 0x3C, 0x3B, 0xFB, 0x6A, 0x01, 0x2A, 0x68, 0x9F, 0x83, 0xE9, 0x53, 0xBD, 0x16, 0xD2
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = {
|
||||||
/* TODO: Update on next change of keys. */
|
/* TODO: Update on next change of keys. */
|
||||||
0x18, 0xA5, 0x6F, 0xEF, 0x72, 0x11, 0x62, 0xC5, 0x1A, 0x14, 0xF1, 0x8C, 0x21, 0x83, 0x27, 0xB7
|
0xE4, 0x45, 0xD0, 0x14, 0xA0, 0xE5, 0xE9, 0x4B, 0xFE, 0x76, 0xF4, 0x29, 0x41, 0xBB, 0x64, 0xED
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 EristaMasterKekSource[se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 EristaMasterKekSource[se::AesBlockSize] = {
|
||||||
/* TODO: Update on next change of keys. */
|
/* TODO: Update on next change of keys. */
|
||||||
0x6E, 0x77, 0x86, 0xAC, 0x83, 0x0A, 0x8D, 0x3E, 0x7D, 0xB7, 0x66, 0xA0, 0x22, 0xB7, 0x6E, 0x67
|
0x00, 0x04, 0x5D, 0xF0, 0x4D, 0xCD, 0x14, 0xA3, 0x1C, 0xBF, 0xDE, 0x48, 0x55, 0xBA, 0x35, 0xC1
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = {
|
||||||
@@ -69,6 +69,9 @@ namespace ams::nxboot {
|
|||||||
{ 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F }, /* 13.0.0 Device Master Key Source Source. */
|
{ 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F }, /* 13.0.0 Device Master Key Source Source. */
|
||||||
{ 0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D }, /* 14.0.0 Device Master Key Source Source. */
|
{ 0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D }, /* 14.0.0 Device Master Key Source Source. */
|
||||||
{ 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 }, /* 15.0.0 Device Master Key Source Source. */
|
{ 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 }, /* 15.0.0 Device Master Key Source Source. */
|
||||||
|
{ 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C }, /* 16.0.0 Device Master Key Source Source. */
|
||||||
|
{ 0xDA, 0xB9, 0xD6, 0x77, 0x52, 0x2D, 0x1F, 0x78, 0x73, 0xC9, 0x98, 0x5B, 0x06, 0xFE, 0xA0, 0x52 }, /* 17.0.0 Device Master Key Source Source. */
|
||||||
|
{ 0x14, 0xF5, 0xA5, 0xD0, 0x73, 0x6D, 0x44, 0x80, 0x5F, 0x31, 0x5A, 0x8F, 0x1E, 0xD4, 0x0D, 0x63 }, /* 18.0.0 Device Master Key Source Source. */
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||||
@@ -84,6 +87,9 @@ namespace ams::nxboot {
|
|||||||
{ 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 }, /* 13.0.0 Device Master Kek Source. */
|
{ 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 }, /* 13.0.0 Device Master Kek Source. */
|
||||||
{ 0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2 }, /* 14.0.0 Device Master Kek Source. */
|
{ 0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2 }, /* 14.0.0 Device Master Kek Source. */
|
||||||
{ 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 }, /* 15.0.0 Device Master Kek Source. */
|
{ 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 }, /* 15.0.0 Device Master Kek Source. */
|
||||||
|
{ 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F }, /* 16.0.0 Device Master Kek Source. */
|
||||||
|
{ 0x21, 0xD6, 0x35, 0xF1, 0x0F, 0x7A, 0xF0, 0x5D, 0xDF, 0x79, 0x1C, 0x7A, 0xE4, 0x32, 0x82, 0x9E }, /* 17.0.0 Device Master Kek Source. */
|
||||||
|
{ 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B }, /* 18.0.0 Device Master Kek Source. */
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||||
@@ -99,6 +105,9 @@ namespace ams::nxboot {
|
|||||||
{ 0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F }, /* 13.0.0 Device Master Kek Source. */
|
{ 0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F }, /* 13.0.0 Device Master Kek Source. */
|
||||||
{ 0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA }, /* 14.0.0 Device Master Kek Source. */
|
{ 0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA }, /* 14.0.0 Device Master Kek Source. */
|
||||||
{ 0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E }, /* 15.0.0 Device Master Kek Source. */
|
{ 0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E }, /* 15.0.0 Device Master Kek Source. */
|
||||||
|
{ 0xFF, 0xF6, 0x4B, 0x0F, 0xFF, 0x0D, 0xC0, 0x4F, 0x56, 0x8A, 0x40, 0x74, 0x67, 0xC5, 0xFE, 0x9F }, /* 16.0.0 Device Master Kek Source. */
|
||||||
|
{ 0x4E, 0xCE, 0x7B, 0x2A, 0xEA, 0x2E, 0x3D, 0x16, 0xD5, 0x2A, 0xDE, 0xF6, 0xF8, 0x6A, 0x7D, 0x43 }, /* 17.0.0 Device Master Kek Source. */
|
||||||
|
{ 0x3B, 0x00, 0x89, 0xD7, 0xA9, 0x9E, 0xB7, 0x70, 0x86, 0x00, 0xC3, 0x49, 0x52, 0x8C, 0xA4, 0xAF }, /* 18.0.0 Device Master Kek Source. */
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySources[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySources[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
|
||||||
@@ -117,6 +126,9 @@ namespace ams::nxboot {
|
|||||||
{ 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 }, /* Master key 0B encrypted with Master key 0C. */
|
{ 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 }, /* Master key 0B encrypted with Master key 0C. */
|
||||||
{ 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 }, /* Master key 0C encrypted with Master key 0D. */
|
{ 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 }, /* Master key 0C encrypted with Master key 0D. */
|
||||||
{ 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 }, /* Master key 0D encrypted with Master key 0E. */
|
{ 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 }, /* Master key 0D encrypted with Master key 0E. */
|
||||||
|
{ 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 }, /* Master key 0E encrypted with Master key 0F. */
|
||||||
|
{ 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD }, /* Master key 0F encrypted with Master key 10. */
|
||||||
|
{ 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 }, /* Master key 10 encrypted with Master key 11. */
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySourcesDev[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySourcesDev[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
|
||||||
@@ -135,6 +147,9 @@ namespace ams::nxboot {
|
|||||||
{ 0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15 }, /* Master key 0B encrypted with Master key 0C. */
|
{ 0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15 }, /* Master key 0B encrypted with Master key 0C. */
|
||||||
{ 0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12 }, /* Master key 0C encrypted with Master key 0D. */
|
{ 0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12 }, /* Master key 0C encrypted with Master key 0D. */
|
||||||
{ 0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D }, /* Master key 0D encrypted with Master key 0E. */
|
{ 0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D }, /* Master key 0D encrypted with Master key 0E. */
|
||||||
|
{ 0x78, 0x66, 0x19, 0xBD, 0x86, 0xE7, 0xC1, 0x09, 0x9B, 0x6F, 0x92, 0xB2, 0x58, 0x7D, 0xCF, 0x26 }, /* Master key 0E encrypted with Master key 0F. */
|
||||||
|
{ 0x39, 0x1E, 0x7E, 0xF8, 0x7E, 0x73, 0xEA, 0x6F, 0xAF, 0x00, 0x3A, 0xB4, 0xAA, 0xB8, 0xB7, 0x59 }, /* Master key 0F encrypted with Master key 10. */
|
||||||
|
{ 0x0C, 0x75, 0x39, 0x15, 0x53, 0xEA, 0x81, 0x11, 0xA3, 0xE0, 0xDC, 0x3D, 0x0E, 0x76, 0xC6, 0xB8 }, /* Master key 10 encrypted with Master key 11. */
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constinit u8 MasterKeys[pkg1::OldMasterKeyCount][se::AesBlockSize] = {};
|
alignas(se::AesBlockSize) constinit u8 MasterKeys[pkg1::OldMasterKeyCount][se::AesBlockSize] = {};
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ namespace ams::nxboot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the key generation is one that we can use. */
|
/* Check that the key generation is one that we can use. */
|
||||||
static_assert(pkg1::KeyGeneration_Count == 15);
|
static_assert(pkg1::KeyGeneration_Count == 18);
|
||||||
if (key_generation >= pkg1::KeyGeneration_Count) {
|
if (key_generation >= pkg1::KeyGeneration_Count) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,6 +255,12 @@ namespace ams::nxboot {
|
|||||||
return ams::TargetFirmware_14_0_0;
|
return ams::TargetFirmware_14_0_0;
|
||||||
} else if (std::memcmp(package1 + 0x10, "20220801", 8) == 0) {
|
} else if (std::memcmp(package1 + 0x10, "20220801", 8) == 0) {
|
||||||
return ams::TargetFirmware_15_0_0;
|
return ams::TargetFirmware_15_0_0;
|
||||||
|
} else if (std::memcmp(package1 + 0x10, "20230111", 8) == 0) {
|
||||||
|
return ams::TargetFirmware_16_0_0;
|
||||||
|
} else if (std::memcmp(package1 + 0x10, "20230906", 8) == 0) {
|
||||||
|
return ams::TargetFirmware_17_0_0;
|
||||||
|
} else if (std::memcmp(package1 + 0x10, "20240207", 8) == 0) {
|
||||||
|
return ams::TargetFirmware_18_0_0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ namespace ams::nxboot {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr u32 MesoshereMetadataLayout0Magic = util::FourCC<'M','S','S','0'>::Code;
|
||||||
|
constexpr u32 MesoshereMetadataLayout1Magic = util::FourCC<'M','S','S','1'>::Code;
|
||||||
|
|
||||||
struct InitialProcessBinaryHeader {
|
struct InitialProcessBinaryHeader {
|
||||||
static constexpr u32 Magic = util::FourCC<'I','N','I','1'>::Code;
|
static constexpr u32 Magic = util::FourCC<'I','N','I','1'>::Code;
|
||||||
|
|
||||||
@@ -159,6 +162,21 @@ namespace ams::nxboot {
|
|||||||
FsVersion_15_0_0,
|
FsVersion_15_0_0,
|
||||||
FsVersion_15_0_0_Exfat,
|
FsVersion_15_0_0_Exfat,
|
||||||
|
|
||||||
|
FsVersion_16_0_0,
|
||||||
|
FsVersion_16_0_0_Exfat,
|
||||||
|
|
||||||
|
FsVersion_16_0_3,
|
||||||
|
FsVersion_16_0_3_Exfat,
|
||||||
|
|
||||||
|
FsVersion_17_0_0,
|
||||||
|
FsVersion_17_0_0_Exfat,
|
||||||
|
|
||||||
|
FsVersion_18_0_0,
|
||||||
|
FsVersion_18_0_0_Exfat,
|
||||||
|
|
||||||
|
FsVersion_18_1_0,
|
||||||
|
FsVersion_18_1_0_Exfat,
|
||||||
|
|
||||||
FsVersion_Count,
|
FsVersion_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -231,13 +249,38 @@ namespace ams::nxboot {
|
|||||||
{ 0x88, 0x7A, 0xC1, 0x50, 0x80, 0x6C, 0x75, 0xCC }, /* FsVersion_14_0_0 */
|
{ 0x88, 0x7A, 0xC1, 0x50, 0x80, 0x6C, 0x75, 0xCC }, /* FsVersion_14_0_0 */
|
||||||
{ 0xD4, 0x88, 0xD1, 0xF2, 0x92, 0x17, 0x35, 0x5C }, /* FsVersion_14_0_0_Exfat */
|
{ 0xD4, 0x88, 0xD1, 0xF2, 0x92, 0x17, 0x35, 0x5C }, /* FsVersion_14_0_0_Exfat */
|
||||||
|
|
||||||
|
|
||||||
{ 0xD0, 0xD4, 0x49, 0x18, 0x14, 0xB5, 0x62, 0xAF }, /* FsVersion_15_0_0 */
|
{ 0xD0, 0xD4, 0x49, 0x18, 0x14, 0xB5, 0x62, 0xAF }, /* FsVersion_15_0_0 */
|
||||||
{ 0x34, 0xC0, 0xD9, 0xED, 0x6A, 0xD1, 0x87, 0x3D }, /* FsVersion_15_0_0_Exfat */
|
{ 0x34, 0xC0, 0xD9, 0xED, 0x6A, 0xD1, 0x87, 0x3D }, /* FsVersion_15_0_0_Exfat */
|
||||||
|
|
||||||
|
{ 0x56, 0xE8, 0x56, 0x56, 0x6C, 0x38, 0xD8, 0xBE }, /* FsVersion_16_0_0 */
|
||||||
|
{ 0xCF, 0xAB, 0x45, 0x0C, 0x2C, 0x53, 0x9D, 0xA9 }, /* FsVersion_16_0_0_Exfat */
|
||||||
|
|
||||||
|
{ 0x39, 0xEE, 0x1F, 0x1E, 0x0E, 0xA7, 0x32, 0x5D }, /* FsVersion_16_0_3 */
|
||||||
|
{ 0x62, 0xC6, 0x5E, 0xFD, 0x9A, 0xBF, 0x7C, 0x43 }, /* FsVersion_16_0_3_Exfat */
|
||||||
|
|
||||||
|
{ 0x27, 0x07, 0x3B, 0xF0, 0xA1, 0xB8, 0xCE, 0x61 }, /* FsVersion_17_0_0 */
|
||||||
|
{ 0xEE, 0x0F, 0x4B, 0xAC, 0x6D, 0x1F, 0xFC, 0x4B }, /* FsVersion_17_0_0_Exfat */
|
||||||
|
|
||||||
|
{ 0x79, 0x5F, 0x5A, 0x5E, 0xB0, 0xC6, 0x77, 0x9E }, /* FsVersion_18_0_0 */
|
||||||
|
{ 0x1E, 0x2C, 0x64, 0xB1, 0xCC, 0xE2, 0x78, 0x24 }, /* FsVersion_18_0_0_Exfat */
|
||||||
|
|
||||||
|
{ 0xA3, 0x39, 0xF0, 0x1C, 0x95, 0xBF, 0xA7, 0x68 }, /* FsVersion_18_1_0 */
|
||||||
|
{ 0x20, 0x4C, 0xBA, 0x86, 0xDE, 0x08, 0x44, 0x6A }, /* FsVersion_18_1_0_Exfat */
|
||||||
};
|
};
|
||||||
|
|
||||||
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
|
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
|
||||||
if (target_firmware >= ams::TargetFirmware_8_0_0) {
|
if (target_firmware >= ams::TargetFirmware_17_0_0) {
|
||||||
|
const u32 *data_32 = reinterpret_cast<const u32 *>(data);
|
||||||
|
const u32 branch_target = (data_32[0] & 0x00FFFFFF);
|
||||||
|
for (size_t i = branch_target; i < branch_target + 0x1000 / sizeof(u32); ++i) {
|
||||||
|
const u32 ini_offset = (i * sizeof(u32)) + data_32[i];
|
||||||
|
if (data_32[i + 1] == 0 && ini_offset <= header->meta.payload_sizes[0] && std::memcmp(data + ini_offset, "INI1", 4) == 0) {
|
||||||
|
return reinterpret_cast<const InitialProcessBinaryHeader *>(data + ini_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
} else if (target_firmware >= ams::TargetFirmware_8_0_0) {
|
||||||
/* Try to find initial process binary. */
|
/* Try to find initial process binary. */
|
||||||
const u32 *data_32 = reinterpret_cast<const u32 *>(data);
|
const u32 *data_32 = reinterpret_cast<const u32 *>(data);
|
||||||
for (size_t i = 0; i < 0x1000 / sizeof(u32); ++i) {
|
for (size_t i = 0; i < 0x1000 / sizeof(u32); ++i) {
|
||||||
@@ -354,15 +397,6 @@ namespace ams::nxboot {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
InitialProcessMeta *FindInitialProcess(const se::Sha256Hash &hash) {
|
|
||||||
for (InitialProcessMeta *cur = std::addressof(g_initial_process_meta); cur != nullptr; cur = cur->next) {
|
|
||||||
if (std::memcmp(std::addressof(cur->kip_hash), std::addressof(hash), sizeof(hash)) == 0) {
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetPatchSegments(const InitialProcessHeader *kip, u32 offset, size_t size) {
|
u32 GetPatchSegments(const InitialProcessHeader *kip, u32 offset, size_t size) {
|
||||||
/* Create segment mask. */
|
/* Create segment mask. */
|
||||||
u32 segments = 0;
|
u32 segments = 0;
|
||||||
@@ -443,78 +477,6 @@ namespace ams::nxboot {
|
|||||||
meta->patches_tail = new_patch;
|
meta->patches_tail = new_patch;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddIps24PatchToKip(InitialProcessMeta *meta, const u8 *ips, s32 size) {
|
|
||||||
while (size > 0) {
|
|
||||||
/* Read offset, stopping at EOF */
|
|
||||||
const u32 offset = (static_cast<u32>(ips[0]) << 16) | (static_cast<u32>(ips[1]) << 8) | (static_cast<u32>(ips[2]) << 0);
|
|
||||||
if (offset == 0x454F46) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read size. */
|
|
||||||
const u16 cur_size = (static_cast<u32>(ips[3]) << 8) | (static_cast<u32>(ips[4]) << 0);
|
|
||||||
|
|
||||||
if (cur_size > 0) {
|
|
||||||
/* Add patch. */
|
|
||||||
AddPatch(meta, offset, ips + 5, cur_size, false);
|
|
||||||
|
|
||||||
/* Advance. */
|
|
||||||
ips += (5 + cur_size);
|
|
||||||
size -= (5 + cur_size);
|
|
||||||
} else {
|
|
||||||
/* Read RLE size */
|
|
||||||
const u16 rle_size = (static_cast<u32>(ips[5]) << 8) | (static_cast<u32>(ips[6]) << 0);
|
|
||||||
|
|
||||||
/* Add patch. */
|
|
||||||
AddPatch(meta, offset, ips + 7, rle_size, true);
|
|
||||||
|
|
||||||
/* Advance. */
|
|
||||||
ips += 8;
|
|
||||||
size -= 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddIps32PatchToKip(InitialProcessMeta *meta, const u8 *ips, s32 size) {
|
|
||||||
while (size > 0) {
|
|
||||||
/* Read offset, stopping at EOF */
|
|
||||||
const u32 offset = (static_cast<u32>(ips[0]) << 24) | (static_cast<u32>(ips[1]) << 16) | (static_cast<u32>(ips[2]) << 8) | (static_cast<u32>(ips[3]) << 0);
|
|
||||||
if (offset == 0x45454F46) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read size. */
|
|
||||||
const u16 cur_size = (static_cast<u32>(ips[4]) << 8) | (static_cast<u32>(ips[5]) << 0);
|
|
||||||
|
|
||||||
if (cur_size > 0) {
|
|
||||||
/* Add patch. */
|
|
||||||
AddPatch(meta, offset, ips + 6, cur_size, false);
|
|
||||||
|
|
||||||
/* Advance. */
|
|
||||||
ips += (6 + cur_size);
|
|
||||||
size -= (6 + cur_size);
|
|
||||||
} else {
|
|
||||||
/* Read RLE size */
|
|
||||||
const u16 rle_size = (static_cast<u32>(ips[6]) << 8) | (static_cast<u32>(ips[7]) << 0);
|
|
||||||
|
|
||||||
/* Add patch. */
|
|
||||||
AddPatch(meta, offset, ips + 8, rle_size, true);
|
|
||||||
|
|
||||||
/* Advance. */
|
|
||||||
ips += 9;
|
|
||||||
size -= 9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddIpsPatchToKip(InitialProcessMeta *meta, const u8 *ips, s32 size) {
|
|
||||||
if (std::memcmp(ips, "PATCH", 5) == 0) {
|
|
||||||
AddIps24PatchToKip(meta, ips + 5, size - 5);
|
|
||||||
} else if (std::memcmp(ips, "IPS32", 5) == 0) {
|
|
||||||
AddIps32PatchToKip(meta, ips + 5, size - 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr const u8 NogcPatch0[] = {
|
constexpr const u8 NogcPatch0[] = {
|
||||||
0x80
|
0x80
|
||||||
};
|
};
|
||||||
@@ -643,6 +605,38 @@ namespace ams::nxboot {
|
|||||||
AddPatch(fs_meta, 0x18F1E9, NogcPatch0, sizeof(NogcPatch0));
|
AddPatch(fs_meta, 0x18F1E9, NogcPatch0, sizeof(NogcPatch0));
|
||||||
AddPatch(fs_meta, 0x169D74, NogcPatch1, sizeof(NogcPatch1));
|
AddPatch(fs_meta, 0x169D74, NogcPatch1, sizeof(NogcPatch1));
|
||||||
break;
|
break;
|
||||||
|
case FsVersion_16_0_0:
|
||||||
|
AddPatch(fs_meta, 0x1866D9, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x160C70, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_16_0_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x1913B9, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x16B950, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_16_0_3:
|
||||||
|
AddPatch(fs_meta, 0x186729, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x160CC0, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_16_0_3_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x191409, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x16B9A0, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_17_0_0:
|
||||||
|
AddPatch(fs_meta, 0x18B149, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x165200, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_17_0_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x195FA9, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x170060, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_18_0_0:
|
||||||
|
AddPatch(fs_meta, 0x18AF49, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x164B50, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_18_0_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x195FD9, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x16FBE0, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -836,106 +830,6 @@ namespace ams::nxboot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TODO ams.tma2: add mount_host patches. */
|
/* TODO ams.tma2: add mount_host patches. */
|
||||||
|
|
||||||
/* Add generic patches. */
|
|
||||||
{
|
|
||||||
/* Create patch path. */
|
|
||||||
char patch_path[0x220];
|
|
||||||
std::memcpy(patch_path, "sdmc:/atmosphere/kip_patches", 0x1D);
|
|
||||||
|
|
||||||
fs::DirectoryHandle patch_root_dir;
|
|
||||||
if (R_SUCCEEDED(fs::OpenDirectory(std::addressof(patch_root_dir), patch_path))) {
|
|
||||||
ON_SCOPE_EXIT { fs::CloseDirectory(patch_root_dir); };
|
|
||||||
|
|
||||||
s64 count;
|
|
||||||
fs::DirectoryEntry entries[1];
|
|
||||||
while (R_SUCCEEDED(fs::ReadDirectory(std::addressof(count), entries, patch_root_dir, util::size(entries))) && count > 0) {
|
|
||||||
/* Check that dir is a dir. */
|
|
||||||
if (fs::GetEntryType(entries[0]) != fs::DirectoryEntryType_Directory) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For compatibility, ignore the old "default_nogc" patches. */
|
|
||||||
if (std::strcmp(entries[0].file_name, "default_nogc") == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get filename length. */
|
|
||||||
const int dir_len = std::strlen(entries[0].file_name);
|
|
||||||
|
|
||||||
/* Adjust patch path. */
|
|
||||||
patch_path[0x1C] = '/';
|
|
||||||
std::memcpy(patch_path + 0x1D, entries[0].file_name, dir_len + 1);
|
|
||||||
|
|
||||||
/* Try to open the patch subdirectory. */
|
|
||||||
fs::DirectoryHandle patch_dir;
|
|
||||||
if (R_SUCCEEDED(fs::OpenDirectory(std::addressof(patch_dir), patch_path))) {
|
|
||||||
ON_SCOPE_EXIT { fs::CloseDirectory(patch_dir); };
|
|
||||||
|
|
||||||
/* Read patches. */
|
|
||||||
while (R_SUCCEEDED(fs::ReadDirectory(std::addressof(count), entries, patch_dir, util::size(entries))) && count > 0) {
|
|
||||||
/* Check that file is a file. */
|
|
||||||
if (fs::GetEntryType(entries[0]) != fs::DirectoryEntryType_File) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get filename length. */
|
|
||||||
const int name_len = std::strlen(entries[0].file_name);
|
|
||||||
|
|
||||||
/* Adjust patch path. */
|
|
||||||
patch_path[0x1D + dir_len] = '/';
|
|
||||||
std::memcpy(patch_path + 0x1D + dir_len + 1, entries[0].file_name, name_len + 1);
|
|
||||||
|
|
||||||
/* Check that file is "{hex}.ips" file. */
|
|
||||||
const int path_len = 0x1D + dir_len + 1 + name_len;
|
|
||||||
if (name_len != 0x44 || std::memcmp(patch_path + path_len - 4, ".ips", 5) != 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check that the filename is hex. */
|
|
||||||
bool valid_name = true;
|
|
||||||
se::Sha256Hash patch_name = {};
|
|
||||||
u32 shift = 4;
|
|
||||||
for (int i = 0; i < name_len - 4; ++i) {
|
|
||||||
const char c = entries[0].file_name[i];
|
|
||||||
|
|
||||||
u8 val;
|
|
||||||
if ('0' <= c && c <= '9') {
|
|
||||||
val = (c - '0');
|
|
||||||
} else if ('a' <= c && c <= 'f') {
|
|
||||||
val = (c - 'a') + 10;
|
|
||||||
} else if ('A' <= c && c <= 'F') {
|
|
||||||
val = (c - 'A') + 10;
|
|
||||||
} else {
|
|
||||||
valid_name = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_name.bytes[i >> 1] |= val << shift;
|
|
||||||
shift ^= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ignore invalid patches. */
|
|
||||||
if (!valid_name) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find kip for the patch. */
|
|
||||||
auto *kip_meta = FindInitialProcess(patch_name);
|
|
||||||
if (kip_meta == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the ips patch. */
|
|
||||||
s64 file_size;
|
|
||||||
if (u8 *ips = static_cast<u8 *>(ReadFile(std::addressof(file_size), patch_path)); ips != nullptr) {
|
|
||||||
AddIpsPatchToKip(kip_meta, ips, static_cast<s32>(file_size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the fs version we're using. */
|
/* Return the fs version we're using. */
|
||||||
@@ -984,7 +878,20 @@ namespace ams::nxboot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set the embedded ini pointer. */
|
/* Set the embedded ini pointer. */
|
||||||
std::memcpy(payload_data + 8, std::addressof(meso_size), sizeof(meso_size));
|
const u32 magic = *reinterpret_cast<const u32 *>(payload_data + 4);
|
||||||
|
if (magic == MesoshereMetadataLayout0Magic) {
|
||||||
|
std::memcpy(payload_data + 8, std::addressof(meso_size), sizeof(meso_size));
|
||||||
|
} else if (magic == MesoshereMetadataLayout1Magic) {
|
||||||
|
if (const u32 meta_offset = *reinterpret_cast<const u32 *>(payload_data + 8); meta_offset <= meso_size - sizeof(meso_size)) {
|
||||||
|
s64 relative_offset = meso_size - meta_offset;
|
||||||
|
std::memcpy(payload_data + meta_offset, std::addressof(relative_offset), sizeof(relative_offset));
|
||||||
|
} else {
|
||||||
|
ShowFatalError("Invalid mesosphere metadata layout!\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ShowFatalError("Unknown mesosphere metadata version!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Get the ini pointer. */
|
/* Get the ini pointer. */
|
||||||
InitialProcessBinaryHeader * const ini = reinterpret_cast<InitialProcessBinaryHeader *>(payload_data + meso_size);
|
InitialProcessBinaryHeader * const ini = reinterpret_cast<InitialProcessBinaryHeader *>(payload_data + meso_size);
|
||||||
|
|||||||
@@ -1002,14 +1002,16 @@ namespace ams::nxboot {
|
|||||||
\
|
\
|
||||||
constexpr u32 SrcLow = RANGE_LOW(SRC_RANGE); \
|
constexpr u32 SrcLow = RANGE_LOW(SRC_RANGE); \
|
||||||
constexpr u32 DstLow = RANGE_LOW(DST_RANGE); \
|
constexpr u32 DstLow = RANGE_LOW(DST_RANGE); \
|
||||||
|
constexpr auto Shift = (SrcLow < DstLow) ? (DstLow - SrcLow) \
|
||||||
|
: (SrcLow - DstLow); \
|
||||||
\
|
\
|
||||||
cur_reg_value &= ~Mask; \
|
cur_reg_value &= ~Mask; \
|
||||||
if constexpr (SrcLow == DstLow) { \
|
if constexpr (SrcLow == DstLow) { \
|
||||||
cur_reg_value |= (src_value & Mask); \
|
cur_reg_value |= (src_value & Mask); \
|
||||||
} else if constexpr (SrcLow < DstLow) { \
|
} else if constexpr (SrcLow < DstLow) { \
|
||||||
cur_reg_value |= ((src_value << (DstLow - SrcLow)) & Mask); \
|
cur_reg_value |= ((src_value << Shift) & Mask); \
|
||||||
} else { \
|
} else { \
|
||||||
cur_reg_value |= ((src_value >> (SrcLow - DstLow)) & Mask); \
|
cur_reg_value |= ((src_value >> Shift) & Mask); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 = b2232894f31953511d33bc665f68216badc3bb07
|
commit = bb767869105d0eb5c38425f54bf20614639a078d
|
||||||
parent = 8ce4f1961580a09381e486cc51c160a00fa86b88
|
parent = ab5cc7568430e2c1b3fa1be6be104b7c5f71eb32
|
||||||
method = merge
|
method = merge
|
||||||
cmdver = 0.4.1
|
cmdver = 0.4.1
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ else ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),clang)
|
|||||||
export ATMOSPHERE_CFLAGS += -Wno-c99-designator -Wno-gnu-alignof-expression -Wno-unused-private-field
|
export ATMOSPHERE_CFLAGS += -Wno-c99-designator -Wno-gnu-alignof-expression -Wno-unused-private-field
|
||||||
endif
|
endif
|
||||||
|
|
||||||
export ATMOSPHERE_CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++20 -Wno-invalid-offsetof
|
export ATMOSPHERE_CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++23 -Wno-invalid-offsetof
|
||||||
export ATMOSPHERE_ASFLAGS :=
|
export ATMOSPHERE_ASFLAGS :=
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_WINDOWS
|
export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_WINDOWS
|
||||||
export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer
|
export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer -fno-data-sections
|
||||||
export ATMOSPHERE_CFLAGS +=
|
export ATMOSPHERE_CFLAGS +=
|
||||||
export ATMOSPHERE_CXXFLAGS +=
|
export ATMOSPHERE_CXXFLAGS +=
|
||||||
export ATMOSPHERE_ASFLAGS +=
|
export ATMOSPHERE_ASFLAGS +=
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
|
|||||||
-Wl,--wrap,exit
|
-Wl,--wrap,exit
|
||||||
else ifeq ($(ATMOSPHERE_BOARD),generic_windows)
|
else ifeq ($(ATMOSPHERE_BOARD),generic_windows)
|
||||||
export CXXREQUIRED :=
|
export CXXREQUIRED :=
|
||||||
export CXXWRAPS := -Wl,--wrap,__p__acmdln
|
export CXXWRAPS := -Wl,--wrap,__p__acmdln -Wl,--wrap,_set_invalid_parameter_handler
|
||||||
else
|
else
|
||||||
export CXXREQUIRED :=
|
export CXXREQUIRED :=
|
||||||
export CXXWRAPS :=
|
export CXXWRAPS :=
|
||||||
@@ -66,7 +66,7 @@ endif
|
|||||||
|
|
||||||
|
|
||||||
ifeq ($(ATMOSPHERE_BOARD),nx-hac-001)
|
ifeq ($(ATMOSPHERE_BOARD),nx-hac-001)
|
||||||
export LDFLAGS = -specs=$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/stratosphere.specs -specs=$(DEVKITPRO)/libnx/switch.specs $(CXXFLAGS) $(CXXWRAPS) $(CXXREQUIRED) -Wl,-Map,$(notdir $*.map)
|
export LDFLAGS = -specs=$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/stratosphere.specs -specs=$(DEVKITPRO)/libnx/switch.specs $(CXXFLAGS) $(CXXWRAPS) $(CXXREQUIRED) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now
|
||||||
else ifeq ($(ATMOSPHERE_OS_NAME),macos)
|
else ifeq ($(ATMOSPHERE_OS_NAME),macos)
|
||||||
export LDFLAGS = $(CXXFLAGS) $(CXXWRAPS) $(CXXREQUIRED) -Wl,-map,$(notdir $@.map)
|
export LDFLAGS = $(CXXFLAGS) $(CXXWRAPS) $(CXXREQUIRED) -Wl,-map,$(notdir $@.map)
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace ams::pkg1 {
|
|||||||
enum MemoryArrange {
|
enum MemoryArrange {
|
||||||
MemoryArrange_Normal = 1,
|
MemoryArrange_Normal = 1,
|
||||||
MemoryArrange_AppletDev = 2,
|
MemoryArrange_AppletDev = 2,
|
||||||
MemoryArrange_SystemDev = 2,
|
MemoryArrange_SystemDev = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MemoryMode {
|
enum MemoryMode {
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ namespace ams::pkg1 {
|
|||||||
KeyGeneration_13_0_0 = 0x0C,
|
KeyGeneration_13_0_0 = 0x0C,
|
||||||
KeyGeneration_14_0_0 = 0x0D,
|
KeyGeneration_14_0_0 = 0x0D,
|
||||||
KeyGeneration_15_0_0 = 0x0E,
|
KeyGeneration_15_0_0 = 0x0E,
|
||||||
|
KeyGeneration_16_0_0 = 0x0F,
|
||||||
|
KeyGeneration_17_0_0 = 0x10,
|
||||||
|
KeyGeneration_18_0_0 = 0x11,
|
||||||
|
|
||||||
KeyGeneration_Count,
|
KeyGeneration_Count,
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ namespace ams::pkg2 {
|
|||||||
|
|
||||||
constexpr inline int PayloadCount = 3;
|
constexpr inline int PayloadCount = 3;
|
||||||
|
|
||||||
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x16 in Nintendo's code. */
|
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x18 in Nintendo's code. */
|
||||||
constexpr inline int CurrentBootloaderVersion = 0x12;
|
constexpr inline int CurrentBootloaderVersion = 0x15;
|
||||||
|
|
||||||
struct Package2Meta {
|
struct Package2Meta {
|
||||||
using Magic = util::FourCC<'P','K','2','1'>;
|
using Magic = util::FourCC<'P','K','2','1'>;
|
||||||
|
|||||||
@@ -177,6 +177,8 @@ namespace ams::fuse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
||||||
|
TargetFirmware_17_0_0,
|
||||||
|
TargetFirmware_16_0_0,
|
||||||
TargetFirmware_15_0_0,
|
TargetFirmware_15_0_0,
|
||||||
TargetFirmware_13_2_1,
|
TargetFirmware_13_2_1,
|
||||||
TargetFirmware_12_0_2,
|
TargetFirmware_12_0_2,
|
||||||
|
|||||||
@@ -19,33 +19,19 @@
|
|||||||
namespace ams::kern::init {
|
namespace ams::kern::init {
|
||||||
|
|
||||||
struct alignas(util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)) KInitArguments {
|
struct alignas(util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)) KInitArguments {
|
||||||
u64 ttbr0;
|
|
||||||
u64 ttbr1;
|
|
||||||
u64 tcr;
|
|
||||||
u64 mair;
|
|
||||||
u64 cpuactlr;
|
u64 cpuactlr;
|
||||||
u64 cpuectlr;
|
u64 cpuectlr;
|
||||||
u64 sctlr;
|
|
||||||
u64 sp;
|
u64 sp;
|
||||||
u64 entrypoint;
|
u64 entrypoint;
|
||||||
u64 argument;
|
u64 argument;
|
||||||
u64 setup_function;
|
|
||||||
u64 exception_stack;
|
|
||||||
};
|
};
|
||||||
static_assert(alignof(KInitArguments) == util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE));
|
static_assert(alignof(KInitArguments) == util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE));
|
||||||
static_assert(sizeof(KInitArguments) == std::max(INIT_ARGUMENTS_SIZE, util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)));
|
static_assert(sizeof(KInitArguments) == std::max(INIT_ARGUMENTS_SIZE, util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)));
|
||||||
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, ttbr0) == INIT_ARGUMENTS_TTBR0);
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, ttbr1) == INIT_ARGUMENTS_TTBR1);
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, tcr) == INIT_ARGUMENTS_TCR);
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, mair) == INIT_ARGUMENTS_MAIR);
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, cpuactlr) == INIT_ARGUMENTS_CPUACTLR);
|
static_assert(AMS_OFFSETOF(KInitArguments, cpuactlr) == INIT_ARGUMENTS_CPUACTLR);
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, cpuectlr) == INIT_ARGUMENTS_CPUECTLR);
|
static_assert(AMS_OFFSETOF(KInitArguments, cpuectlr) == INIT_ARGUMENTS_CPUECTLR);
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, sctlr) == INIT_ARGUMENTS_SCTLR);
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, sp) == INIT_ARGUMENTS_SP);
|
static_assert(AMS_OFFSETOF(KInitArguments, sp) == INIT_ARGUMENTS_SP);
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT);
|
static_assert(AMS_OFFSETOF(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT);
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT);
|
static_assert(AMS_OFFSETOF(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT);
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, setup_function) == INIT_ARGUMENTS_SETUP_FUNCTION);
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, exception_stack) == INIT_ARGUMENTS_EXCEPTION_STACK);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -23,17 +23,6 @@
|
|||||||
|
|
||||||
namespace ams::kern::arch::arm64::init {
|
namespace ams::kern::arch::arm64::init {
|
||||||
|
|
||||||
inline void ClearPhysicalMemory(KPhysicalAddress address, size_t size) {
|
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(size, sizeof(u64)));
|
|
||||||
|
|
||||||
/* This Physical Address -> void * conversion is valid, because this is init page table code. */
|
|
||||||
/* The MMU is necessarily not yet turned on, if we are creating an initial page table. */
|
|
||||||
volatile u64 *ptr = reinterpret_cast<volatile u64 *>(GetInteger(address));
|
|
||||||
for (size_t i = 0; i < size / sizeof(u64); ++i) {
|
|
||||||
ptr[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NOTE: Nintendo uses virtual functions, rather than a concept + template. */
|
/* NOTE: Nintendo uses virtual functions, rather than a concept + template. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept IsInitialPageAllocator = requires (T &t, KPhysicalAddress phys_addr, size_t size) {
|
concept IsInitialPageAllocator = requires (T &t, KPhysicalAddress phys_addr, size_t size) {
|
||||||
@@ -41,25 +30,23 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
{ t.Free(phys_addr, size) } -> std::same_as<void>;
|
{ t.Free(phys_addr, size) } -> std::same_as<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<IsInitialPageAllocator _PageAllocator>
|
class KInitialPageTable {
|
||||||
class KInitialPageTableTemplate {
|
|
||||||
public:
|
|
||||||
using PageAllocator = _PageAllocator;
|
|
||||||
private:
|
private:
|
||||||
KPhysicalAddress m_l1_tables[2];
|
KPhysicalAddress m_l1_tables[2];
|
||||||
u32 m_num_entries[2];
|
u32 m_num_entries[2];
|
||||||
public:
|
public:
|
||||||
KInitialPageTableTemplate(KVirtualAddress start_address, KVirtualAddress end_address, PageAllocator &allocator) {
|
template<IsInitialPageAllocator PageAllocator>
|
||||||
|
KInitialPageTable(KVirtualAddress start_address, KVirtualAddress end_address, PageAllocator &allocator) {
|
||||||
/* Set tables. */
|
/* Set tables. */
|
||||||
m_l1_tables[0] = AllocateNewPageTable(allocator);
|
m_l1_tables[0] = AllocateNewPageTable(allocator, 0);
|
||||||
m_l1_tables[1] = AllocateNewPageTable(allocator);
|
m_l1_tables[1] = AllocateNewPageTable(allocator, 0);
|
||||||
|
|
||||||
/* Set counts. */
|
/* Set counts. */
|
||||||
m_num_entries[0] = MaxPageTableEntries;
|
m_num_entries[0] = MaxPageTableEntries;
|
||||||
m_num_entries[1] = ((end_address / L1BlockSize) & (MaxPageTableEntries - 1)) - ((start_address / L1BlockSize) & (MaxPageTableEntries - 1)) + 1;
|
m_num_entries[1] = ((end_address / L1BlockSize) & (MaxPageTableEntries - 1)) - ((start_address / L1BlockSize) & (MaxPageTableEntries - 1)) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
KInitialPageTableTemplate() {
|
KInitialPageTable() {
|
||||||
/* Set tables. */
|
/* Set tables. */
|
||||||
m_l1_tables[0] = util::AlignDown(cpu::GetTtbr0El1(), PageSize);
|
m_l1_tables[0] = util::AlignDown(cpu::GetTtbr0El1(), PageSize);
|
||||||
m_l1_tables[1] = util::AlignDown(cpu::GetTtbr1El1(), PageSize);
|
m_l1_tables[1] = util::AlignDown(cpu::GetTtbr1El1(), PageSize);
|
||||||
@@ -82,30 +69,34 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
return GetInteger(m_l1_tables[1]);
|
return GetInteger(m_l1_tables[1]);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KVirtualAddress address) const {
|
constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KVirtualAddress address, u64 phys_to_virt_offset = 0) const {
|
||||||
const size_t index = (GetInteger(address) >> (BITSIZEOF(address) - 1)) & 1;
|
const size_t index = (GetInteger(address) >> (BITSIZEOF(address) - 1)) & 1;
|
||||||
L1PageTableEntry *l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[index]));
|
L1PageTableEntry *l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[index]) + phys_to_virt_offset);
|
||||||
return l1_table + ((GetInteger(address) / L1BlockSize) & (m_num_entries[index] - 1));
|
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, u64 phys_to_virt_offset = 0) {
|
||||||
L2PageTableEntry *l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(entry->GetTable()));
|
L2PageTableEntry *l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(entry->GetTable()) + phys_to_virt_offset);
|
||||||
return l2_table + ((GetInteger(address) / L2BlockSize) & (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, u64 phys_to_virt_offset = 0) {
|
||||||
L3PageTableEntry *l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(entry->GetTable()));
|
L3PageTableEntry *l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(entry->GetTable()) + phys_to_virt_offset);
|
||||||
return l3_table + ((GetInteger(address) / L3BlockSize) & (MaxPageTableEntries - 1));
|
return l3_table + ((GetInteger(address) / L3BlockSize) & (MaxPageTableEntries - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(PageAllocator &allocator) {
|
template<IsInitialPageAllocator PageAllocator>
|
||||||
auto address = allocator.Allocate(PageSize);
|
static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(PageAllocator &allocator, u64 phys_to_virt_offset) {
|
||||||
ClearNewPageTable(address);
|
MESOSPHERE_UNUSED(phys_to_virt_offset);
|
||||||
return address;
|
return allocator.Allocate(PageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address) {
|
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address, u64 phys_to_virt_offset) {
|
||||||
ClearPhysicalMemory(address, PageSize);
|
/* Convert to a deferenceable address, and clear. */
|
||||||
|
volatile u64 *ptr = reinterpret_cast<volatile u64 *>(GetInteger(address) + phys_to_virt_offset);
|
||||||
|
for (size_t i = 0; i < PageSize / sizeof(u64); ++i) {
|
||||||
|
ptr[i] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
static consteval size_t GetMaximumOverheadSize(size_t size) {
|
static consteval size_t GetMaximumOverheadSize(size_t size) {
|
||||||
@@ -327,7 +318,8 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, PageAllocator &allocator) {
|
template<IsInitialPageAllocator PageAllocator>
|
||||||
|
void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, PageAllocator &allocator, u64 phys_to_virt_offset) {
|
||||||
/* Ensure that addresses and sizes are page aligned. */
|
/* Ensure that addresses and sizes are page aligned. */
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize));
|
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize));
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(phys_addr), PageSize));
|
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(phys_addr), PageSize));
|
||||||
@@ -335,7 +327,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 = this->GetL1Entry(virt_addr);
|
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr, phys_to_virt_offset);
|
||||||
|
|
||||||
/* 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) {
|
||||||
@@ -349,12 +341,12 @@ 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 = AllocateNewPageTable(allocator);
|
KPhysicalAddress new_table = AllocateNewPageTable(allocator, phys_to_virt_offset);
|
||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
||||||
}
|
}
|
||||||
|
|
||||||
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
|
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr, phys_to_virt_offset);
|
||||||
|
|
||||||
/* Can we make a contiguous L2 block? */
|
/* Can we make a contiguous L2 block? */
|
||||||
if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && size >= L2ContiguousBlockSize) {
|
if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && size >= L2ContiguousBlockSize) {
|
||||||
@@ -380,12 +372,12 @@ 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 = AllocateNewPageTable(allocator);
|
KPhysicalAddress new_table = AllocateNewPageTable(allocator, phys_to_virt_offset);
|
||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
||||||
}
|
}
|
||||||
|
|
||||||
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
|
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr, phys_to_virt_offset);
|
||||||
|
|
||||||
/* Can we make a contiguous L3 block? */
|
/* Can we make a contiguous L3 block? */
|
||||||
if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && size >= L3ContiguousBlockSize) {
|
if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && size >= L3ContiguousBlockSize) {
|
||||||
@@ -410,6 +402,98 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UnmapTtbr0Entries(u64 phys_to_virt_offset) {
|
||||||
|
/* Ensure data consistency before we unmap. */
|
||||||
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
|
|
||||||
|
/* Define helper, as we only want to clear non-nGnRE pages. */
|
||||||
|
constexpr auto ShouldUnmap = [](const PageTableEntry *entry) ALWAYS_INLINE_LAMBDA -> bool {
|
||||||
|
return entry->GetPageAttribute() != PageTableEntry::PageAttribute_Device_nGnRE;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Iterate all L1 entries. */
|
||||||
|
L1PageTableEntry * const l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[0]) + phys_to_virt_offset);
|
||||||
|
for (size_t l1_index = 0; l1_index < m_num_entries[0]; l1_index++) {
|
||||||
|
/* Get L1 entry. */
|
||||||
|
L1PageTableEntry * const l1_entry = l1_table + l1_index;
|
||||||
|
if (l1_entry->IsBlock()) {
|
||||||
|
/* Unmap the L1 entry, if we should. */
|
||||||
|
if (ShouldUnmap(l1_entry)) {
|
||||||
|
*static_cast<PageTableEntry *>(l1_entry) = InvalidPageTableEntry;
|
||||||
|
}
|
||||||
|
} else if (l1_entry->IsTable()) {
|
||||||
|
/* Get the L2 table. */
|
||||||
|
L2PageTableEntry * const l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(l1_entry->GetTable()) + phys_to_virt_offset);
|
||||||
|
|
||||||
|
/* Unmap all L2 entries, as relevant. */
|
||||||
|
size_t remaining_l2_entries = 0;
|
||||||
|
for (size_t l2_index = 0; l2_index < MaxPageTableEntries; ++l2_index) {
|
||||||
|
/* Get L2 entry. */
|
||||||
|
L2PageTableEntry * const l2_entry = l2_table + l2_index;
|
||||||
|
if (l2_entry->IsBlock()) {
|
||||||
|
const size_t num_to_clear = (l2_entry->IsContiguous() ? L2ContiguousBlockSize : L2BlockSize) / L2BlockSize;
|
||||||
|
|
||||||
|
if (ShouldUnmap(l2_entry)) {
|
||||||
|
for (size_t i = 0; i < num_to_clear; ++i) {
|
||||||
|
static_cast<PageTableEntry *>(l2_entry)[i] = InvalidPageTableEntry;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remaining_l2_entries += num_to_clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
l2_index = l2_index + num_to_clear - 1;
|
||||||
|
} else if (l2_entry->IsTable()) {
|
||||||
|
/* Get the L3 table. */
|
||||||
|
L3PageTableEntry * const l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(l2_entry->GetTable()) + phys_to_virt_offset);
|
||||||
|
|
||||||
|
/* Unmap all L3 entries, as relevant. */
|
||||||
|
size_t remaining_l3_entries = 0;
|
||||||
|
for (size_t l3_index = 0; l3_index < MaxPageTableEntries; ++l3_index) {
|
||||||
|
/* Get L3 entry. */
|
||||||
|
if (L3PageTableEntry * const l3_entry = l3_table + l3_index; l3_entry->IsBlock()) {
|
||||||
|
const size_t num_to_clear = (l3_entry->IsContiguous() ? L3ContiguousBlockSize : L3BlockSize) / L3BlockSize;
|
||||||
|
|
||||||
|
if (ShouldUnmap(l3_entry)) {
|
||||||
|
for (size_t i = 0; i < num_to_clear; ++i) {
|
||||||
|
static_cast<PageTableEntry *>(l3_entry)[i] = InvalidPageTableEntry;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remaining_l3_entries += num_to_clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
l3_index = l3_index + num_to_clear - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we unmapped all L3 entries, clear the L2 entry. */
|
||||||
|
if (remaining_l3_entries == 0) {
|
||||||
|
*static_cast<PageTableEntry *>(l2_entry) = InvalidPageTableEntry;
|
||||||
|
|
||||||
|
/* Invalidate the entire tlb. */
|
||||||
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
|
cpu::InvalidateEntireTlb();
|
||||||
|
} else {
|
||||||
|
remaining_l2_entries++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we unmapped all L2 entries, clear the L1 entry. */
|
||||||
|
if (remaining_l2_entries == 0) {
|
||||||
|
*static_cast<PageTableEntry *>(l1_entry) = InvalidPageTableEntry;
|
||||||
|
|
||||||
|
/* Invalidate the entire tlb. */
|
||||||
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
|
cpu::InvalidateEntireTlb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Invalidate the entire tlb. */
|
||||||
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
|
cpu::InvalidateEntireTlb();
|
||||||
|
}
|
||||||
|
|
||||||
KPhysicalAddress GetPhysicalAddress(KVirtualAddress virt_addr) const {
|
KPhysicalAddress GetPhysicalAddress(KVirtualAddress virt_addr) const {
|
||||||
/* Get the L1 entry. */
|
/* Get the L1 entry. */
|
||||||
const L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
const L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
||||||
@@ -798,6 +882,12 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
const size_t ind_max = ((aligned_end - aligned_start) / align) - 1;
|
const size_t ind_max = ((aligned_end - aligned_start) / align) - 1;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (const uintptr_t random_address = aligned_start + (KSystemControl::Init::GenerateRandomRange(0, ind_max) * align); this->TryAllocate(random_address, size)) {
|
if (const uintptr_t random_address = aligned_start + (KSystemControl::Init::GenerateRandomRange(0, ind_max) * align); this->TryAllocate(random_address, size)) {
|
||||||
|
/* Clear the allocated pages. */
|
||||||
|
volatile u64 *ptr = reinterpret_cast<volatile u64 *>(random_address);
|
||||||
|
for (size_t i = 0; i < size / sizeof(u64); ++i) {
|
||||||
|
ptr[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return random_address;
|
return random_address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -861,6 +951,4 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
};
|
};
|
||||||
static_assert(IsInitialPageAllocator<KInitialPageAllocator>);
|
static_assert(IsInitialPageAllocator<KInitialPageAllocator>);
|
||||||
|
|
||||||
using KInitialPageTable = KInitialPageTableTemplate<KInitialPageAllocator>;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,3 +94,8 @@ label_done:
|
|||||||
ENABLE_FPU(xtmp1) \
|
ENABLE_FPU(xtmp1) \
|
||||||
GET_THREAD_CONTEXT_AND_RESTORE_FPCR_FPSR(ctx, xtmp1, xtmp2, wtmp1, wtmp2) \
|
GET_THREAD_CONTEXT_AND_RESTORE_FPCR_FPSR(ctx, xtmp1, xtmp2, wtmp1, wtmp2) \
|
||||||
RESTORE_FPU32_ALL_REGISTERS(ctx, xtmp1)
|
RESTORE_FPU32_ALL_REGISTERS(ctx, xtmp1)
|
||||||
|
|
||||||
|
#define ERET_WITH_SPECULATION_BARRIER \
|
||||||
|
eret; \
|
||||||
|
dsb nsh; \
|
||||||
|
isb
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#define THREAD_KERNEL_STACK_TOP 0x280
|
#define THREAD_KERNEL_STACK_TOP 0x280
|
||||||
|
|
||||||
/* ams::kern::KThread::StackParameters, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp */
|
/* 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 0x130
|
#define THREAD_STACK_PARAMETERS_SIZE 0x140
|
||||||
#define THREAD_STACK_PARAMETERS_SVC_PERMISSION 0x00
|
#define THREAD_STACK_PARAMETERS_SVC_PERMISSION 0x00
|
||||||
#define THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS 0x18
|
#define THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS 0x18
|
||||||
#define THREAD_STACK_PARAMETERS_CUR_THREAD 0x20
|
#define THREAD_STACK_PARAMETERS_CUR_THREAD 0x20
|
||||||
@@ -34,7 +34,8 @@
|
|||||||
#define THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS 0x2D
|
#define THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS 0x2D
|
||||||
#define THREAD_STACK_PARAMETERS_IS_PINNED 0x2E
|
#define THREAD_STACK_PARAMETERS_IS_PINNED 0x2E
|
||||||
#define THREAD_STACK_PARAMETERS_RESERVED_2F 0x2F
|
#define THREAD_STACK_PARAMETERS_RESERVED_2F 0x2F
|
||||||
#define THREAD_STACK_PARAMETERS_THREAD_CONTEXT 0x30
|
#define THREAD_STACK_PARAMETERS_RESERVED_30 0x30
|
||||||
|
#define THREAD_STACK_PARAMETERS_THREAD_CONTEXT 0x40
|
||||||
|
|
||||||
#define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_CALLING_SVC (0)
|
#define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_CALLING_SVC (0)
|
||||||
#define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_EXCEPTION_HANDLER (1)
|
#define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_EXCEPTION_HANDLER (1)
|
||||||
@@ -245,25 +246,18 @@
|
|||||||
#define THREAD_LOCAL_REGION_SIZE 0x200
|
#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 */
|
/* 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_SIZE 0x28
|
||||||
#define INIT_ARGUMENTS_TTBR0 0x00
|
#define INIT_ARGUMENTS_CPUACTLR 0x00
|
||||||
#define INIT_ARGUMENTS_TTBR1 0x08
|
#define INIT_ARGUMENTS_CPUECTLR 0x08
|
||||||
#define INIT_ARGUMENTS_TCR 0x10
|
#define INIT_ARGUMENTS_SP 0x10
|
||||||
#define INIT_ARGUMENTS_MAIR 0x18
|
#define INIT_ARGUMENTS_ENTRYPOINT 0x18
|
||||||
#define INIT_ARGUMENTS_CPUACTLR 0x20
|
#define INIT_ARGUMENTS_ARGUMENT 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 */
|
/* 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. */
|
/* 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_NEEDS_SCHEDULING 0x00
|
||||||
#define KSCHEDULER_INTERRUPT_TASK_RUNNABLE 0x01
|
#define KSCHEDULER_INTERRUPT_TASK_RUNNABLE 0x01
|
||||||
#define KSCHEDULER_HIGHEST_PRIORITY_THREAD 0x10
|
#define KSCHEDULER_HIGHEST_PRIORITY_THREAD 0x18
|
||||||
#define KSCHEDULER_IDLE_THREAD_STACK 0x18
|
#define KSCHEDULER_IDLE_THREAD_STACK 0x20
|
||||||
#define KSCHEDULER_PREVIOUS_THREAD 0x20
|
#define KSCHEDULER_PREVIOUS_THREAD 0x28
|
||||||
#define KSCHEDULER_INTERRUPT_TASK_MANAGER 0x28
|
#define KSCHEDULER_INTERRUPT_TASK_MANAGER 0x30
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ namespace ams::kern::arch::arm64::cpu {
|
|||||||
#error "Unknown Board for cpu::NumCores"
|
#error "Unknown Board for cpu::NumCores"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
constexpr inline u32 El0Aarch64PsrMask = 0xF0000000;
|
||||||
|
constexpr inline u32 El0Aarch32PsrMask = 0xFE0FFE20;
|
||||||
|
|
||||||
/* Initialization. */
|
/* Initialization. */
|
||||||
NOINLINE void InitializeInterruptThreads(s32 core_id);
|
NOINLINE void InitializeInterruptThreads(s32 core_id);
|
||||||
|
|
||||||
@@ -186,6 +189,14 @@ namespace ams::kern::arch::arm64::cpu {
|
|||||||
return (par >> (BITSIZEOF(par) - BITSIZEOF(u8))) == 0xFF;
|
return (par >> (BITSIZEOF(par) - BITSIZEOF(u8))) == 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void StoreDataCacheForInitArguments(const void *addr, size_t size) {
|
||||||
|
const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), DataCacheLineSize);
|
||||||
|
for (size_t stored = 0; stored < size; stored += cpu::DataCacheLineSize) {
|
||||||
|
__asm__ __volatile__("dc cvac, %[cur]" :: [cur]"r"(start + stored) : "memory");
|
||||||
|
}
|
||||||
|
DataSynchronizationBarrier();
|
||||||
|
}
|
||||||
|
|
||||||
/* Synchronization helpers. */
|
/* Synchronization helpers. */
|
||||||
NOINLINE void SynchronizeAllCores();
|
NOINLINE void SynchronizeAllCores();
|
||||||
void SynchronizeCores(u64 core_mask);
|
void SynchronizeCores(u64 core_mask);
|
||||||
|
|||||||
@@ -372,6 +372,10 @@ namespace ams::kern::arch::arm64::cpu {
|
|||||||
this->SetBit(19, en);
|
this->SetBit(19, en);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE bool GetWxn() const {
|
||||||
|
return this->GetBits(19, 1) != 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Accessors for timer registers. */
|
/* Accessors for timer registers. */
|
||||||
|
|||||||
@@ -178,7 +178,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, KSystemResource *system_resource, KResourceLimit *resource_limit);
|
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, 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);
|
||||||
@@ -208,15 +208,15 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll);
|
Result MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
||||||
Result MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
Result MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll);
|
||||||
|
|
||||||
bool MergePages(KProcessAddress virt_addr, PageLinkedList *page_list);
|
bool MergePages(KProcessAddress virt_addr, PageLinkedList *page_list);
|
||||||
|
|
||||||
ALWAYS_INLINE Result SeparatePagesImpl(KProcessAddress virt_addr, size_t block_size, PageLinkedList *page_list, bool reuse_ll);
|
ALWAYS_INLINE Result SeparatePagesImpl(KProcessAddress virt_addr, size_t block_size, PageLinkedList *page_list, bool reuse_ll);
|
||||||
Result SeparatePages(KProcessAddress virt_addr, size_t block_size, PageLinkedList *page_list, bool reuse_ll);
|
Result SeparatePages(KProcessAddress virt_addr, size_t block_size, PageLinkedList *page_list, bool reuse_ll);
|
||||||
|
|
||||||
Result ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, PageLinkedList *page_list, bool reuse_ll);
|
Result ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, bool flush_mapping, PageLinkedList *page_list, bool reuse_ll);
|
||||||
|
|
||||||
static ALWAYS_INLINE void PteDataMemoryBarrier() {
|
static ALWAYS_INLINE void PteDataMemoryBarrier() {
|
||||||
cpu::DataMemoryBarrierInnerShareableStore();
|
cpu::DataMemoryBarrierInnerShareableStore();
|
||||||
|
|||||||
@@ -161,9 +161,12 @@ namespace ams::kern::arch::arm64 {
|
|||||||
constexpr ALWAYS_INLINE bool IsPrivilegedExecuteNever() const { return this->GetBits(53, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsPrivilegedExecuteNever() const { return this->GetBits(53, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsContiguous() const { return this->GetBits(52, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsContiguous() const { return this->GetBits(52, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsGlobal() const { return this->GetBits(11, 1) == 0; }
|
constexpr ALWAYS_INLINE bool IsGlobal() const { return this->GetBits(11, 1) == 0; }
|
||||||
constexpr ALWAYS_INLINE AccessFlag GetAccessFlag() const { return static_cast<AccessFlag>(this->GetBits(10, 1)); }
|
constexpr ALWAYS_INLINE AccessFlag GetAccessFlag() const { return static_cast<AccessFlag>(this->SelectBits(10, 1)); }
|
||||||
constexpr ALWAYS_INLINE Shareable GetShareable() const { return static_cast<Shareable>(this->GetBits(8, 2)); }
|
constexpr ALWAYS_INLINE Shareable GetShareable() const { return static_cast<Shareable>(this->SelectBits(8, 2)); }
|
||||||
constexpr ALWAYS_INLINE PageAttribute GetPageAttribute() const { return static_cast<PageAttribute>(this->GetBits(2, 3)); }
|
constexpr ALWAYS_INLINE PageAttribute GetPageAttribute() const { return static_cast<PageAttribute>(this->SelectBits(2, 3)); }
|
||||||
|
constexpr ALWAYS_INLINE int GetAccessFlagInteger() const { return static_cast<int>(this->GetBits(10, 1)); }
|
||||||
|
constexpr ALWAYS_INLINE int GetShareableInteger() const { return static_cast<int>(this->GetBits(8, 2)); }
|
||||||
|
constexpr ALWAYS_INLINE int GetPageAttributeInteger() const { return static_cast<int>(this->GetBits(2, 3)); }
|
||||||
constexpr ALWAYS_INLINE bool IsReadOnly() const { return this->GetBits(7, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsReadOnly() const { return this->GetBits(7, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsUserAccessible() const { return this->GetBits(6, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsUserAccessible() const { return this->GetBits(6, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBits(5, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBits(5, 1) != 0; }
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
KPhysicalAddress phys_addr;
|
KPhysicalAddress phys_addr;
|
||||||
size_t block_size;
|
size_t block_size;
|
||||||
u8 sw_reserved_bits;
|
u8 sw_reserved_bits;
|
||||||
|
u8 attr;
|
||||||
|
|
||||||
constexpr bool IsHeadMergeDisabled() const { return (this->sw_reserved_bits & PageTableEntry::SoftwareReservedBit_DisableMergeHead) != 0; }
|
constexpr bool IsHeadMergeDisabled() const { return (this->sw_reserved_bits & PageTableEntry::SoftwareReservedBit_DisableMergeHead) != 0; }
|
||||||
constexpr bool IsHeadAndBodyMergeDisabled() const { return (this->sw_reserved_bits & PageTableEntry::SoftwareReservedBit_DisableMergeHeadAndBody) != 0; }
|
constexpr bool IsHeadAndBodyMergeDisabled() const { return (this->sw_reserved_bits & PageTableEntry::SoftwareReservedBit_DisableMergeHeadAndBody) != 0; }
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ 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, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
Result Initialize(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
||||||
R_RETURN(m_page_table.InitializeForProcess(id, as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, system_resource, resource_limit));
|
R_RETURN(m_page_table.InitializeForProcess(flags, from_back, pool, code_address, code_size, system_resource, resource_limit));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Finalize() { m_page_table.Finalize(); }
|
void Finalize() { m_page_table.Finalize(); }
|
||||||
@@ -98,8 +98,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
R_RETURN(m_page_table.MapIoRegion(dst_address, phys_addr, size, mapping, perm));
|
R_RETURN(m_page_table.MapIoRegion(dst_address, phys_addr, size, mapping, perm));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size) {
|
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping) {
|
||||||
R_RETURN(m_page_table.UnmapIoRegion(dst_address, phys_addr, size));
|
R_RETURN(m_page_table.UnmapIoRegion(dst_address, phys_addr, size, mapping));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) {
|
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) {
|
||||||
@@ -110,12 +110,12 @@ namespace ams::kern::arch::arm64 {
|
|||||||
R_RETURN(m_page_table.MapRegion(region_type, perm));
|
R_RETURN(m_page_table.MapRegion(region_type, perm));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapInsecureMemory(KProcessAddress address, size_t size) {
|
Result MapInsecurePhysicalMemory(KProcessAddress address, size_t size) {
|
||||||
R_RETURN(m_page_table.MapInsecureMemory(address, size));
|
R_RETURN(m_page_table.MapInsecurePhysicalMemory(address, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result UnmapInsecureMemory(KProcessAddress address, size_t size) {
|
Result UnmapInsecurePhysicalMemory(KProcessAddress address, size_t size) {
|
||||||
R_RETURN(m_page_table.UnmapInsecureMemory(address, size));
|
R_RETURN(m_page_table.UnmapInsecurePhysicalMemory(address, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapPageGroup(KProcessAddress addr, const KPageGroup &pg, KMemoryState state, KMemoryPermission perm) {
|
Result MapPageGroup(KProcessAddress addr, const KPageGroup &pg, KMemoryState state, KMemoryPermission perm) {
|
||||||
@@ -150,20 +150,24 @@ namespace ams::kern::arch::arm64 {
|
|||||||
R_RETURN(m_page_table.InvalidateProcessDataCache(address, size));
|
R_RETURN(m_page_table.InvalidateProcessDataCache(address, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result InvalidateCurrentProcessDataCache(KProcessAddress address, size_t size) {
|
||||||
|
R_RETURN(m_page_table.InvalidateCurrentProcessDataCache(address, size));
|
||||||
|
}
|
||||||
|
|
||||||
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size) {
|
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size) {
|
||||||
R_RETURN(m_page_table.ReadDebugMemory(buffer, address, size));
|
R_RETURN(m_page_table.ReadDebugMemory(buffer, address, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size) {
|
Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size, KMemoryState state) {
|
||||||
R_RETURN(m_page_table.ReadDebugIoMemory(buffer, address, size));
|
R_RETURN(m_page_table.ReadDebugIoMemory(buffer, address, size, state));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size) {
|
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size) {
|
||||||
R_RETURN(m_page_table.WriteDebugMemory(address, buffer, size));
|
R_RETURN(m_page_table.WriteDebugMemory(address, buffer, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size) {
|
Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size, KMemoryState state) {
|
||||||
R_RETURN(m_page_table.WriteDebugIoMemory(address, buffer, size));
|
R_RETURN(m_page_table.WriteDebugIoMemory(address, buffer, size, state));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap) {
|
Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap) {
|
||||||
@@ -296,6 +300,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const { return m_page_table.IsInUnsafeAliasRegion(addr, size); }
|
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const { return m_page_table.IsInUnsafeAliasRegion(addr, size); }
|
||||||
|
|
||||||
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return m_page_table.CanContain(addr, size, state); }
|
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return m_page_table.CanContain(addr, size, state); }
|
||||||
|
bool CanContain(KProcessAddress addr, size_t size, ams::svc::MemoryState state) const { return m_page_table.CanContain(addr, size, state); }
|
||||||
|
|
||||||
KProcessAddress GetAddressSpaceStart() const { return m_page_table.GetAddressSpaceStart(); }
|
KProcessAddress GetAddressSpaceStart() const { return m_page_table.GetAddressSpaceStart(); }
|
||||||
KProcessAddress GetHeapRegionStart() const { return m_page_table.GetHeapRegionStart(); }
|
KProcessAddress GetHeapRegionStart() const { return m_page_table.GetHeapRegionStart(); }
|
||||||
@@ -311,6 +316,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
size_t GetKernelMapRegionSize() const { return m_page_table.GetKernelMapRegionSize(); }
|
size_t GetKernelMapRegionSize() const { return m_page_table.GetKernelMapRegionSize(); }
|
||||||
size_t GetAliasCodeRegionSize() const { return m_page_table.GetAliasCodeRegionSize(); }
|
size_t GetAliasCodeRegionSize() const { return m_page_table.GetAliasCodeRegionSize(); }
|
||||||
|
|
||||||
|
size_t GetAliasRegionExtraSize() const { return m_page_table.GetAliasRegionExtraSize(); }
|
||||||
|
|
||||||
size_t GetNormalMemorySize() const { return m_page_table.GetNormalMemorySize(); }
|
size_t GetNormalMemorySize() const { return m_page_table.GetNormalMemorySize(); }
|
||||||
|
|
||||||
size_t GetCodeSize() const { return m_page_table.GetCodeSize(); }
|
size_t GetCodeSize() const { return m_page_table.GetCodeSize(); }
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
" prfm pstl1keep, %[m_next_ticket]\n"
|
" prfm pstl1keep, %[m_next_ticket]\n"
|
||||||
"1:\n"
|
"1:\n"
|
||||||
" ldaxrh %w[tmp0], %[m_next_ticket]\n"
|
" ldxrh %w[tmp0], %[m_next_ticket]\n"
|
||||||
" add %w[tmp1], %w[tmp0], #0x1\n"
|
" add %w[tmp1], %w[tmp0], #0x1\n"
|
||||||
" stxrh %w[got_lock], %w[tmp1], %[m_next_ticket]\n"
|
" stxrh %w[got_lock], %w[tmp1], %[m_next_ticket]\n"
|
||||||
" cbnz %w[got_lock], 1b\n"
|
" cbnz %w[got_lock], 1b\n"
|
||||||
|
|||||||
@@ -23,9 +23,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
class KSupervisorPageTable {
|
class KSupervisorPageTable {
|
||||||
private:
|
private:
|
||||||
KPageTable m_page_table;
|
KPageTable m_page_table;
|
||||||
u64 m_ttbr0_identity[cpu::NumCores];
|
|
||||||
public:
|
public:
|
||||||
constexpr KSupervisorPageTable() : m_page_table(util::ConstantInitialize), m_ttbr0_identity() { /* ... */ }
|
constexpr KSupervisorPageTable() : m_page_table(util::ConstantInitialize) { /* ... */ }
|
||||||
|
|
||||||
NOINLINE void Initialize(s32 core_id);
|
NOINLINE void Initialize(s32 core_id);
|
||||||
|
|
||||||
@@ -61,8 +60,6 @@ namespace ams::kern::arch::arm64 {
|
|||||||
return m_page_table.GetPhysicalAddress(out, address);
|
return m_page_table.GetPhysicalAddress(out, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u64 GetIdentityMapTtbr0(s32 core_id) const { return m_ttbr0_identity[core_id]; }
|
|
||||||
|
|
||||||
void DumpMemoryBlocks() const {
|
void DumpMemoryBlocks() const {
|
||||||
return m_page_table.DumpMemoryBlocks();
|
return m_page_table.DumpMemoryBlocks();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <mesosphere/kern_common.hpp>
|
#include <mesosphere/kern_common.hpp>
|
||||||
#include <mesosphere/kern_select_cpu.hpp>
|
#include <mesosphere/kern_select_cpu.hpp>
|
||||||
#include <mesosphere/kern_select_interrupt_manager.hpp>
|
|
||||||
|
|
||||||
namespace ams::kern::arch::arm64::smc {
|
namespace ams::kern::arch::arm64::smc {
|
||||||
|
|
||||||
template<int SmcId, bool DisableInterrupt>
|
template<int SmcId>
|
||||||
void SecureMonitorCall(u64 *buf) {
|
void SecureMonitorCall(u64 *buf) {
|
||||||
/* Load arguments into registers. */
|
/* Load arguments into registers. */
|
||||||
register u64 x0 asm("x0") = buf[0];
|
register u64 x0 asm("x0") = buf[0];
|
||||||
@@ -32,34 +31,18 @@ namespace ams::kern::arch::arm64::smc {
|
|||||||
register u64 x6 asm("x6") = buf[6];
|
register u64 x6 asm("x6") = buf[6];
|
||||||
register u64 x7 asm("x7") = buf[7];
|
register u64 x7 asm("x7") = buf[7];
|
||||||
|
|
||||||
|
/* Backup the current thread pointer. */
|
||||||
|
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue();
|
||||||
|
|
||||||
/* Perform the call. */
|
/* Perform the call. */
|
||||||
if constexpr (DisableInterrupt) {
|
__asm__ __volatile__("smc %c[smc_id]"
|
||||||
KScopedInterruptDisable di;
|
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
||||||
|
: [smc_id]"i"(SmcId)
|
||||||
|
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
|
||||||
|
);
|
||||||
|
|
||||||
/* Backup the current thread pointer. */
|
/* Restore the current thread pointer into X18. */
|
||||||
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue();
|
cpu::SetCurrentThreadPointerValue(current_thread_pointer_value);
|
||||||
|
|
||||||
__asm__ __volatile__("smc %c[smc_id]"
|
|
||||||
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
|
||||||
: [smc_id]"i"(SmcId)
|
|
||||||
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Restore the current thread pointer into X18. */
|
|
||||||
cpu::SetCurrentThreadPointerValue(current_thread_pointer_value);
|
|
||||||
} else {
|
|
||||||
/* Backup the current thread pointer. */
|
|
||||||
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue();
|
|
||||||
|
|
||||||
__asm__ __volatile__("smc %c[smc_id]"
|
|
||||||
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
|
||||||
: [smc_id]"i"(SmcId)
|
|
||||||
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Restore the current thread pointer into X18. */
|
|
||||||
cpu::SetCurrentThreadPointerValue(current_thread_pointer_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store arguments to output. */
|
/* Store arguments to output. */
|
||||||
buf[0] = x0;
|
buf[0] = x0;
|
||||||
@@ -78,18 +61,18 @@ namespace ams::kern::arch::arm64::smc {
|
|||||||
PsciFunction_CpuOn = 0xC4000003,
|
PsciFunction_CpuOn = 0xC4000003,
|
||||||
};
|
};
|
||||||
|
|
||||||
template<int SmcId, bool DisableInterrupt>
|
template<int SmcId>
|
||||||
u64 PsciCall(PsciFunction function, u64 x1 = 0, u64 x2 = 0, u64 x3 = 0, u64 x4 = 0, u64 x5 = 0, u64 x6 = 0, u64 x7 = 0) {
|
u64 PsciCall(PsciFunction function, u64 x1 = 0, u64 x2 = 0, u64 x3 = 0, u64 x4 = 0, u64 x5 = 0, u64 x6 = 0, u64 x7 = 0) {
|
||||||
ams::svc::lp64::SecureMonitorArguments args = { { function, x1, x2, x3, x4, x5, x6, x7 } };
|
ams::svc::lp64::SecureMonitorArguments args = { { function, x1, x2, x3, x4, x5, x6, x7 } };
|
||||||
|
|
||||||
SecureMonitorCall<SmcId, DisableInterrupt>(args.r);
|
SecureMonitorCall<SmcId>(args.r);
|
||||||
|
|
||||||
return args.r[0];
|
return args.r[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int SmcId, bool DisableInterrupt>
|
template<int SmcId>
|
||||||
u64 CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
u64 CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
||||||
return PsciCall<SmcId, DisableInterrupt>(PsciFunction_CpuOn, core_id, entrypoint, arg);
|
return PsciCall<SmcId>(PsciFunction_CpuOn, core_id, entrypoint, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,12 +25,15 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
static constexpr size_t SecureAppletMemorySize = 4_MB;
|
static constexpr size_t SecureAppletMemorySize = 4_MB;
|
||||||
public:
|
public:
|
||||||
class Init : public KSystemControlBase::Init {
|
class Init : public KSystemControlBase::Init {
|
||||||
|
private:
|
||||||
|
friend class KSystemControlBase::Init;
|
||||||
|
private:
|
||||||
|
static void CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
||||||
public:
|
public:
|
||||||
/* Initialization. */
|
/* Initialization. */
|
||||||
static size_t GetRealMemorySize();
|
static size_t GetRealMemorySize();
|
||||||
static size_t GetIntendedMemorySize();
|
static size_t GetIntendedMemorySize();
|
||||||
static bool ShouldIncreaseThreadResourceLimit();
|
static bool ShouldIncreaseThreadResourceLimit();
|
||||||
static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
|
||||||
static size_t GetApplicationPoolSize();
|
static size_t GetApplicationPoolSize();
|
||||||
static size_t GetAppletPoolSize();
|
static size_t GetAppletPoolSize();
|
||||||
static size_t GetMinimumNonSecureSystemPoolSize();
|
static size_t GetMinimumNonSecureSystemPoolSize();
|
||||||
|
|||||||
@@ -26,6 +26,6 @@ namespace ams::kern::init {
|
|||||||
|
|
||||||
static_assert(util::IsPowerOfTwo(alignof(KInitArguments)) && util::IsPowerOfTwo(sizeof(KInitArguments)));
|
static_assert(util::IsPowerOfTwo(alignof(KInitArguments)) && util::IsPowerOfTwo(sizeof(KInitArguments)));
|
||||||
|
|
||||||
KPhysicalAddress GetInitArgumentsAddress(s32 core_id);
|
KInitArguments *GetInitArguments(s32 core_id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,6 +114,23 @@ namespace ams::kern::init::Elf::Elf64 {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Relr {
|
||||||
|
private:
|
||||||
|
Xword m_info;
|
||||||
|
public:
|
||||||
|
constexpr ALWAYS_INLINE bool IsLocation() const {
|
||||||
|
return (m_info & 1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE Xword GetLocation() const {
|
||||||
|
return m_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE Xword GetBitmap() const {
|
||||||
|
return m_info >> 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
enum DynamicTag {
|
enum DynamicTag {
|
||||||
DT_NULL = 0,
|
DT_NULL = 0,
|
||||||
DT_RELA = 7,
|
DT_RELA = 7,
|
||||||
@@ -121,6 +138,10 @@ namespace ams::kern::init::Elf::Elf64 {
|
|||||||
DT_REL = 17,
|
DT_REL = 17,
|
||||||
DT_RELENT = 19,
|
DT_RELENT = 19,
|
||||||
|
|
||||||
|
DT_RELRSZ = 35,
|
||||||
|
DT_RELR = 36,
|
||||||
|
DT_RELRENT = 37,
|
||||||
|
|
||||||
DT_RELACOUNT = 0x6ffffff9,
|
DT_RELACOUNT = 0x6ffffff9,
|
||||||
DT_RELCOUNT = 0x6ffffffa
|
DT_RELCOUNT = 0x6ffffffa
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,8 +31,22 @@ namespace ams::kern::init {
|
|||||||
u32 dynamic_offset;
|
u32 dynamic_offset;
|
||||||
u32 init_array_offset;
|
u32 init_array_offset;
|
||||||
u32 init_array_end_offset;
|
u32 init_array_end_offset;
|
||||||
|
u32 sysreg_offset;
|
||||||
};
|
};
|
||||||
static_assert(util::is_pod<KernelLayout>::value);
|
static_assert(util::is_pod<KernelLayout>::value);
|
||||||
static_assert(sizeof(KernelLayout) == 0x30);
|
static_assert(sizeof(KernelLayout) == 0x34);
|
||||||
|
|
||||||
|
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||||
|
struct KernelSystemRegisters {
|
||||||
|
u64 ttbr0_el1;
|
||||||
|
u64 ttbr1_el1;
|
||||||
|
u64 tcr_el1;
|
||||||
|
u64 mair_el1;
|
||||||
|
u64 sctlr_el1;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
struct KernelSystemRegisters {
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -42,6 +42,11 @@
|
|||||||
#define MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP
|
#define MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP
|
||||||
#define MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP
|
#define MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP
|
||||||
|
|
||||||
|
/* NOTE: In 16.0.0, Nintendo deleted the creation time field for KProcess, */
|
||||||
|
/* but this may be useful for some debugging applications, and so can be. */
|
||||||
|
/* re-enabled by toggling this define. */
|
||||||
|
//#define MESOSPHERE_ENABLE_PROCESS_CREATION_TIME
|
||||||
|
|
||||||
/* NOTE: This enables fast class token storage using a class member. */
|
/* NOTE: This enables fast class token storage using a class member. */
|
||||||
/* This saves a virtual call when doing KAutoObject->DynCast<>(), */
|
/* This saves a virtual call when doing KAutoObject->DynCast<>(), */
|
||||||
/* at the cost of storing class tokens inside the class object. */
|
/* at the cost of storing class tokens inside the class object. */
|
||||||
|
|||||||
@@ -32,10 +32,17 @@ namespace ams::kern {
|
|||||||
struct InitialProcessBinaryLayout {
|
struct InitialProcessBinaryLayout {
|
||||||
uintptr_t address;
|
uintptr_t address;
|
||||||
uintptr_t _08;
|
uintptr_t _08;
|
||||||
|
uintptr_t kern_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InitialProcessBinaryLayoutWithSize {
|
||||||
|
InitialProcessBinaryLayout layout;
|
||||||
|
size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
KPhysicalAddress GetInitialProcessBinaryPhysicalAddress();
|
KPhysicalAddress GetInitialProcessBinaryPhysicalAddress();
|
||||||
void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr);
|
size_t GetInitialProcessBinarySize();
|
||||||
|
void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr, size_t size);
|
||||||
|
|
||||||
u64 GetInitialProcessIdMin();
|
u64 GetInitialProcessIdMin();
|
||||||
u64 GetInitialProcessIdMax();
|
u64 GetInitialProcessIdMax();
|
||||||
|
|||||||
@@ -40,12 +40,16 @@ namespace ams::kern {
|
|||||||
static uintptr_t GetAddressSpaceStart(size_t width, Type type);
|
static uintptr_t GetAddressSpaceStart(size_t width, Type type);
|
||||||
static size_t GetAddressSpaceSize(size_t width, Type type);
|
static size_t GetAddressSpaceSize(size_t width, Type type);
|
||||||
|
|
||||||
|
static void SetAddressSpaceSize(size_t width, Type type, size_t size);
|
||||||
|
|
||||||
constexpr KAddressSpaceInfo(size_t bw, size_t a, size_t s, Type t) : m_bit_width(bw), m_address(a), m_size(s), m_type(t) { /* ... */ }
|
constexpr KAddressSpaceInfo(size_t bw, size_t a, size_t s, Type t) : m_bit_width(bw), m_address(a), m_size(s), m_type(t) { /* ... */ }
|
||||||
|
|
||||||
constexpr size_t GetWidth() const { return m_bit_width; }
|
constexpr size_t GetWidth() const { return m_bit_width; }
|
||||||
constexpr size_t GetAddress() const { return m_address; }
|
constexpr size_t GetAddress() const { return m_address; }
|
||||||
constexpr size_t GetSize() const { return m_size; }
|
constexpr size_t GetSize() const { return m_size; }
|
||||||
constexpr Type GetType() const { return m_type; }
|
constexpr Type GetType() const { return m_type; }
|
||||||
|
|
||||||
|
constexpr void SetSize(size_t size) { m_size = size; }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool Close() {
|
ALWAYS_INLINE bool Close() {
|
||||||
/* Atomically decrement the reference count, not allowing it to become negative. */
|
/* Atomically decrement the reference count, not allowing it to decrement past zero. */
|
||||||
u32 cur = m_value.Load<std::memory_order_relaxed>();
|
u32 cur = m_value.Load<std::memory_order_relaxed>();
|
||||||
do {
|
do {
|
||||||
MESOSPHERE_ABORT_UNLESS(cur > 0);
|
MESOSPHERE_ABORT_UNLESS(cur > 0);
|
||||||
@@ -257,7 +257,7 @@ namespace ams::kern {
|
|||||||
class KScopedAutoObject {
|
class KScopedAutoObject {
|
||||||
NON_COPYABLE(KScopedAutoObject);
|
NON_COPYABLE(KScopedAutoObject);
|
||||||
private:
|
private:
|
||||||
template<typename U>
|
template<typename U> requires std::derived_from<U, KAutoObject>
|
||||||
friend class KScopedAutoObject;
|
friend class KScopedAutoObject;
|
||||||
private:
|
private:
|
||||||
T *m_obj;
|
T *m_obj;
|
||||||
@@ -358,7 +358,7 @@ namespace ams::kern {
|
|||||||
void Detach() {
|
void Detach() {
|
||||||
/* Close our object, if we have one. */
|
/* Close our object, if we have one. */
|
||||||
if (T * const object = m_object; AMS_LIKELY(object != nullptr)) {
|
if (T * const object = m_object; AMS_LIKELY(object != nullptr)) {
|
||||||
/* Set our object to a debug sentinel value, which will cause crash if accessed. */
|
/* Set our object to a debug sentinel value, which will cause a crash if accessed. */
|
||||||
m_object = reinterpret_cast<T *>(1);
|
m_object = reinterpret_cast<T *>(1);
|
||||||
|
|
||||||
/* Close reference to our object. */
|
/* Close reference to our object. */
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ namespace ams::kern {
|
|||||||
return m_process_holder.Get();
|
return m_process_holder.Get();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
void PushDebugEvent(ams::svc::DebugEvent event, uintptr_t param0 = 0, uintptr_t param1 = 0, uintptr_t param2 = 0, uintptr_t param3 = 0, uintptr_t param4 = 0);
|
void PushDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
|
||||||
void EnqueueDebugEventInfo(KEventInfo *info);
|
void EnqueueDebugEventInfo(KEventInfo *info);
|
||||||
|
|
||||||
template<typename T> requires (std::same_as<T, ams::svc::lp64::DebugEventInfo> || std::same_as<T, ams::svc::ilp32::DebugEventInfo>)
|
template<typename T> requires (std::same_as<T, ams::svc::lp64::DebugEventInfo> || std::same_as<T, ams::svc::ilp32::DebugEventInfo>)
|
||||||
@@ -85,13 +85,13 @@ namespace ams::kern {
|
|||||||
/* NOTE: This is public/virtual override in Nintendo's kernel. */
|
/* NOTE: This is public/virtual override in Nintendo's kernel. */
|
||||||
void OnFinalizeSynchronizationObject();
|
void OnFinalizeSynchronizationObject();
|
||||||
private:
|
private:
|
||||||
static Result ProcessDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4);
|
static Result ProcessDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
|
||||||
public:
|
public:
|
||||||
static Result OnDebugEvent(ams::svc::DebugEvent event, uintptr_t param0 = 0, uintptr_t param1 = 0, uintptr_t param2 = 0, uintptr_t param3 = 0, uintptr_t param4 = 0);
|
static Result OnDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
|
||||||
static Result OnExitProcess(KProcess *process);
|
static Result OnExitProcess(KProcess *process);
|
||||||
static Result OnTerminateProcess(KProcess *process);
|
static Result OnTerminateProcess(KProcess *process);
|
||||||
static Result OnExitThread(KThread *thread);
|
static Result OnExitThread(KThread *thread);
|
||||||
static KEventInfo *CreateDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4, u64 thread_id);
|
static KEventInfo *CreateDebugEvent(ams::svc::DebugEvent event, u64 thread_id, const uintptr_t *params, size_t num_params);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace ams::kern {
|
|||||||
ams::svc::DebugException exception_type;
|
ams::svc::DebugException exception_type;
|
||||||
s32 exception_data_count;
|
s32 exception_data_count;
|
||||||
uintptr_t exception_address;
|
uintptr_t exception_address;
|
||||||
uintptr_t exception_data[4];
|
uintptr_t exception_data[std::max<size_t>(4, cpu::NumCores)];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InfoSystemCall {
|
struct InfoSystemCall {
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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, KProcessAddress src) const;
|
void Load(const KPageGroup &pg, KVirtualAddress data) const;
|
||||||
Result SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter ¶ms) const;
|
Result SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter ¶ms) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ namespace ams::kern {
|
|||||||
class KIoPool final : public KAutoObjectWithSlabHeapAndContainer<KIoPool, KAutoObjectWithList> {
|
class KIoPool final : public KAutoObjectWithSlabHeapAndContainer<KIoPool, KAutoObjectWithList> {
|
||||||
MESOSPHERE_AUTOOBJECT_TRAITS(KIoPool, KAutoObject);
|
MESOSPHERE_AUTOOBJECT_TRAITS(KIoPool, KAutoObject);
|
||||||
private:
|
private:
|
||||||
using IoRegionList = util::IntrusiveListMemberTraits<&KIoRegion::m_pool_list_node>::ListType;
|
using IoRegionTree = util::IntrusiveRedBlackTreeBaseTraits<KIoRegion>::TreeType<KIoRegion>;
|
||||||
private:
|
private:
|
||||||
KLightLock m_lock;
|
KLightLock m_lock;
|
||||||
IoRegionList m_io_region_list;
|
IoRegionTree m_io_region_tree;
|
||||||
ams::svc::IoPoolType m_pool_type;
|
ams::svc::IoPoolType m_pool_type;
|
||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -23,11 +23,30 @@ namespace ams::kern {
|
|||||||
class KProcess;
|
class KProcess;
|
||||||
class KIoPool;
|
class KIoPool;
|
||||||
|
|
||||||
class KIoRegion final : public KAutoObjectWithSlabHeapAndContainer<KIoRegion, KAutoObjectWithList> {
|
class KIoRegion final : public KAutoObjectWithSlabHeapAndContainer<KIoRegion, KAutoObjectWithList>, public util::IntrusiveRedBlackTreeBaseNode<KIoRegion> {
|
||||||
MESOSPHERE_AUTOOBJECT_TRAITS(KIoRegion, KAutoObject);
|
MESOSPHERE_AUTOOBJECT_TRAITS(KIoRegion, KAutoObject);
|
||||||
private:
|
private:
|
||||||
friend class KProcess;
|
friend class KProcess;
|
||||||
friend class KIoPool;
|
friend class KIoPool;
|
||||||
|
public:
|
||||||
|
using RedBlackKeyType = KPhysicalAddress;
|
||||||
|
|
||||||
|
static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const RedBlackKeyType &v) { return v; }
|
||||||
|
static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const KIoRegion &v) { return v.GetAddress(); }
|
||||||
|
|
||||||
|
template<typename T> requires (std::same_as<T, KIoRegion> || std::same_as<T, RedBlackKeyType>)
|
||||||
|
static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KIoRegion &rhs) {
|
||||||
|
const RedBlackKeyType lval = GetRedBlackKey(lhs);
|
||||||
|
const RedBlackKeyType rval = GetRedBlackKey(rhs);
|
||||||
|
|
||||||
|
if (lval < rval) {
|
||||||
|
return -1;
|
||||||
|
} else if (lval == rval) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
KLightLock m_lock;
|
KLightLock m_lock;
|
||||||
KIoPool *m_pool;
|
KIoPool *m_pool;
|
||||||
@@ -38,7 +57,6 @@ namespace ams::kern {
|
|||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
bool m_is_mapped;
|
bool m_is_mapped;
|
||||||
util::IntrusiveListNode m_process_list_node;
|
util::IntrusiveListNode m_process_list_node;
|
||||||
util::IntrusiveListNode m_pool_list_node;
|
|
||||||
public:
|
public:
|
||||||
explicit KIoRegion() : m_pool(nullptr), m_is_initialized(false) { /* ... */ }
|
explicit KIoRegion() : m_pool(nullptr), m_is_initialized(false) { /* ... */ }
|
||||||
|
|
||||||
@@ -51,12 +69,25 @@ namespace ams::kern {
|
|||||||
Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm);
|
Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm);
|
||||||
Result Unmap(KProcessAddress address, size_t size);
|
Result Unmap(KProcessAddress address, size_t size);
|
||||||
|
|
||||||
bool Overlaps(KPhysicalAddress address, size_t size) const {
|
constexpr bool Overlaps(KPhysicalAddress address, size_t size) const {
|
||||||
return m_physical_address <= (address + size - 1) && address <= (m_physical_address + m_size - 1);
|
return m_physical_address <= (address + size - 1) && address <= (m_physical_address + m_size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; }
|
constexpr ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; }
|
||||||
ALWAYS_INLINE size_t GetSize() const { return m_size; }
|
constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; }
|
||||||
|
|
||||||
|
constexpr uintptr_t GetHint() const {
|
||||||
|
/* TODO: Is this architecture specific? */
|
||||||
|
if (m_size >= 2_MB) {
|
||||||
|
return GetInteger(m_physical_address) & (2_MB - 1);
|
||||||
|
} else if (m_size >= 64_KB) {
|
||||||
|
return GetInteger(m_physical_address) & (64_KB - 1);
|
||||||
|
} else if (m_size >= 4_KB) {
|
||||||
|
return GetInteger(m_physical_address) & (4_KB - 1);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace ams::kern {
|
|||||||
KMemoryState_FlagCanChangeAttribute = (1 << 24),
|
KMemoryState_FlagCanChangeAttribute = (1 << 24),
|
||||||
KMemoryState_FlagCanCodeMemory = (1 << 25),
|
KMemoryState_FlagCanCodeMemory = (1 << 25),
|
||||||
KMemoryState_FlagLinearMapped = (1 << 26),
|
KMemoryState_FlagLinearMapped = (1 << 26),
|
||||||
|
KMemoryState_FlagCanPermissionLock = (1 << 27),
|
||||||
|
|
||||||
KMemoryState_FlagsData = KMemoryState_FlagCanReprotect | KMemoryState_FlagCanUseIpc |
|
KMemoryState_FlagsData = KMemoryState_FlagCanReprotect | KMemoryState_FlagCanUseIpc |
|
||||||
KMemoryState_FlagCanUseNonDeviceIpc | KMemoryState_FlagCanUseNonSecureIpc |
|
KMemoryState_FlagCanUseNonDeviceIpc | KMemoryState_FlagCanUseNonSecureIpc |
|
||||||
@@ -66,18 +67,22 @@ namespace ams::kern {
|
|||||||
|
|
||||||
|
|
||||||
KMemoryState_Free = ams::svc::MemoryState_Free,
|
KMemoryState_Free = ams::svc::MemoryState_Free,
|
||||||
KMemoryState_Io = ams::svc::MemoryState_Io | KMemoryState_FlagMapped | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap,
|
|
||||||
KMemoryState_Static = ams::svc::MemoryState_Static | KMemoryState_FlagMapped | KMemoryState_FlagCanQueryPhysical,
|
KMemoryState_IoMemory = ams::svc::MemoryState_Io | KMemoryState_FlagMapped | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap,
|
||||||
|
KMemoryState_IoRegister = ams::svc::MemoryState_Io | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap,
|
||||||
|
|
||||||
|
|
||||||
|
KMemoryState_Static = ams::svc::MemoryState_Static | KMemoryState_FlagCanQueryPhysical,
|
||||||
KMemoryState_Code = ams::svc::MemoryState_Code | KMemoryState_FlagsCode | KMemoryState_FlagCanMapProcess,
|
KMemoryState_Code = ams::svc::MemoryState_Code | KMemoryState_FlagsCode | KMemoryState_FlagCanMapProcess,
|
||||||
KMemoryState_CodeData = ams::svc::MemoryState_CodeData | KMemoryState_FlagsData | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeMemory,
|
KMemoryState_CodeData = ams::svc::MemoryState_CodeData | KMemoryState_FlagsData | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeMemory | KMemoryState_FlagCanPermissionLock,
|
||||||
KMemoryState_Normal = ams::svc::MemoryState_Normal | KMemoryState_FlagsData | KMemoryState_FlagCanCodeMemory,
|
KMemoryState_Normal = ams::svc::MemoryState_Normal | KMemoryState_FlagsData | KMemoryState_FlagCanCodeMemory,
|
||||||
KMemoryState_Shared = ams::svc::MemoryState_Shared | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped,
|
KMemoryState_Shared = ams::svc::MemoryState_Shared | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped,
|
||||||
|
|
||||||
/* KMemoryState_Alias was removed after 1.0.0. */
|
/* KMemoryState_Alias was removed after 1.0.0. */
|
||||||
|
|
||||||
KMemoryState_AliasCode = ams::svc::MemoryState_AliasCode | KMemoryState_FlagsCode | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeAlias,
|
KMemoryState_AliasCode = ams::svc::MemoryState_AliasCode | KMemoryState_FlagsCode | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeAlias,
|
||||||
KMemoryState_AliasCodeData = ams::svc::MemoryState_AliasCodeData | KMemoryState_FlagsData | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeAlias | KMemoryState_FlagCanCodeMemory,
|
KMemoryState_AliasCodeData = ams::svc::MemoryState_AliasCodeData | KMemoryState_FlagsData | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeAlias | KMemoryState_FlagCanCodeMemory
|
||||||
|
| KMemoryState_FlagCanPermissionLock,
|
||||||
|
|
||||||
KMemoryState_Ipc = ams::svc::MemoryState_Ipc | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap
|
KMemoryState_Ipc = ams::svc::MemoryState_Ipc | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap
|
||||||
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||||
@@ -85,7 +90,7 @@ namespace ams::kern {
|
|||||||
KMemoryState_Stack = ams::svc::MemoryState_Stack | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap
|
KMemoryState_Stack = ams::svc::MemoryState_Stack | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap
|
||||||
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||||
|
|
||||||
KMemoryState_ThreadLocal = ams::svc::MemoryState_ThreadLocal | KMemoryState_FlagMapped | KMemoryState_FlagLinearMapped,
|
KMemoryState_ThreadLocal = ams::svc::MemoryState_ThreadLocal | KMemoryState_FlagLinearMapped,
|
||||||
|
|
||||||
KMemoryState_Transfered = ams::svc::MemoryState_Transfered | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanChangeAttribute
|
KMemoryState_Transfered = ams::svc::MemoryState_Transfered | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanChangeAttribute
|
||||||
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||||
@@ -104,43 +109,44 @@ namespace ams::kern {
|
|||||||
KMemoryState_NonDeviceIpc = ams::svc::MemoryState_NonDeviceIpc | KMemoryState_FlagsMisc | KMemoryState_FlagCanUseNonDeviceIpc,
|
KMemoryState_NonDeviceIpc = ams::svc::MemoryState_NonDeviceIpc | KMemoryState_FlagsMisc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||||
|
|
||||||
|
|
||||||
KMemoryState_Kernel = ams::svc::MemoryState_Kernel | KMemoryState_FlagMapped,
|
KMemoryState_Kernel = ams::svc::MemoryState_Kernel,
|
||||||
|
|
||||||
KMemoryState_GeneratedCode = ams::svc::MemoryState_GeneratedCode | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanDebug | KMemoryState_FlagLinearMapped,
|
KMemoryState_GeneratedCode = ams::svc::MemoryState_GeneratedCode | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanDebug | KMemoryState_FlagLinearMapped,
|
||||||
KMemoryState_CodeOut = ams::svc::MemoryState_CodeOut | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped,
|
KMemoryState_CodeOut = ams::svc::MemoryState_CodeOut | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped,
|
||||||
|
|
||||||
KMemoryState_Coverage = ams::svc::MemoryState_Coverage | KMemoryState_FlagMapped,
|
KMemoryState_Coverage = ams::svc::MemoryState_Coverage | KMemoryState_FlagMapped,
|
||||||
|
|
||||||
KMemoryState_Insecure = ams::svc::MemoryState_Insecure | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped | KMemoryState_FlagCanChangeAttribute
|
KMemoryState_Insecure = ams::svc::MemoryState_Insecure | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped | KMemoryState_FlagCanChangeAttribute
|
||||||
| KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap
|
| KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanQueryPhysical
|
||||||
| KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
| KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
static_assert(KMemoryState_Free == 0x00000000);
|
static_assert(KMemoryState_Free == 0x00000000);
|
||||||
static_assert(KMemoryState_Io == 0x00182001);
|
static_assert(KMemoryState_IoMemory == 0x00182001);
|
||||||
static_assert(KMemoryState_Static == 0x00042002);
|
static_assert(KMemoryState_IoRegister == 0x00180001);
|
||||||
|
static_assert(KMemoryState_Static == 0x00040002);
|
||||||
static_assert(KMemoryState_Code == 0x04DC7E03);
|
static_assert(KMemoryState_Code == 0x04DC7E03);
|
||||||
static_assert(KMemoryState_CodeData == 0x07FEBD04);
|
static_assert(KMemoryState_CodeData == 0x0FFEBD04);
|
||||||
static_assert(KMemoryState_Normal == 0x077EBD05);
|
static_assert(KMemoryState_Normal == 0x077EBD05);
|
||||||
static_assert(KMemoryState_Shared == 0x04402006);
|
static_assert(KMemoryState_Shared == 0x04402006);
|
||||||
|
|
||||||
static_assert(KMemoryState_AliasCode == 0x04DD7E08);
|
static_assert(KMemoryState_AliasCode == 0x04DD7E08);
|
||||||
static_assert(KMemoryState_AliasCodeData == 0x07FFBD09);
|
static_assert(KMemoryState_AliasCodeData == 0x0FFFBD09);
|
||||||
static_assert(KMemoryState_Ipc == 0x045C3C0A);
|
static_assert(KMemoryState_Ipc == 0x045C3C0A);
|
||||||
static_assert(KMemoryState_Stack == 0x045C3C0B);
|
static_assert(KMemoryState_Stack == 0x045C3C0B);
|
||||||
static_assert(KMemoryState_ThreadLocal == 0x0400200C);
|
static_assert(KMemoryState_ThreadLocal == 0x0400000C);
|
||||||
static_assert(KMemoryState_Transfered == 0x055C3C0D);
|
static_assert(KMemoryState_Transfered == 0x055C3C0D);
|
||||||
static_assert(KMemoryState_SharedTransfered == 0x045C380E);
|
static_assert(KMemoryState_SharedTransfered == 0x045C380E);
|
||||||
static_assert(KMemoryState_SharedCode == 0x0440380F);
|
static_assert(KMemoryState_SharedCode == 0x0440380F);
|
||||||
static_assert(KMemoryState_Inaccessible == 0x00000010);
|
static_assert(KMemoryState_Inaccessible == 0x00000010);
|
||||||
static_assert(KMemoryState_NonSecureIpc == 0x045C3811);
|
static_assert(KMemoryState_NonSecureIpc == 0x045C3811);
|
||||||
static_assert(KMemoryState_NonDeviceIpc == 0x044C2812);
|
static_assert(KMemoryState_NonDeviceIpc == 0x044C2812);
|
||||||
static_assert(KMemoryState_Kernel == 0x00002013);
|
static_assert(KMemoryState_Kernel == 0x00000013);
|
||||||
static_assert(KMemoryState_GeneratedCode == 0x04402214);
|
static_assert(KMemoryState_GeneratedCode == 0x04402214);
|
||||||
static_assert(KMemoryState_CodeOut == 0x04402015);
|
static_assert(KMemoryState_CodeOut == 0x04402015);
|
||||||
static_assert(KMemoryState_Coverage == 0x00002016);
|
static_assert(KMemoryState_Coverage == 0x00002016); /* TODO: Is this correct? */
|
||||||
static_assert(KMemoryState_Insecure == 0x05583817);
|
static_assert(KMemoryState_Insecure == 0x055C3817);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum KMemoryPermission : u8 {
|
enum KMemoryPermission : u8 {
|
||||||
@@ -171,20 +177,21 @@ namespace ams::kern {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constexpr KMemoryPermission ConvertToKMemoryPermission(ams::svc::MemoryPermission perm) {
|
constexpr KMemoryPermission ConvertToKMemoryPermission(ams::svc::MemoryPermission perm) {
|
||||||
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));
|
return static_cast<KMemoryPermission>((util::ToUnderlying(perm) & KMemoryPermission_UserMask) | KMemoryPermission_KernelRead | ((util::ToUnderlying(perm) & ams::svc::MemoryPermission_Write) ? KMemoryPermission_KernelWrite : KMemoryPermission_None) | (perm == ams::svc::MemoryPermission_None ? KMemoryPermission_NotMapped : KMemoryPermission_None));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum KMemoryAttribute : u8 {
|
enum KMemoryAttribute : u8 {
|
||||||
KMemoryAttribute_None = 0x00,
|
KMemoryAttribute_None = 0x00,
|
||||||
KMemoryAttribute_All = 0xFF,
|
KMemoryAttribute_All = 0xFF,
|
||||||
KMemoryAttribute_UserMask = KMemoryAttribute_All,
|
KMemoryAttribute_UserMask = KMemoryAttribute_All,
|
||||||
|
|
||||||
KMemoryAttribute_Locked = ams::svc::MemoryAttribute_Locked,
|
KMemoryAttribute_Locked = ams::svc::MemoryAttribute_Locked,
|
||||||
KMemoryAttribute_IpcLocked = ams::svc::MemoryAttribute_IpcLocked,
|
KMemoryAttribute_IpcLocked = ams::svc::MemoryAttribute_IpcLocked,
|
||||||
KMemoryAttribute_DeviceShared = ams::svc::MemoryAttribute_DeviceShared,
|
KMemoryAttribute_DeviceShared = ams::svc::MemoryAttribute_DeviceShared,
|
||||||
KMemoryAttribute_Uncached = ams::svc::MemoryAttribute_Uncached,
|
KMemoryAttribute_Uncached = ams::svc::MemoryAttribute_Uncached,
|
||||||
|
KMemoryAttribute_PermissionLocked = ams::svc::MemoryAttribute_PermissionLocked,
|
||||||
|
|
||||||
KMemoryAttribute_SetMask = KMemoryAttribute_Uncached,
|
KMemoryAttribute_SetMask = KMemoryAttribute_Uncached | KMemoryAttribute_PermissionLocked,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum KMemoryBlockDisableMergeAttribute : u8 {
|
enum KMemoryBlockDisableMergeAttribute : u8 {
|
||||||
@@ -258,6 +265,10 @@ namespace ams::kern {
|
|||||||
return m_state;
|
return m_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr ams::svc::MemoryState GetSvcState() const {
|
||||||
|
return static_cast<ams::svc::MemoryState>(m_state & KMemoryState_Mask);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr KMemoryPermission GetPermission() const {
|
constexpr KMemoryPermission GetPermission() const {
|
||||||
return m_permission;
|
return m_permission;
|
||||||
}
|
}
|
||||||
@@ -320,6 +331,10 @@ namespace ams::kern {
|
|||||||
return this->GetEndAddress() - 1;
|
return this->GetEndAddress() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr KMemoryState GetState() const {
|
||||||
|
return m_memory_state;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr u16 GetIpcLockCount() const {
|
constexpr u16 GetIpcLockCount() const {
|
||||||
return m_ipc_lock_count;
|
return m_ipc_lock_count;
|
||||||
}
|
}
|
||||||
@@ -439,6 +454,14 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr void UpdateAttribute(u32 mask, u32 attr) {
|
||||||
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
MESOSPHERE_ASSERT((mask & KMemoryAttribute_IpcLocked) == 0);
|
||||||
|
MESOSPHERE_ASSERT((mask & KMemoryAttribute_DeviceShared) == 0);
|
||||||
|
|
||||||
|
m_attribute = static_cast<KMemoryAttribute>((m_attribute & ~mask) | attr);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr void Split(KMemoryBlock *block, KProcessAddress addr) {
|
constexpr void Split(KMemoryBlock *block, KProcessAddress addr) {
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
MESOSPHERE_ASSERT(this->GetAddress() < addr);
|
MESOSPHERE_ASSERT(this->GetAddress() < addr);
|
||||||
|
|||||||
@@ -104,7 +104,9 @@ namespace ams::kern {
|
|||||||
void Update(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, KMemoryBlockDisableMergeAttribute clear_disable_attr);
|
void Update(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, KMemoryBlockDisableMergeAttribute clear_disable_attr);
|
||||||
void UpdateLock(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, MemoryBlockLockFunction lock_func, KMemoryPermission perm);
|
void UpdateLock(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, MemoryBlockLockFunction lock_func, KMemoryPermission perm);
|
||||||
|
|
||||||
void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm, KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr);
|
void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm, KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, KMemoryBlockDisableMergeAttribute clear_disable_attr);
|
||||||
|
|
||||||
|
void UpdateAttribute(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, u32 mask, u32 attr);
|
||||||
|
|
||||||
iterator FindIterator(KProcessAddress address) const {
|
iterator FindIterator(KProcessAddress address) const {
|
||||||
return m_memory_block_tree.find(KMemoryBlock(util::ConstantInitialize, address, 1, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None));
|
return m_memory_block_tree.find(KMemoryBlock(util::ConstantInitialize, address, 1, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None));
|
||||||
|
|||||||
@@ -183,10 +183,10 @@ namespace ams::kern {
|
|||||||
return std::make_tuple(total_size, kernel_size);
|
return std::make_tuple(total_size, kernel_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitializeLinearMemoryAddresses(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start) {
|
static void InitializeLinearMemoryAddresses(u64 phys_to_virt_diff) {
|
||||||
/* Set static differences. */
|
/* Set static differences. */
|
||||||
s_linear_phys_to_virt_diff = GetInteger(linear_virtual_start) - GetInteger(aligned_linear_phys_start);
|
s_linear_phys_to_virt_diff = phys_to_virt_diff;
|
||||||
s_linear_virt_to_phys_diff = GetInteger(aligned_linear_phys_start) - GetInteger(linear_virtual_start);
|
s_linear_virt_to_phys_diff = -phys_to_virt_diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitializeLinearMemoryRegionTrees();
|
static void InitializeLinearMemoryRegionTrees();
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random);
|
Result AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random, s32 min_heap_index);
|
||||||
public:
|
public:
|
||||||
KMemoryManager()
|
KMemoryManager()
|
||||||
: m_pool_locks(), m_pool_managers_head(), m_pool_managers_tail(), m_managers(), m_num_managers(), m_optimized_process_ids(), m_has_optimized_process()
|
: m_pool_locks(), m_pool_managers_head(), m_pool_managers_tail(), m_managers(), m_num_managers(), m_optimized_process_ids(), m_has_optimized_process()
|
||||||
@@ -199,7 +199,7 @@ namespace ams::kern {
|
|||||||
NOINLINE void FinalizeOptimizedMemory(u64 process_id, Pool pool);
|
NOINLINE void FinalizeOptimizedMemory(u64 process_id, Pool pool);
|
||||||
|
|
||||||
NOINLINE KPhysicalAddress AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
|
NOINLINE KPhysicalAddress AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
|
||||||
NOINLINE Result AllocateAndOpen(KPageGroup *out, size_t num_pages, u32 option);
|
NOINLINE Result AllocateAndOpen(KPageGroup *out, size_t num_pages, size_t align_pages, u32 option);
|
||||||
NOINLINE Result AllocateForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern);
|
NOINLINE Result AllocateForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern);
|
||||||
|
|
||||||
Pool GetPool(KPhysicalAddress address) const {
|
Pool GetPool(KPhysicalAddress address) const {
|
||||||
|
|||||||
@@ -212,7 +212,9 @@ namespace ams::kern {
|
|||||||
static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() == (0x44E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() == (0x44E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_DramKernelSecureAppletMemory = KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 0).SetAttribute(KMemoryRegionAttr_LinearMapped);
|
constexpr inline const auto KMemoryRegionType_DramKernelSecureAppletMemory = KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 0).SetAttribute(KMemoryRegionAttr_LinearMapped);
|
||||||
|
constexpr inline const auto KMemoryRegionType_DramKernelSecureUnknown = KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 1).SetAttribute(KMemoryRegionAttr_LinearMapped);
|
||||||
static_assert(KMemoryRegionType_DramKernelSecureAppletMemory.GetValue() == (0x18E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
static_assert(KMemoryRegionType_DramKernelSecureAppletMemory.GetValue() == (0x18E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
||||||
|
static_assert(KMemoryRegionType_DramKernelSecureUnknown.GetValue() == (0x28E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_DramReservedEarly = KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
|
constexpr inline const auto KMemoryRegionType_DramReservedEarly = KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
|
||||||
static_assert(KMemoryRegionType_DramReservedEarly.GetValue() == (0x16 | KMemoryRegionAttr_NoUserMap));
|
static_assert(KMemoryRegionType_DramReservedEarly.GetValue() == (0x16 | KMemoryRegionAttr_NoUserMap));
|
||||||
@@ -228,53 +230,55 @@ namespace ams::kern {
|
|||||||
constexpr inline const auto KMemoryRegionType_DramPoolPartition = KMemoryRegionType_DramHeapBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
|
constexpr inline const auto KMemoryRegionType_DramPoolPartition = KMemoryRegionType_DramHeapBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
|
||||||
static_assert(KMemoryRegionType_DramPoolPartition.GetValue() == (0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
static_assert(KMemoryRegionType_DramPoolPartition.GetValue() == (0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_DramPoolManagement = KMemoryRegionType_DramPoolPartition.DeriveTransition(0, 2).DeriveTransition().SetAttribute(KMemoryRegionAttr_CarveoutProtected);
|
constexpr inline const auto KMemoryRegionType_DramPoolManagement = KMemoryRegionType_DramPoolPartition.Derive(4, 0).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
|
||||||
constexpr inline const auto KMemoryRegionType_DramUserPool = KMemoryRegionType_DramPoolPartition.DeriveTransition(1, 2).DeriveTransition();
|
/* UNUSED: .Derive(4, 1); */
|
||||||
static_assert(KMemoryRegionType_DramPoolManagement.GetValue() == (0x166 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_CarveoutProtected));
|
/* UNUSED: .Derive(4, 2); */
|
||||||
static_assert(KMemoryRegionType_DramUserPool.GetValue() == (0x1A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
constexpr inline const auto KMemoryRegionType_DramUserPool = KMemoryRegionType_DramPoolPartition.Derive(4, 3);
|
||||||
|
static_assert(KMemoryRegionType_DramPoolManagement.GetValue() == (0xE6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_CarveoutProtected));
|
||||||
|
static_assert(KMemoryRegionType_DramUserPool .GetValue() == (0x266 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_DramApplicationPool = KMemoryRegionType_DramUserPool.Derive(4, 0);
|
constexpr inline const auto KMemoryRegionType_DramApplicationPool = KMemoryRegionType_DramUserPool.Derive(4, 0);
|
||||||
constexpr inline const auto KMemoryRegionType_DramAppletPool = KMemoryRegionType_DramUserPool.Derive(4, 1);
|
constexpr inline const auto KMemoryRegionType_DramAppletPool = KMemoryRegionType_DramUserPool.Derive(4, 1);
|
||||||
constexpr inline const auto KMemoryRegionType_DramSystemNonSecurePool = KMemoryRegionType_DramUserPool.Derive(4, 2);
|
constexpr inline const auto KMemoryRegionType_DramSystemNonSecurePool = KMemoryRegionType_DramUserPool.Derive(4, 2);
|
||||||
constexpr inline const auto KMemoryRegionType_DramSystemPool = KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
|
constexpr inline const auto KMemoryRegionType_DramSystemPool = KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
|
||||||
static_assert(KMemoryRegionType_DramApplicationPool .GetValue() == (0x7A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
static_assert(KMemoryRegionType_DramApplicationPool .GetValue() == (0xE66 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||||
static_assert(KMemoryRegionType_DramAppletPool .GetValue() == (0xBA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
static_assert(KMemoryRegionType_DramAppletPool .GetValue() == (0x1666 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||||
static_assert(KMemoryRegionType_DramSystemNonSecurePool.GetValue() == (0xDA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
static_assert(KMemoryRegionType_DramSystemNonSecurePool.GetValue() == (0x1A66 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||||
static_assert(KMemoryRegionType_DramSystemPool .GetValue() == (0x13A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_CarveoutProtected));
|
static_assert(KMemoryRegionType_DramSystemPool .GetValue() == (0x2666 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_CarveoutProtected));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramHeapBase = KMemoryRegionType_Dram.DeriveSparse(1, 3, 0);
|
constexpr inline const auto KMemoryRegionType_VirtualDramHeapBase = KMemoryRegionType_Dram.DeriveSparse(1, 4, 0);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelPtHeap = KMemoryRegionType_Dram.DeriveSparse(1, 3, 1);
|
constexpr inline const auto KMemoryRegionType_VirtualDramKernelPtHeap = KMemoryRegionType_Dram.DeriveSparse(1, 4, 1);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelTraceBuffer = KMemoryRegionType_Dram.DeriveSparse(1, 3, 2);
|
constexpr inline const auto KMemoryRegionType_VirtualDramKernelTraceBuffer = KMemoryRegionType_Dram.DeriveSparse(1, 4, 2);
|
||||||
static_assert(KMemoryRegionType_VirtualDramHeapBase .GetValue() == 0x1A);
|
static_assert(KMemoryRegionType_VirtualDramHeapBase .GetValue() == 0x1A);
|
||||||
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); */
|
/* UNUSED: .DeriveSparse(2, 2, 0); */
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramUnknownDebug = KMemoryRegionType_Dram.DeriveSparse(2, 2, 1);
|
constexpr inline const auto KMemoryRegionType_VirtualDramUnknownDebug = KMemoryRegionType_Dram.Advance(2).Derive(4, 0);
|
||||||
static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x52));
|
constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory = KMemoryRegionType_Dram.Advance(2).Derive(4, 1);
|
||||||
|
/* UNUSED: .Derive(4, 2); */
|
||||||
|
constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureUnknown = KMemoryRegionType_Dram.Advance(2).Derive(4, 3);
|
||||||
|
static_assert(KMemoryRegionType_VirtualDramUnknownDebug .GetValue() == (0x32));
|
||||||
|
static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x52));
|
||||||
|
static_assert(KMemoryRegionType_VirtualDramKernelSecureUnknown .GetValue() == (0x92));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory = KMemoryRegionType_Dram.DeriveSparse(3, 1, 0);
|
|
||||||
static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x62));
|
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelInitPt = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
|
constexpr inline const auto KMemoryRegionType_VirtualDramKernelInitPt = KMemoryRegionType_VirtualDramHeapBase.Derive(4, 0);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramPoolManagement = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
|
constexpr inline const auto KMemoryRegionType_VirtualDramPoolManagement = KMemoryRegionType_VirtualDramHeapBase.Derive(4, 1);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramUserPool = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
|
constexpr inline const auto KMemoryRegionType_VirtualDramUserPool = KMemoryRegionType_VirtualDramHeapBase.Derive(4, 2);
|
||||||
static_assert(KMemoryRegionType_VirtualDramKernelInitPt .GetValue() == 0x19A);
|
/* UNUSED: .Derive(4, 3); */
|
||||||
static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x29A);
|
static_assert(KMemoryRegionType_VirtualDramKernelInitPt .GetValue() == 0x31A);
|
||||||
static_assert(KMemoryRegionType_VirtualDramUserPool .GetValue() == 0x31A);
|
static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x51A);
|
||||||
|
static_assert(KMemoryRegionType_VirtualDramUserPool .GetValue() == 0x61A);
|
||||||
|
|
||||||
/* NOTE: For unknown reason, the pools are derived out-of-order here. */
|
constexpr inline const auto KMemoryRegionType_VirtualDramApplicationPool = KMemoryRegionType_VirtualDramUserPool.Derive(4, 0);
|
||||||
/* It's worth eventually trying to understand why Nintendo made this choice. */
|
constexpr inline const auto KMemoryRegionType_VirtualDramAppletPool = KMemoryRegionType_VirtualDramUserPool.Derive(4, 1);
|
||||||
/* UNUSED: .Derive(6, 0); */
|
constexpr inline const auto KMemoryRegionType_VirtualDramSystemNonSecurePool = KMemoryRegionType_VirtualDramUserPool.Derive(4, 2);
|
||||||
/* UNUSED: .Derive(6, 1); */
|
constexpr inline const auto KMemoryRegionType_VirtualDramSystemPool = KMemoryRegionType_VirtualDramUserPool.Derive(4, 3);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramAppletPool = KMemoryRegionType_VirtualDramUserPool.Derive(6, 2);
|
static_assert(KMemoryRegionType_VirtualDramApplicationPool .GetValue() == 0x361A);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramApplicationPool = KMemoryRegionType_VirtualDramUserPool.Derive(6, 3);
|
static_assert(KMemoryRegionType_VirtualDramAppletPool .GetValue() == 0x561A);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramSystemNonSecurePool = KMemoryRegionType_VirtualDramUserPool.Derive(6, 4);
|
static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x661A);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramSystemPool = KMemoryRegionType_VirtualDramUserPool.Derive(6, 5);
|
static_assert(KMemoryRegionType_VirtualDramSystemPool .GetValue() == 0x961A);
|
||||||
static_assert(KMemoryRegionType_VirtualDramAppletPool .GetValue() == 0x1B1A);
|
|
||||||
static_assert(KMemoryRegionType_VirtualDramApplicationPool .GetValue() == 0x271A);
|
|
||||||
static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x2B1A);
|
|
||||||
static_assert(KMemoryRegionType_VirtualDramSystemPool .GetValue() == 0x331A);
|
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_ArchDeviceBase = KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly();
|
constexpr inline const auto KMemoryRegionType_ArchDeviceBase = KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly();
|
||||||
constexpr inline const auto KMemoryRegionType_BoardDeviceBase = KMemoryRegionType_Kernel.DeriveTransition(0, 2).SetDenseOnly();
|
constexpr inline const auto KMemoryRegionType_BoardDeviceBase = KMemoryRegionType_Kernel.DeriveTransition(0, 2).SetDenseOnly();
|
||||||
@@ -328,12 +332,14 @@ namespace ams::kern {
|
|||||||
static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31);
|
static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31);
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
|
constexpr ALWAYS_INLINE KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
|
||||||
if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) {
|
if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
|
||||||
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
|
|
||||||
} else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
|
|
||||||
return KMemoryRegionType_VirtualDramKernelPtHeap;
|
return KMemoryRegionType_VirtualDramKernelPtHeap;
|
||||||
} else if (KMemoryRegionType_DramKernelSecureAppletMemory.IsAncestorOf(type_id)) {
|
} else if (KMemoryRegionType_DramKernelSecureAppletMemory.IsAncestorOf(type_id)) {
|
||||||
return KMemoryRegionType_VirtualDramKernelSecureAppletMemory;
|
return KMemoryRegionType_VirtualDramKernelSecureAppletMemory;
|
||||||
|
} else if (KMemoryRegionType_DramKernelSecureUnknown.IsAncestorOf(type_id)) {
|
||||||
|
return KMemoryRegionType_VirtualDramKernelSecureUnknown;
|
||||||
|
} else if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) {
|
||||||
|
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
|
||||||
} else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) {
|
} else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) {
|
||||||
return KMemoryRegionType_VirtualDramUnknownDebug;
|
return KMemoryRegionType_VirtualDramUnknownDebug;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace ams::kern {
|
|||||||
/* Check that the object is closed. */
|
/* Check that the object is closed. */
|
||||||
R_UNLESS(derived->IsServerClosed(), svc::ResultInvalidState());
|
R_UNLESS(derived->IsServerClosed(), svc::ResultInvalidState());
|
||||||
|
|
||||||
return Delete(obj.GetPointerUnsafe(), name);
|
R_RETURN(Delete(obj.GetPointerUnsafe(), name));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Derived> requires std::derived_from<Derived, KAutoObject>
|
template<typename Derived> requires std::derived_from<Derived, KAutoObject>
|
||||||
|
|||||||
@@ -145,6 +145,8 @@ namespace ams::kern {
|
|||||||
|
|
||||||
bool IsEquivalentTo(const KPageGroup &rhs) const;
|
bool IsEquivalentTo(const KPageGroup &rhs) const;
|
||||||
|
|
||||||
|
Result CopyRangeTo(KPageGroup &out, size_t offset, size_t size) const;
|
||||||
|
|
||||||
ALWAYS_INLINE bool operator==(const KPageGroup &rhs) const {
|
ALWAYS_INLINE bool operator==(const KPageGroup &rhs) const {
|
||||||
return this->IsEquivalentTo(rhs);
|
return this->IsEquivalentTo(rhs);
|
||||||
}
|
}
|
||||||
@@ -158,8 +160,16 @@ namespace ams::kern {
|
|||||||
private:
|
private:
|
||||||
const KPageGroup *m_pg;
|
const KPageGroup *m_pg;
|
||||||
public:
|
public:
|
||||||
explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup *gp) : m_pg(gp) { if (m_pg) { m_pg->Open(); } }
|
explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup *gp, bool not_first = true) : m_pg(gp) {
|
||||||
explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup &gp) : KScopedPageGroup(std::addressof(gp)) { /* ... */ }
|
if (m_pg) {
|
||||||
|
if (not_first) {
|
||||||
|
m_pg->Open();
|
||||||
|
} else {
|
||||||
|
m_pg->OpenFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup &gp, bool not_first = true) : KScopedPageGroup(std::addressof(gp), not_first) { /* ... */ }
|
||||||
ALWAYS_INLINE ~KScopedPageGroup() { if (m_pg) { m_pg->Close(); } }
|
ALWAYS_INLINE ~KScopedPageGroup() { if (m_pg) { m_pg->Close(); } }
|
||||||
|
|
||||||
ALWAYS_INLINE void CancelClose() {
|
ALWAYS_INLINE void CancelClose() {
|
||||||
|
|||||||
@@ -57,11 +57,29 @@ namespace ams::kern {
|
|||||||
using TraversalEntry = KPageTableImpl::TraversalEntry;
|
using TraversalEntry = KPageTableImpl::TraversalEntry;
|
||||||
using TraversalContext = KPageTableImpl::TraversalContext;
|
using TraversalContext = KPageTableImpl::TraversalContext;
|
||||||
|
|
||||||
struct MemoryRange {
|
class MemoryRange {
|
||||||
KPhysicalAddress address;
|
private:
|
||||||
size_t size;
|
KPhysicalAddress m_address;
|
||||||
|
size_t m_size;
|
||||||
|
bool m_heap;
|
||||||
|
u8 m_attr;
|
||||||
|
public:
|
||||||
|
constexpr MemoryRange() : m_address(Null<KPhysicalAddress>), m_size(0), m_heap(false), m_attr(0) { /* ... */ }
|
||||||
|
|
||||||
void Close();
|
void Set(KPhysicalAddress address, size_t size, bool heap, u8 attr) {
|
||||||
|
m_address = address;
|
||||||
|
m_size = size;
|
||||||
|
m_heap = heap;
|
||||||
|
m_attr = attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr KPhysicalAddress GetAddress() const { return m_address; }
|
||||||
|
constexpr size_t GetSize() const { return m_size; }
|
||||||
|
constexpr bool IsHeap() const { return m_heap; }
|
||||||
|
constexpr u8 GetAttribute() const { return m_attr; }
|
||||||
|
|
||||||
|
void Open();
|
||||||
|
void Close();
|
||||||
};
|
};
|
||||||
protected:
|
protected:
|
||||||
enum MemoryFillValue {
|
enum MemoryFillValue {
|
||||||
@@ -71,14 +89,24 @@ namespace ams::kern {
|
|||||||
MemoryFillValue_Heap = 'Z',
|
MemoryFillValue_Heap = 'Z',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RegionType {
|
||||||
|
RegionType_KernelMap = 0,
|
||||||
|
RegionType_Stack = 1,
|
||||||
|
RegionType_Alias = 2,
|
||||||
|
RegionType_Heap = 3,
|
||||||
|
|
||||||
|
RegionType_Count,
|
||||||
|
};
|
||||||
|
|
||||||
enum OperationType {
|
enum OperationType {
|
||||||
OperationType_Map = 0,
|
OperationType_Map = 0,
|
||||||
OperationType_MapFirst = 1,
|
OperationType_MapGroup = 1,
|
||||||
OperationType_MapGroup = 2,
|
OperationType_MapFirstGroup = 2,
|
||||||
OperationType_Unmap = 3,
|
OperationType_Unmap = 3,
|
||||||
OperationType_ChangePermissions = 4,
|
OperationType_ChangePermissions = 4,
|
||||||
OperationType_ChangePermissionsAndRefresh = 5,
|
OperationType_ChangePermissionsAndRefresh = 5,
|
||||||
OperationType_Separate = 6,
|
OperationType_ChangePermissionsAndRefreshAndFlush = 6,
|
||||||
|
OperationType_Separate = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr size_t MaxPhysicalMapAlignment = 1_GB;
|
static constexpr size_t MaxPhysicalMapAlignment = 1_GB;
|
||||||
@@ -149,15 +177,9 @@ namespace ams::kern {
|
|||||||
private:
|
private:
|
||||||
KProcessAddress m_address_space_start;
|
KProcessAddress m_address_space_start;
|
||||||
KProcessAddress m_address_space_end;
|
KProcessAddress m_address_space_end;
|
||||||
KProcessAddress m_heap_region_start;
|
KProcessAddress m_region_starts[RegionType_Count];
|
||||||
KProcessAddress m_heap_region_end;
|
KProcessAddress m_region_ends[RegionType_Count];
|
||||||
KProcessAddress m_current_heap_end;
|
KProcessAddress m_current_heap_end;
|
||||||
KProcessAddress m_alias_region_start;
|
|
||||||
KProcessAddress m_alias_region_end;
|
|
||||||
KProcessAddress m_stack_region_start;
|
|
||||||
KProcessAddress m_stack_region_end;
|
|
||||||
KProcessAddress m_kernel_map_region_start;
|
|
||||||
KProcessAddress m_kernel_map_region_end;
|
|
||||||
KProcessAddress m_alias_code_region_start;
|
KProcessAddress m_alias_code_region_start;
|
||||||
KProcessAddress m_alias_code_region_end;
|
KProcessAddress m_alias_code_region_end;
|
||||||
KProcessAddress m_code_region_start;
|
KProcessAddress m_code_region_start;
|
||||||
@@ -167,6 +189,7 @@ namespace ams::kern {
|
|||||||
size_t m_mapped_unsafe_physical_memory;
|
size_t m_mapped_unsafe_physical_memory;
|
||||||
size_t m_mapped_insecure_memory;
|
size_t m_mapped_insecure_memory;
|
||||||
size_t m_mapped_ipc_server_memory;
|
size_t m_mapped_ipc_server_memory;
|
||||||
|
size_t m_alias_region_extra_size;
|
||||||
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;
|
KLightLock m_device_map_lock;
|
||||||
@@ -187,12 +210,12 @@ namespace ams::kern {
|
|||||||
MemoryFillValue m_stack_fill_value;
|
MemoryFillValue m_stack_fill_value;
|
||||||
public:
|
public:
|
||||||
constexpr explicit KPageTableBase(util::ConstantInitializeTag)
|
constexpr explicit KPageTableBase(util::ConstantInitializeTag)
|
||||||
: m_address_space_start(Null<KProcessAddress>), m_address_space_end(Null<KProcessAddress>), m_heap_region_start(Null<KProcessAddress>),
|
: m_address_space_start(Null<KProcessAddress>), m_address_space_end(Null<KProcessAddress>),
|
||||||
m_heap_region_end(Null<KProcessAddress>), m_current_heap_end(Null<KProcessAddress>), m_alias_region_start(Null<KProcessAddress>),
|
m_region_starts{Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>},
|
||||||
m_alias_region_end(Null<KProcessAddress>), m_stack_region_start(Null<KProcessAddress>), m_stack_region_end(Null<KProcessAddress>),
|
m_region_ends{Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>},
|
||||||
m_kernel_map_region_start(Null<KProcessAddress>), m_kernel_map_region_end(Null<KProcessAddress>), m_alias_code_region_start(Null<KProcessAddress>),
|
m_current_heap_end(Null<KProcessAddress>), m_alias_code_region_start(Null<KProcessAddress>),
|
||||||
m_alias_code_region_end(Null<KProcessAddress>), m_code_region_start(Null<KProcessAddress>), m_code_region_end(Null<KProcessAddress>),
|
m_alias_code_region_end(Null<KProcessAddress>), m_code_region_start(Null<KProcessAddress>), m_code_region_end(Null<KProcessAddress>),
|
||||||
m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(), m_mapped_ipc_server_memory(),
|
m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(), m_mapped_ipc_server_memory(), m_alias_region_extra_size(),
|
||||||
m_general_lock(), m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize),
|
m_general_lock(), m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize),
|
||||||
m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(),
|
m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(),
|
||||||
m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), m_cached_physical_heap_region(),
|
m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), m_cached_physical_heap_region(),
|
||||||
@@ -204,7 +227,7 @@ namespace ams::kern {
|
|||||||
explicit KPageTableBase() { /* ... */ }
|
explicit 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, KSystemResource *system_resource, KResourceLimit *resource_limit);
|
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit);
|
||||||
|
|
||||||
void Finalize();
|
void Finalize();
|
||||||
|
|
||||||
@@ -220,21 +243,25 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool IsInAliasRegion(KProcessAddress addr, size_t size) const {
|
constexpr bool IsInAliasRegion(KProcessAddress addr, size_t size) const {
|
||||||
return this->Contains(addr, size) && m_alias_region_start <= addr && addr + size - 1 <= m_alias_region_end - 1;
|
return this->Contains(addr, size) && m_region_starts[RegionType_Alias] <= addr && addr + size - 1 <= m_region_ends[RegionType_Alias] - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const {
|
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const {
|
||||||
/* Even though Unsafe physical memory is KMemoryState_Normal, it must be mapped inside the alias code region. */
|
/* Even though Unsafe physical memory is KMemoryState_Normal, it must be mapped inside the alias code region. */
|
||||||
return this->CanContain(addr, size, KMemoryState_AliasCode);
|
return this->CanContain(addr, size, ams::svc::MemoryState_AliasCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE KScopedLightLock AcquireDeviceMapLock() {
|
ALWAYS_INLINE KScopedLightLock AcquireDeviceMapLock() {
|
||||||
return KScopedLightLock(m_device_map_lock);
|
return KScopedLightLock(m_device_map_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
KProcessAddress GetRegionAddress(KMemoryState state) const;
|
KProcessAddress GetRegionAddress(ams::svc::MemoryState state) const;
|
||||||
size_t GetRegionSize(KMemoryState state) const;
|
size_t GetRegionSize(ams::svc::MemoryState state) const;
|
||||||
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const;
|
bool CanContain(KProcessAddress addr, size_t size, ams::svc::MemoryState state) const;
|
||||||
|
|
||||||
|
ALWAYS_INLINE KProcessAddress GetRegionAddress(KMemoryState state) const { return this->GetRegionAddress(static_cast<ams::svc::MemoryState>(state & KMemoryState_Mask)); }
|
||||||
|
ALWAYS_INLINE size_t GetRegionSize(KMemoryState state) const { return this->GetRegionSize(static_cast<ams::svc::MemoryState>(state & KMemoryState_Mask)); }
|
||||||
|
ALWAYS_INLINE bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return this->CanContain(addr, size, static_cast<ams::svc::MemoryState>(state & KMemoryState_Mask)); }
|
||||||
protected:
|
protected:
|
||||||
/* NOTE: These three functions (Operate, Operate, FinalizeUpdate) are virtual functions */
|
/* NOTE: These three functions (Operate, Operate, FinalizeUpdate) are virtual functions */
|
||||||
/* in Nintendo's kernel. We devirtualize them, since KPageTable is the only derived */
|
/* in Nintendo's kernel. We devirtualize them, since KPageTable is the only derived */
|
||||||
@@ -292,6 +319,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result CheckMemoryState(const KMemoryInfo &info, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const;
|
Result CheckMemoryState(const KMemoryInfo &info, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const;
|
||||||
|
Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KMemoryBlockManager::const_iterator it, KProcessAddress last_addr, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const;
|
||||||
Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const;
|
Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const;
|
||||||
Result CheckMemoryState(size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const {
|
Result CheckMemoryState(size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const {
|
||||||
R_RETURN(this->CheckMemoryState(nullptr, nullptr, nullptr, out_blocks_needed, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr));
|
R_RETURN(this->CheckMemoryState(nullptr, nullptr, nullptr, out_blocks_needed, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr));
|
||||||
@@ -305,9 +333,9 @@ namespace ams::kern {
|
|||||||
|
|
||||||
Result QueryInfoImpl(KMemoryInfo *out_info, ams::svc::PageInfo *out_page, KProcessAddress address) const;
|
Result QueryInfoImpl(KMemoryInfo *out_info, ams::svc::PageInfo *out_page, KProcessAddress address) const;
|
||||||
|
|
||||||
Result QueryMappingImpl(KProcessAddress *out, KPhysicalAddress address, size_t size, KMemoryState state) const;
|
Result QueryMappingImpl(KProcessAddress *out, KPhysicalAddress address, size_t size, ams::svc::MemoryState state) const;
|
||||||
|
|
||||||
Result AllocateAndMapPagesImpl(PageLinkedList *page_list, KProcessAddress address, size_t num_pages, KMemoryPermission perm);
|
Result AllocateAndMapPagesImpl(PageLinkedList *page_list, KProcessAddress address, size_t num_pages, const KPageProperties &properties);
|
||||||
Result MapPageGroupImpl(PageLinkedList *page_list, KProcessAddress address, const KPageGroup &pg, const KPageProperties properties, bool reuse_ll);
|
Result MapPageGroupImpl(PageLinkedList *page_list, KProcessAddress address, const KPageGroup &pg, const KPageProperties properties, bool reuse_ll);
|
||||||
|
|
||||||
void RemapPageGroup(PageLinkedList *page_list, KProcessAddress address, size_t size, const KPageGroup &pg);
|
void RemapPageGroup(PageLinkedList *page_list, KProcessAddress address, size_t size, const KPageGroup &pg);
|
||||||
@@ -319,9 +347,9 @@ namespace ams::kern {
|
|||||||
|
|
||||||
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 MapIoImpl(KProcessAddress *out, PageLinkedList *page_list, KPhysicalAddress phys_addr, size_t size, KMemoryState state, KMemoryPermission perm);
|
||||||
Result ReadIoMemoryImpl(void *buffer, KPhysicalAddress phys_addr, size_t size);
|
Result ReadIoMemoryImpl(void *buffer, KPhysicalAddress phys_addr, size_t size, KMemoryState state);
|
||||||
Result WriteIoMemoryImpl(KPhysicalAddress phys_addr, const void *buffer, size_t size);
|
Result WriteIoMemoryImpl(KPhysicalAddress phys_addr, const void *buffer, size_t size, KMemoryState state);
|
||||||
|
|
||||||
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);
|
||||||
@@ -355,19 +383,19 @@ namespace ams::kern {
|
|||||||
Result SetMaxHeapSize(size_t size);
|
Result SetMaxHeapSize(size_t size);
|
||||||
Result QueryInfo(KMemoryInfo *out_info, ams::svc::PageInfo *out_page_info, KProcessAddress addr) const;
|
Result QueryInfo(KMemoryInfo *out_info, ams::svc::PageInfo *out_page_info, KProcessAddress addr) const;
|
||||||
Result QueryPhysicalAddress(ams::svc::PhysicalMemoryInfo *out, KProcessAddress address) const;
|
Result QueryPhysicalAddress(ams::svc::PhysicalMemoryInfo *out, KProcessAddress address) const;
|
||||||
Result QueryStaticMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { R_RETURN(this->QueryMappingImpl(out, address, size, KMemoryState_Static)); }
|
Result QueryStaticMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { R_RETURN(this->QueryMappingImpl(out, address, size, ams::svc::MemoryState_Static)); }
|
||||||
Result QueryIoMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { R_RETURN(this->QueryMappingImpl(out, address, size, KMemoryState_Io)); }
|
Result QueryIoMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { R_RETURN(this->QueryMappingImpl(out, address, size, ams::svc::MemoryState_Io)); }
|
||||||
Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||||
Result UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
Result UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||||
Result MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
Result MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||||
Result UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
Result UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||||
Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
||||||
Result MapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm);
|
Result MapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm);
|
||||||
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size);
|
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping);
|
||||||
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
||||||
Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm);
|
Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm);
|
||||||
Result MapInsecureMemory(KProcessAddress address, size_t size);
|
Result MapInsecurePhysicalMemory(KProcessAddress address, size_t size);
|
||||||
Result UnmapInsecureMemory(KProcessAddress address, size_t size);
|
Result UnmapInsecurePhysicalMemory(KProcessAddress address, size_t size);
|
||||||
|
|
||||||
Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) {
|
Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) {
|
||||||
R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start, region_num_pages, state, perm));
|
R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start, region_num_pages, state, perm));
|
||||||
@@ -391,12 +419,13 @@ namespace ams::kern {
|
|||||||
Result MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr);
|
Result MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr);
|
||||||
|
|
||||||
Result InvalidateProcessDataCache(KProcessAddress address, size_t size);
|
Result InvalidateProcessDataCache(KProcessAddress address, size_t size);
|
||||||
|
Result InvalidateCurrentProcessDataCache(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 ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size, KMemoryState state);
|
||||||
|
|
||||||
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 WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size, KMemoryState state);
|
||||||
|
|
||||||
Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap);
|
Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap);
|
||||||
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap);
|
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap);
|
||||||
@@ -457,24 +486,30 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
KProcessAddress GetAddressSpaceStart() const { return m_address_space_start; }
|
KProcessAddress GetAddressSpaceStart() const { return m_address_space_start; }
|
||||||
KProcessAddress GetHeapRegionStart() const { return m_heap_region_start; }
|
|
||||||
KProcessAddress GetAliasRegionStart() const { return m_alias_region_start; }
|
KProcessAddress GetHeapRegionStart() const { return m_region_starts[RegionType_Heap]; }
|
||||||
KProcessAddress GetStackRegionStart() const { return m_stack_region_start; }
|
KProcessAddress GetAliasRegionStart() const { return m_region_starts[RegionType_Alias]; }
|
||||||
KProcessAddress GetKernelMapRegionStart() const { return m_kernel_map_region_start; }
|
KProcessAddress GetStackRegionStart() const { return m_region_starts[RegionType_Stack]; }
|
||||||
|
KProcessAddress GetKernelMapRegionStart() const { return m_region_starts[RegionType_KernelMap]; }
|
||||||
|
|
||||||
KProcessAddress GetAliasCodeRegionStart() const { return m_alias_code_region_start; }
|
KProcessAddress GetAliasCodeRegionStart() const { return m_alias_code_region_start; }
|
||||||
|
|
||||||
size_t GetAddressSpaceSize() const { return m_address_space_end - m_address_space_start; }
|
size_t GetAddressSpaceSize() const { return m_address_space_end - m_address_space_start; }
|
||||||
size_t GetHeapRegionSize() const { return m_heap_region_end - m_heap_region_start; }
|
|
||||||
size_t GetAliasRegionSize() const { return m_alias_region_end - m_alias_region_start; }
|
size_t GetHeapRegionSize() const { return m_region_ends[RegionType_Heap] - m_region_starts[RegionType_Heap]; }
|
||||||
size_t GetStackRegionSize() const { return m_stack_region_end - m_stack_region_start; }
|
size_t GetAliasRegionSize() const { return m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias]; }
|
||||||
size_t GetKernelMapRegionSize() const { return m_kernel_map_region_end - m_kernel_map_region_start; }
|
size_t GetStackRegionSize() const { return m_region_ends[RegionType_Stack] - m_region_starts[RegionType_Stack]; }
|
||||||
|
size_t GetKernelMapRegionSize() const { return m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap]; }
|
||||||
|
|
||||||
size_t GetAliasCodeRegionSize() const { return m_alias_code_region_end - m_alias_code_region_start; }
|
size_t GetAliasCodeRegionSize() const { return m_alias_code_region_end - m_alias_code_region_start; }
|
||||||
|
|
||||||
|
size_t GetAliasRegionExtraSize() const { return m_alias_region_extra_size; }
|
||||||
|
|
||||||
size_t GetNormalMemorySize() const {
|
size_t GetNormalMemorySize() const {
|
||||||
/* Lock the table. */
|
/* Lock the table. */
|
||||||
KScopedLightLock lk(m_general_lock);
|
KScopedLightLock lk(m_general_lock);
|
||||||
|
|
||||||
return (m_current_heap_end - m_heap_region_start) + m_mapped_physical_memory_size;
|
return (m_current_heap_end - m_region_starts[RegionType_Heap]) + m_mapped_physical_memory_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetCodeSize() const;
|
size_t GetCodeSize() const;
|
||||||
|
|||||||
@@ -234,11 +234,11 @@ namespace ams::kern {
|
|||||||
KPriorityQueueImpl m_scheduled_queue;
|
KPriorityQueueImpl m_scheduled_queue;
|
||||||
KPriorityQueueImpl m_suggested_queue;
|
KPriorityQueueImpl m_suggested_queue;
|
||||||
private:
|
private:
|
||||||
constexpr ALWAYS_INLINE void ClearAffinityBit(u64 &affinity, s32 core) {
|
static constexpr ALWAYS_INLINE void ClearAffinityBit(u64 &affinity, s32 core) {
|
||||||
affinity &= ~(UINT64_C(1) << core);
|
affinity &= ~(UINT64_C(1) << core);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE s32 GetNextCore(u64 &affinity) {
|
static constexpr ALWAYS_INLINE s32 GetNextCore(u64 &affinity) {
|
||||||
const s32 core = __builtin_ctzll(static_cast<unsigned long long>(affinity));
|
const s32 core = __builtin_ctzll(static_cast<unsigned long long>(affinity));
|
||||||
ClearAffinityBit(affinity, core);
|
ClearAffinityBit(affinity, core);
|
||||||
return core;
|
return core;
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ namespace ams::kern {
|
|||||||
bool m_is_signaled;
|
bool m_is_signaled;
|
||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
bool m_is_application;
|
bool m_is_application;
|
||||||
|
bool m_is_default_application_system_resource;
|
||||||
char m_name[13];
|
char m_name[13];
|
||||||
util::Atomic<u16> m_num_running_threads;
|
util::Atomic<u16> m_num_running_threads;
|
||||||
u32 m_flags;
|
u32 m_flags;
|
||||||
@@ -84,7 +85,9 @@ namespace ams::kern {
|
|||||||
KCapabilities m_capabilities;
|
KCapabilities m_capabilities;
|
||||||
ams::svc::ProgramId m_program_id;
|
ams::svc::ProgramId m_program_id;
|
||||||
u64 m_process_id;
|
u64 m_process_id;
|
||||||
|
#if defined(MESOSPHERE_ENABLE_PROCESS_CREATION_TIME)
|
||||||
s64 m_creation_time;
|
s64 m_creation_time;
|
||||||
|
#endif
|
||||||
KProcessAddress m_code_address;
|
KProcessAddress m_code_address;
|
||||||
size_t m_code_size;
|
size_t m_code_size;
|
||||||
size_t m_main_thread_stack_size;
|
size_t m_main_thread_stack_size;
|
||||||
@@ -108,6 +111,7 @@ namespace ams::kern {
|
|||||||
KWaitObject m_wait_object;
|
KWaitObject m_wait_object;
|
||||||
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];
|
||||||
|
u64 m_running_thread_switch_counts[cpu::NumCores];
|
||||||
KThread *m_pinned_threads[cpu::NumCores];
|
KThread *m_pinned_threads[cpu::NumCores];
|
||||||
util::Atomic<s64> m_cpu_time;
|
util::Atomic<s64> m_cpu_time;
|
||||||
util::Atomic<s64> m_num_process_switches;
|
util::Atomic<s64> m_num_process_switches;
|
||||||
@@ -175,6 +179,8 @@ namespace ams::kern {
|
|||||||
|
|
||||||
constexpr bool IsApplication() const { return m_is_application; }
|
constexpr bool IsApplication() const { return m_is_application; }
|
||||||
|
|
||||||
|
constexpr bool IsDefaultApplicationSystemResource() const { return m_is_default_application_system_resource; }
|
||||||
|
|
||||||
constexpr bool IsSuspended() const { return m_is_suspended; }
|
constexpr bool IsSuspended() const { return m_is_suspended; }
|
||||||
constexpr void SetSuspended(bool suspended) { m_is_suspended = suspended; }
|
constexpr void SetSuspended(bool suspended) { m_is_suspended = suspended; }
|
||||||
|
|
||||||
@@ -277,17 +283,26 @@ namespace ams::kern {
|
|||||||
void IncrementRunningThreadCount();
|
void IncrementRunningThreadCount();
|
||||||
void DecrementRunningThreadCount();
|
void DecrementRunningThreadCount();
|
||||||
|
|
||||||
|
size_t GetRequiredSecureMemorySizeNonDefault() const {
|
||||||
|
return (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) ? static_cast<KSecureSystemResource *>(m_system_resource)->CalculateRequiredSecureMemorySize() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetRequiredSecureMemorySize() const {
|
||||||
|
return m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->CalculateRequiredSecureMemorySize() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t GetTotalSystemResourceSize() const {
|
size_t GetTotalSystemResourceSize() const {
|
||||||
return m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->GetSize() : 0;
|
return (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) ? static_cast<KSecureSystemResource *>(m_system_resource)->GetSize() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetUsedSystemResourceSize() const {
|
size_t GetUsedSystemResourceSize() const {
|
||||||
return m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->GetUsedSize() : 0;
|
return (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) ? static_cast<KSecureSystemResource *>(m_system_resource)->GetUsedSize() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRunningThread(s32 core, KThread *thread, u64 idle_count) {
|
void SetRunningThread(s32 core, KThread *thread, u64 idle_count, u64 switch_count) {
|
||||||
m_running_threads[core] = thread;
|
m_running_threads[core] = thread;
|
||||||
m_running_thread_idle_counts[core] = idle_count;
|
m_running_thread_idle_counts[core] = idle_count;
|
||||||
|
m_running_thread_switch_counts[core] = switch_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearRunningThread(KThread *thread) {
|
void ClearRunningThread(KThread *thread) {
|
||||||
@@ -306,6 +321,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
constexpr KThread *GetRunningThread(s32 core) const { return m_running_threads[core]; }
|
constexpr KThread *GetRunningThread(s32 core) const { return m_running_threads[core]; }
|
||||||
constexpr u64 GetRunningThreadIdleCount(s32 core) const { return m_running_thread_idle_counts[core]; }
|
constexpr u64 GetRunningThreadIdleCount(s32 core) const { return m_running_thread_idle_counts[core]; }
|
||||||
|
constexpr u64 GetRunningThreadSwitchCount(s32 core) const { return m_running_thread_switch_counts[core]; }
|
||||||
|
|
||||||
void RegisterThread(KThread *thread);
|
void RegisterThread(KThread *thread);
|
||||||
void UnregisterThread(KThread *thread);
|
void UnregisterThread(KThread *thread);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ namespace ams::kern {
|
|||||||
bool interrupt_task_runnable{false};
|
bool interrupt_task_runnable{false};
|
||||||
bool should_count_idle{false};
|
bool should_count_idle{false};
|
||||||
u64 idle_count{0};
|
u64 idle_count{0};
|
||||||
|
u64 switch_count{0};
|
||||||
KThread *highest_priority_thread{nullptr};
|
KThread *highest_priority_thread{nullptr};
|
||||||
void *idle_thread_stack{nullptr};
|
void *idle_thread_stack{nullptr};
|
||||||
KThread *prev_thread{nullptr};
|
KThread *prev_thread{nullptr};
|
||||||
@@ -67,6 +68,7 @@ namespace ams::kern {
|
|||||||
m_state.interrupt_task_runnable = false;
|
m_state.interrupt_task_runnable = false;
|
||||||
m_state.should_count_idle = false;
|
m_state.should_count_idle = false;
|
||||||
m_state.idle_count = 0;
|
m_state.idle_count = 0;
|
||||||
|
m_state.switch_count = 0;
|
||||||
m_state.idle_thread_stack = nullptr;
|
m_state.idle_thread_stack = nullptr;
|
||||||
m_state.highest_priority_thread = nullptr;
|
m_state.highest_priority_thread = nullptr;
|
||||||
m_state.prev_thread = nullptr;
|
m_state.prev_thread = nullptr;
|
||||||
@@ -93,6 +95,10 @@ namespace ams::kern {
|
|||||||
return m_state.idle_count;
|
return m_state.idle_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE u64 GetSwitchCount() const {
|
||||||
|
return m_state.switch_count;
|
||||||
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE KThread *GetIdleThread() const {
|
ALWAYS_INLINE KThread *GetIdleThread() const {
|
||||||
return m_idle_thread;
|
return m_idle_thread;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
|
||||||
if (this->IsLockedByCurrentThread()) {
|
if (this->IsLockedByCurrentThread()) {
|
||||||
/* If we already own the lock, we can just increment the count. */
|
/* If we already own the lock, the lock count should be > 0. */
|
||||||
|
/* For debug, ensure this is true. */
|
||||||
MESOSPHERE_ASSERT(m_lock_count > 0);
|
MESOSPHERE_ASSERT(m_lock_count > 0);
|
||||||
m_lock_count++;
|
|
||||||
} else {
|
} else {
|
||||||
/* Otherwise, we want to disable scheduling and acquire the spinlock. */
|
/* Otherwise, we want to disable scheduling and acquire the spinlock. */
|
||||||
SchedulerType::DisableScheduling();
|
SchedulerType::DisableScheduling();
|
||||||
@@ -61,10 +61,12 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_ASSERT(m_lock_count == 0);
|
MESOSPHERE_ASSERT(m_lock_count == 0);
|
||||||
MESOSPHERE_ASSERT(m_owner_thread == nullptr);
|
MESOSPHERE_ASSERT(m_owner_thread == nullptr);
|
||||||
|
|
||||||
/* Increment count, take ownership. */
|
/* Take ownership of the lock. */
|
||||||
m_lock_count = 1;
|
|
||||||
m_owner_thread = GetCurrentThreadPointer();
|
m_owner_thread = GetCurrentThreadPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Increment the lock count. */
|
||||||
|
m_lock_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
MESOSPHERE_ALWAYS_INLINE_IF_RELEASE void Unlock() {
|
MESOSPHERE_ALWAYS_INLINE_IF_RELEASE void Unlock() {
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ namespace ams::kern {
|
|||||||
|
|
||||||
struct InitialProcessBinaryLayout;
|
struct InitialProcessBinaryLayout;
|
||||||
|
|
||||||
|
namespace init {
|
||||||
|
|
||||||
|
struct KInitArguments;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ams::kern {
|
namespace ams::kern {
|
||||||
@@ -40,14 +46,16 @@ namespace ams::kern {
|
|||||||
static constinit inline KSpinLock s_random_lock;
|
static constinit inline KSpinLock s_random_lock;
|
||||||
public:
|
public:
|
||||||
class Init {
|
class Init {
|
||||||
|
private:
|
||||||
|
static void CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
||||||
public:
|
public:
|
||||||
/* Initialization. */
|
/* Initialization. */
|
||||||
static size_t GetRealMemorySize();
|
static size_t GetRealMemorySize();
|
||||||
static size_t GetIntendedMemorySize();
|
static size_t GetIntendedMemorySize();
|
||||||
static KPhysicalAddress GetKernelPhysicalBaseAddress(KPhysicalAddress base_address);
|
static KPhysicalAddress GetKernelPhysicalBaseAddress(KPhysicalAddress base_address);
|
||||||
static void GetInitialProcessBinaryLayout(InitialProcessBinaryLayout *out);
|
static void GetInitialProcessBinaryLayout(InitialProcessBinaryLayout *out, KPhysicalAddress kern_base_address);
|
||||||
static bool ShouldIncreaseThreadResourceLimit();
|
static bool ShouldIncreaseThreadResourceLimit();
|
||||||
static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
static void TurnOnCpu(u64 core_id, const ams::kern::init::KInitArguments *args);
|
||||||
static size_t GetApplicationPoolSize();
|
static size_t GetApplicationPoolSize();
|
||||||
static size_t GetAppletPoolSize();
|
static size_t GetAppletPoolSize();
|
||||||
static size_t GetMinimumNonSecureSystemPoolSize();
|
static size_t GetMinimumNonSecureSystemPoolSize();
|
||||||
@@ -57,9 +65,11 @@ namespace ams::kern {
|
|||||||
static void GenerateRandom(u64 *dst, size_t count);
|
static void GenerateRandom(u64 *dst, size_t count);
|
||||||
static u64 GenerateRandomRange(u64 min, u64 max);
|
static u64 GenerateRandomRange(u64 min, u64 max);
|
||||||
};
|
};
|
||||||
|
protected:
|
||||||
|
static NOINLINE void InitializePhase1Base(u64 seed);
|
||||||
public:
|
public:
|
||||||
/* Initialization. */
|
/* Initialization. */
|
||||||
static NOINLINE void InitializePhase1(bool skip_target_system = false);
|
static NOINLINE void InitializePhase1();
|
||||||
static NOINLINE void InitializePhase2();
|
static NOINLINE void InitializePhase2();
|
||||||
static NOINLINE u32 GetCreateProcessMemoryPool();
|
static NOINLINE u32 GetCreateProcessMemoryPool();
|
||||||
|
|
||||||
|
|||||||
@@ -108,10 +108,12 @@ namespace ams::kern {
|
|||||||
u8 exception_flags;
|
u8 exception_flags;
|
||||||
bool is_pinned;
|
bool is_pinned;
|
||||||
u8 reserved_2f;
|
u8 reserved_2f;
|
||||||
|
u8 reserved_30[0x10];
|
||||||
KThreadContext context;
|
KThreadContext context;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(util::IsAligned(AMS_OFFSETOF(StackParameters, context), 0x10));
|
static_assert(util::IsAligned(AMS_OFFSETOF(StackParameters, context), 0x10));
|
||||||
|
static_assert(sizeof(StackParameters) == THREAD_STACK_PARAMETERS_SIZE);
|
||||||
|
|
||||||
static_assert(AMS_OFFSETOF(StackParameters, svc_access_flags) == THREAD_STACK_PARAMETERS_SVC_PERMISSION);
|
static_assert(AMS_OFFSETOF(StackParameters, svc_access_flags) == THREAD_STACK_PARAMETERS_SVC_PERMISSION);
|
||||||
static_assert(AMS_OFFSETOF(StackParameters, caller_save_fpu_registers) == THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS);
|
static_assert(AMS_OFFSETOF(StackParameters, caller_save_fpu_registers) == THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS);
|
||||||
@@ -123,8 +125,10 @@ namespace ams::kern {
|
|||||||
static_assert(AMS_OFFSETOF(StackParameters, exception_flags) == THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS);
|
static_assert(AMS_OFFSETOF(StackParameters, exception_flags) == THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS);
|
||||||
static_assert(AMS_OFFSETOF(StackParameters, is_pinned) == THREAD_STACK_PARAMETERS_IS_PINNED);
|
static_assert(AMS_OFFSETOF(StackParameters, is_pinned) == THREAD_STACK_PARAMETERS_IS_PINNED);
|
||||||
static_assert(AMS_OFFSETOF(StackParameters, reserved_2f) == THREAD_STACK_PARAMETERS_RESERVED_2F);
|
static_assert(AMS_OFFSETOF(StackParameters, reserved_2f) == THREAD_STACK_PARAMETERS_RESERVED_2F);
|
||||||
|
static_assert(AMS_OFFSETOF(StackParameters, reserved_30) == THREAD_STACK_PARAMETERS_RESERVED_30);
|
||||||
static_assert(AMS_OFFSETOF(StackParameters, context) == THREAD_STACK_PARAMETERS_THREAD_CONTEXT);
|
static_assert(AMS_OFFSETOF(StackParameters, context) == THREAD_STACK_PARAMETERS_THREAD_CONTEXT);
|
||||||
|
|
||||||
|
|
||||||
static_assert(ExceptionFlag_IsCallingSvc == THREAD_EXCEPTION_FLAG_IS_CALLING_SVC);
|
static_assert(ExceptionFlag_IsCallingSvc == THREAD_EXCEPTION_FLAG_IS_CALLING_SVC);
|
||||||
static_assert(ExceptionFlag_IsInExceptionHandler == THREAD_EXCEPTION_FLAG_IS_IN_EXCEPTION_HANDLER);
|
static_assert(ExceptionFlag_IsInExceptionHandler == THREAD_EXCEPTION_FLAG_IS_IN_EXCEPTION_HANDLER);
|
||||||
static_assert(ExceptionFlag_IsFpuContextRestoreNeeded == THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED);
|
static_assert(ExceptionFlag_IsFpuContextRestoreNeeded == THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED);
|
||||||
@@ -197,6 +201,28 @@ namespace ams::kern {
|
|||||||
};
|
};
|
||||||
static_assert(ams::util::HasRedBlackKeyType<ConditionVariableComparator>);
|
static_assert(ams::util::HasRedBlackKeyType<ConditionVariableComparator>);
|
||||||
static_assert(std::same_as<ams::util::RedBlackKeyType<ConditionVariableComparator, void>, ConditionVariableComparator::RedBlackKeyType>);
|
static_assert(std::same_as<ams::util::RedBlackKeyType<ConditionVariableComparator, void>, ConditionVariableComparator::RedBlackKeyType>);
|
||||||
|
|
||||||
|
struct LockWithPriorityInheritanceComparator {
|
||||||
|
struct RedBlackKeyType {
|
||||||
|
s32 m_priority;
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE s32 GetPriority() const {
|
||||||
|
return m_priority;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if (lhs.GetPriority() < rhs.GetPriority()) {
|
||||||
|
/* Sort by priority. */
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(ams::util::HasRedBlackKeyType<LockWithPriorityInheritanceComparator>);
|
||||||
|
static_assert(std::same_as<ams::util::RedBlackKeyType<LockWithPriorityInheritanceComparator, void>, LockWithPriorityInheritanceComparator::RedBlackKeyType>);
|
||||||
private:
|
private:
|
||||||
util::IntrusiveListNode m_process_list_node;
|
util::IntrusiveListNode m_process_list_node;
|
||||||
util::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node;
|
util::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node;
|
||||||
@@ -205,6 +231,67 @@ namespace ams::kern {
|
|||||||
using ConditionVariableThreadTreeTraits = util::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&KThread::m_condvar_arbiter_tree_node>;
|
using ConditionVariableThreadTreeTraits = util::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&KThread::m_condvar_arbiter_tree_node>;
|
||||||
using ConditionVariableThreadTree = ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
|
using ConditionVariableThreadTree = ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
|
||||||
|
|
||||||
|
using LockWithPriorityInheritanceThreadTreeTraits = util::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&KThread::m_condvar_arbiter_tree_node>;
|
||||||
|
using LockWithPriorityInheritanceThreadTree = ConditionVariableThreadTreeTraits::TreeType<LockWithPriorityInheritanceComparator>;
|
||||||
|
public:
|
||||||
|
class LockWithPriorityInheritanceInfo : public KSlabAllocated<LockWithPriorityInheritanceInfo>, public util::IntrusiveListBaseNode<LockWithPriorityInheritanceInfo> {
|
||||||
|
private:
|
||||||
|
LockWithPriorityInheritanceThreadTree m_tree;
|
||||||
|
KProcessAddress m_address_key;
|
||||||
|
KThread *m_owner;
|
||||||
|
u32 m_waiter_count;
|
||||||
|
public:
|
||||||
|
constexpr LockWithPriorityInheritanceInfo() : m_tree(), m_address_key(Null<KProcessAddress>), m_owner(nullptr), m_waiter_count() {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
static LockWithPriorityInheritanceInfo *Create(KProcessAddress address_key) {
|
||||||
|
/* Create a new lock info. */
|
||||||
|
auto *new_lock = LockWithPriorityInheritanceInfo::Allocate();
|
||||||
|
MESOSPHERE_ABORT_UNLESS(new_lock != nullptr);
|
||||||
|
|
||||||
|
/* Set the new lock's address key. */
|
||||||
|
new_lock->m_address_key = address_key;
|
||||||
|
|
||||||
|
return new_lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetOwner(KThread *new_owner) {
|
||||||
|
/* Set new owner. */
|
||||||
|
m_owner = new_owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddWaiter(KThread *waiter) {
|
||||||
|
/* Insert the waiter. */
|
||||||
|
m_tree.insert(*waiter);
|
||||||
|
m_waiter_count++;
|
||||||
|
|
||||||
|
waiter->SetWaitingLockInfo(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool RemoveWaiter(KThread *waiter) {
|
||||||
|
m_tree.erase(m_tree.iterator_to(*waiter));
|
||||||
|
|
||||||
|
waiter->SetWaitingLockInfo(nullptr);
|
||||||
|
|
||||||
|
return (--m_waiter_count) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
KThread *GetHighestPriorityWaiter() { return std::addressof(m_tree.front()); }
|
||||||
|
const KThread *GetHighestPriorityWaiter() const { return std::addressof(m_tree.front()); }
|
||||||
|
|
||||||
|
LockWithPriorityInheritanceThreadTree &GetThreadTree() { return m_tree; }
|
||||||
|
const LockWithPriorityInheritanceThreadTree &GetThreadTree() const { return m_tree; }
|
||||||
|
|
||||||
|
constexpr KProcessAddress GetAddressKey() const { return m_address_key; }
|
||||||
|
|
||||||
|
constexpr KThread *GetOwner() const { return m_owner; }
|
||||||
|
|
||||||
|
constexpr u32 GetWaiterCount() const { return m_waiter_count; }
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
using LockWithPriorityInheritanceInfoList = util::IntrusiveListBaseTraits<LockWithPriorityInheritanceInfo>::ListType;
|
||||||
|
|
||||||
ConditionVariableThreadTree *m_condvar_tree;
|
ConditionVariableThreadTree *m_condvar_tree;
|
||||||
uintptr_t m_condvar_key;
|
uintptr_t m_condvar_key;
|
||||||
alignas(16) KThreadContext::CallerSaveFpuRegisters m_caller_save_fpu_registers;
|
alignas(16) KThreadContext::CallerSaveFpuRegisters m_caller_save_fpu_registers;
|
||||||
@@ -224,9 +311,9 @@ namespace ams::kern {
|
|||||||
s64 m_last_scheduled_tick;
|
s64 m_last_scheduled_tick;
|
||||||
QueueEntry m_per_core_priority_queue_entry[cpu::NumCores];
|
QueueEntry m_per_core_priority_queue_entry[cpu::NumCores];
|
||||||
KThreadQueue *m_wait_queue;
|
KThreadQueue *m_wait_queue;
|
||||||
WaiterList m_waiter_list;
|
LockWithPriorityInheritanceInfoList m_held_lock_info_list;
|
||||||
|
LockWithPriorityInheritanceInfo *m_waiting_lock_info;
|
||||||
WaiterList m_pinned_waiter_list;
|
WaiterList m_pinned_waiter_list;
|
||||||
KThread *m_lock_owner;
|
|
||||||
uintptr_t m_debug_params[3];
|
uintptr_t m_debug_params[3];
|
||||||
KAutoObject *m_closed_object;
|
KAutoObject *m_closed_object;
|
||||||
u32 m_address_key_value;
|
u32 m_address_key_value;
|
||||||
@@ -260,8 +347,8 @@ namespace ams::kern {
|
|||||||
m_process_list_node{}, m_condvar_arbiter_tree_node{util::ConstantInitialize}, m_priority{-1}, m_condvar_tree{}, m_condvar_key{},
|
m_process_list_node{}, m_condvar_arbiter_tree_node{util::ConstantInitialize}, m_priority{-1}, m_condvar_tree{}, m_condvar_key{},
|
||||||
m_caller_save_fpu_registers{}, m_virtual_affinity_mask{}, m_physical_affinity_mask{}, m_thread_id{}, m_cpu_time{0}, m_address_key{Null<KProcessAddress>}, m_parent{},
|
m_caller_save_fpu_registers{}, m_virtual_affinity_mask{}, m_physical_affinity_mask{}, m_thread_id{}, m_cpu_time{0}, m_address_key{Null<KProcessAddress>}, m_parent{},
|
||||||
m_kernel_stack_top{}, m_light_ipc_data{}, m_tls_address{Null<KProcessAddress>}, m_tls_heap_address{}, m_activity_pause_lock{}, m_sync_object_buffer{util::ConstantInitialize},
|
m_kernel_stack_top{}, m_light_ipc_data{}, m_tls_address{Null<KProcessAddress>}, m_tls_heap_address{}, m_activity_pause_lock{}, m_sync_object_buffer{util::ConstantInitialize},
|
||||||
m_schedule_count{}, m_last_scheduled_tick{}, m_per_core_priority_queue_entry{}, m_wait_queue{}, m_waiter_list{}, m_pinned_waiter_list{},
|
m_schedule_count{}, m_last_scheduled_tick{}, m_per_core_priority_queue_entry{}, m_wait_queue{}, m_held_lock_info_list{}, m_waiting_lock_info{},
|
||||||
m_lock_owner{}, m_debug_params{}, m_closed_object{}, m_address_key_value{}, m_suspend_request_flags{}, m_suspend_allowed_flags{}, m_synced_index{},
|
m_pinned_waiter_list{}, m_debug_params{}, m_closed_object{}, m_address_key_value{}, m_suspend_request_flags{}, m_suspend_allowed_flags{}, m_synced_index{},
|
||||||
m_wait_result{svc::ResultNoSynchronizationObject()}, m_debug_exception_result{ResultSuccess()}, m_base_priority{}, m_base_priority_on_unpin{},
|
m_wait_result{svc::ResultNoSynchronizationObject()}, m_debug_exception_result{ResultSuccess()}, m_base_priority{}, m_base_priority_on_unpin{},
|
||||||
m_physical_ideal_core_id{}, m_virtual_ideal_core_id{}, m_num_kernel_waiters{}, m_current_core_id{}, m_core_id{}, m_original_physical_affinity_mask{},
|
m_physical_ideal_core_id{}, m_virtual_ideal_core_id{}, m_num_kernel_waiters{}, m_current_core_id{}, m_core_id{}, m_original_physical_affinity_mask{},
|
||||||
m_original_physical_ideal_core_id{}, m_num_core_migration_disables{}, m_thread_state{}, m_termination_requested{false}, m_wait_cancelled{},
|
m_original_physical_ideal_core_id{}, m_num_core_migration_disables{}, m_thread_state{}, m_termination_requested{false}, m_wait_cancelled{},
|
||||||
@@ -407,6 +494,10 @@ namespace ams::kern {
|
|||||||
void ClearUsermodeExceptionSvcPermissions();
|
void ClearUsermodeExceptionSvcPermissions();
|
||||||
private:
|
private:
|
||||||
void UpdateState();
|
void UpdateState();
|
||||||
|
|
||||||
|
ALWAYS_INLINE void AddHeldLock(LockWithPriorityInheritanceInfo *lock_info);
|
||||||
|
ALWAYS_INLINE LockWithPriorityInheritanceInfo *FindHeldLock(KProcessAddress address_key);
|
||||||
|
|
||||||
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);
|
||||||
@@ -441,6 +532,8 @@ namespace ams::kern {
|
|||||||
constexpr uintptr_t GetAddressArbiterKey() const { return m_condvar_key; }
|
constexpr uintptr_t GetAddressArbiterKey() const { return m_condvar_key; }
|
||||||
|
|
||||||
constexpr void SetConditionVariable(ConditionVariableThreadTree *tree, KProcessAddress address, uintptr_t cv_key, u32 value) {
|
constexpr void SetConditionVariable(ConditionVariableThreadTree *tree, KProcessAddress address, uintptr_t cv_key, u32 value) {
|
||||||
|
MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr);
|
||||||
|
|
||||||
m_condvar_tree = tree;
|
m_condvar_tree = tree;
|
||||||
m_condvar_key = cv_key;
|
m_condvar_key = cv_key;
|
||||||
m_address_key = address;
|
m_address_key = address;
|
||||||
@@ -456,6 +549,8 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr void SetAddressArbiter(ConditionVariableThreadTree *tree, uintptr_t address) {
|
constexpr void SetAddressArbiter(ConditionVariableThreadTree *tree, uintptr_t address) {
|
||||||
|
MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr);
|
||||||
|
|
||||||
m_condvar_tree = tree;
|
m_condvar_tree = tree;
|
||||||
m_condvar_key = address;
|
m_condvar_key = address;
|
||||||
}
|
}
|
||||||
@@ -491,15 +586,17 @@ namespace ams::kern {
|
|||||||
|
|
||||||
void AddWaiter(KThread *thread);
|
void AddWaiter(KThread *thread);
|
||||||
void RemoveWaiter(KThread *thread);
|
void RemoveWaiter(KThread *thread);
|
||||||
KThread *RemoveWaiterByKey(s32 *out_num_waiters, KProcessAddress key);
|
KThread *RemoveWaiterByKey(bool *out_has_waiters, KProcessAddress key);
|
||||||
|
|
||||||
constexpr KProcessAddress GetAddressKey() const { return m_address_key; }
|
constexpr KProcessAddress GetAddressKey() const { return m_address_key; }
|
||||||
constexpr u32 GetAddressKeyValue() const { return m_address_key_value; }
|
constexpr u32 GetAddressKeyValue() const { return m_address_key_value; }
|
||||||
constexpr void SetAddressKey(KProcessAddress key) { m_address_key = key; }
|
constexpr void SetAddressKey(KProcessAddress key) { MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr); m_address_key = key; }
|
||||||
constexpr void SetAddressKey(KProcessAddress key, u32 val) { m_address_key = key; m_address_key_value = val; }
|
constexpr void SetAddressKey(KProcessAddress key, u32 val) { MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr); m_address_key = key; m_address_key_value = val; }
|
||||||
|
|
||||||
constexpr void SetLockOwner(KThread *owner) { m_lock_owner = owner; }
|
constexpr void SetWaitingLockInfo(LockWithPriorityInheritanceInfo *lock) { m_waiting_lock_info = lock; }
|
||||||
constexpr KThread *GetLockOwner() const { return m_lock_owner; }
|
constexpr LockWithPriorityInheritanceInfo *GetWaitingLockInfo() { return m_waiting_lock_info; }
|
||||||
|
|
||||||
|
constexpr KThread *GetLockOwner() const { return m_waiting_lock_info != nullptr ? m_waiting_lock_info->GetOwner() : nullptr; }
|
||||||
|
|
||||||
constexpr void ClearWaitQueue() { m_wait_queue = nullptr; }
|
constexpr void ClearWaitQueue() { m_wait_queue = nullptr; }
|
||||||
|
|
||||||
@@ -529,8 +626,6 @@ namespace ams::kern {
|
|||||||
constexpr u32 *GetLightSessionData() const { return m_light_ipc_data; }
|
constexpr u32 *GetLightSessionData() const { return m_light_ipc_data; }
|
||||||
constexpr void SetLightSessionData(u32 *data) { m_light_ipc_data = data; }
|
constexpr void SetLightSessionData(u32 *data) { m_light_ipc_data = data; }
|
||||||
|
|
||||||
bool HasWaiters() const { return !m_waiter_list.empty(); }
|
|
||||||
|
|
||||||
constexpr s64 GetLastScheduledTick() const { return m_last_scheduled_tick; }
|
constexpr s64 GetLastScheduledTick() const { return m_last_scheduled_tick; }
|
||||||
constexpr void SetLastScheduledTick(s64 tick) { m_last_scheduled_tick = tick; }
|
constexpr void SetLastScheduledTick(s64 tick) { m_last_scheduled_tick = tick; }
|
||||||
|
|
||||||
|
|||||||
@@ -120,10 +120,6 @@ namespace ams::kern {
|
|||||||
return m_address == rhs;
|
return m_address == rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE bool operator!=(uintptr_t rhs) const {
|
|
||||||
return m_address != rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allow getting the address explicitly, for use in accessors. */
|
/* Allow getting the address explicitly, for use in accessors. */
|
||||||
constexpr ALWAYS_INLINE uintptr_t GetValue() const {
|
constexpr ALWAYS_INLINE uintptr_t GetValue() const {
|
||||||
return m_address;
|
return m_address;
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ namespace ams::kern {
|
|||||||
static constexpr s32 ExitWorkerPriority = 11;
|
static constexpr s32 ExitWorkerPriority = 11;
|
||||||
|
|
||||||
enum WorkerType {
|
enum WorkerType {
|
||||||
WorkerType_Exit,
|
WorkerType_ExitThread,
|
||||||
|
WorkerType_ExitProcess,
|
||||||
|
|
||||||
WorkerType_Count,
|
WorkerType_Count,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -164,8 +164,9 @@ namespace ams::kern {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename Derived, typename Base, bool SupportDynamicExpansion = false> requires std::derived_from<Base, KAutoObjectWithList>
|
template<typename Derived, typename Base, bool SupportDynamicExpansion = false>
|
||||||
class KAutoObjectWithSlabHeapAndContainer : public KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion> {
|
class KAutoObjectWithSlabHeapAndContainer : public KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion> {
|
||||||
|
static_assert(std::derived_from<Base, KAutoObjectWithList>);
|
||||||
private:
|
private:
|
||||||
static constinit inline KAutoObjectWithListContainer<Derived> s_container;
|
static constinit inline KAutoObjectWithListContainer<Derived> s_container;
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr inline u32 El0PsrMask = 0xFF0FFE20;
|
|
||||||
|
|
||||||
enum EsrEc : u32 {
|
enum EsrEc : u32 {
|
||||||
EsrEc_Unknown = 0b000000,
|
EsrEc_Unknown = 0b000000,
|
||||||
EsrEc_WaitForInterruptOrEvent = 0b000001,
|
EsrEc_WaitForInterruptOrEvent = 0b000001,
|
||||||
@@ -61,7 +59,9 @@ namespace ams::kern::arch::arm64 {
|
|||||||
EsrEc_BrkInstruction = 0b111100,
|
EsrEc_BrkInstruction = 0b111100,
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr u32 GetInstructionData(const KExceptionContext *context, u64 esr) {
|
|
||||||
|
|
||||||
|
u32 GetInstructionDataSupervisorMode(const KExceptionContext *context, u64 esr) {
|
||||||
/* Check for THUMB usermode */
|
/* Check for THUMB usermode */
|
||||||
if ((context->psr & 0x3F) == 0x30) {
|
if ((context->psr & 0x3F) == 0x30) {
|
||||||
u32 insn = *reinterpret_cast<u16 *>(context->pc & ~0x1);
|
u32 insn = *reinterpret_cast<u16 *>(context->pc & ~0x1);
|
||||||
@@ -76,6 +76,37 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 GetInstructionDataUserMode(const KExceptionContext *context) {
|
||||||
|
/* Check for THUMB usermode */
|
||||||
|
u32 insn = 0;
|
||||||
|
if ((context->psr & 0x3F) == 0x30) {
|
||||||
|
u16 insn_high = 0;
|
||||||
|
if (UserspaceAccess::CopyMemoryFromUser(std::addressof(insn_high), reinterpret_cast<u16 *>(context->pc & ~0x1), sizeof(insn_high))) {
|
||||||
|
insn = insn_high;
|
||||||
|
|
||||||
|
/* Check if the instruction was a THUMB mode branch prefix. */
|
||||||
|
if (((insn >> 11) & 0b11110) == 0b11110) {
|
||||||
|
u16 insn_low = 0;
|
||||||
|
if (UserspaceAccess::CopyMemoryFromUser(std::addressof(insn_low), reinterpret_cast<u16 *>((context->pc & ~0x1) + sizeof(u16)), sizeof(insn_low))) {
|
||||||
|
insn = (static_cast<u32>(insn_high) << 16) | (static_cast<u32>(insn_low) << 0);
|
||||||
|
} else {
|
||||||
|
insn = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
insn = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
u32 insn_value = 0;
|
||||||
|
if (UserspaceAccess::CopyMemoryFromUser(std::addressof(insn_value), reinterpret_cast<u32 *>(context->pc), sizeof(insn_value))) {
|
||||||
|
insn = insn_value;
|
||||||
|
} else {
|
||||||
|
insn = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return insn;
|
||||||
|
}
|
||||||
|
|
||||||
void HandleUserException(KExceptionContext *context, u64 esr, u64 far, u64 afsr0, u64 afsr1, u32 data) {
|
void HandleUserException(KExceptionContext *context, u64 esr, u64 far, u64 afsr0, u64 afsr1, u32 data) {
|
||||||
KProcess &cur_process = GetCurrentProcess();
|
KProcess &cur_process = GetCurrentProcess();
|
||||||
bool should_process_user_exception = KTargetSystem::IsUserExceptionHandlersEnabled();
|
bool should_process_user_exception = KTargetSystem::IsUserExceptionHandlersEnabled();
|
||||||
@@ -134,7 +165,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
info->sp = context->sp;
|
info->sp = context->sp;
|
||||||
info->lr = context->x[30];
|
info->lr = context->x[30];
|
||||||
info->pc = context->pc;
|
info->pc = context->pc;
|
||||||
info->pstate = (context->psr & El0PsrMask);
|
info->pstate = (context->psr & cpu::El0Aarch64PsrMask);
|
||||||
info->afsr0 = afsr0;
|
info->afsr0 = afsr0;
|
||||||
info->afsr1 = afsr1;
|
info->afsr1 = afsr1;
|
||||||
info->esr = esr;
|
info->esr = esr;
|
||||||
@@ -151,7 +182,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
info->pc = context->pc;
|
info->pc = context->pc;
|
||||||
info->flags = 1;
|
info->flags = 1;
|
||||||
|
|
||||||
info->status_64.pstate = (context->psr & El0PsrMask);
|
info->status_64.pstate = (context->psr & cpu::El0Aarch32PsrMask);
|
||||||
info->status_64.afsr0 = afsr0;
|
info->status_64.afsr0 = afsr0;
|
||||||
info->status_64.afsr1 = afsr1;
|
info->status_64.afsr1 = afsr1;
|
||||||
info->status_64.esr = esr;
|
info->status_64.esr = esr;
|
||||||
@@ -192,6 +223,13 @@ namespace ams::kern::arch::arm64 {
|
|||||||
type = ams::svc::ExceptionType_InstructionAbort;
|
type = ams::svc::ExceptionType_InstructionAbort;
|
||||||
break;
|
break;
|
||||||
case EsrEc_DataAbortEl0:
|
case EsrEc_DataAbortEl0:
|
||||||
|
/* If esr.IFSC is "Alignment Fault", return UnalignedData instead of DataAbort. */
|
||||||
|
if ((esr & 0x3F) == 0b100001) {
|
||||||
|
type = ams::svc::ExceptionType_UnalignedData;
|
||||||
|
} else {
|
||||||
|
type = ams::svc::ExceptionType_DataAbort;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
type = ams::svc::ExceptionType_DataAbort;
|
type = ams::svc::ExceptionType_DataAbort;
|
||||||
break;
|
break;
|
||||||
@@ -231,73 +269,71 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
{
|
{
|
||||||
/* Collect additional information based on the ec. */
|
/* Collect additional information based on the ec. */
|
||||||
ams::svc::DebugException exception;
|
uintptr_t params[3] = {};
|
||||||
uintptr_t param2 = 0;
|
|
||||||
uintptr_t param3 = 0;
|
|
||||||
switch (ec) {
|
switch (ec) {
|
||||||
case EsrEc_Unknown:
|
case EsrEc_Unknown:
|
||||||
case EsrEc_IllegalExecution:
|
case EsrEc_IllegalExecution:
|
||||||
case EsrEc_BkptInstruction:
|
case EsrEc_BkptInstruction:
|
||||||
case EsrEc_BrkInstruction:
|
case EsrEc_BrkInstruction:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_UndefinedInstruction;
|
params[0] = ams::svc::DebugException_UndefinedInstruction;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
param3 = data;
|
params[2] = data;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_PcAlignmentFault:
|
case EsrEc_PcAlignmentFault:
|
||||||
case EsrEc_SpAlignmentFault:
|
case EsrEc_SpAlignmentFault:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_AlignmentFault;
|
params[0] = ams::svc::DebugException_AlignmentFault;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_Svc32:
|
case EsrEc_Svc32:
|
||||||
case EsrEc_Svc64:
|
case EsrEc_Svc64:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_UndefinedSystemCall;
|
params[0] = ams::svc::DebugException_UndefinedSystemCall;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
param3 = (esr & 0xFF);
|
params[2] = (esr & 0xFF);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_BreakPointEl0:
|
case EsrEc_BreakPointEl0:
|
||||||
case EsrEc_SoftwareStepEl0:
|
case EsrEc_SoftwareStepEl0:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_BreakPoint;
|
params[0] = ams::svc::DebugException_BreakPoint;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
param3 = ams::svc::BreakPointType_HardwareInstruction;
|
params[2] = ams::svc::BreakPointType_HardwareInstruction;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_WatchPointEl0:
|
case EsrEc_WatchPointEl0:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_BreakPoint;
|
params[0] = ams::svc::DebugException_BreakPoint;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
param3 = ams::svc::BreakPointType_HardwareData;
|
params[2] = ams::svc::BreakPointType_HardwareData;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_SErrorInterrupt:
|
case EsrEc_SErrorInterrupt:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_MemorySystemError;
|
params[0] = ams::svc::DebugException_MemorySystemError;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_InstructionAbortEl0:
|
case EsrEc_InstructionAbortEl0:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_InstructionAbort;
|
params[0] = ams::svc::DebugException_InstructionAbort;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_DataAbortEl0:
|
case EsrEc_DataAbortEl0:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_DataAbort;
|
params[0] = ams::svc::DebugException_DataAbort;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process the debug event. */
|
/* Process the debug event. */
|
||||||
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, exception, param2, param3);
|
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params));
|
||||||
|
|
||||||
/* If we should stop processing the exception, do so. */
|
/* If we should stop processing the exception, do so. */
|
||||||
if (svc::ResultStopProcessingException::Includes(result)) {
|
if (svc::ResultStopProcessingException::Includes(result)) {
|
||||||
@@ -342,7 +378,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
/* If the SVC is handled, handle it. */
|
/* If the SVC is handled, handle it. */
|
||||||
if (!svc::ResultNotHandled::Includes(result)) {
|
if (!svc::ResultNotHandled::Includes(result)) {
|
||||||
/* If we successfully enter jit debug, stop processing the exception. */
|
/* If we successfully enter jit debug, stop processing the exception. */
|
||||||
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, exception, param2, param3)) {
|
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, static_cast<ams::svc::DebugException>(params[0]), params[1], params[2])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -399,7 +435,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
e_ctx->x[30] = info.info64.lr;
|
e_ctx->x[30] = info.info64.lr;
|
||||||
e_ctx->sp = info.info64.sp;
|
e_ctx->sp = info.info64.sp;
|
||||||
e_ctx->pc = info.info64.pc;
|
e_ctx->pc = info.info64.pc;
|
||||||
e_ctx->psr = (info.info64.pstate & El0PsrMask) | (e_ctx->psr & ~El0PsrMask);
|
e_ctx->psr = (info.info64.pstate & cpu::El0Aarch64PsrMask) | (e_ctx->psr & ~cpu::El0Aarch64PsrMask);
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < util::size(info.info32.r); ++i) {
|
for (size_t i = 0; i < util::size(info.info32.r); ++i) {
|
||||||
e_ctx->x[i] = info.info32.r[i];
|
e_ctx->x[i] = info.info32.r[i];
|
||||||
@@ -407,7 +443,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
e_ctx->x[14] = info.info32.lr;
|
e_ctx->x[14] = info.info32.lr;
|
||||||
e_ctx->x[13] = info.info32.sp;
|
e_ctx->x[13] = info.info32.sp;
|
||||||
e_ctx->pc = info.info32.pc;
|
e_ctx->pc = info.info32.pc;
|
||||||
e_ctx->psr = (info.info32.status_64.pstate & El0PsrMask) | (e_ctx->psr & ~El0PsrMask);
|
e_ctx->psr = (info.info32.status_64.pstate & cpu::El0Aarch32PsrMask) | (e_ctx->psr & ~cpu::El0Aarch32PsrMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note that PC was adjusted. */
|
/* Note that PC was adjusted. */
|
||||||
@@ -422,58 +458,56 @@ namespace ams::kern::arch::arm64 {
|
|||||||
GetCurrentThread().RestoreDebugParams(std::addressof(far), std::addressof(esr), std::addressof(data));
|
GetCurrentThread().RestoreDebugParams(std::addressof(far), std::addressof(esr), std::addressof(data));
|
||||||
|
|
||||||
/* Collect additional information based on the ec. */
|
/* Collect additional information based on the ec. */
|
||||||
ams::svc::DebugException exception;
|
uintptr_t params[3] = {};
|
||||||
uintptr_t param2 = 0;
|
|
||||||
uintptr_t param3 = 0;
|
|
||||||
switch ((esr >> 26) & 0x3F) {
|
switch ((esr >> 26) & 0x3F) {
|
||||||
case EsrEc_Unknown:
|
case EsrEc_Unknown:
|
||||||
case EsrEc_IllegalExecution:
|
case EsrEc_IllegalExecution:
|
||||||
case EsrEc_BkptInstruction:
|
case EsrEc_BkptInstruction:
|
||||||
case EsrEc_BrkInstruction:
|
case EsrEc_BrkInstruction:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_UndefinedInstruction;
|
params[0] = ams::svc::DebugException_UndefinedInstruction;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
param3 = data;
|
params[2] = data;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_PcAlignmentFault:
|
case EsrEc_PcAlignmentFault:
|
||||||
case EsrEc_SpAlignmentFault:
|
case EsrEc_SpAlignmentFault:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_AlignmentFault;
|
params[0] = ams::svc::DebugException_AlignmentFault;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_Svc32:
|
case EsrEc_Svc32:
|
||||||
case EsrEc_Svc64:
|
case EsrEc_Svc64:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_UndefinedSystemCall;
|
params[0] = ams::svc::DebugException_UndefinedSystemCall;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
param3 = (esr & 0xFF);
|
params[2] = (esr & 0xFF);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_SErrorInterrupt:
|
case EsrEc_SErrorInterrupt:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_MemorySystemError;
|
params[0] = ams::svc::DebugException_MemorySystemError;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_InstructionAbortEl0:
|
case EsrEc_InstructionAbortEl0:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_InstructionAbort;
|
params[0] = ams::svc::DebugException_InstructionAbort;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_DataAbortEl0:
|
case EsrEc_DataAbortEl0:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_DataAbort;
|
params[0] = ams::svc::DebugException_DataAbort;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process the debug event. */
|
/* Process the debug event. */
|
||||||
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, exception, param2, param3);
|
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params));
|
||||||
|
|
||||||
/* If the SVC is handled, handle it. */
|
/* If the SVC is handled, handle it. */
|
||||||
if (!svc::ResultNotHandled::Includes(result)) {
|
if (!svc::ResultNotHandled::Includes(result)) {
|
||||||
@@ -483,7 +517,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If we successfully enter jit debug, restore. */
|
/* If we successfully enter jit debug, restore. */
|
||||||
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, exception, param2, param3)) {
|
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, static_cast<ams::svc::DebugException>(params[0]), params[1], params[2])) {
|
||||||
svc::RestoreContext(reinterpret_cast<uintptr_t>(e_ctx));
|
svc::RestoreContext(reinterpret_cast<uintptr_t>(e_ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -507,9 +541,10 @@ namespace ams::kern::arch::arm64 {
|
|||||||
MESOSPHERE_ASSERT(!KInterruptManager::AreInterruptsEnabled());
|
MESOSPHERE_ASSERT(!KInterruptManager::AreInterruptsEnabled());
|
||||||
|
|
||||||
/* Retrieve information about the exception. */
|
/* Retrieve information about the exception. */
|
||||||
const u64 esr = cpu::GetEsrEl1();
|
const bool is_user_mode = (context->psr & 0xF) == 0;
|
||||||
const u64 afsr0 = cpu::GetAfsr0El1();
|
const u64 esr = cpu::GetEsrEl1();
|
||||||
const u64 afsr1 = cpu::GetAfsr1El1();
|
const u64 afsr0 = cpu::GetAfsr0El1();
|
||||||
|
const u64 afsr1 = cpu::GetAfsr1El1();
|
||||||
u64 far = 0;
|
u64 far = 0;
|
||||||
u32 data = 0;
|
u32 data = 0;
|
||||||
|
|
||||||
@@ -520,7 +555,12 @@ namespace ams::kern::arch::arm64 {
|
|||||||
case EsrEc_BkptInstruction:
|
case EsrEc_BkptInstruction:
|
||||||
case EsrEc_BrkInstruction:
|
case EsrEc_BrkInstruction:
|
||||||
far = context->pc;
|
far = context->pc;
|
||||||
data = GetInstructionData(context, esr);
|
/* NOTE: Nintendo always calls GetInstructionDataUserMode. */
|
||||||
|
if (is_user_mode) {
|
||||||
|
data = GetInstructionDataUserMode(context);
|
||||||
|
} else {
|
||||||
|
data = GetInstructionDataSupervisorMode(context, esr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_Svc32:
|
case EsrEc_Svc32:
|
||||||
if (context->psr & 0x20) {
|
if (context->psr & 0x20) {
|
||||||
@@ -549,7 +589,6 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
/* Verify that spsr's M is allowable (EL0t). */
|
/* Verify that spsr's M is allowable (EL0t). */
|
||||||
{
|
{
|
||||||
const bool is_user_mode = (context->psr & 0xF) == 0;
|
|
||||||
if (is_user_mode) {
|
if (is_user_mode) {
|
||||||
/* If the user disable count is set, we may need to pin the current thread. */
|
/* If the user disable count is set, we may need to pin the current thread. */
|
||||||
if (GetCurrentThread().GetUserDisableCount() != 0 && GetCurrentProcess().GetPinnedThread(GetCurrentCoreId()) == nullptr) {
|
if (GetCurrentThread().GetUserDisableCount() != 0 && GetCurrentProcess().GetPinnedThread(GetCurrentCoreId()) == nullptr) {
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
static_assert(ForbiddenWatchPointFlagsMask == 0xFFFFFFFF00F0E006ul);
|
static_assert(ForbiddenWatchPointFlagsMask == 0xFFFFFFFF00F0E006ul);
|
||||||
|
|
||||||
constexpr inline u32 El0PsrMask = 0xFF0FFE20;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t KDebug::GetProgramCounter(const KThread &thread) {
|
uintptr_t KDebug::GetProgramCounter(const KThread &thread) {
|
||||||
@@ -104,7 +102,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
out->lr = e_ctx->x[30];
|
out->lr = e_ctx->x[30];
|
||||||
out->sp = e_ctx->sp;
|
out->sp = e_ctx->sp;
|
||||||
out->pc = e_ctx->pc;
|
out->pc = e_ctx->pc;
|
||||||
out->pstate = (e_ctx->psr & El0PsrMask);
|
out->pstate = (e_ctx->psr & cpu::El0Aarch64PsrMask);
|
||||||
|
|
||||||
/* Adjust PC if we should. */
|
/* Adjust PC if we should. */
|
||||||
if (e_ctx->write == 0 && thread->IsCallingSvc()) {
|
if (e_ctx->write == 0 && thread->IsCallingSvc()) {
|
||||||
@@ -119,7 +117,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
out->lr = 0;
|
out->lr = 0;
|
||||||
out->sp = 0;
|
out->sp = 0;
|
||||||
out->pc = e_ctx->pc;
|
out->pc = e_ctx->pc;
|
||||||
out->pstate = (e_ctx->psr & El0PsrMask);
|
out->pstate = (e_ctx->psr & cpu::El0Aarch32PsrMask);
|
||||||
|
|
||||||
/* Adjust PC if we should. */
|
/* Adjust PC if we should. */
|
||||||
if (e_ctx->write == 0 && thread->IsCallingSvc()) {
|
if (e_ctx->write == 0 && thread->IsCallingSvc()) {
|
||||||
@@ -166,7 +164,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
e_ctx->x[30] = ctx.lr;
|
e_ctx->x[30] = ctx.lr;
|
||||||
e_ctx->sp = ctx.sp;
|
e_ctx->sp = ctx.sp;
|
||||||
e_ctx->pc = ctx.pc;
|
e_ctx->pc = ctx.pc;
|
||||||
e_ctx->psr = ((ctx.pstate & El0PsrMask) | (e_ctx->psr & ~El0PsrMask));
|
e_ctx->psr = ((ctx.pstate & cpu::El0Aarch64PsrMask) | (e_ctx->psr & ~cpu::El0Aarch64PsrMask));
|
||||||
e_ctx->tpidr = ctx.tpidr;
|
e_ctx->tpidr = ctx.tpidr;
|
||||||
} else {
|
} else {
|
||||||
e_ctx->x[13] = static_cast<u32>(ctx.r[13]);
|
e_ctx->x[13] = static_cast<u32>(ctx.r[13]);
|
||||||
@@ -174,7 +172,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
e_ctx->x[30] = 0;
|
e_ctx->x[30] = 0;
|
||||||
e_ctx->sp = 0;
|
e_ctx->sp = 0;
|
||||||
e_ctx->pc = static_cast<u32>(ctx.pc);
|
e_ctx->pc = static_cast<u32>(ctx.pc);
|
||||||
e_ctx->psr = ((ctx.pstate & El0PsrMask) | (e_ctx->psr & ~El0PsrMask));
|
e_ctx->psr = ((ctx.pstate & cpu::El0Aarch32PsrMask) | (e_ctx->psr & ~cpu::El0Aarch32PsrMask));
|
||||||
e_ctx->tpidr = ctx.tpidr;
|
e_ctx->tpidr = ctx.tpidr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +249,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result KDebug::BreakIfAttached(ams::svc::BreakReason break_reason, uintptr_t address, size_t size) {
|
Result KDebug::BreakIfAttached(ams::svc::BreakReason break_reason, uintptr_t address, size_t size) {
|
||||||
R_RETURN(KDebugBase::OnDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_UserBreak, GetProgramCounter(GetCurrentThread()), break_reason, address, size));
|
const uintptr_t params[5] = { ams::svc::DebugException_UserBreak, GetProgramCounter(GetCurrentThread()), break_reason, address, size };
|
||||||
|
R_RETURN(KDebugBase::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MESOSPHERE_SET_HW_BREAK_POINT(ID, FLAGS, VALUE) \
|
#define MESOSPHERE_SET_HW_BREAK_POINT(ID, FLAGS, VALUE) \
|
||||||
@@ -366,7 +365,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
value = 0;
|
value = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the watchkpoint. */
|
/* Set the watchpoint. */
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case ams::svc::HardwareBreakPointRegisterName_D0: MESOSPHERE_SET_HW_WATCH_POINT( 0, flags, value); break;
|
case ams::svc::HardwareBreakPointRegisterName_D0: MESOSPHERE_SET_HW_WATCH_POINT( 0, flags, value); break;
|
||||||
case ams::svc::HardwareBreakPointRegisterName_D1: MESOSPHERE_SET_HW_WATCH_POINT( 1, flags, value); break;
|
case ams::svc::HardwareBreakPointRegisterName_D1: MESOSPHERE_SET_HW_WATCH_POINT( 1, flags, value); break;
|
||||||
|
|||||||
@@ -207,10 +207,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
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, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
Result KPageTable::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
||||||
/* The input ID isn't actually used. */
|
|
||||||
MESOSPHERE_UNUSED(id);
|
|
||||||
|
|
||||||
/* Get an ASID */
|
/* Get an ASID */
|
||||||
m_asid = g_asid_manager.Reserve();
|
m_asid = g_asid_manager.Reserve();
|
||||||
ON_RESULT_FAILURE { g_asid_manager.Release(m_asid); };
|
ON_RESULT_FAILURE { g_asid_manager.Release(m_asid); };
|
||||||
@@ -225,10 +222,10 @@ namespace ams::kern::arch::arm64 {
|
|||||||
ON_RESULT_FAILURE_2 { m_manager->Free(new_table); };
|
ON_RESULT_FAILURE_2 { m_manager->Free(new_table); };
|
||||||
|
|
||||||
/* Initialize our base table. */
|
/* Initialize our base table. */
|
||||||
const size_t as_width = GetAddressSpaceWidth(as_type);
|
const size_t as_width = GetAddressSpaceWidth(flags);
|
||||||
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, system_resource, resource_limit));
|
R_TRY(KPageTableBase::InitializeForProcess(flags, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, system_resource, resource_limit));
|
||||||
|
|
||||||
/* Note that we've updated the table (since we created it). */
|
/* Note that we've updated the table (since we created it). */
|
||||||
this->NoteUpdated();
|
this->NoteUpdated();
|
||||||
@@ -239,9 +236,15 @@ namespace ams::kern::arch::arm64 {
|
|||||||
/* Only process tables should be finalized. */
|
/* Only process tables should be finalized. */
|
||||||
MESOSPHERE_ASSERT(!this->IsKernel());
|
MESOSPHERE_ASSERT(!this->IsKernel());
|
||||||
|
|
||||||
|
/* NOTE: Here Nintendo calls an unknown OnFinalize function. */
|
||||||
|
/* this->OnFinalize(); */
|
||||||
|
|
||||||
/* Note that we've updated (to ensure we're synchronized). */
|
/* Note that we've updated (to ensure we're synchronized). */
|
||||||
this->NoteUpdated();
|
this->NoteUpdated();
|
||||||
|
|
||||||
|
/* NOTE: Here Nintendo calls a second unknown OnFinalize function. */
|
||||||
|
/* this->OnFinalize2(); */
|
||||||
|
|
||||||
/* Free all pages in the table. */
|
/* Free all pages in the table. */
|
||||||
{
|
{
|
||||||
/* Get implementation objects. */
|
/* Get implementation objects. */
|
||||||
@@ -255,7 +258,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
/* Begin the traversal. */
|
/* Begin the traversal. */
|
||||||
TraversalContext context;
|
TraversalContext context;
|
||||||
TraversalEntry cur_entry = { .phys_addr = Null<KPhysicalAddress>, .block_size = 0, .sw_reserved_bits = 0 };
|
TraversalEntry cur_entry = { .phys_addr = Null<KPhysicalAddress>, .block_size = 0, .sw_reserved_bits = 0, .attr = 0 };
|
||||||
bool cur_valid = false;
|
bool cur_valid = false;
|
||||||
TraversalEntry next_entry;
|
TraversalEntry next_entry;
|
||||||
bool next_valid;
|
bool next_valid;
|
||||||
@@ -265,7 +268,9 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
/* Iterate over entries. */
|
/* Iterate over entries. */
|
||||||
while (true) {
|
while (true) {
|
||||||
if ((!next_valid && !cur_valid) || (next_valid && cur_valid && next_entry.phys_addr == cur_entry.phys_addr + cur_entry.block_size)) {
|
/* NOTE: Nintendo really does check next_entry.attr == (cur_entry.attr != 0)...but attr is always zero as of 18.0.0, and this is "probably" for the new console or debug-only anyway, */
|
||||||
|
/* so we'll implement the weird logic verbatim even though it doesn't match the GetContiguousRange logic. */
|
||||||
|
if ((!next_valid && !cur_valid) || (next_valid && cur_valid && next_entry.phys_addr == cur_entry.phys_addr + cur_entry.block_size && next_entry.attr == (cur_entry.attr ? 1 : 0))) {
|
||||||
cur_entry.block_size += next_entry.block_size;
|
cur_entry.block_size += next_entry.block_size;
|
||||||
} else {
|
} else {
|
||||||
if (cur_valid && IsHeapPhysicalAddressForFinalize(cur_entry.phys_addr)) {
|
if (cur_valid && IsHeapPhysicalAddressForFinalize(cur_entry.phys_addr)) {
|
||||||
@@ -348,7 +353,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(virt_addr), PageSize));
|
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(virt_addr), PageSize));
|
||||||
MESOSPHERE_ASSERT(this->ContainsPages(virt_addr, num_pages));
|
MESOSPHERE_ASSERT(this->ContainsPages(virt_addr, num_pages));
|
||||||
|
|
||||||
if (operation == OperationType_Map || operation == OperationType_MapFirst) {
|
if (operation == OperationType_Map) {
|
||||||
MESOSPHERE_ABORT_UNLESS(is_pa_valid);
|
MESOSPHERE_ABORT_UNLESS(is_pa_valid);
|
||||||
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize));
|
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize));
|
||||||
} else {
|
} else {
|
||||||
@@ -375,12 +380,13 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case OperationType_Map:
|
case OperationType_Map:
|
||||||
case OperationType_MapFirst:
|
R_RETURN(this->MapContiguous(virt_addr, phys_addr, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, page_list, reuse_ll));
|
||||||
R_RETURN(this->MapContiguous(virt_addr, phys_addr, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, operation != OperationType_MapFirst, page_list, reuse_ll));
|
|
||||||
case OperationType_ChangePermissions:
|
case OperationType_ChangePermissions:
|
||||||
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, false, page_list, reuse_ll));
|
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, false, false, page_list, reuse_ll));
|
||||||
case OperationType_ChangePermissionsAndRefresh:
|
case OperationType_ChangePermissionsAndRefresh:
|
||||||
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, true, page_list, reuse_ll));
|
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, true, false, page_list, reuse_ll));
|
||||||
|
case OperationType_ChangePermissionsAndRefreshAndFlush:
|
||||||
|
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, true, true, page_list, reuse_ll));
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,7 +403,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
auto entry_template = this->GetEntryTemplate(properties);
|
auto entry_template = this->GetEntryTemplate(properties);
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case OperationType_MapGroup:
|
case OperationType_MapGroup:
|
||||||
R_RETURN(this->MapGroup(virt_addr, page_group, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, page_list, reuse_ll));
|
case OperationType_MapFirstGroup:
|
||||||
|
R_RETURN(this->MapGroup(virt_addr, page_group, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, operation != OperationType_MapFirstGroup, page_list, reuse_ll));
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -754,7 +761,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll) {
|
Result KPageTable::MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll) {
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
/* Cache initial addresses for use on cleanup. */
|
/* Cache initial addresses for use on cleanup. */
|
||||||
@@ -825,21 +832,17 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
/* Open references to the pages, if we should. */
|
/* Open references to the pages, if we should. */
|
||||||
if (IsHeapPhysicalAddress(orig_phys_addr)) {
|
if (IsHeapPhysicalAddress(orig_phys_addr)) {
|
||||||
if (not_first) {
|
Kernel::GetMemoryManager().Open(orig_phys_addr, num_pages);
|
||||||
Kernel::GetMemoryManager().Open(orig_phys_addr, num_pages);
|
|
||||||
} else {
|
|
||||||
Kernel::GetMemoryManager().OpenFirst(orig_phys_addr, num_pages);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll) {
|
Result KPageTable::MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll) {
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
/* We want to maintain a new reference to every page in the group. */
|
/* We want to maintain a new reference to every page in the group. */
|
||||||
KScopedPageGroup spg(pg);
|
KScopedPageGroup spg(pg, not_first);
|
||||||
|
|
||||||
/* Cache initial address for use on cleanup. */
|
/* Cache initial address for use on cleanup. */
|
||||||
const KProcessAddress orig_virt_addr = virt_addr;
|
const KProcessAddress orig_virt_addr = virt_addr;
|
||||||
@@ -1233,7 +1236,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
R_RETURN(this->SeparatePagesImpl(virt_addr, block_size, page_list, reuse_ll));
|
R_RETURN(this->SeparatePagesImpl(virt_addr, block_size, page_list, reuse_ll));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, PageLinkedList *page_list, bool reuse_ll) {
|
Result KPageTable::ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, bool flush_mapping, PageLinkedList *page_list, bool reuse_ll) {
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
/* Separate pages before we change permissions. */
|
/* Separate pages before we change permissions. */
|
||||||
@@ -1451,8 +1454,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
KScopedSchedulerLock sl;
|
KScopedSchedulerLock sl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finally, apply the changes as directed, flushing the mappings before they're applied. */
|
/* Finally, apply the changes as directed, flushing the mappings before they're applied (if we should). */
|
||||||
ApplyEntryTemplate(entry_template, ApplyOption_FlushDataCache);
|
ApplyEntryTemplate(entry_template, flush_mapping ? ApplyOption_FlushDataCache : ApplyOption_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We've succeeded, now perform what coalescing we can. */
|
/* We've succeeded, now perform what coalescing we can. */
|
||||||
|
|||||||
@@ -46,12 +46,14 @@ namespace ams::kern::arch::arm64 {
|
|||||||
out_entry->block_size = L3BlockSize;
|
out_entry->block_size = L3BlockSize;
|
||||||
}
|
}
|
||||||
out_entry->sw_reserved_bits = l3_entry->GetSoftwareReservedBits();
|
out_entry->sw_reserved_bits = l3_entry->GetSoftwareReservedBits();
|
||||||
|
out_entry->attr = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
out_entry->phys_addr = Null<KPhysicalAddress>;
|
out_entry->phys_addr = Null<KPhysicalAddress>;
|
||||||
out_entry->block_size = L3BlockSize;
|
out_entry->block_size = L3BlockSize;
|
||||||
out_entry->sw_reserved_bits = 0;
|
out_entry->sw_reserved_bits = 0;
|
||||||
|
out_entry->attr = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,6 +71,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
out_entry->block_size = L2BlockSize;
|
out_entry->block_size = L2BlockSize;
|
||||||
}
|
}
|
||||||
out_entry->sw_reserved_bits = l2_entry->GetSoftwareReservedBits();
|
out_entry->sw_reserved_bits = l2_entry->GetSoftwareReservedBits();
|
||||||
|
out_entry->attr = 0;
|
||||||
|
|
||||||
/* Set the output context. */
|
/* Set the output context. */
|
||||||
out_context->l3_entry = nullptr;
|
out_context->l3_entry = nullptr;
|
||||||
@@ -79,6 +82,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
out_entry->phys_addr = Null<KPhysicalAddress>;
|
out_entry->phys_addr = Null<KPhysicalAddress>;
|
||||||
out_entry->block_size = L2BlockSize;
|
out_entry->block_size = L2BlockSize;
|
||||||
out_entry->sw_reserved_bits = 0;
|
out_entry->sw_reserved_bits = 0;
|
||||||
|
out_entry->attr = 0;
|
||||||
|
|
||||||
out_context->l3_entry = nullptr;
|
out_context->l3_entry = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -108,6 +113,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
out_entry->phys_addr = Null<KPhysicalAddress>;
|
out_entry->phys_addr = Null<KPhysicalAddress>;
|
||||||
out_entry->block_size = L1BlockSize;
|
out_entry->block_size = L1BlockSize;
|
||||||
out_entry->sw_reserved_bits = 0;
|
out_entry->sw_reserved_bits = 0;
|
||||||
|
out_entry->attr = 0;
|
||||||
|
|
||||||
out_context->l2_entry = nullptr;
|
out_context->l2_entry = nullptr;
|
||||||
out_context->l3_entry = nullptr;
|
out_context->l3_entry = nullptr;
|
||||||
return false;
|
return false;
|
||||||
@@ -119,6 +126,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
out_entry->phys_addr = Null<KPhysicalAddress>;
|
out_entry->phys_addr = Null<KPhysicalAddress>;
|
||||||
out_entry->block_size = L1BlockSize;
|
out_entry->block_size = L1BlockSize;
|
||||||
out_entry->sw_reserved_bits = 0;
|
out_entry->sw_reserved_bits = 0;
|
||||||
|
out_entry->attr = 0;
|
||||||
out_context->l1_entry = m_table + m_num_entries;
|
out_context->l1_entry = m_table + m_num_entries;
|
||||||
out_context->l2_entry = nullptr;
|
out_context->l2_entry = nullptr;
|
||||||
out_context->l3_entry = nullptr;
|
out_context->l3_entry = nullptr;
|
||||||
@@ -220,6 +228,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
out_entry->phys_addr = Null<KPhysicalAddress>;
|
out_entry->phys_addr = Null<KPhysicalAddress>;
|
||||||
out_entry->block_size = L1BlockSize;
|
out_entry->block_size = L1BlockSize;
|
||||||
out_entry->sw_reserved_bits = 0;
|
out_entry->sw_reserved_bits = 0;
|
||||||
|
out_entry->attr = 0;
|
||||||
context->l1_entry = m_table + m_num_entries;
|
context->l1_entry = m_table + m_num_entries;
|
||||||
context->l2_entry = nullptr;
|
context->l2_entry = nullptr;
|
||||||
context->l3_entry = nullptr;
|
context->l3_entry = nullptr;
|
||||||
@@ -353,12 +362,12 @@ namespace ams::kern::arch::arm64 {
|
|||||||
l1_entry->IsPrivilegedExecuteNever(),
|
l1_entry->IsPrivilegedExecuteNever(),
|
||||||
l1_entry->IsContiguous(),
|
l1_entry->IsContiguous(),
|
||||||
!l1_entry->IsGlobal(),
|
!l1_entry->IsGlobal(),
|
||||||
static_cast<int>(l1_entry->GetAccessFlag()),
|
static_cast<int>(l1_entry->GetAccessFlagInteger()),
|
||||||
static_cast<unsigned int>(l1_entry->GetShareable()),
|
static_cast<unsigned int>(l1_entry->GetShareableInteger()),
|
||||||
l1_entry->IsReadOnly(),
|
l1_entry->IsReadOnly(),
|
||||||
l1_entry->IsUserAccessible(),
|
l1_entry->IsUserAccessible(),
|
||||||
l1_entry->IsNonSecure(),
|
l1_entry->IsNonSecure(),
|
||||||
static_cast<int>(l1_entry->GetPageAttribute()),
|
static_cast<int>(l1_entry->GetPageAttributeInteger()),
|
||||||
l1_entry->IsHeadMergeDisabled(),
|
l1_entry->IsHeadMergeDisabled(),
|
||||||
l1_entry->IsHeadAndBodyMergeDisabled(),
|
l1_entry->IsHeadAndBodyMergeDisabled(),
|
||||||
l1_entry->IsTailMergeDisabled());
|
l1_entry->IsTailMergeDisabled());
|
||||||
@@ -398,12 +407,12 @@ namespace ams::kern::arch::arm64 {
|
|||||||
l2_entry->IsPrivilegedExecuteNever(),
|
l2_entry->IsPrivilegedExecuteNever(),
|
||||||
l2_entry->IsContiguous(),
|
l2_entry->IsContiguous(),
|
||||||
!l2_entry->IsGlobal(),
|
!l2_entry->IsGlobal(),
|
||||||
static_cast<int>(l2_entry->GetAccessFlag()),
|
static_cast<int>(l2_entry->GetAccessFlagInteger()),
|
||||||
static_cast<unsigned int>(l2_entry->GetShareable()),
|
static_cast<unsigned int>(l2_entry->GetShareableInteger()),
|
||||||
l2_entry->IsReadOnly(),
|
l2_entry->IsReadOnly(),
|
||||||
l2_entry->IsUserAccessible(),
|
l2_entry->IsUserAccessible(),
|
||||||
l2_entry->IsNonSecure(),
|
l2_entry->IsNonSecure(),
|
||||||
static_cast<int>(l2_entry->GetPageAttribute()),
|
static_cast<int>(l2_entry->GetPageAttributeInteger()),
|
||||||
l2_entry->IsHeadMergeDisabled(),
|
l2_entry->IsHeadMergeDisabled(),
|
||||||
l2_entry->IsHeadAndBodyMergeDisabled(),
|
l2_entry->IsHeadAndBodyMergeDisabled(),
|
||||||
l2_entry->IsTailMergeDisabled());
|
l2_entry->IsTailMergeDisabled());
|
||||||
@@ -443,12 +452,12 @@ namespace ams::kern::arch::arm64 {
|
|||||||
l3_entry->IsPrivilegedExecuteNever(),
|
l3_entry->IsPrivilegedExecuteNever(),
|
||||||
l3_entry->IsContiguous(),
|
l3_entry->IsContiguous(),
|
||||||
!l3_entry->IsGlobal(),
|
!l3_entry->IsGlobal(),
|
||||||
static_cast<int>(l3_entry->GetAccessFlag()),
|
static_cast<int>(l3_entry->GetAccessFlagInteger()),
|
||||||
static_cast<unsigned int>(l3_entry->GetShareable()),
|
static_cast<unsigned int>(l3_entry->GetShareableInteger()),
|
||||||
l3_entry->IsReadOnly(),
|
l3_entry->IsReadOnly(),
|
||||||
l3_entry->IsUserAccessible(),
|
l3_entry->IsUserAccessible(),
|
||||||
l3_entry->IsNonSecure(),
|
l3_entry->IsNonSecure(),
|
||||||
static_cast<int>(l3_entry->GetPageAttribute()),
|
static_cast<int>(l3_entry->GetPageAttributeInteger()),
|
||||||
l3_entry->IsHeadMergeDisabled(),
|
l3_entry->IsHeadMergeDisabled(),
|
||||||
l3_entry->IsHeadAndBodyMergeDisabled(),
|
l3_entry->IsHeadAndBodyMergeDisabled(),
|
||||||
l3_entry->IsTailMergeDisabled());
|
l3_entry->IsTailMergeDisabled());
|
||||||
|
|||||||
@@ -18,12 +18,8 @@
|
|||||||
namespace ams::kern::arch::arm64 {
|
namespace ams::kern::arch::arm64 {
|
||||||
|
|
||||||
void KSupervisorPageTable::Initialize(s32 core_id) {
|
void KSupervisorPageTable::Initialize(s32 core_id) {
|
||||||
/* Get the identity mapping ttbr0. */
|
/* Verify that sctlr_el1 has the wxn bit set. */
|
||||||
m_ttbr0_identity[core_id] = cpu::GetTtbr0El1();
|
MESOSPHERE_ABORT_UNLESS(cpu::SystemControlRegisterAccessor().GetWxn());
|
||||||
|
|
||||||
/* Set sctlr_el1 */
|
|
||||||
cpu::SystemControlRegisterAccessor().SetWxn(true).Store();
|
|
||||||
cpu::EnsureInstructionConsistency();
|
|
||||||
|
|
||||||
/* Invalidate the entire TLB. */
|
/* Invalidate the entire TLB. */
|
||||||
cpu::InvalidateEntireTlb();
|
cpu::InvalidateEntireTlb();
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ namespace ams::kern::arch::arm64 {
|
|||||||
/* Send KDebug event for this thread's creation. */
|
/* Send KDebug event for this thread's creation. */
|
||||||
{
|
{
|
||||||
KScopedInterruptEnable ei;
|
KScopedInterruptEnable ei;
|
||||||
KDebug::OnDebugEvent(ams::svc::DebugEvent_CreateThread, GetCurrentThread().GetId(), GetInteger(GetCurrentThread().GetThreadLocalRegionAddress()));
|
|
||||||
|
const uintptr_t params[2] = { GetCurrentThread().GetId(), GetInteger(GetCurrentThread().GetThreadLocalRegionAddress()) };
|
||||||
|
KDebug::OnDebugEvent(ams::svc::DebugEvent_CreateThread, params, util::size(params));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle any pending dpc. */
|
/* Handle any pending dpc. */
|
||||||
@@ -40,8 +42,6 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr inline u32 El0PsrMask = 0xFF0FFE20;
|
|
||||||
|
|
||||||
ALWAYS_INLINE bool IsFpuEnabled() {
|
ALWAYS_INLINE bool IsFpuEnabled() {
|
||||||
return cpu::ArchitecturalFeatureAccessControlRegisterAccessor().IsFpEnabled();
|
return cpu::ArchitecturalFeatureAccessControlRegisterAccessor().IsFpEnabled();
|
||||||
}
|
}
|
||||||
@@ -96,8 +96,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
/* SP */
|
/* SP */
|
||||||
/* | */
|
/* | */
|
||||||
/* v */
|
/* v */
|
||||||
/* | u64 argument | u64 entrypoint | KThread::StackParameters (size 0x130) | */
|
/* | u64 argument | u64 entrypoint | KThread::StackParameters (size 0x140) | */
|
||||||
static_assert(sizeof(KThread::StackParameters) == 0x130);
|
static_assert(sizeof(KThread::StackParameters) == 0x140);
|
||||||
|
|
||||||
u64 *stack = GetPointer<u64>(sp);
|
u64 *stack = GetPointer<u64>(sp);
|
||||||
*(--stack) = GetInteger(pc);
|
*(--stack) = GetInteger(pc);
|
||||||
@@ -191,7 +191,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
out->lr = e_ctx->x[30];
|
out->lr = e_ctx->x[30];
|
||||||
out->sp = e_ctx->sp;
|
out->sp = e_ctx->sp;
|
||||||
out->pc = e_ctx->pc;
|
out->pc = e_ctx->pc;
|
||||||
out->pstate = e_ctx->psr & El0PsrMask;
|
out->pstate = e_ctx->psr & cpu::El0Aarch64PsrMask;
|
||||||
|
|
||||||
/* Get the thread's general purpose registers. */
|
/* Get the thread's general purpose registers. */
|
||||||
if (thread->IsCallingSvc()) {
|
if (thread->IsCallingSvc()) {
|
||||||
@@ -227,7 +227,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
} else {
|
} else {
|
||||||
/* Set special registers. */
|
/* Set special registers. */
|
||||||
out->pc = static_cast<u32>(e_ctx->pc);
|
out->pc = static_cast<u32>(e_ctx->pc);
|
||||||
out->pstate = e_ctx->psr & El0PsrMask;
|
out->pstate = e_ctx->psr & cpu::El0Aarch32PsrMask;
|
||||||
|
|
||||||
/* Get the thread's general purpose registers. */
|
/* Get the thread's general purpose registers. */
|
||||||
for (size_t i = 0; i < 15; ++i) {
|
for (size_t i = 0; i < 15; ++i) {
|
||||||
|
|||||||
@@ -596,8 +596,11 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory32BitEPvPKvm:
|
|||||||
/* Save our return address. */
|
/* Save our return address. */
|
||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
|
/* Prepare return address for read failure. */
|
||||||
|
adr x10, 4f
|
||||||
|
|
||||||
1: /* Set our return address so that on read failure we continue as though we read -1. */
|
1: /* Set our return address so that on read failure we continue as though we read -1. */
|
||||||
adr x30, 4f
|
mov x30, x10
|
||||||
|
|
||||||
/* Read the word from io. */
|
/* Read the word from io. */
|
||||||
ldtr w9, [x5]
|
ldtr w9, [x5]
|
||||||
@@ -643,8 +646,11 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory16BitEPvPKvm:
|
|||||||
/* Save our return address. */
|
/* Save our return address. */
|
||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
|
/* Prepare return address for read failure. */
|
||||||
|
adr x10, 4f
|
||||||
|
|
||||||
1: /* Set our return address so that on read failure we continue as though we read -1. */
|
1: /* Set our return address so that on read failure we continue as though we read -1. */
|
||||||
adr x30, 4f
|
mov x30, x10
|
||||||
|
|
||||||
/* Read the word from io. */
|
/* Read the word from io. */
|
||||||
ldtrh w9, [x5]
|
ldtrh w9, [x5]
|
||||||
@@ -690,8 +696,11 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess16ReadIoMemory8BitEPvPKvm:
|
|||||||
/* Save our return address. */
|
/* Save our return address. */
|
||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
|
/* Prepare return address for read failure. */
|
||||||
|
adr x10, 4f
|
||||||
|
|
||||||
1: /* Set our return address so that on read failure we continue as though we read -1. */
|
1: /* Set our return address so that on read failure we continue as though we read -1. */
|
||||||
adr x30, 4f
|
mov x30, x10
|
||||||
|
|
||||||
/* Read the word from io. */
|
/* Read the word from io. */
|
||||||
ldtrb w9, [x5]
|
ldtrb w9, [x5]
|
||||||
@@ -737,11 +746,14 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory32BitEPvPKvm:
|
|||||||
/* Save our return address. */
|
/* Save our return address. */
|
||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
|
/* Prepare return address for failure. */
|
||||||
|
adr x10, 2f
|
||||||
|
|
||||||
1: /* Read the word from normal memory. */
|
1: /* Read the word from normal memory. */
|
||||||
ldtr w9, [x5]
|
ldtr w9, [x5]
|
||||||
|
|
||||||
/* Set our return address so that on read failure we continue. */
|
/* Set our return address so that on failure we continue. */
|
||||||
adr x30, 2f
|
mov x30, x10
|
||||||
|
|
||||||
/* Write the word to io. */
|
/* Write the word to io. */
|
||||||
sttr w9, [x5]
|
sttr w9, [x5]
|
||||||
@@ -779,11 +791,14 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory16BitEPvPKvm:
|
|||||||
/* Save our return address. */
|
/* Save our return address. */
|
||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
|
/* Prepare return address for failure. */
|
||||||
|
adr x10, 2f
|
||||||
|
|
||||||
1: /* Read the word from normal memory. */
|
1: /* Read the word from normal memory. */
|
||||||
ldtrh w9, [x5]
|
ldtrh w9, [x5]
|
||||||
|
|
||||||
/* Set our return address so that on read failure we continue. */
|
/* Set our return address so that on failure we continue. */
|
||||||
adr x30, 2f
|
mov x30, x10
|
||||||
|
|
||||||
/* Write the word to io. */
|
/* Write the word to io. */
|
||||||
sttrh w9, [x5]
|
sttrh w9, [x5]
|
||||||
@@ -821,11 +836,14 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17WriteIoMemory8BitEPvPKvm:
|
|||||||
/* Save our return address. */
|
/* Save our return address. */
|
||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
|
/* Prepare return address for failure. */
|
||||||
|
adr x10, 2f
|
||||||
|
|
||||||
1: /* Read the word from normal memory. */
|
1: /* Read the word from normal memory. */
|
||||||
ldtrb w9, [x5]
|
ldtrb w9, [x5]
|
||||||
|
|
||||||
/* Set our return address so that on read failure we continue. */
|
/* Set our return address so that on failure we continue. */
|
||||||
adr x30, 2f
|
mov x30, x10
|
||||||
|
|
||||||
/* Write the word to io. */
|
/* Write the word to io. */
|
||||||
sttrb w9, [x5]
|
sttrb w9, [x5]
|
||||||
|
|||||||
@@ -130,4 +130,4 @@ _ZN3ams4kern3svc14RestoreContextEm:
|
|||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
ERET_WITH_SPECULATION_BARRIER
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ _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, #(THREAD_LOCAL_REGION_DISABLE_COUNT)]
|
add x10, x10, #(THREAD_LOCAL_REGION_DISABLE_COUNT)
|
||||||
|
ldtrh w10, [x10]
|
||||||
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. */
|
||||||
@@ -194,7 +195,7 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
|
|||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
ERET_WITH_SPECULATION_BARRIER
|
||||||
|
|
||||||
5: /* Return from SVC. */
|
5: /* Return from SVC. */
|
||||||
|
|
||||||
@@ -297,7 +298,7 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
|
|||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
ERET_WITH_SPECULATION_BARRIER
|
||||||
|
|
||||||
/* ams::kern::arch::arm64::SvcHandler32() */
|
/* ams::kern::arch::arm64::SvcHandler32() */
|
||||||
.section .text._ZN3ams4kern4arch5arm6412SvcHandler32Ev, "ax", %progbits
|
.section .text._ZN3ams4kern4arch5arm6412SvcHandler32Ev, "ax", %progbits
|
||||||
@@ -352,7 +353,8 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
|
|||||||
|
|
||||||
/* 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, #(THREAD_LOCAL_REGION_DISABLE_COUNT)]
|
add x10, x10, #(THREAD_LOCAL_REGION_DISABLE_COUNT)
|
||||||
|
ldtrh w10, [x10]
|
||||||
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. */
|
||||||
@@ -467,7 +469,7 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
|
|||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
ERET_WITH_SPECULATION_BARRIER
|
||||||
|
|
||||||
5: /* Return from SVC. */
|
5: /* Return from SVC. */
|
||||||
|
|
||||||
@@ -547,4 +549,4 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
|
|||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
ERET_WITH_SPECULATION_BARRIER
|
||||||
|
|||||||
@@ -142,10 +142,10 @@ namespace ams::kern::svc {
|
|||||||
/* Get the target firmware. */
|
/* Get the target firmware. */
|
||||||
const auto target_fw = kern::GetTargetFirmware();
|
const auto target_fw = kern::GetTargetFirmware();
|
||||||
|
|
||||||
/* 10.0.0 broke the ABI for QueryIoMapping. */
|
/* 10.0.0 broke the ABI for QueryIoMapping, and renamed it to QueryMemoryMapping. */
|
||||||
if (target_fw < TargetFirmware_10_0_0) {
|
if (target_fw < TargetFirmware_10_0_0) {
|
||||||
if (table_64) { ::ams::kern::svc::PatchSvcTableEntry(table_64, svc::SvcId_QueryIoMapping, LegacyQueryIoMapping::Call64); }
|
if (table_64) { ::ams::kern::svc::PatchSvcTableEntry(table_64, svc::SvcId_QueryMemoryMapping, LegacyQueryIoMapping::Call64); }
|
||||||
if (table_64_from_32) { ::ams::kern::svc::PatchSvcTableEntry(table_64_from_32, svc::SvcId_QueryIoMapping, LegacyQueryIoMapping::Call64From32); }
|
if (table_64_from_32) { ::ams::kern::svc::PatchSvcTableEntry(table_64_from_32, svc::SvcId_QueryMemoryMapping, LegacyQueryIoMapping::Call64From32); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 6.0.0 broke the ABI for GetFutureThreadInfo, and renamed it to GetDebugFutureThreadInfo. */
|
/* 6.0.0 broke the ABI for GetFutureThreadInfo, and renamed it to GetDebugFutureThreadInfo. */
|
||||||
|
|||||||
@@ -1133,17 +1133,17 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
size_t cur_size;
|
size_t cur_size;
|
||||||
{
|
{
|
||||||
/* Get the current contiguous range. */
|
/* Get the current contiguous range. */
|
||||||
KPageTableBase::MemoryRange contig_range = { .address = Null<KPhysicalAddress>, .size = 0 };
|
KPageTableBase::MemoryRange contig_range;
|
||||||
R_TRY(page_table->OpenMemoryRangeForMapDeviceAddressSpace(std::addressof(contig_range), process_address + mapped_size, size - mapped_size, ConvertToKMemoryPermission(device_perm), is_aligned));
|
R_TRY(page_table->OpenMemoryRangeForMapDeviceAddressSpace(std::addressof(contig_range), process_address + mapped_size, size - mapped_size, ConvertToKMemoryPermission(device_perm), is_aligned));
|
||||||
|
|
||||||
/* Ensure we close the range when we're done. */
|
/* Ensure we close the range when we're done. */
|
||||||
ON_SCOPE_EXIT { contig_range.Close(); };
|
ON_SCOPE_EXIT { contig_range.Close(); };
|
||||||
|
|
||||||
/* Get the current size. */
|
/* Get the current size. */
|
||||||
cur_size = contig_range.size;
|
cur_size = contig_range.GetSize();
|
||||||
|
|
||||||
/* Map the device page. */
|
/* Map the device page. */
|
||||||
R_TRY(this->MapDevicePage(contig_range.address, contig_range.size, cur_addr, device_perm));
|
R_TRY(this->MapDevicePage(contig_range.GetAddress(), cur_size, cur_addr, device_perm));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
@@ -1288,7 +1288,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
MESOSPHERE_ASSERT(((device_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. */
|
/* 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 = { .address = Null<KPhysicalAddress>, .size = 0 };
|
KPageTableBase::MemoryRange contig_range;
|
||||||
if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), process_address, size))) {
|
if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), process_address, size))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1300,8 +1300,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
/* Walk the directory. */
|
/* Walk the directory. */
|
||||||
KProcessAddress cur_process_address = process_address;
|
KProcessAddress cur_process_address = process_address;
|
||||||
size_t remaining_size = size;
|
size_t remaining_size = size;
|
||||||
KPhysicalAddress cur_phys_address = contig_range.address;
|
KPhysicalAddress cur_phys_address = contig_range.GetAddress();
|
||||||
size_t remaining_in_range = contig_range.size;
|
size_t remaining_in_range = contig_range.GetSize();
|
||||||
bool first = true;
|
bool first = true;
|
||||||
u32 first_attr = 0;
|
u32 first_attr = 0;
|
||||||
while (remaining_size > 0) {
|
while (remaining_size > 0) {
|
||||||
@@ -1347,8 +1347,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
}
|
}
|
||||||
range_open = true;
|
range_open = true;
|
||||||
|
|
||||||
cur_phys_address = contig_range.address;
|
cur_phys_address = contig_range.GetAddress();
|
||||||
remaining_in_range = contig_range.size;
|
remaining_in_range = contig_range.GetSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the physical address is expected. */
|
/* Check that the physical address is expected. */
|
||||||
@@ -1390,8 +1390,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
}
|
}
|
||||||
range_open = true;
|
range_open = true;
|
||||||
|
|
||||||
cur_phys_address = contig_range.address;
|
cur_phys_address = contig_range.GetAddress();
|
||||||
remaining_in_range = contig_range.size;
|
remaining_in_range = contig_range.GetSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the physical address is expected, and there's enough in the range. */
|
/* Check that the physical address is expected, and there's enough in the range. */
|
||||||
|
|||||||
@@ -18,6 +18,12 @@
|
|||||||
#include "kern_secure_monitor.hpp"
|
#include "kern_secure_monitor.hpp"
|
||||||
#include "kern_lps_driver.hpp"
|
#include "kern_lps_driver.hpp"
|
||||||
|
|
||||||
|
namespace ams::kern::init {
|
||||||
|
|
||||||
|
void StartOtherCore(const ams::kern::init::KInitArguments *init_args);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace ams::kern::board::nintendo::nx {
|
namespace ams::kern::board::nintendo::nx {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -26,7 +32,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
class SavedSystemRegisters {
|
class SavedSystemRegisters {
|
||||||
private:
|
private:
|
||||||
u64 ttbr0_el1;
|
u64 ttbr0_el1;
|
||||||
u64 tcr_el1;
|
|
||||||
u64 elr_el1;
|
u64 elr_el1;
|
||||||
u64 sp_el0;
|
u64 sp_el0;
|
||||||
u64 spsr_el1;
|
u64 spsr_el1;
|
||||||
@@ -67,15 +72,10 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
constinit KLightLock g_request_lock;
|
constinit KLightLock g_request_lock;
|
||||||
constinit KLightLock g_cv_lock;
|
constinit KLightLock g_cv_lock;
|
||||||
constinit KLightConditionVariable g_cv{util::ConstantInitialize};
|
constinit KLightConditionVariable g_cv{util::ConstantInitialize};
|
||||||
constinit KPhysicalAddress g_sleep_buffer_phys_addrs[cpu::NumCores];
|
|
||||||
alignas(1_KB) constinit u64 g_sleep_buffers[cpu::NumCores][1_KB / sizeof(u64)];
|
alignas(1_KB) constinit u64 g_sleep_buffers[cpu::NumCores][1_KB / sizeof(u64)];
|
||||||
|
constinit ams::kern::init::KInitArguments g_sleep_init_arguments[cpu::NumCores];
|
||||||
constinit SavedSystemRegisters g_sleep_system_registers[cpu::NumCores] = {};
|
constinit SavedSystemRegisters g_sleep_system_registers[cpu::NumCores] = {};
|
||||||
|
|
||||||
void PowerOnCpu(int core_id, KPhysicalAddress entry_phys_addr, u64 context_id) {
|
|
||||||
/* Request the secure monitor power on the core. */
|
|
||||||
::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor, true>(cpu::MultiprocessorAffinityRegisterAccessor().GetCpuOnArgument() | core_id, GetInteger(entry_phys_addr), context_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitOtherCpuPowerOff() {
|
void WaitOtherCpuPowerOff() {
|
||||||
constexpr u64 PmcPhysicalAddress = 0x7000E400;
|
constexpr u64 PmcPhysicalAddress = 0x7000E400;
|
||||||
constexpr u32 PWRGATE_STATUS_CE123_MASK = ((1u << 3) - 1) << 9;
|
constexpr u32 PWRGATE_STATUS_CE123_MASK = ((1u << 3) - 1) << 9;
|
||||||
@@ -91,7 +91,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
void SavedSystemRegisters::Save() {
|
void SavedSystemRegisters::Save() {
|
||||||
/* Save system registers. */
|
/* Save system registers. */
|
||||||
this->ttbr0_el1 = cpu::GetTtbr0El1();
|
this->ttbr0_el1 = cpu::GetTtbr0El1();
|
||||||
this->tcr_el1 = cpu::GetTcrEl1();
|
|
||||||
this->tpidr_el0 = cpu::GetTpidrEl0();
|
this->tpidr_el0 = cpu::GetTpidrEl0();
|
||||||
this->elr_el1 = cpu::GetElrEl1();
|
this->elr_el1 = cpu::GetElrEl1();
|
||||||
this->sp_el0 = cpu::GetSpEl0();
|
this->sp_el0 = cpu::GetSpEl0();
|
||||||
@@ -407,7 +406,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
/* Restore system registers. */
|
/* Restore system registers. */
|
||||||
cpu::SetTtbr0El1 (this->ttbr0_el1);
|
cpu::SetTtbr0El1 (this->ttbr0_el1);
|
||||||
cpu::SetTcrEl1 (this->tcr_el1);
|
|
||||||
cpu::SetTpidrEl0 (this->tpidr_el0);
|
cpu::SetTpidrEl0 (this->tpidr_el0);
|
||||||
cpu::SetElrEl1 (this->elr_el1);
|
cpu::SetElrEl1 (this->elr_el1);
|
||||||
cpu::SetSpEl0 (this->sp_el0);
|
cpu::SetSpEl0 (this->sp_el0);
|
||||||
@@ -473,18 +471,20 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KSleepManager::ProcessRequests(uintptr_t buffer) {
|
void KSleepManager::ProcessRequests(uintptr_t sleep_buffer) {
|
||||||
const auto target_fw = GetTargetFirmware();
|
const auto target_fw = GetTargetFirmware();
|
||||||
const s32 core_id = GetCurrentCoreId();
|
const s32 core_id = GetCurrentCoreId();
|
||||||
KPhysicalAddress resume_entry_phys_addr = Null<KPhysicalAddress>;
|
|
||||||
|
ams::kern::init::KInitArguments * const init_args = g_sleep_init_arguments + core_id;
|
||||||
|
KPhysicalAddress start_core_phys_addr = Null<KPhysicalAddress>;
|
||||||
|
KPhysicalAddress init_args_phys_addr = Null<KPhysicalAddress>;
|
||||||
|
|
||||||
/* Get the physical addresses we'll need. */
|
/* Get the physical addresses we'll need. */
|
||||||
{
|
{
|
||||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(g_sleep_buffer_phys_addrs[core_id]), KProcessAddress(buffer)));
|
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(start_core_phys_addr), KProcessAddress(&::ams::kern::init::StartOtherCore)));
|
||||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(resume_entry_phys_addr), KProcessAddress(&::ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry)));
|
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(init_args_phys_addr), KProcessAddress(init_args)));
|
||||||
|
|
||||||
}
|
}
|
||||||
const KPhysicalAddress sleep_buffer_phys_addr = g_sleep_buffer_phys_addrs[core_id];
|
|
||||||
const u64 target_core_mask = (1ul << core_id);
|
const u64 target_core_mask = (1ul << core_id);
|
||||||
|
|
||||||
const bool use_legacy_lps_driver = target_fw < TargetFirmware_2_0_0;
|
const bool use_legacy_lps_driver = target_fw < TargetFirmware_2_0_0;
|
||||||
@@ -512,24 +512,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
/* Save the system registers for the current core. */
|
/* Save the system registers for the current core. */
|
||||||
g_sleep_system_registers[core_id].Save();
|
g_sleep_system_registers[core_id].Save();
|
||||||
|
|
||||||
/* Change the translation tables to use the kernel table. */
|
|
||||||
{
|
|
||||||
/* Get the current value of the translation control register. */
|
|
||||||
const u64 tcr = cpu::GetTcrEl1();
|
|
||||||
|
|
||||||
/* Disable translation table walks on tlb miss. */
|
|
||||||
cpu::TranslationControlRegisterAccessor(tcr).SetEpd0(true).Store();
|
|
||||||
cpu::EnsureInstructionConsistency();
|
|
||||||
|
|
||||||
/* Change the translation table base (ttbr0) to use the kernel table. */
|
|
||||||
cpu::SetTtbr0El1(Kernel::GetKernelPageTable().GetIdentityMapTtbr0(core_id));
|
|
||||||
cpu::EnsureInstructionConsistency();
|
|
||||||
|
|
||||||
/* Enable translation table walks on tlb miss. */
|
|
||||||
cpu::TranslationControlRegisterAccessor(tcr).SetEpd0(false).Store();
|
|
||||||
cpu::EnsureInstructionConsistency();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Invalidate the entire tlb. */
|
/* Invalidate the entire tlb. */
|
||||||
cpu::InvalidateEntireTlb();
|
cpu::InvalidateEntireTlb();
|
||||||
|
|
||||||
@@ -547,15 +529,30 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
/* Save the interrupt manager's state. */
|
/* Save the interrupt manager's state. */
|
||||||
Kernel::GetInterruptManager().Save(core_id);
|
Kernel::GetInterruptManager().Save(core_id);
|
||||||
|
|
||||||
|
/* Setup the initial arguments. */
|
||||||
|
{
|
||||||
|
/* Determine whether we're running on a cortex-a53 or a-57. */
|
||||||
|
cpu::MainIdRegisterAccessor midr_el1;
|
||||||
|
const auto implementer = midr_el1.GetImplementer();
|
||||||
|
const auto primary_part = midr_el1.GetPrimaryPartNumber();
|
||||||
|
const bool needs_cpu_ctlr = (implementer == cpu::MainIdRegisterAccessor::Implementer::ArmLimited) && (primary_part == cpu::MainIdRegisterAccessor::PrimaryPartNumber::CortexA57 || primary_part == cpu::MainIdRegisterAccessor::PrimaryPartNumber::CortexA53);
|
||||||
|
|
||||||
|
init_args->cpuactlr = needs_cpu_ctlr ? cpu::GetCpuActlrEl1() : 0;
|
||||||
|
init_args->cpuectlr = needs_cpu_ctlr ? cpu::GetCpuEctlrEl1() : 0;
|
||||||
|
init_args->sp = 0;
|
||||||
|
init_args->entrypoint = reinterpret_cast<uintptr_t>(::ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry);
|
||||||
|
init_args->argument = sleep_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
/* Ensure that all cores get to this point before continuing. */
|
/* Ensure that all cores get to this point before continuing. */
|
||||||
cpu::SynchronizeAllCores();
|
cpu::SynchronizeAllCores();
|
||||||
|
|
||||||
/* Log that the core is going to sleep. */
|
/* Log that the core is going to sleep. */
|
||||||
MESOSPHERE_LOG("Core[%d]: Going to sleep, buffer = %010lx\n", core_id, GetInteger(sleep_buffer_phys_addr));
|
MESOSPHERE_LOG("Core[%d]: Going to sleep, buffer = %010lx\n", core_id, sleep_buffer);
|
||||||
|
|
||||||
/* If we're on a core other than zero, we can just invoke the sleep handler. */
|
/* If we're on a core other than zero, we can just invoke the sleep handler. */
|
||||||
if (core_id != 0) {
|
if (core_id != 0) {
|
||||||
CpuSleepHandler(GetInteger(sleep_buffer_phys_addr), GetInteger(resume_entry_phys_addr));
|
CpuSleepHandler(sleep_buffer, GetInteger(start_core_phys_addr), GetInteger(init_args_phys_addr));
|
||||||
} else {
|
} else {
|
||||||
/* Wait for all other cores to be powered off. */
|
/* Wait for all other cores to be powered off. */
|
||||||
WaitOtherCpuPowerOff();
|
WaitOtherCpuPowerOff();
|
||||||
@@ -574,9 +571,9 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
/* Invoke the sleep handler. */
|
/* Invoke the sleep handler. */
|
||||||
if (!use_legacy_lps_driver) {
|
if (!use_legacy_lps_driver) {
|
||||||
/* When not using the legacy driver, invoke directly. */
|
/* When not using the legacy driver, invoke directly. */
|
||||||
CpuSleepHandler(GetInteger(sleep_buffer_phys_addr), GetInteger(resume_entry_phys_addr));
|
CpuSleepHandler(sleep_buffer, GetInteger(start_core_phys_addr), GetInteger(init_args_phys_addr));
|
||||||
} else {
|
} else {
|
||||||
lps::InvokeCpuSleepHandler(GetInteger(sleep_buffer_phys_addr), GetInteger(resume_entry_phys_addr));
|
lps::InvokeCpuSleepHandler(sleep_buffer, GetInteger(start_core_phys_addr), GetInteger(init_args_phys_addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore the debug log state. */
|
/* Restore the debug log state. */
|
||||||
@@ -586,8 +583,10 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
MESOSPHERE_LOG("Exiting SC7\n");
|
MESOSPHERE_LOG("Exiting SC7\n");
|
||||||
|
|
||||||
/* Wake up the other cores. */
|
/* Wake up the other cores. */
|
||||||
|
cpu::MultiprocessorAffinityRegisterAccessor mpidr;
|
||||||
|
const auto arg = mpidr.GetCpuOnArgument();
|
||||||
for (s32 i = 1; i < static_cast<s32>(cpu::NumCores); ++i) {
|
for (s32 i = 1; i < static_cast<s32>(cpu::NumCores); ++i) {
|
||||||
PowerOnCpu(i, resume_entry_phys_addr, GetInteger(g_sleep_buffer_phys_addrs[i]));
|
KSystemControl::Init::TurnOnCpu(arg | i, g_sleep_init_arguments + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,14 +22,12 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
private:
|
private:
|
||||||
static void ResumeEntry(uintptr_t arg);
|
static void ResumeEntry(uintptr_t arg);
|
||||||
|
|
||||||
static void InvalidateDataCacheForResumeEntry(uintptr_t level);
|
|
||||||
|
|
||||||
static void ProcessRequests(uintptr_t buffer);
|
static void ProcessRequests(uintptr_t buffer);
|
||||||
public:
|
public:
|
||||||
static void Initialize();
|
static void Initialize();
|
||||||
static void SleepSystem();
|
static void SleepSystem();
|
||||||
public:
|
public:
|
||||||
static void CpuSleepHandler(uintptr_t arg, uintptr_t entry);
|
static void CpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_args);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,14 +22,14 @@
|
|||||||
mov reg, #(((val) >> 0x00) & 0xFFFF); \
|
mov reg, #(((val) >> 0x00) & 0xFFFF); \
|
||||||
movk reg, #(((val) >> 0x10) & 0xFFFF), lsl#16
|
movk reg, #(((val) >> 0x10) & 0xFFFF), lsl#16
|
||||||
|
|
||||||
/* ams::kern::board::nintendo::nx::KSleepManager::CpuSleepHandler(uintptr_t arg, uintptr_t entry) */
|
/* ams::kern::board::nintendo::nx::KSleepManager::CpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_arg) */
|
||||||
.section .sleep._ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm, "ax", %progbits
|
.section .sleep._ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm, "ax", %progbits
|
||||||
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm
|
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm
|
||||||
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm, %function
|
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm, %function
|
||||||
_ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
|
_ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm:
|
||||||
/* Save arguments. */
|
/* Save arguments. */
|
||||||
mov x16, x0
|
mov x16, x1
|
||||||
mov x17, x1
|
mov x17, x2
|
||||||
|
|
||||||
/* Enable access to FPU registers. */
|
/* Enable access to FPU registers. */
|
||||||
mrs x1, cpacr_el1
|
mrs x1, cpacr_el1
|
||||||
@@ -74,28 +74,8 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
|
|||||||
stp q28, q29, [x0], #0x20
|
stp q28, q29, [x0], #0x20
|
||||||
stp q30, q31, [x0], #0x20
|
stp q30, q31, [x0], #0x20
|
||||||
|
|
||||||
/* Save cpuactlr/cpuectlr. */
|
/* Save tpidr/cntv_cval_el0. */
|
||||||
mrs x1, cpuectlr_el1
|
mrs x1, tpidr_el1
|
||||||
mrs x2, cpuactlr_el1
|
|
||||||
stp x1, x2, [x0], #0x10
|
|
||||||
|
|
||||||
/* Save ttbr0/ttbr1. */
|
|
||||||
mrs x1, ttbr0_el1
|
|
||||||
mrs x2, ttbr1_el1
|
|
||||||
stp x1, x2, [x0], #0x10
|
|
||||||
|
|
||||||
/* Save tcr/mair. */
|
|
||||||
mrs x1, tcr_el1
|
|
||||||
mrs x2, mair_el1
|
|
||||||
stp x1, x2, [x0], #0x10
|
|
||||||
|
|
||||||
/* Save sctlr/tpidr. */
|
|
||||||
mrs x1, sctlr_el1
|
|
||||||
mrs x2, tpidr_el1
|
|
||||||
stp x1, x2, [x0], #0x10
|
|
||||||
|
|
||||||
/* Save the virtual resumption entrypoint and cntv_cval_el0. */
|
|
||||||
adr x1, 77f
|
|
||||||
mrs x2, cntv_cval_el0
|
mrs x2, cntv_cval_el0
|
||||||
stp x1, x2, [x0], #0x10
|
stp x1, x2, [x0], #0x10
|
||||||
|
|
||||||
@@ -114,8 +94,8 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
|
|||||||
1: /* Suspend. */
|
1: /* Suspend. */
|
||||||
LOAD_IMMEDIATE_32(x0, 0xC4000001)
|
LOAD_IMMEDIATE_32(x0, 0xC4000001)
|
||||||
LOAD_IMMEDIATE_32(x1, 0x0201001B)
|
LOAD_IMMEDIATE_32(x1, 0x0201001B)
|
||||||
mov x2, x17
|
mov x2, x16
|
||||||
mov x3, x16
|
mov x3, x17
|
||||||
smc #1
|
smc #1
|
||||||
0: b 0b
|
0: b 0b
|
||||||
|
|
||||||
@@ -124,65 +104,6 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
|
|||||||
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm
|
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm
|
||||||
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, %function
|
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, %function
|
||||||
_ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm:
|
_ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm:
|
||||||
/* Mask interrupts. */
|
|
||||||
msr daifset, #0xF
|
|
||||||
|
|
||||||
/* Save the argument. */
|
|
||||||
mov x21, x0
|
|
||||||
|
|
||||||
/* Check that we're at the correct exception level. */
|
|
||||||
mrs x0, currentel
|
|
||||||
|
|
||||||
/* Check if we're EL1. */
|
|
||||||
cmp x0, #0x4
|
|
||||||
b.eq 3f
|
|
||||||
|
|
||||||
/* Check if we're EL2. */
|
|
||||||
cmp x0, #0x8
|
|
||||||
b.eq 2f
|
|
||||||
|
|
||||||
1: /* We're running at EL3. */
|
|
||||||
b 1b
|
|
||||||
|
|
||||||
2: /* We're running at EL2. */
|
|
||||||
b 2b
|
|
||||||
|
|
||||||
3: /* We're running at EL1. */
|
|
||||||
|
|
||||||
/* Invalidate the L1 cache. */
|
|
||||||
mov x0, #0
|
|
||||||
bl _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm
|
|
||||||
|
|
||||||
/* Get the current core id. */
|
|
||||||
mrs x0, mpidr_el1
|
|
||||||
and x0, x0, #0xFF
|
|
||||||
|
|
||||||
/* If we're on core0, we want to invalidate the L2 cache. */
|
|
||||||
cbnz x0, 4f
|
|
||||||
|
|
||||||
mov x0, #1
|
|
||||||
bl _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm
|
|
||||||
|
|
||||||
4: /* Invalidate the L1 cache. */
|
|
||||||
mov x0, #0
|
|
||||||
bl _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm
|
|
||||||
|
|
||||||
/* Invalidate the instruction cache. */
|
|
||||||
ic ialluis
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* Invalidate the entire tlb. */
|
|
||||||
tlbi vmalle1is
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* Switch to sp 1. */
|
|
||||||
msr spsel, #1
|
|
||||||
|
|
||||||
/* Prepare to restore the saved context. */
|
|
||||||
mov x0, x21
|
|
||||||
|
|
||||||
/* Enable access to FPU registers. */
|
/* Enable access to FPU registers. */
|
||||||
mrs x1, cpacr_el1
|
mrs x1, cpacr_el1
|
||||||
orr x1, x1, #0x100000
|
orr x1, x1, #0x100000
|
||||||
@@ -226,121 +147,12 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm:
|
|||||||
ldp q28, q29, [x0], #0x20
|
ldp q28, q29, [x0], #0x20
|
||||||
ldp q30, q31, [x0], #0x20
|
ldp q30, q31, [x0], #0x20
|
||||||
|
|
||||||
/* Restore cpuactlr/cpuectlr. */
|
/* Restore tpidr/cntv_cval_el0. */
|
||||||
ldp x1, x2, [x0], #0x10
|
ldp x1, x2, [x0], #0x10
|
||||||
mrs x3, cpuectlr_el1
|
msr tpidr_el1, x1
|
||||||
cmp x1, x3
|
msr cntv_cval_el0, x2
|
||||||
5: b.ne 5b
|
|
||||||
mrs x3, cpuactlr_el1
|
|
||||||
cmp x2, x3
|
|
||||||
6: b.ne 6b
|
|
||||||
|
|
||||||
/* Restore ttbr0/ttbr1. */
|
|
||||||
ldp x1, x2, [x0], #0x10
|
|
||||||
msr ttbr0_el1, x1
|
|
||||||
msr ttbr1_el1, x2
|
|
||||||
|
|
||||||
/* Restore tcr/mair. */
|
|
||||||
ldp x1, x2, [x0], #0x10
|
|
||||||
msr tcr_el1, x1
|
|
||||||
msr mair_el1, x2
|
|
||||||
|
|
||||||
/* Get sctlr, tpidr, the entrypoint, and cntv_cval_el0. */
|
|
||||||
ldp x1, x2, [x0], #0x10
|
|
||||||
ldp x3, x4, [x0], #0x10
|
|
||||||
|
|
||||||
/* Set the global context back into x18/tpidr. */
|
|
||||||
msr tpidr_el1, x2
|
|
||||||
msr cntv_cval_el0, x4
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* Restore sctlr with the wxn bit cleared. */
|
|
||||||
bic x2, x1, #0x80000
|
|
||||||
msr sctlr_el1, x2
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* Jump to the entrypoint. */
|
|
||||||
br x3
|
|
||||||
|
|
||||||
77: /* Virtual resumption entrypoint. */
|
|
||||||
|
|
||||||
/* Restore sctlr. */
|
|
||||||
msr sctlr_el1, x1
|
|
||||||
dsb sy
|
dsb sy
|
||||||
isb
|
isb
|
||||||
|
|
||||||
ret
|
/* Return. */
|
||||||
|
|
||||||
/* ams::kern::board::nintendo::nx::KSleepManager::InvalidateDataCacheForResumeEntry(uintptr_t level) */
|
|
||||||
.section .sleep._ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm, "ax", %progbits
|
|
||||||
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm
|
|
||||||
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm, %function
|
|
||||||
_ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm:
|
|
||||||
/* cpu::DataSynchronizationBarrier(); */
|
|
||||||
dsb sy
|
|
||||||
|
|
||||||
/* const u64 level_sel_value = level << 1; */
|
|
||||||
lsl x8, x0, #1
|
|
||||||
|
|
||||||
/* cpu::SetCsselrEl1(level_sel_value); */
|
|
||||||
msr csselr_el1, x8
|
|
||||||
|
|
||||||
/* cpu::InstructionMemoryBarrier(); */
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* CacheSizeIdAccessor ccsidr_el1; */
|
|
||||||
mrs x13, ccsidr_el1
|
|
||||||
|
|
||||||
/* const int num_ways = ccsidr_el1.GetAssociativity(); */
|
|
||||||
ubfx w10, w13, #3, #0xA
|
|
||||||
|
|
||||||
/* const int line_size = ccsidr_el1.GetLineSize(); */
|
|
||||||
and w11, w13, #7
|
|
||||||
|
|
||||||
/* const int num_sets = ccsidr_el1.GetNumberOfSets(); */
|
|
||||||
ubfx w13, w13, #0xD, #0xF
|
|
||||||
|
|
||||||
/* int way = 0; */
|
|
||||||
mov w9, wzr
|
|
||||||
|
|
||||||
/* const u64 set_shift = static_cast<u64>(line_size + 4); */
|
|
||||||
add w11, w11, #4
|
|
||||||
|
|
||||||
/* const u64 way_shift = static_cast<u64>(__builtin_clz(num_ways)); */
|
|
||||||
clz w12, w10
|
|
||||||
|
|
||||||
|
|
||||||
0: /* do { */
|
|
||||||
/* int set = 0; */
|
|
||||||
mov w14, wzr
|
|
||||||
|
|
||||||
/* const u64 way_value = (static_cast<u64>(way) << way_shift); */
|
|
||||||
lsl w15, w9, w12
|
|
||||||
|
|
||||||
1: /* do { */
|
|
||||||
|
|
||||||
/* const u64 isw_value = (static_cast<u64>(set) << set_shift) | way_value | level_sel_value; */
|
|
||||||
lsl w16, w14, w11
|
|
||||||
orr w16, w16, w15
|
|
||||||
sxtw x16, w16
|
|
||||||
orr x16, x16, x8
|
|
||||||
|
|
||||||
/* __asm__ __volatile__("dc isw, %0" :: "r"(isw_value) : "memory"); */
|
|
||||||
dc isw, x16
|
|
||||||
|
|
||||||
/* while (set <= num_sets); */
|
|
||||||
cmp w13, w14
|
|
||||||
add w14, w14, #1
|
|
||||||
b.ne 1b
|
|
||||||
|
|
||||||
/* while (way <= num_ways); */
|
|
||||||
cmp w9, w10
|
|
||||||
add w9, w9, #1
|
|
||||||
b.ne 0b
|
|
||||||
|
|
||||||
/* cpu::EnsureInstructionConsistency(); */
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
ret
|
ret
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
/* TODO: Move this into a header for the MC in general. */
|
/* TODO: Move this into a header for the MC in general. */
|
||||||
constexpr u32 MemoryControllerConfigurationRegister = 0x70019050;
|
constexpr u32 MemoryControllerConfigurationRegister = 0x70019050;
|
||||||
u32 config_value;
|
u32 config_value;
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(smc::init::ReadWriteRegister(&config_value, MemoryControllerConfigurationRegister, 0, 0));
|
smc::init::ReadWriteRegister(std::addressof(config_value), MemoryControllerConfigurationRegister, 0, 0);
|
||||||
return static_cast<size_t>(config_value & 0x3FFF) << 20;
|
return static_cast<size_t>(config_value & 0x3FFF) << 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,10 +367,14 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
|
size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
|
||||||
/* Verify that our minimum is at least as large as Nintendo's. */
|
/* Verify that our minimum is at least as large as Nintendo's. */
|
||||||
constexpr size_t MinimumSize = ::ams::svc::RequiredNonSecureSystemMemorySize;
|
constexpr size_t MinimumSizeWithFatal = ::ams::svc::RequiredNonSecureSystemMemorySizeWithFatal;
|
||||||
static_assert(MinimumSize >= 0x29C8000);
|
static_assert(MinimumSizeWithFatal >= 0x2C04000);
|
||||||
|
|
||||||
return MinimumSize;
|
constexpr size_t MinimumSizeWithoutFatal = ::ams::svc::RequiredNonSecureSystemMemorySize;
|
||||||
|
static_assert(MinimumSizeWithoutFatal >= 0x2A00000);
|
||||||
|
|
||||||
|
/* Include fatal in non-seure size on 16.0.0+. */
|
||||||
|
return kern::GetTargetFirmware() >= ams::TargetFirmware_16_0_0 ? MinimumSizeWithFatal : MinimumSizeWithoutFatal;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 KSystemControl::Init::GetDebugLogUartPort() {
|
u8 KSystemControl::Init::GetDebugLogUartPort() {
|
||||||
@@ -382,8 +386,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
return static_cast<u8>((value >> 32) & 0xFF);
|
return static_cast<u8>((value >> 32) & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KSystemControl::Init::CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
void KSystemControl::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor, false>(core_id, entrypoint, arg)) == 0);
|
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor>(core_id, entrypoint, arg)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Randomness for Initialization. */
|
/* Randomness for Initialization. */
|
||||||
@@ -398,40 +402,41 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
/* System Initialization. */
|
/* System Initialization. */
|
||||||
void KSystemControl::InitializePhase1() {
|
void KSystemControl::InitializePhase1() {
|
||||||
/* Initialize our random generator. */
|
/* Configure KTargetSystem. */
|
||||||
|
{
|
||||||
|
/* Set IsDebugMode. */
|
||||||
|
{
|
||||||
|
KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
|
||||||
|
|
||||||
|
/* If debug mode, we want to initialize uart logging. */
|
||||||
|
KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set Kernel Configuration. */
|
||||||
|
{
|
||||||
|
const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)};
|
||||||
|
|
||||||
|
KTargetSystem::EnableDebugMemoryFill(kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>());
|
||||||
|
KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>());
|
||||||
|
KTargetSystem::EnableDynamicResourceLimits(!kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>());
|
||||||
|
KTargetSystem::EnableUserPmuAccess(kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>());
|
||||||
|
|
||||||
|
g_call_smc_on_panic = kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set Kernel Debugging. */
|
||||||
|
{
|
||||||
|
/* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */
|
||||||
|
/* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */
|
||||||
|
KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize random and resource limit. */
|
||||||
{
|
{
|
||||||
u64 seed;
|
u64 seed;
|
||||||
smc::GenerateRandomBytes(std::addressof(seed), sizeof(seed));
|
smc::GenerateRandomBytes(std::addressof(seed), sizeof(seed));
|
||||||
s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
|
KSystemControlBase::InitializePhase1Base(seed);
|
||||||
s_initialized_random_generator = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set IsDebugMode. */
|
|
||||||
{
|
|
||||||
KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
|
|
||||||
|
|
||||||
/* If debug mode, we want to initialize uart logging. */
|
|
||||||
KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode());
|
|
||||||
KDebugLog::Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set Kernel Configuration. */
|
|
||||||
{
|
|
||||||
const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)};
|
|
||||||
|
|
||||||
KTargetSystem::EnableDebugMemoryFill(kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>());
|
|
||||||
KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>());
|
|
||||||
KTargetSystem::EnableDynamicResourceLimits(!kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>());
|
|
||||||
KTargetSystem::EnableUserPmuAccess(kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>());
|
|
||||||
|
|
||||||
g_call_smc_on_panic = kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set Kernel Debugging. */
|
|
||||||
{
|
|
||||||
/* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */
|
|
||||||
/* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */
|
|
||||||
KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure the Kernel Carveout region. */
|
/* Configure the Kernel Carveout region. */
|
||||||
@@ -441,9 +446,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
smc::ConfigureCarveout(0, carveout.GetAddress(), carveout.GetSize());
|
smc::ConfigureCarveout(0, carveout.GetAddress(), carveout.GetSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the system resource limit (and potentially other things). */
|
|
||||||
KSystemControlBase::InitializePhase1(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KSystemControl::InitializePhase2() {
|
void KSystemControl::InitializePhase2() {
|
||||||
@@ -599,8 +601,9 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
if (g_call_smc_on_panic) {
|
if (g_call_smc_on_panic) {
|
||||||
/* If we should, instruct the secure monitor to display a panic screen. */
|
/* If we should, instruct the secure monitor to display a panic screen. */
|
||||||
smc::Panic(0xF00);
|
smc::ShowError(0xF00);
|
||||||
}
|
}
|
||||||
|
|
||||||
AMS_INFINITE_LOOP();
|
AMS_INFINITE_LOOP();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user