Compare commits
161 Commits
1.4.0
...
1.6.0-prer
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -38,7 +38,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,93 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
## 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 = 9513a5412057b1f1bc44ed8e717c57c726763a88
|
||||||
parent = 99f6a96845b6097d50f5059eea9245d27876f26a
|
parent = e4d08ae0c5342cdb0875d164522a63ec9d233052
|
||||||
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 - 17.0.0**
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Arbitrary SDMMC backend selection
|
* Arbitrary SDMMC backend selection
|
||||||
|
|||||||
24
emummc/source/FS/FS_offsets.c
vendored
24
emummc/source/FS/FS_offsets.c
vendored
@@ -63,6 +63,12 @@
|
|||||||
#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 "../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 +143,12 @@ 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);
|
||||||
|
|
||||||
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 +246,18 @@ 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));
|
||||||
default:
|
default:
|
||||||
fatal_abort(Fatal_UnknownVersion);
|
fatal_abort(Fatal_UnknownVersion);
|
||||||
}
|
}
|
||||||
|
|||||||
9
emummc/source/FS/FS_versions.h
vendored
9
emummc/source/FS/FS_versions.h
vendored
@@ -92,6 +92,15 @@ 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_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__
|
||||||
@@ -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 0x43, 0xDB, 0x9D, 0x88, 0xDB, 0x38, 0xE9, 0xBF, 0x3D, 0xD7, 0x83, 0x39, 0xEF, 0xB1, 0x4F, 0xA7
|
||||||
|
|
||||||
/* 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 0x8D, 0xEE, 0x9E, 0x11, 0x36, 0x3A, 0x9B, 0x0A, 0x6A, 0xC7, 0xBB, 0xE9, 0xD1, 0x03, 0xF7, 0x80
|
||||||
|
|
||||||
/* 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,8 @@ _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. */
|
||||||
|
|
||||||
/* 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 +125,8 @@ _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. */
|
||||||
|
|
||||||
/* 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 +141,8 @@ _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. */
|
||||||
|
|
||||||
/* 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 +157,8 @@ _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. */
|
||||||
|
|
||||||
/* 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 +173,5 @@ _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. */
|
||||||
|
|||||||
@@ -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 == 17);
|
||||||
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[] = {
|
||||||
|
|||||||
@@ -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
|
0x8D, 0xEE, 0x9E, 0x11, 0x36, 0x3A, 0x9B, 0x0A, 0x6A, 0xC7, 0xBB, 0xE9, 0xD1, 0x03, 0xF7, 0x80
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
0x43, 0xDB, 0x9D, 0x88, 0xDB, 0x38, 0xE9, 0xBF, 0x3D, 0xD7, 0x83, 0x39, 0xEF, 0xB1, 0x4F, 0xA7
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
0x71, 0xB9, 0xA6, 0xC0, 0xFF, 0x97, 0x6B, 0x0C, 0xB4, 0x40, 0xB9, 0xD5, 0x81, 0x5D, 0x81, 0x90
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = {
|
||||||
@@ -69,6 +69,8 @@ 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. */
|
||||||
};
|
};
|
||||||
|
|
||||||
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 +86,8 @@ 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. */
|
||||||
};
|
};
|
||||||
|
|
||||||
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 +103,8 @@ 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. */
|
||||||
};
|
};
|
||||||
|
|
||||||
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 +123,8 @@ 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. */
|
||||||
};
|
};
|
||||||
|
|
||||||
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 +143,8 @@ 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. */
|
||||||
};
|
};
|
||||||
|
|
||||||
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 == 17);
|
||||||
if (key_generation >= pkg1::KeyGeneration_Count) {
|
if (key_generation >= pkg1::KeyGeneration_Count) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,6 +255,10 @@ 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;
|
||||||
}
|
}
|
||||||
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,15 @@ 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_Count,
|
FsVersion_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -231,13 +243,32 @@ 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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
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) {
|
||||||
@@ -643,6 +674,30 @@ 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;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -984,7 +1039,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);
|
||||||
|
|||||||
@@ -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 = 132558c33865f6a21f06caa31bdfc6b1f92bd9b2
|
||||||
parent = 8ce4f1961580a09381e486cc51c160a00fa86b88
|
parent = d389ef639ed2988325523f1d95f90030a3370541
|
||||||
method = merge
|
method = merge
|
||||||
cmdver = 0.4.1
|
cmdver = 0.4.1
|
||||||
|
|||||||
@@ -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 :=
|
||||||
|
|||||||
@@ -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,8 @@ 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_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 = 0x14;
|
||||||
|
|
||||||
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 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 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; }
|
||||||
|
|||||||
@@ -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 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) {
|
||||||
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(as_type, enable_aslr, enable_das_merge, 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) {
|
||||||
@@ -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(); }
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
@@ -34,8 +34,14 @@ namespace ams::kern {
|
|||||||
uintptr_t _08;
|
uintptr_t _08;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|||||||
@@ -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 {
|
||||||
@@ -175,16 +181,17 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -158,8 +158,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,26 @@ 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;
|
||||||
|
public:
|
||||||
|
constexpr MemoryRange() : m_address(Null<KPhysicalAddress>), m_size(0), m_heap(false) { /* ... */ }
|
||||||
|
|
||||||
void Close();
|
void Set(KPhysicalAddress address, size_t size, bool heap) {
|
||||||
|
m_address = address;
|
||||||
|
m_size = size;
|
||||||
|
m_heap = heap;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr KPhysicalAddress GetAddress() const { return m_address; }
|
||||||
|
constexpr size_t GetSize() const { return m_size; }
|
||||||
|
constexpr bool IsHeap() const { return m_heap; }
|
||||||
|
|
||||||
|
void Open();
|
||||||
|
void Close();
|
||||||
};
|
};
|
||||||
protected:
|
protected:
|
||||||
enum MemoryFillValue {
|
enum MemoryFillValue {
|
||||||
@@ -72,13 +87,14 @@ namespace ams::kern {
|
|||||||
};
|
};
|
||||||
|
|
||||||
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;
|
||||||
@@ -225,16 +241,20 @@ namespace ams::kern {
|
|||||||
|
|
||||||
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 +312,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,7 +326,7 @@ 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, KMemoryPermission perm);
|
||||||
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);
|
||||||
@@ -319,9 +340,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,15 +376,15 @@ 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 MapInsecureMemory(KProcessAddress address, size_t size);
|
||||||
@@ -391,12 +412,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);
|
||||||
|
|||||||
@@ -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,6 +46,8 @@ 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();
|
||||||
@@ -47,7 +55,7 @@ namespace ams::kern {
|
|||||||
static KPhysicalAddress GetKernelPhysicalBaseAddress(KPhysicalAddress base_address);
|
static KPhysicalAddress GetKernelPhysicalBaseAddress(KPhysicalAddress base_address);
|
||||||
static void GetInitialProcessBinaryLayout(InitialProcessBinaryLayout *out);
|
static void GetInitialProcessBinaryLayout(InitialProcessBinaryLayout *out);
|
||||||
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;
|
||||||
@@ -231,73 +262,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 +371,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 +428,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 +436,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 +451,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 +510,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 +534,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 +548,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 +582,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) \
|
||||||
|
|||||||
@@ -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 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) {
|
||||||
/* 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); };
|
||||||
@@ -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. */
|
||||||
@@ -348,7 +351,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 +378,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 +401,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 +759,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 +830,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 +1234,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 +1452,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. */
|
||||||
|
|||||||
@@ -353,12 +353,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 +398,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 +443,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
|
||||||
|
|||||||
@@ -194,7 +194,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 +297,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
|
||||||
@@ -467,7 +467,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 +547,4 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
|
|||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
ERET_WITH_SPECULATION_BARRIER
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,7 +386,7 @@ 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, false>(core_id, entrypoint, arg)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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() {
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ namespace ams::kern::board::nintendo::nx::lps {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry) {
|
void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_arg) {
|
||||||
/* Verify that we're allowed to perform suspension. */
|
/* Verify that we're allowed to perform suspension. */
|
||||||
MESOSPHERE_ABORT_UNLESS(g_lps_init_done);
|
MESOSPHERE_ABORT_UNLESS(g_lps_init_done);
|
||||||
MESOSPHERE_ABORT_UNLESS(GetCurrentCoreId() == 0);
|
MESOSPHERE_ABORT_UNLESS(GetCurrentCoreId() == 0);
|
||||||
@@ -416,7 +416,7 @@ namespace ams::kern::board::nintendo::nx::lps {
|
|||||||
Read(g_pmc_address + APBDEV_PMC_SCRATCH0);
|
Read(g_pmc_address + APBDEV_PMC_SCRATCH0);
|
||||||
|
|
||||||
/* Invoke the sleep hander. */
|
/* Invoke the sleep hander. */
|
||||||
KSleepManager::CpuSleepHandler(arg, entry);
|
KSleepManager::CpuSleepHandler(arg, entry, entry_arg);
|
||||||
|
|
||||||
/* Disable deep power down. */
|
/* Disable deep power down. */
|
||||||
Write(g_pmc_address + APBDEV_PMC_DPD_ENABLE, 0);
|
Write(g_pmc_address + APBDEV_PMC_DPD_ENABLE, 0);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
Result EnableSuspend(bool enable);
|
Result EnableSuspend(bool enable);
|
||||||
void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry);
|
void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_arg);
|
||||||
void ResumeBpmpFirmware();
|
void ResumeBpmpFirmware();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,13 @@ namespace ams::kern::init::Elf {
|
|||||||
void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic) {
|
void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic) {
|
||||||
uintptr_t dyn_rel = 0;
|
uintptr_t dyn_rel = 0;
|
||||||
uintptr_t dyn_rela = 0;
|
uintptr_t dyn_rela = 0;
|
||||||
|
uintptr_t dyn_relr = 0;
|
||||||
uintptr_t rel_count = 0;
|
uintptr_t rel_count = 0;
|
||||||
uintptr_t rela_count = 0;
|
uintptr_t rela_count = 0;
|
||||||
|
uintptr_t relr_sz = 0;
|
||||||
uintptr_t rel_ent = 0;
|
uintptr_t rel_ent = 0;
|
||||||
uintptr_t rela_ent = 0;
|
uintptr_t rela_ent = 0;
|
||||||
|
uintptr_t relr_ent = 0;
|
||||||
|
|
||||||
/* Iterate over all tags, identifying important extents. */
|
/* Iterate over all tags, identifying important extents. */
|
||||||
for (const Dyn *cur_entry = dynamic; cur_entry->GetTag() != DT_NULL; cur_entry++) {
|
for (const Dyn *cur_entry = dynamic; cur_entry->GetTag() != DT_NULL; cur_entry++) {
|
||||||
@@ -35,43 +38,99 @@ namespace ams::kern::init::Elf {
|
|||||||
case DT_RELA:
|
case DT_RELA:
|
||||||
dyn_rela = base_address + cur_entry->GetPtr();
|
dyn_rela = base_address + cur_entry->GetPtr();
|
||||||
break;
|
break;
|
||||||
|
case DT_RELR:
|
||||||
|
dyn_relr = base_address + cur_entry->GetPtr();
|
||||||
|
break;
|
||||||
case DT_RELENT:
|
case DT_RELENT:
|
||||||
rel_ent = cur_entry->GetValue();
|
rel_ent = cur_entry->GetValue();
|
||||||
break;
|
break;
|
||||||
case DT_RELAENT:
|
case DT_RELAENT:
|
||||||
rela_ent = cur_entry->GetValue();
|
rela_ent = cur_entry->GetValue();
|
||||||
break;
|
break;
|
||||||
|
case DT_RELRENT:
|
||||||
|
relr_ent = cur_entry->GetValue();
|
||||||
|
break;
|
||||||
case DT_RELCOUNT:
|
case DT_RELCOUNT:
|
||||||
rel_count = cur_entry->GetValue();
|
rel_count = cur_entry->GetValue();
|
||||||
break;
|
break;
|
||||||
case DT_RELACOUNT:
|
case DT_RELACOUNT:
|
||||||
rela_count = cur_entry->GetValue();
|
rela_count = cur_entry->GetValue();
|
||||||
break;
|
break;
|
||||||
|
case DT_RELRSZ:
|
||||||
|
relr_sz = cur_entry->GetValue();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply all Rel relocations */
|
/* Apply all Rel relocations */
|
||||||
for (size_t i = 0; i < rel_count; i++) {
|
if (rel_count > 0) {
|
||||||
const auto &rel = *reinterpret_cast<const Elf::Rel *>(dyn_rel + rel_ent * i);
|
/* Check that the rel relocations are applyable. */
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(dyn_rel != 0);
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(rel_ent == sizeof(Elf::Rel));
|
||||||
|
|
||||||
/* Only allow architecture-specific relocations. */
|
for (size_t i = 0; i < rel_count; ++i) {
|
||||||
while (rel.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
|
const auto &rel = reinterpret_cast<const Elf::Rel *>(dyn_rel)[i];
|
||||||
|
|
||||||
/* Apply the relocation. */
|
/* Only allow architecture-specific relocations. */
|
||||||
Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rel.GetOffset());
|
while (rel.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
|
||||||
*target_address += base_address;
|
|
||||||
|
/* Apply the relocation. */
|
||||||
|
Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rel.GetOffset());
|
||||||
|
*target_address += base_address;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply all Rela relocations. */
|
/* Apply all Rela relocations. */
|
||||||
for (size_t i = 0; i < rela_count; i++) {
|
if (rela_count > 0) {
|
||||||
const auto &rela = *reinterpret_cast<const Elf::Rela *>(dyn_rela + rela_ent * i);
|
/* Check that the rela relocations are applyable. */
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(dyn_rela != 0);
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(rela_ent == sizeof(Elf::Rela));
|
||||||
|
|
||||||
/* Only allow architecture-specific relocations. */
|
for (size_t i = 0; i < rela_count; ++i) {
|
||||||
while (rela.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
|
const auto &rela = reinterpret_cast<const Elf::Rela *>(dyn_rela)[i];
|
||||||
|
|
||||||
/* Apply the relocation. */
|
/* Only allow architecture-specific relocations. */
|
||||||
Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rela.GetOffset());
|
while (rela.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
|
||||||
*target_address = base_address + rela.GetAddend();
|
|
||||||
|
/* Apply the relocation. */
|
||||||
|
Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rela.GetOffset());
|
||||||
|
*target_address = base_address + rela.GetAddend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply all Relr relocations. */
|
||||||
|
if (relr_sz >= sizeof(Elf::Relr)) {
|
||||||
|
/* Check that the relr relocations are applyable. */
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(dyn_relr != 0);
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(relr_ent == sizeof(Elf::Relr));
|
||||||
|
|
||||||
|
const size_t relr_count = relr_sz / sizeof(Elf::Relr);
|
||||||
|
|
||||||
|
Elf::Addr *where = nullptr;
|
||||||
|
for (size_t i = 0; i < relr_count; ++i) {
|
||||||
|
const auto &relr = reinterpret_cast<const Elf::Relr *>(dyn_relr)[i];
|
||||||
|
|
||||||
|
if (relr.IsLocation()) {
|
||||||
|
/* Update location. */
|
||||||
|
where = reinterpret_cast<Elf::Addr *>(base_address + relr.GetLocation());
|
||||||
|
|
||||||
|
/* Apply the relocation. */
|
||||||
|
*(where++) += base_address;
|
||||||
|
} else {
|
||||||
|
/* Get the bitmap. */
|
||||||
|
u64 bitmap = relr.GetBitmap();
|
||||||
|
|
||||||
|
/* Apply all relocations. */
|
||||||
|
while (bitmap != 0) {
|
||||||
|
const u64 next = util::CountTrailingZeros(bitmap);
|
||||||
|
bitmap &= ~(static_cast<u64>(1) << next);
|
||||||
|
where[next] += base_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
where += BITSIZEOF(bitmap) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace ams::kern::init {
|
|||||||
|
|
||||||
/* For macro convenience. */
|
/* For macro convenience. */
|
||||||
using KSessionRequestMappings = KSessionRequest::SessionMappings::DynamicMappings;
|
using KSessionRequestMappings = KSessionRequest::SessionMappings::DynamicMappings;
|
||||||
|
using KThreadLockInfo = KThread::LockWithPriorityInheritanceInfo;
|
||||||
|
|
||||||
#define SLAB_COUNT(CLASS) g_slab_resource_counts.num_##CLASS
|
#define SLAB_COUNT(CLASS) g_slab_resource_counts.num_##CLASS
|
||||||
|
|
||||||
@@ -43,8 +44,9 @@ namespace ams::kern::init {
|
|||||||
HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
|
HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
|
||||||
HANDLER(KIoPool, (SLAB_COUNT(KIoPool)), ## __VA_ARGS__) \
|
HANDLER(KIoPool, (SLAB_COUNT(KIoPool)), ## __VA_ARGS__) \
|
||||||
HANDLER(KIoRegion, (SLAB_COUNT(KIoRegion)), ## __VA_ARGS__) \
|
HANDLER(KIoRegion, (SLAB_COUNT(KIoRegion)), ## __VA_ARGS__) \
|
||||||
|
HANDLER(KSessionRequestMappings, (SLAB_COUNT(KSessionRequestMappings)), ## __VA_ARGS__) \
|
||||||
HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \
|
HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \
|
||||||
HANDLER(KSessionRequestMappings, (SLAB_COUNT(KSessionRequestMappings)), ## __VA_ARGS__)
|
HANDLER(KThreadLockInfo, (SLAB_COUNT(KThread)), ## __VA_ARGS__)
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -140,7 +142,7 @@ namespace ams::kern::init {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t CalculateSlabHeapGapSize() {
|
size_t CalculateSlabHeapGapSize() {
|
||||||
constexpr size_t KernelSlabHeapGapSize = 2_MB - 320_KB;
|
constexpr size_t KernelSlabHeapGapSize = 2_MB - 356_KB;
|
||||||
static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax);
|
static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax);
|
||||||
return KernelSlabHeapGapSize;
|
return KernelSlabHeapGapSize;
|
||||||
}
|
}
|
||||||
@@ -169,6 +171,9 @@ namespace ams::kern::init {
|
|||||||
const KMemoryRegion &slab_region = KMemoryLayout::GetSlabRegion();
|
const KMemoryRegion &slab_region = KMemoryLayout::GetSlabRegion();
|
||||||
KVirtualAddress address = slab_region.GetAddress();
|
KVirtualAddress address = slab_region.GetAddress();
|
||||||
|
|
||||||
|
/* Clear the slab region. */
|
||||||
|
std::memset(GetVoidPointer(address), 0, slab_region.GetSize());
|
||||||
|
|
||||||
/* Initialize slab type array to be in sorted order. */
|
/* Initialize slab type array to be in sorted order. */
|
||||||
KSlabType slab_types[KSlabType_Count];
|
KSlabType slab_types[KSlabType_Count];
|
||||||
for (size_t i = 0; i < util::size(slab_types); i++) { slab_types[i] = static_cast<KSlabType>(i); }
|
for (size_t i = 0; i < util::size(slab_types); i++) { slab_types[i] = static_cast<KSlabType>(i); }
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
constinit KPhysicalAddress g_initial_process_binary_phys_addr = Null<KPhysicalAddress>;
|
constinit KPhysicalAddress g_initial_process_binary_phys_addr = Null<KPhysicalAddress>;
|
||||||
constinit KVirtualAddress g_initial_process_binary_address = Null<KVirtualAddress>;
|
constinit KVirtualAddress g_initial_process_binary_address = Null<KVirtualAddress>;
|
||||||
|
constinit size_t g_initial_process_binary_size = 0;
|
||||||
constinit InitialProcessBinaryHeader g_initial_process_binary_header = {};
|
constinit InitialProcessBinaryHeader g_initial_process_binary_header = {};
|
||||||
constinit size_t g_initial_process_secure_memory_size = 0;
|
constinit size_t g_initial_process_secure_memory_size = 0;
|
||||||
constinit u64 g_initial_process_id_min = std::numeric_limits<u64>::max();
|
constinit u64 g_initial_process_id_min = std::numeric_limits<u64>::max();
|
||||||
@@ -155,40 +156,14 @@ namespace ams::kern {
|
|||||||
KPageGroup *process_pg = std::addressof(pg);
|
KPageGroup *process_pg = std::addressof(pg);
|
||||||
ON_SCOPE_EXIT { process_pg->Close(); };
|
ON_SCOPE_EXIT { process_pg->Close(); };
|
||||||
|
|
||||||
/* Get the temporary region. */
|
|
||||||
const auto &temp_region = KMemoryLayout::GetTempRegion();
|
|
||||||
MESOSPHERE_ABORT_UNLESS(temp_region.GetEndAddress() != 0);
|
|
||||||
|
|
||||||
/* Map the process's memory into the temporary region. */
|
|
||||||
KProcessAddress temp_address = Null<KProcessAddress>;
|
|
||||||
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().MapPageGroup(std::addressof(temp_address), pg, temp_region.GetAddress(), temp_region.GetSize() / PageSize, KMemoryState_Kernel, KMemoryPermission_KernelReadWrite));
|
|
||||||
|
|
||||||
/* Setup the new page group's memory, so that we can load the process. */
|
|
||||||
{
|
|
||||||
/* Copy the unaligned ending of the compressed binary. */
|
|
||||||
if (const size_t unaligned_size = binary_size - util::AlignDown(binary_size, PageSize); unaligned_size != 0) {
|
|
||||||
std::memcpy(GetVoidPointer(temp_address + process_size - unaligned_size), GetVoidPointer(data + binary_size - unaligned_size), unaligned_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy the aligned part of the compressed binary. */
|
|
||||||
if (const size_t aligned_size = util::AlignDown(binary_size, PageSize); aligned_size != 0 && src_pool == dst_pool) {
|
|
||||||
std::memmove(GetVoidPointer(temp_address + process_size - binary_size), GetVoidPointer(temp_address), aligned_size);
|
|
||||||
} else {
|
|
||||||
if (src_pool != dst_pool) {
|
|
||||||
std::memcpy(GetVoidPointer(temp_address + process_size - binary_size), GetVoidPointer(data), aligned_size);
|
|
||||||
Kernel::GetMemoryManager().Close(KMemoryLayout::GetLinearPhysicalAddress(data), aligned_size / PageSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear the first part of the memory. */
|
|
||||||
std::memset(GetVoidPointer(temp_address), 0, process_size - binary_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load the process. */
|
/* Load the process. */
|
||||||
MESOSPHERE_R_ABORT_UNLESS(reader.Load(temp_address, params, temp_address + process_size - binary_size));
|
reader.Load(pg, data);
|
||||||
|
|
||||||
/* Unmap the temporary mapping. */
|
/* If necessary, close/release the aligned part of the data we just loaded. */
|
||||||
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().UnmapPageGroup(temp_address, pg, KMemoryState_Kernel));
|
if (const size_t aligned_bin_size = util::AlignDown(binary_size, PageSize); aligned_bin_size != 0 && src_pool != dst_pool) {
|
||||||
|
Kernel::GetMemoryManager().Close(KMemoryLayout::GetLinearPhysicalAddress(data), aligned_bin_size / PageSize);
|
||||||
|
Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_PhysicalMemoryMax, aligned_bin_size);
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a KProcess object. */
|
/* Create a KProcess object. */
|
||||||
new_process = KProcess::Create();
|
new_process = KProcess::Create();
|
||||||
@@ -241,11 +216,6 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_R_ABORT_UNLESS(new_process->Initialize(params, *process_pg, reader.GetCapabilities(), reader.GetNumCapabilities(), std::addressof(Kernel::GetSystemResourceLimit()), dst_pool, reader.IsImmortal()));
|
MESOSPHERE_R_ABORT_UNLESS(new_process->Initialize(params, *process_pg, reader.GetCapabilities(), reader.GetNumCapabilities(), std::addressof(Kernel::GetSystemResourceLimit()), dst_pool, reader.IsImmortal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release the memory that was previously reserved. */
|
|
||||||
if (const size_t aligned_bin_size = util::AlignDown(binary_size, PageSize); aligned_bin_size != 0 && src_pool != dst_pool) {
|
|
||||||
Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_PhysicalMemoryMax, aligned_bin_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the process's memory permissions. */
|
/* Set the process's memory permissions. */
|
||||||
MESOSPHERE_R_ABORT_UNLESS(reader.SetMemoryPermissions(new_process->GetPageTable(), params));
|
MESOSPHERE_R_ABORT_UNLESS(reader.SetMemoryPermissions(new_process->GetPageTable(), params));
|
||||||
|
|
||||||
@@ -275,10 +245,11 @@ namespace ams::kern {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr) {
|
void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr, size_t size) {
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr == Null<KPhysicalAddress>);
|
MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr == Null<KPhysicalAddress>);
|
||||||
|
|
||||||
g_initial_process_binary_phys_addr = phys_addr;
|
g_initial_process_binary_phys_addr = phys_addr;
|
||||||
|
g_initial_process_binary_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
KPhysicalAddress GetInitialProcessBinaryPhysicalAddress() {
|
KPhysicalAddress GetInitialProcessBinaryPhysicalAddress() {
|
||||||
@@ -287,6 +258,12 @@ namespace ams::kern {
|
|||||||
return g_initial_process_binary_phys_addr;
|
return g_initial_process_binary_phys_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t GetInitialProcessBinarySize() {
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr != Null<KPhysicalAddress>);
|
||||||
|
|
||||||
|
return g_initial_process_binary_size;
|
||||||
|
}
|
||||||
|
|
||||||
u64 GetInitialProcessIdMin() {
|
u64 GetInitialProcessIdMin() {
|
||||||
return g_initial_process_id_min;
|
return g_initial_process_id_min;
|
||||||
}
|
}
|
||||||
@@ -305,14 +282,17 @@ namespace ams::kern {
|
|||||||
LoadInitialProcessBinaryHeader();
|
LoadInitialProcessBinaryHeader();
|
||||||
|
|
||||||
if (g_initial_process_binary_header.num_processes > 0) {
|
if (g_initial_process_binary_header.num_processes > 0) {
|
||||||
/* Reserve pages for the initial process binary from the system resource limit. */
|
/* Ensure that we have a non-zero size. */
|
||||||
const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize);
|
const size_t expected_size = g_initial_process_binary_size;
|
||||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, total_size));
|
MESOSPHERE_INIT_ABORT_UNLESS(expected_size != 0);
|
||||||
|
|
||||||
/* The initial process binary is potentially over-allocated, so free any extra pages. */
|
/* Ensure that the size we need to reserve is as we expect it to be. */
|
||||||
if (total_size < InitialProcessBinarySizeMax) {
|
const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize);
|
||||||
Kernel::GetMemoryManager().Close(KMemoryLayout::GetLinearPhysicalAddress(g_initial_process_binary_address + total_size), (InitialProcessBinarySizeMax - total_size) / PageSize);
|
MESOSPHERE_ABORT_UNLESS(total_size == expected_size);
|
||||||
}
|
MESOSPHERE_ABORT_UNLESS(total_size <= InitialProcessBinarySizeMax);
|
||||||
|
|
||||||
|
/* Reserve pages for the initial process binary from the system resource limit. */
|
||||||
|
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, total_size));
|
||||||
|
|
||||||
return total_size;
|
return total_size;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool DecrementIfLessThan(s32 *out, KProcessAddress address, s32 value) {
|
ALWAYS_INLINE bool DecrementIfLessThan(s32 *out, KProcessAddress address, s32 value) {
|
||||||
KScopedInterruptDisable di;
|
/* NOTE: If scheduler lock is not held here, interrupt disable is required. */
|
||||||
|
/* KScopedInterruptDisable di; */
|
||||||
|
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
||||||
|
|
||||||
if (!cpu::CanAccessAtomic(address)) {
|
if (!cpu::CanAccessAtomic(address)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -34,7 +36,9 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool UpdateIfEqual(s32 *out, KProcessAddress address, s32 value, s32 new_value) {
|
ALWAYS_INLINE bool UpdateIfEqual(s32 *out, KProcessAddress address, s32 value, s32 new_value) {
|
||||||
KScopedInterruptDisable di;
|
/* NOTE: If scheduler lock is not held here, interrupt disable is required. */
|
||||||
|
/* KScopedInterruptDisable di; */
|
||||||
|
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
||||||
|
|
||||||
if (!cpu::CanAccessAtomic(address)) {
|
if (!cpu::CanAccessAtomic(address)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
constexpr uintptr_t Invalid = std::numeric_limits<uintptr_t>::max();
|
constexpr uintptr_t Invalid = std::numeric_limits<uintptr_t>::max();
|
||||||
|
|
||||||
constexpr KAddressSpaceInfo AddressSpaceInfos[] = {
|
constinit KAddressSpaceInfo AddressSpaceInfos[] = {
|
||||||
{ 32, ams::svc::AddressSmallMap32Start, ams::svc::AddressSmallMap32Size, KAddressSpaceInfo::Type_MapSmall, },
|
{ 32, ams::svc::AddressSmallMap32Start, ams::svc::AddressSmallMap32Size, KAddressSpaceInfo::Type_MapSmall, },
|
||||||
{ 32, ams::svc::AddressLargeMap32Start, ams::svc::AddressLargeMap32Size, KAddressSpaceInfo::Type_MapLarge, },
|
{ 32, ams::svc::AddressLargeMap32Start, ams::svc::AddressLargeMap32Size, KAddressSpaceInfo::Type_MapLarge, },
|
||||||
{ 32, Invalid, ams::svc::AddressMemoryRegionHeap32Size, KAddressSpaceInfo::Type_Heap, },
|
{ 32, Invalid, ams::svc::AddressMemoryRegionHeap32Size, KAddressSpaceInfo::Type_Heap, },
|
||||||
@@ -37,67 +37,27 @@ namespace ams::kern {
|
|||||||
{ 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, },
|
{ 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, },
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr bool IsAllowedIndexForAddress(size_t index) {
|
KAddressSpaceInfo &GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) {
|
||||||
return index < util::size(AddressSpaceInfos) && AddressSpaceInfos[index].GetAddress() != Invalid;
|
for (auto &info : AddressSpaceInfos) {
|
||||||
}
|
if (info.GetWidth() == width && info.GetType() == type) {
|
||||||
|
return info;
|
||||||
constexpr size_t AddressSpaceIndices32Bit[KAddressSpaceInfo::Type_Count] = {
|
}
|
||||||
0, 1, 0, 2, 0, 3,
|
}
|
||||||
};
|
MESOSPHERE_PANIC("Could not find AddressSpaceInfo");
|
||||||
|
|
||||||
constexpr size_t AddressSpaceIndices36Bit[KAddressSpaceInfo::Type_Count] = {
|
|
||||||
4, 5, 4, 6, 4, 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr size_t AddressSpaceIndices39Bit[KAddressSpaceInfo::Type_Count] = {
|
|
||||||
9, 8, 8, 10, 12, 11,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr bool IsAllowed32BitType(KAddressSpaceInfo::Type type) {
|
|
||||||
return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Map39Bit && type != KAddressSpaceInfo::Type_Stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool IsAllowed36BitType(KAddressSpaceInfo::Type type) {
|
|
||||||
return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Map39Bit && type != KAddressSpaceInfo::Type_Stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool IsAllowed39BitType(KAddressSpaceInfo::Type type) {
|
|
||||||
return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_MapLarge;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) {
|
uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) {
|
||||||
switch (width) {
|
return GetAddressSpaceInfo(width, type).GetAddress();
|
||||||
case 32:
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowed32BitType(type));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[type]));
|
|
||||||
return AddressSpaceInfos[AddressSpaceIndices32Bit[type]].GetAddress();
|
|
||||||
case 36:
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowed36BitType(type));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[type]));
|
|
||||||
return AddressSpaceInfos[AddressSpaceIndices36Bit[type]].GetAddress();
|
|
||||||
case 39:
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowed39BitType(type));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[type]));
|
|
||||||
return AddressSpaceInfos[AddressSpaceIndices39Bit[type]].GetAddress();
|
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) {
|
size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) {
|
||||||
switch (width) {
|
return GetAddressSpaceInfo(width, type).GetSize();
|
||||||
case 32:
|
}
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowed32BitType(type));
|
|
||||||
return AddressSpaceInfos[AddressSpaceIndices32Bit[type]].GetSize();
|
void KAddressSpaceInfo::SetAddressSpaceSize(size_t width, Type type, size_t size) {
|
||||||
case 36:
|
GetAddressSpaceInfo(width, type).SetSize(size);
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowed36BitType(type));
|
|
||||||
return AddressSpaceInfos[AddressSpaceIndices36Bit[type]].GetSize();
|
|
||||||
case 39:
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowed39BitType(type));
|
|
||||||
return AddressSpaceInfos[AddressSpaceIndices39Bit[type]].GetSize();
|
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,34 +77,35 @@ namespace ams::kern {
|
|||||||
KScopedSchedulerLock sl;
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
/* Remove waiter thread. */
|
/* Remove waiter thread. */
|
||||||
s32 num_waiters;
|
bool has_waiters;
|
||||||
KThread *next_owner_thread = owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
|
KThread * const next_owner_thread = owner_thread->RemoveWaiterByKey(std::addressof(has_waiters), addr);
|
||||||
|
|
||||||
/* Determine the next tag. */
|
/* Determine the next tag. */
|
||||||
u32 next_value = 0;
|
u32 next_value = 0;
|
||||||
if (next_owner_thread != nullptr) {
|
if (next_owner_thread != nullptr) {
|
||||||
next_value = next_owner_thread->GetAddressKeyValue();
|
next_value = next_owner_thread->GetAddressKeyValue();
|
||||||
if (num_waiters > 1) {
|
if (has_waiters) {
|
||||||
next_value |= ams::svc::HandleWaitMask;
|
next_value |= ams::svc::HandleWaitMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the value to userspace. */
|
|
||||||
Result result;
|
|
||||||
if (AMS_LIKELY(WriteToUser(addr, std::addressof(next_value)))) {
|
|
||||||
result = ResultSuccess();
|
|
||||||
} else {
|
|
||||||
result = svc::ResultInvalidCurrentMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Signal the next owner thread. */
|
|
||||||
next_owner_thread->EndWait(result);
|
|
||||||
R_RETURN(result);
|
|
||||||
} else {
|
|
||||||
/* Just write the value to userspace. */
|
|
||||||
R_UNLESS(WriteToUser(addr, std::addressof(next_value)), svc::ResultInvalidCurrentMemory());
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Synchronize memory before proceeding. */
|
||||||
|
cpu::DataMemoryBarrierInnerShareable();
|
||||||
|
|
||||||
|
/* Write the value to userspace. */
|
||||||
|
Result result;
|
||||||
|
if (AMS_LIKELY(WriteToUser(addr, std::addressof(next_value)))) {
|
||||||
|
result = ResultSuccess();
|
||||||
|
} else {
|
||||||
|
result = svc::ResultInvalidCurrentMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If necessary, signal the next owner thread. */
|
||||||
|
if (next_owner_thread != nullptr) {
|
||||||
|
next_owner_thread->EndWait(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
R_RETURN(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +158,8 @@ namespace ams::kern {
|
|||||||
u32 prev_tag;
|
u32 prev_tag;
|
||||||
bool can_access;
|
bool can_access;
|
||||||
{
|
{
|
||||||
KScopedInterruptDisable di;
|
/* NOTE: If scheduler lock is not held here, interrupt disable is required. */
|
||||||
|
/* KScopedInterruptDisable di; */
|
||||||
|
|
||||||
can_access = cpu::CanAccessAtomic(address);
|
can_access = cpu::CanAccessAtomic(address);
|
||||||
if (AMS_LIKELY(can_access)) {
|
if (AMS_LIKELY(can_access)) {
|
||||||
@@ -198,9 +200,11 @@ namespace ams::kern {
|
|||||||
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetConditionVariableKey() == cv_key)) {
|
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetConditionVariableKey() == cv_key)) {
|
||||||
KThread *target_thread = std::addressof(*it);
|
KThread *target_thread = std::addressof(*it);
|
||||||
|
|
||||||
this->SignalImpl(target_thread);
|
|
||||||
it = m_tree.erase(it);
|
it = m_tree.erase(it);
|
||||||
target_thread->ClearConditionVariable();
|
target_thread->ClearConditionVariable();
|
||||||
|
|
||||||
|
this->SignalImpl(target_thread);
|
||||||
|
|
||||||
++num_waiters;
|
++num_waiters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,15 +234,15 @@ namespace ams::kern {
|
|||||||
/* Update the value and process for the next owner. */
|
/* Update the value and process for the next owner. */
|
||||||
{
|
{
|
||||||
/* Remove waiter thread. */
|
/* Remove waiter thread. */
|
||||||
s32 num_waiters;
|
bool has_waiters;
|
||||||
KThread *next_owner_thread = cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), GetInteger(addr));
|
KThread *next_owner_thread = cur_thread->RemoveWaiterByKey(std::addressof(has_waiters), GetInteger(addr));
|
||||||
|
|
||||||
/* Update for the next owner thread. */
|
/* Update for the next owner thread. */
|
||||||
u32 next_value = 0;
|
u32 next_value = 0;
|
||||||
if (next_owner_thread != nullptr) {
|
if (next_owner_thread != nullptr) {
|
||||||
/* Get the next tag value. */
|
/* Get the next tag value. */
|
||||||
next_value = next_owner_thread->GetAddressKeyValue();
|
next_value = next_owner_thread->GetAddressKeyValue();
|
||||||
if (num_waiters > 1) {
|
if (has_waiters) {
|
||||||
next_value |= ams::svc::HandleWaitMask;
|
next_value |= ams::svc::HandleWaitMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,12 +118,12 @@ namespace ams::kern {
|
|||||||
const size_t cur_size = std::min(remaining, info.GetEndAddress() - GetInteger(cur_address));
|
const size_t cur_size = std::min(remaining, info.GetEndAddress() - GetInteger(cur_address));
|
||||||
|
|
||||||
/* Read the memory. */
|
/* Read the memory. */
|
||||||
if (info.GetState() != KMemoryState_Io) {
|
if (info.GetSvcState() != ams::svc::MemoryState_Io) {
|
||||||
/* The memory is normal memory. */
|
/* The memory is normal memory. */
|
||||||
R_TRY(target_pt.ReadDebugMemory(GetVoidPointer(buffer), cur_address, cur_size));
|
R_TRY(target_pt.ReadDebugMemory(GetVoidPointer(buffer), cur_address, cur_size));
|
||||||
} else {
|
} else {
|
||||||
/* The memory is IO memory. */
|
/* The memory is IO memory. */
|
||||||
R_TRY(target_pt.ReadDebugIoMemory(GetVoidPointer(buffer), cur_address, cur_size));
|
R_TRY(target_pt.ReadDebugIoMemory(GetVoidPointer(buffer), cur_address, cur_size, info.GetState()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
@@ -181,12 +181,12 @@ namespace ams::kern {
|
|||||||
const size_t cur_size = std::min(remaining, info.GetEndAddress() - GetInteger(cur_address));
|
const size_t cur_size = std::min(remaining, info.GetEndAddress() - GetInteger(cur_address));
|
||||||
|
|
||||||
/* Read the memory. */
|
/* Read the memory. */
|
||||||
if (info.GetState() != KMemoryState_Io) {
|
if (info.GetSvcState() != ams::svc::MemoryState_Io) {
|
||||||
/* The memory is normal memory. */
|
/* The memory is normal memory. */
|
||||||
R_TRY(target_pt.WriteDebugMemory(cur_address, GetVoidPointer(buffer), cur_size));
|
R_TRY(target_pt.WriteDebugMemory(cur_address, GetVoidPointer(buffer), cur_size));
|
||||||
} else {
|
} else {
|
||||||
/* The memory is IO memory. */
|
/* The memory is IO memory. */
|
||||||
R_TRY(target_pt.WriteDebugIoMemory(cur_address, GetVoidPointer(buffer), cur_size));
|
R_TRY(target_pt.WriteDebugIoMemory(cur_address, GetVoidPointer(buffer), cur_size, info.GetState()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
@@ -219,12 +219,21 @@ namespace ams::kern {
|
|||||||
const s32 core_id = GetCurrentCoreId();
|
const s32 core_id = GetCurrentCoreId();
|
||||||
KThread *thread = process->GetRunningThread(core_id);
|
KThread *thread = process->GetRunningThread(core_id);
|
||||||
|
|
||||||
/* Check that the thread's idle count is correct. */
|
/* We want to check that the thread is actually running. */
|
||||||
R_UNLESS(process->GetRunningThreadIdleCount(core_id) == Kernel::GetScheduler(core_id).GetIdleCount(), svc::ResultNoThread());
|
/* If it is, then the scheduler will have just switched from the thread to the current thread. */
|
||||||
|
/* This implies exactly one switch will have taken place, and the current thread will be on the current core. */
|
||||||
/* Check that the thread is running on the current core. */
|
const auto &scheduler = Kernel::GetScheduler(core_id);
|
||||||
R_UNLESS(thread != nullptr, svc::ResultUnknownThread());
|
if (!(thread != nullptr && thread->GetActiveCore() == core_id && process->GetRunningThreadSwitchCount(core_id) + 1 == scheduler.GetSwitchCount())) {
|
||||||
R_UNLESS(thread->GetActiveCore() == core_id, svc::ResultUnknownThread());
|
/* The most recent thread switch was from a thread other than the expected one to the current one. */
|
||||||
|
/* We want to use the appropriate result to inform userland about what thread we switched from. */
|
||||||
|
if (scheduler.GetIdleCount() + 1 == scheduler.GetSwitchCount()) {
|
||||||
|
/* We switched from the idle thread. */
|
||||||
|
R_THROW(svc::ResultNoThread());
|
||||||
|
} else {
|
||||||
|
/* We switched from some other unknown thread. */
|
||||||
|
R_THROW(svc::ResultUnknownThread());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the thread's exception context. */
|
/* Get the thread's exception context. */
|
||||||
GetExceptionContext(thread)->GetSvcThreadContext(out_context);
|
GetExceptionContext(thread)->GetSvcThreadContext(out_context);
|
||||||
@@ -280,7 +289,7 @@ namespace ams::kern {
|
|||||||
m_old_process_state = target->SetDebugObject(this);
|
m_old_process_state = target->SetDebugObject(this);
|
||||||
|
|
||||||
/* Send an event for our attaching to the process. */
|
/* Send an event for our attaching to the process. */
|
||||||
this->PushDebugEvent(ams::svc::DebugEvent_CreateProcess);
|
this->PushDebugEvent(ams::svc::DebugEvent_CreateProcess, nullptr, 0);
|
||||||
|
|
||||||
/* Send events for attaching to each thread in the process. */
|
/* Send events for attaching to each thread in the process. */
|
||||||
{
|
{
|
||||||
@@ -295,7 +304,8 @@ namespace ams::kern {
|
|||||||
it->SetDebugAttached();
|
it->SetDebugAttached();
|
||||||
|
|
||||||
/* Send the event. */
|
/* Send the event. */
|
||||||
this->PushDebugEvent(ams::svc::DebugEvent_CreateThread, it->GetId(), GetInteger(it->GetThreadLocalRegionAddress()));
|
const uintptr_t params[2] = { it->GetId(), GetInteger(it->GetThreadLocalRegionAddress()) };
|
||||||
|
this->PushDebugEvent(ams::svc::DebugEvent_CreateThread, params, util::size(params));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -306,7 +316,8 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Send an exception event to represent our attaching. */
|
/* Send an exception event to represent our attaching. */
|
||||||
this->PushDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_DebuggerAttached);
|
const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::DebugException_DebuggerAttached) };
|
||||||
|
this->PushDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params));
|
||||||
|
|
||||||
/* Signal. */
|
/* Signal. */
|
||||||
this->NotifyAvailable();
|
this->NotifyAvailable();
|
||||||
@@ -344,22 +355,22 @@ namespace ams::kern {
|
|||||||
/* Get the currently active threads. */
|
/* Get the currently active threads. */
|
||||||
constexpr u64 ThreadIdNoThread = -1ll;
|
constexpr u64 ThreadIdNoThread = -1ll;
|
||||||
constexpr u64 ThreadIdUnknownThread = -2ll;
|
constexpr u64 ThreadIdUnknownThread = -2ll;
|
||||||
u64 thread_ids[cpu::NumCores];
|
uintptr_t debug_info_params[1 + cpu::NumCores] = { static_cast<uintptr_t>(ams::svc::DebugException_DebuggerBreak), };
|
||||||
for (size_t i = 0; i < util::size(thread_ids); ++i) {
|
for (size_t i = 0; i < cpu::NumCores; ++i) {
|
||||||
/* Get the currently running thread. */
|
/* Get the currently running thread. */
|
||||||
KThread *thread = target->GetRunningThread(i);
|
KThread *thread = target->GetRunningThread(i);
|
||||||
|
|
||||||
/* Check that the thread's idle count is correct. */
|
/* Check that the thread's idle count is correct. */
|
||||||
if (target->GetRunningThreadIdleCount(i) == Kernel::GetScheduler(i).GetIdleCount()) {
|
if (target->GetRunningThreadIdleCount(i) == Kernel::GetScheduler(i).GetIdleCount()) {
|
||||||
if (thread != nullptr && static_cast<size_t>(thread->GetActiveCore()) == i) {
|
if (thread != nullptr && static_cast<size_t>(thread->GetActiveCore()) == i) {
|
||||||
thread_ids[i] = thread->GetId();
|
debug_info_params[1 + i] = thread->GetId();
|
||||||
} else {
|
} else {
|
||||||
/* We found an unknown thread. */
|
/* We found an unknown thread. */
|
||||||
thread_ids[i] = ThreadIdUnknownThread;
|
debug_info_params[1 + i] = ThreadIdUnknownThread;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* We didn't find a thread. */
|
/* We didn't find a thread. */
|
||||||
thread_ids[i] = ThreadIdNoThread;
|
debug_info_params[1 + i] = ThreadIdNoThread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,11 +384,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Send an exception event to represent our breaking the process. */
|
/* Send an exception event to represent our breaking the process. */
|
||||||
/* TODO: How should this be handled in the case of more than 4 physical cores? */
|
this->PushDebugEvent(ams::svc::DebugEvent_Exception, debug_info_params, util::size(debug_info_params));
|
||||||
static_assert(util::size(thread_ids) <= 4);
|
|
||||||
[&]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA {
|
|
||||||
this->PushDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_DebuggerBreak, thread_ids[Ix]...);
|
|
||||||
}(std::make_index_sequence<util::size(thread_ids)>());
|
|
||||||
|
|
||||||
/* Signal. */
|
/* Signal. */
|
||||||
this->NotifyAvailable();
|
this->NotifyAvailable();
|
||||||
@@ -725,7 +732,7 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
KEventInfo *KDebugBase::CreateDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4, u64 cur_thread_id) {
|
KEventInfo *KDebugBase::CreateDebugEvent(ams::svc::DebugEvent event, u64 cur_thread_id, const uintptr_t *params, size_t num_params) {
|
||||||
/* Allocate a new event. */
|
/* Allocate a new event. */
|
||||||
KEventInfo *info = KEventInfo::Allocate();
|
KEventInfo *info = KEventInfo::Allocate();
|
||||||
|
|
||||||
@@ -740,23 +747,33 @@ namespace ams::kern {
|
|||||||
switch (event) {
|
switch (event) {
|
||||||
case ams::svc::DebugEvent_CreateProcess:
|
case ams::svc::DebugEvent_CreateProcess:
|
||||||
{
|
{
|
||||||
/* ... */
|
/* Check parameters. */
|
||||||
|
MESOSPHERE_ASSERT(params == nullptr);
|
||||||
|
MESOSPHERE_ASSERT(num_params == 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugEvent_CreateThread:
|
case ams::svc::DebugEvent_CreateThread:
|
||||||
{
|
{
|
||||||
|
/* Check parameters. */
|
||||||
|
MESOSPHERE_ASSERT(params != nullptr);
|
||||||
|
MESOSPHERE_ASSERT(num_params == 2);
|
||||||
|
|
||||||
/* Set the thread id. */
|
/* Set the thread id. */
|
||||||
info->thread_id = param0;
|
info->thread_id = params[0];
|
||||||
|
|
||||||
/* Set the thread creation info. */
|
/* Set the thread creation info. */
|
||||||
info->info.create_thread.thread_id = param0;
|
info->info.create_thread.thread_id = params[0];
|
||||||
info->info.create_thread.tls_address = param1;
|
info->info.create_thread.tls_address = params[1];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugEvent_ExitProcess:
|
case ams::svc::DebugEvent_ExitProcess:
|
||||||
{
|
{
|
||||||
|
/* Check parameters. */
|
||||||
|
MESOSPHERE_ASSERT(params != nullptr);
|
||||||
|
MESOSPHERE_ASSERT(num_params == 1);
|
||||||
|
|
||||||
/* Set the exit reason. */
|
/* Set the exit reason. */
|
||||||
info->info.exit_process.reason = static_cast<ams::svc::ProcessExitReason>(param0);
|
info->info.exit_process.reason = static_cast<ams::svc::ProcessExitReason>(params[0]);
|
||||||
|
|
||||||
/* Clear the thread id and flags. */
|
/* Clear the thread id and flags. */
|
||||||
info->thread_id = 0;
|
info->thread_id = 0;
|
||||||
@@ -765,30 +782,40 @@ namespace ams::kern {
|
|||||||
break;
|
break;
|
||||||
case ams::svc::DebugEvent_ExitThread:
|
case ams::svc::DebugEvent_ExitThread:
|
||||||
{
|
{
|
||||||
|
/* Check parameters. */
|
||||||
|
MESOSPHERE_ASSERT(params != nullptr);
|
||||||
|
MESOSPHERE_ASSERT(num_params == 2);
|
||||||
|
|
||||||
/* Set the thread id. */
|
/* Set the thread id. */
|
||||||
info->thread_id = param0;
|
info->thread_id = params[0];
|
||||||
|
|
||||||
/* Set the exit reason. */
|
/* Set the exit reason. */
|
||||||
info->info.exit_thread.reason = static_cast<ams::svc::ThreadExitReason>(param1);
|
info->info.exit_thread.reason = static_cast<ams::svc::ThreadExitReason>(params[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugEvent_Exception:
|
case ams::svc::DebugEvent_Exception:
|
||||||
{
|
{
|
||||||
|
/* Check parameters. */
|
||||||
|
MESOSPHERE_ASSERT(params != nullptr);
|
||||||
|
MESOSPHERE_ASSERT(num_params >= 1);
|
||||||
|
|
||||||
/* Set the thread id. */
|
/* Set the thread id. */
|
||||||
info->thread_id = cur_thread_id;
|
info->thread_id = cur_thread_id;
|
||||||
|
|
||||||
/* Set the exception type, and clear the count. */
|
/* Set the exception type, and clear the count. */
|
||||||
info->info.exception.exception_type = static_cast<ams::svc::DebugException>(param0);
|
info->info.exception.exception_type = static_cast<ams::svc::DebugException>(params[0]);
|
||||||
info->info.exception.exception_data_count = 0;
|
info->info.exception.exception_data_count = 0;
|
||||||
switch (static_cast<ams::svc::DebugException>(param0)) {
|
switch (static_cast<ams::svc::DebugException>(params[0])) {
|
||||||
case ams::svc::DebugException_UndefinedInstruction:
|
case ams::svc::DebugException_UndefinedInstruction:
|
||||||
case ams::svc::DebugException_BreakPoint:
|
case ams::svc::DebugException_BreakPoint:
|
||||||
case ams::svc::DebugException_UndefinedSystemCall:
|
case ams::svc::DebugException_UndefinedSystemCall:
|
||||||
{
|
{
|
||||||
info->info.exception.exception_address = param1;
|
MESOSPHERE_ASSERT(num_params >= 3);
|
||||||
|
|
||||||
|
info->info.exception.exception_address = params[1];
|
||||||
|
|
||||||
info->info.exception.exception_data_count = 1;
|
info->info.exception.exception_data_count = 1;
|
||||||
info->info.exception.exception_data[0] = param2;
|
info->info.exception.exception_data[0] = params[2];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugException_DebuggerAttached:
|
case ams::svc::DebugException_DebuggerAttached:
|
||||||
@@ -800,12 +827,14 @@ namespace ams::kern {
|
|||||||
break;
|
break;
|
||||||
case ams::svc::DebugException_UserBreak:
|
case ams::svc::DebugException_UserBreak:
|
||||||
{
|
{
|
||||||
info->info.exception.exception_address = param1;
|
MESOSPHERE_ASSERT(num_params >= 2);
|
||||||
|
|
||||||
info->info.exception.exception_data_count = 3;
|
info->info.exception.exception_address = params[1];
|
||||||
info->info.exception.exception_data[0] = param2;
|
|
||||||
info->info.exception.exception_data[1] = param3;
|
info->info.exception.exception_data_count = 0;
|
||||||
info->info.exception.exception_data[2] = param4;
|
for (size_t i = 2; i < num_params; ++i) {
|
||||||
|
info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugException_DebuggerBreak:
|
case ams::svc::DebugException_DebuggerBreak:
|
||||||
@@ -814,11 +843,10 @@ namespace ams::kern {
|
|||||||
|
|
||||||
info->info.exception.exception_address = 0;
|
info->info.exception.exception_address = 0;
|
||||||
|
|
||||||
info->info.exception.exception_data_count = 4;
|
info->info.exception.exception_data_count = 0;
|
||||||
info->info.exception.exception_data[0] = param1;
|
for (size_t i = 1; i < num_params; ++i) {
|
||||||
info->info.exception.exception_data[1] = param2;
|
info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i];
|
||||||
info->info.exception.exception_data[2] = param3;
|
}
|
||||||
info->info.exception.exception_data[3] = param4;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugException_MemorySystemError:
|
case ams::svc::DebugException_MemorySystemError:
|
||||||
@@ -831,7 +859,9 @@ namespace ams::kern {
|
|||||||
case ams::svc::DebugException_AlignmentFault:
|
case ams::svc::DebugException_AlignmentFault:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
info->info.exception.exception_address = param1;
|
MESOSPHERE_ASSERT(num_params >= 2);
|
||||||
|
|
||||||
|
info->info.exception.exception_address = params[1];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -843,9 +873,9 @@ namespace ams::kern {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KDebugBase::PushDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) {
|
void KDebugBase::PushDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) {
|
||||||
/* Create and enqueue and event. */
|
/* Create and enqueue and event. */
|
||||||
if (KEventInfo *new_info = CreateDebugEvent(event, param0, param1, param2, param3, param4, GetCurrentThread().GetId()); new_info != nullptr) {
|
if (KEventInfo *new_info = CreateDebugEvent(event, GetCurrentThread().GetId(), params, num_params); new_info != nullptr) {
|
||||||
this->EnqueueDebugEventInfo(new_info);
|
this->EnqueueDebugEventInfo(new_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -952,7 +982,10 @@ namespace ams::kern {
|
|||||||
break;
|
break;
|
||||||
case ams::svc::DebugException_DebuggerBreak:
|
case ams::svc::DebugException_DebuggerBreak:
|
||||||
{
|
{
|
||||||
MESOSPHERE_ASSERT(info->info.exception.exception_data_count == 4);
|
/* TODO: How does this work with non-4 cpu count? */
|
||||||
|
static_assert(cpu::NumCores <= 4);
|
||||||
|
|
||||||
|
MESOSPHERE_ASSERT(info->info.exception.exception_data_count == cpu::NumCores);
|
||||||
out->info.exception.specific.debugger_break.active_thread_ids[0] = info->info.exception.exception_data[0];
|
out->info.exception.specific.debugger_break.active_thread_ids[0] = info->info.exception.exception_data[0];
|
||||||
out->info.exception.specific.debugger_break.active_thread_ids[1] = info->info.exception.exception_data[1];
|
out->info.exception.specific.debugger_break.active_thread_ids[1] = info->info.exception.exception_data[1];
|
||||||
out->info.exception.specific.debugger_break.active_thread_ids[2] = info->info.exception.exception_data[2];
|
out->info.exception.specific.debugger_break.active_thread_ids[2] = info->info.exception.exception_data[2];
|
||||||
@@ -1066,7 +1099,7 @@ namespace ams::kern {
|
|||||||
return !empty || !m_is_attached || this->GetProcessUnsafe()->IsTerminated();
|
return !empty || !m_is_attached || this->GetProcessUnsafe()->IsTerminated();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KDebugBase::ProcessDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) {
|
Result KDebugBase::ProcessDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) {
|
||||||
/* Get the current process. */
|
/* Get the current process. */
|
||||||
KProcess *process = GetCurrentProcessPointer();
|
KProcess *process = GetCurrentProcessPointer();
|
||||||
|
|
||||||
@@ -1108,7 +1141,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Push the event. */
|
/* Push the event. */
|
||||||
debug->PushDebugEvent(event, param0, param1, param2, param3, param4);
|
debug->PushDebugEvent(event, params, num_params);
|
||||||
debug->NotifyAvailable();
|
debug->NotifyAvailable();
|
||||||
|
|
||||||
/* Set the process as breaked. */
|
/* Set the process as breaked. */
|
||||||
@@ -1144,9 +1177,9 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KDebugBase::OnDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) {
|
Result KDebugBase::OnDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) {
|
||||||
if (KProcess *process = GetCurrentProcessPointer(); process != nullptr && process->IsAttachedToDebugger()) {
|
if (KProcess *process = GetCurrentProcessPointer(); process != nullptr && process->IsAttachedToDebugger()) {
|
||||||
R_RETURN(ProcessDebugEvent(event, param0, param1, param2, param3, param4));
|
R_RETURN(ProcessDebugEvent(event, params, num_params));
|
||||||
}
|
}
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -1161,7 +1194,8 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Push the event. */
|
/* Push the event. */
|
||||||
if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) {
|
if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) {
|
||||||
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, ams::svc::ProcessExitReason_ExitProcess);
|
const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::ProcessExitReason_ExitProcess) };
|
||||||
|
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, params, util::size(params));
|
||||||
debug->NotifyAvailable();
|
debug->NotifyAvailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1179,7 +1213,8 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Push the event. */
|
/* Push the event. */
|
||||||
if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) {
|
if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) {
|
||||||
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, ams::svc::ProcessExitReason_TerminateProcess);
|
const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::ProcessExitReason_TerminateProcess) };
|
||||||
|
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, params, util::size(params));
|
||||||
debug->NotifyAvailable();
|
debug->NotifyAvailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1193,7 +1228,8 @@ namespace ams::kern {
|
|||||||
/* Check if we're attached to a debugger. */
|
/* Check if we're attached to a debugger. */
|
||||||
if (KProcess *process = thread->GetOwnerProcess(); process != nullptr && process->IsAttachedToDebugger()) {
|
if (KProcess *process = thread->GetOwnerProcess(); process != nullptr && process->IsAttachedToDebugger()) {
|
||||||
/* If we are, submit the event. */
|
/* If we are, submit the event. */
|
||||||
R_TRY(OnDebugEvent(ams::svc::DebugEvent_ExitThread, thread->GetId(), thread->IsTerminationRequested() ? ams::svc::ThreadExitReason_TerminateThread : ams::svc::ThreadExitReason_ExitThread));
|
const uintptr_t params[2] = { thread->GetId(), static_cast<uintptr_t>(thread->IsTerminationRequested() ? ams::svc::ThreadExitReason_TerminateThread : ams::svc::ThreadExitReason_ExitThread) };
|
||||||
|
R_TRY(OnDebugEvent(ams::svc::DebugEvent_ExitThread, params, util::size(params)));
|
||||||
}
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
|||||||
@@ -73,6 +73,120 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NOINLINE void LoadInitialProcessSegment(const KPageGroup &pg, size_t seg_offset, size_t seg_size, size_t binary_size, KVirtualAddress data, bool compressed) {
|
||||||
|
/* Save the original binary extents, for later use. */
|
||||||
|
const KPhysicalAddress binary_phys = KMemoryLayout::GetLinearPhysicalAddress(data);
|
||||||
|
|
||||||
|
/* Create a page group representing the segment. */
|
||||||
|
KPageGroup segment_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
||||||
|
if (size_t remaining_size = util::AlignUp(seg_size, PageSize); remaining_size != 0) {
|
||||||
|
/* Find the pages whose data corresponds to the segment. */
|
||||||
|
size_t cur_offset = 0;
|
||||||
|
for (auto it = pg.begin(); it != pg.end() && remaining_size > 0; ++it) {
|
||||||
|
/* Get the current size. */
|
||||||
|
const size_t cur_size = it->GetSize();
|
||||||
|
|
||||||
|
/* Determine if the offset is in range. */
|
||||||
|
const size_t rel_diff = seg_offset - cur_offset;
|
||||||
|
const bool is_before = cur_offset <= seg_offset;
|
||||||
|
cur_offset += cur_size;
|
||||||
|
if (is_before && seg_offset < cur_offset) {
|
||||||
|
/* It is, so add the block. */
|
||||||
|
const size_t block_size = std::min<size_t>(cur_size - rel_diff, remaining_size);
|
||||||
|
MESOSPHERE_R_ABORT_UNLESS(segment_pg.AddBlock(it->GetAddress() + rel_diff, block_size / PageSize));
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
cur_offset = seg_offset + block_size;
|
||||||
|
remaining_size -= block_size;
|
||||||
|
seg_offset += block_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup the new page group's memory so that we can load the segment. */
|
||||||
|
{
|
||||||
|
KVirtualAddress last_block = Null<KVirtualAddress>;
|
||||||
|
KVirtualAddress last_data = Null<KVirtualAddress>;
|
||||||
|
size_t last_copy_size = 0;
|
||||||
|
size_t last_clear_size = 0;
|
||||||
|
size_t remaining_copy_size = binary_size;
|
||||||
|
for (const auto &block : segment_pg) {
|
||||||
|
/* Get the current block extents. */
|
||||||
|
const auto block_addr = block.GetAddress();
|
||||||
|
const size_t block_size = block.GetSize();
|
||||||
|
if (remaining_copy_size > 0) {
|
||||||
|
/* Determine if we need to copy anything. */
|
||||||
|
const size_t cur_size = std::min<size_t>(block_size, remaining_copy_size);
|
||||||
|
|
||||||
|
/* NOTE: The first block may potentially overlap the binary we want to copy to. */
|
||||||
|
/* Consider e.g. the case where the overall compressed image has size 0x40000, seg_offset is 0x30000, and binary_size is > 0x20000. */
|
||||||
|
/* Suppose too that data points, say, 0x18000 into the compressed image. */
|
||||||
|
/* Suppose finally that we simply naively copy in order. */
|
||||||
|
/* The first iteration of this loop will perform an 0x10000 copy from image+0x18000 to image + 0x30000 (as there is no overlap). */
|
||||||
|
/* The second iteration will perform a copy from image+0x28000 to <allocated pages>. */
|
||||||
|
/* However, the first copy will have trashed the data in the second copy. */
|
||||||
|
/* Thus, we must copy the first block after-the-fact to avoid potentially trashing data in the overlap case. */
|
||||||
|
/* It is guaranteed by pre-condition that only the very first block can overlap with the physical binary, so we can simply memmove it at the end. */
|
||||||
|
if (last_block != Null<KVirtualAddress>) {
|
||||||
|
/* This is guaranteed by pre-condition, but for ease of debugging, check for no overlap. */
|
||||||
|
MESOSPHERE_ASSERT(!util::HasOverlap(GetInteger(binary_phys), binary_size, GetInteger(block_addr), cur_size));
|
||||||
|
MESOSPHERE_UNUSED(binary_phys);
|
||||||
|
|
||||||
|
/* We need to copy. */
|
||||||
|
std::memcpy(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block_addr)), GetVoidPointer(data), cur_size);
|
||||||
|
|
||||||
|
/* If we need to, clear past where we're copying. */
|
||||||
|
if (cur_size != block_size) {
|
||||||
|
std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block_addr + cur_size)), 0, block_size - cur_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
remaining_copy_size -= cur_size;
|
||||||
|
data += cur_size;
|
||||||
|
} else {
|
||||||
|
/* Save the first block, which may potentially overlap, so that we can copy it later. */
|
||||||
|
last_block = KMemoryLayout::GetLinearVirtualAddress(block_addr);
|
||||||
|
last_data = data;
|
||||||
|
last_copy_size = cur_size;
|
||||||
|
last_clear_size = block_size - cur_size;
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
remaining_copy_size -= cur_size;
|
||||||
|
data += cur_size;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* We don't have data to copy, so we should just clear the pages. */
|
||||||
|
std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block_addr)), 0, block_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle a last block. */
|
||||||
|
if (last_copy_size != 0) {
|
||||||
|
if (last_block != last_data) {
|
||||||
|
std::memmove(GetVoidPointer(last_block), GetVoidPointer(last_data), last_copy_size);
|
||||||
|
}
|
||||||
|
if (last_clear_size != 0) {
|
||||||
|
std::memset(GetVoidPointer(last_block + last_copy_size), 0, last_clear_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If compressed, uncompress the data. */
|
||||||
|
if (compressed) {
|
||||||
|
/* Get the temporary region. */
|
||||||
|
const auto &temp_region = KMemoryLayout::GetTempRegion();
|
||||||
|
MESOSPHERE_ABORT_UNLESS(temp_region.GetEndAddress() != 0);
|
||||||
|
|
||||||
|
/* Map the process's memory into the temporary region. */
|
||||||
|
KProcessAddress temp_address = Null<KProcessAddress>;
|
||||||
|
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().MapPageGroup(std::addressof(temp_address), segment_pg, temp_region.GetAddress(), temp_region.GetSize() / PageSize, KMemoryState_Kernel, KMemoryPermission_KernelReadWrite));
|
||||||
|
ON_SCOPE_EXIT { MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().UnmapPageGroup(temp_address, segment_pg, KMemoryState_Kernel)); };
|
||||||
|
|
||||||
|
/* Uncompress the data. */
|
||||||
|
BlzUncompress(GetVoidPointer(temp_address + binary_size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KInitialProcessReader::MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const {
|
Result KInitialProcessReader::MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const {
|
||||||
@@ -113,11 +227,13 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_ABORT_UNLESS(start_address == 0);
|
MESOSPHERE_ABORT_UNLESS(start_address == 0);
|
||||||
|
|
||||||
/* Set fields in parameter. */
|
/* Set fields in parameter. */
|
||||||
out->code_address = map_start + start_address;
|
out->code_address = map_start + start_address;
|
||||||
out->code_num_pages = util::AlignUp(end_address - start_address, PageSize) / PageSize;
|
out->code_num_pages = util::AlignUp(end_address - start_address, PageSize) / PageSize;
|
||||||
out->program_id = m_kip_header.GetProgramId();
|
out->program_id = m_kip_header.GetProgramId();
|
||||||
out->version = m_kip_header.GetVersion();
|
out->version = m_kip_header.GetVersion();
|
||||||
out->flags = 0;
|
out->flags = 0;
|
||||||
|
out->reslimit = ams::svc::InvalidHandle;
|
||||||
|
out->system_resource_num_pages = 0;
|
||||||
MESOSPHERE_ABORT_UNLESS((out->code_address / PageSize) + out->code_num_pages <= (map_end / PageSize));
|
MESOSPHERE_ABORT_UNLESS((out->code_address / PageSize) + out->code_num_pages <= (map_end / PageSize));
|
||||||
|
|
||||||
/* Copy name field. */
|
/* Copy name field. */
|
||||||
@@ -146,42 +262,55 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KInitialProcessReader::Load(KProcessAddress address, const ams::svc::CreateProcessParameter ¶ms, KProcessAddress src) const {
|
void KInitialProcessReader::Load(const KPageGroup &pg, KVirtualAddress data) const {
|
||||||
/* Prepare to layout the data. */
|
/* Prepare to layout the data. */
|
||||||
const KProcessAddress rx_address = address + m_kip_header.GetRxAddress();
|
const KVirtualAddress rx_data = data;
|
||||||
const KProcessAddress ro_address = address + m_kip_header.GetRoAddress();
|
const KVirtualAddress ro_data = rx_data + m_kip_header.GetRxCompressedSize();
|
||||||
const KProcessAddress rw_address = address + m_kip_header.GetRwAddress();
|
const KVirtualAddress rw_data = ro_data + m_kip_header.GetRoCompressedSize();
|
||||||
const u8 *rx_binary = GetPointer<const u8>(src);
|
const size_t rx_size = m_kip_header.GetRxSize();
|
||||||
const u8 *ro_binary = rx_binary + m_kip_header.GetRxCompressedSize();
|
const size_t ro_size = m_kip_header.GetRoSize();
|
||||||
const u8 *rw_binary = ro_binary + m_kip_header.GetRoCompressedSize();
|
const size_t rw_size = m_kip_header.GetRwSize();
|
||||||
|
|
||||||
/* Copy text. */
|
/* If necessary, setup bss. */
|
||||||
if (util::AlignUp(m_kip_header.GetRxSize(), PageSize)) {
|
if (const size_t bss_size = m_kip_header.GetBssSize(); bss_size > 0) {
|
||||||
std::memmove(GetVoidPointer(rx_address), rx_binary, m_kip_header.GetRxCompressedSize());
|
/* Determine how many additional pages are needed for bss. */
|
||||||
if (m_kip_header.IsRxCompressed()) {
|
const u64 rw_end = util::AlignUp<u64>(m_kip_header.GetRwAddress() + m_kip_header.GetRwSize(), PageSize);
|
||||||
BlzUncompress(GetVoidPointer(rx_address + m_kip_header.GetRxCompressedSize()));
|
const u64 bss_end = util::AlignUp<u64>(m_kip_header.GetBssAddress() + m_kip_header.GetBssSize(), PageSize);
|
||||||
|
if (rw_end != bss_end) {
|
||||||
|
/* Find the pages corresponding to bss. */
|
||||||
|
size_t cur_offset = 0;
|
||||||
|
size_t remaining_size = bss_end - rw_end;
|
||||||
|
size_t bss_offset = rw_end - m_kip_header.GetRxAddress();
|
||||||
|
for (auto it = pg.begin(); it != pg.end() && remaining_size > 0; ++it) {
|
||||||
|
/* Get the current size. */
|
||||||
|
const size_t cur_size = it->GetSize();
|
||||||
|
|
||||||
|
/* Determine if the offset is in range. */
|
||||||
|
const size_t rel_diff = bss_offset - cur_offset;
|
||||||
|
const bool is_before = cur_offset <= bss_offset;
|
||||||
|
cur_offset += cur_size;
|
||||||
|
if (is_before && bss_offset < cur_offset) {
|
||||||
|
/* It is, so clear the bss range. */
|
||||||
|
const size_t block_size = std::min<size_t>(cur_size - rel_diff, remaining_size);
|
||||||
|
std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(it->GetAddress() + rel_diff)), 0, block_size);
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
cur_offset = bss_offset + block_size;
|
||||||
|
remaining_size -= block_size;
|
||||||
|
bss_offset += block_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy rodata. */
|
/* Load .rwdata. */
|
||||||
if (util::AlignUp(m_kip_header.GetRoSize(), PageSize)) {
|
LoadInitialProcessSegment(pg, m_kip_header.GetRwAddress() - m_kip_header.GetRxAddress(), rw_size, m_kip_header.GetRwCompressedSize(), rw_data, m_kip_header.IsRwCompressed());
|
||||||
std::memmove(GetVoidPointer(ro_address), ro_binary, m_kip_header.GetRoCompressedSize());
|
|
||||||
if (m_kip_header.IsRoCompressed()) {
|
|
||||||
BlzUncompress(GetVoidPointer(ro_address + m_kip_header.GetRoCompressedSize()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy rwdata. */
|
/* Load .rodata. */
|
||||||
if (util::AlignUp(m_kip_header.GetRwSize(), PageSize)) {
|
LoadInitialProcessSegment(pg, m_kip_header.GetRoAddress() - m_kip_header.GetRxAddress(), ro_size, m_kip_header.GetRoCompressedSize(), ro_data, m_kip_header.IsRoCompressed());
|
||||||
std::memmove(GetVoidPointer(rw_address), rw_binary, m_kip_header.GetRwCompressedSize());
|
|
||||||
if (m_kip_header.IsRwCompressed()) {
|
|
||||||
BlzUncompress(GetVoidPointer(rw_address + m_kip_header.GetRwCompressedSize()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MESOSPHERE_UNUSED(params);
|
/* Load .text. */
|
||||||
|
LoadInitialProcessSegment(pg, m_kip_header.GetRxAddress() - m_kip_header.GetRxAddress(), rx_size, m_kip_header.GetRxCompressedSize(), rx_data, m_kip_header.IsRxCompressed());
|
||||||
R_SUCCEED();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KInitialProcessReader::SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter ¶ms) const {
|
Result KInitialProcessReader::SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter ¶ms) const {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Check if the address/size falls within any allowable extents. */
|
/* Check if the address/size falls within any allowable extents. */
|
||||||
for (const auto &extents : g_io_region_extents) {
|
for (const auto &extents : g_io_region_extents) {
|
||||||
if (extents.address <= address && address + size - 1 <= extents.address + extents.size - 1) {
|
if (extents.size != 0 && extents.address <= address && address + size - 1 <= extents.address + extents.size - 1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,12 +106,23 @@ namespace ams::kern {
|
|||||||
KScopedLightLock lk(m_lock);
|
KScopedLightLock lk(m_lock);
|
||||||
|
|
||||||
/* Check that the desired range isn't already in our pool. */
|
/* Check that the desired range isn't already in our pool. */
|
||||||
for (const auto ®ion : m_io_region_list) {
|
{
|
||||||
R_UNLESS(!region.Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
|
/* Get the lowest region with address >= the new region that's already in our tree. */
|
||||||
|
auto lowest_after = m_io_region_tree.nfind_key(new_region->GetAddress());
|
||||||
|
if (lowest_after != m_io_region_tree.end()) {
|
||||||
|
R_UNLESS(!lowest_after->Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is no region with address >= the new region already in our tree, but we also need to check */
|
||||||
|
/* for a region with address < the new region already in our tree. */
|
||||||
|
if (lowest_after != m_io_region_tree.begin()) {
|
||||||
|
auto highest_before = --lowest_after;
|
||||||
|
R_UNLESS(!highest_before->Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the region to our pool. */
|
/* Add the region to our pool. */
|
||||||
m_io_region_list.push_back(*new_region);
|
m_io_region_tree.insert(*new_region);
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -122,8 +133,8 @@ namespace ams::kern {
|
|||||||
/* Lock ourselves. */
|
/* Lock ourselves. */
|
||||||
KScopedLightLock lk(m_lock);
|
KScopedLightLock lk(m_lock);
|
||||||
|
|
||||||
/* Remove the region from our list. */
|
/* Remove the region from our tree. */
|
||||||
m_io_region_list.erase(m_io_region_list.iterator_to(*region));
|
m_io_region_tree.erase(m_io_region_tree.iterator_to(*region));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user