Compare commits

..

46 Commits

Author SHA1 Message Date
Michael Scire
4fa8325f74 ams: update Makefile to build zips with new names 2021-01-05 09:43:09 -08:00
Michael Scire
6baf1d6593 fusee: pass along lcd vendor to exosphere (needed for mariko fatal) 2021-01-05 09:32:57 -08:00
Michael Scire
95b49294df docs/changelog: don't let dreams remain memes 2021-01-05 09:28:08 -08:00
Michael Scire
557903cfa7 fusee: perform only pmic reboots on mariko 2021-01-05 00:57:37 -08:00
Michael Scire
c06f0440fd ams: provisional changelog for 0.17.0, release sometime this week 2021-01-05 00:45:32 -08:00
Michael Scire
23cb37d6be pmic: use correct shutdown impl for erista power-off 2021-01-05 00:30:28 -08:00
Michael Scire
a2535c7330 sept: fix sdram parameter scratch save 2021-01-05 00:22:38 -08:00
Michael Scire
e43a960b5d ams: mariko support implies 0.17.0 2021-01-04 17:20:54 -08:00
Michael Scire
feed7550f5 sept: fixes to work with new hwinit/etc 2021-01-04 17:18:13 -08:00
Michael Scire
be897d728d sept is erista-only, and doesn't need mariko sdram (space saving measure) 2021-01-04 14:10:59 -08:00
Michael Scire
0dc6bcb180 fusee: fix overcorrection for boot reason address 2021-01-04 11:33:27 -08:00
Michael Scire
45bae80f18 fusee: sdram scratch fixes 2021-01-04 02:37:05 -08:00
Michael Scire
6e9675916c fusee: implement mariko warmboot firmware cache 2021-01-04 00:55:52 -08:00
Michael Scire
b74742e0a1 fusee/exo: fixes to allow booting (sleep broken until warmboot cache implemented) 2021-01-03 23:46:13 -08:00
Michael Scire
d153a8fa5a fusee: commit pre-rendered splash binary 2021-01-03 22:47:24 -08:00
hexkyz
fa53d11cae fusee: fix regulator configuration 2021-01-03 16:24:54 +00:00
Michael Scire
200da4c2da fusee: execute more ccplex boot code out of iram 2021-01-01 16:44:43 -08:00
Michael Scire
539dbf0800 fusee: use pre-rendered splash screen instead of bmp 2021-01-01 16:26:00 -08:00
Michael Scire
c3bf204627 fusee: minor hwinit fixes 2021-01-01 16:03:57 -08:00
hexkyz
2920c042e1 fusee: fix cluster bringup for mariko 2021-01-01 16:37:16 +00:00
Michael Scire
a968d0be32 fusee: fix support for mariko key derivation/package1 parsing 2020-12-31 23:29:00 -08:00
Michael Scire
52c7932f1f fusee: add special log level for sd card debug 2020-12-31 18:35:26 -08:00
Michael Scire
ec398dc612 fusee/sept: build fixes 2020-12-31 18:07:11 -08:00
hexkyz
a35a30efcd fusee: fix mariko master key derivation 2020-12-31 16:02:49 -08:00
hexkyz
8402ea7e93 fusee: cleanup code and start fleshing out mariko keygen 2020-12-31 16:02:49 -08:00
hexkyz
c356e1ab36 fusee: start fleshing out nxboot for Mariko 2020-12-31 16:02:49 -08:00
hexkyz
4d4fc19cba fusee: accurately match Mariko pk1ldr 2020-12-31 16:02:49 -08:00
hexkyz
0a0cc52846 fusee: 11.0.0 support 2020-12-31 16:02:49 -08:00
hexkyz
f40fa150d8 fusee/sept: delegate SoC selection to individual components and keep common code SoC-agnostic 2020-12-31 16:02:48 -08:00
hexkyz
db8a367834 fusee: artificially raise main length to avoid elf compilation issues (final size will be much smaller) 2020-12-31 16:02:48 -08:00
hexkyz
d083384f2f fusee: move dsi register write to the proper configuration list 2020-12-31 16:02:48 -08:00
hexkyz
83fa9983bf fusee: update display code for mariko 2020-12-31 16:02:48 -08:00
Michael Scire
b9428dd2f3 fusee: fixup extents for chainloader/stack 2020-12-31 16:02:48 -08:00
Michael Scire
dc52610bd8 fusee-primary: fix reboot-to-self for decompressed code 2020-12-31 16:02:48 -08:00
Michael Scire
7ed9bdd374 fusee/sept: fix fuse driver to not infinitely recurse on get_soc_type() 2020-12-31 16:02:48 -08:00
Michael Scire
1107d4858c fusee: fixup common for primary 2020-12-31 16:02:48 -08:00
Michael Scire
eb1b624219 fusee: uncompress fusee-primary, which is now getting pretty big. 2020-12-31 16:02:48 -08:00
hexkyz
5012782237 fusee: implement mariko sdram params saving 2020-12-31 16:02:47 -08:00
hexkyz
736360e965 fusee: mariko sdram initialization 2020-12-31 16:02:47 -08:00
hexkyz
4111aa0a83 fusee: initial mariko hwinit 2020-12-31 16:02:47 -08:00
hexkyz
6671d46c8d fusee: support mariko in sdmmc 2020-12-31 16:02:47 -08:00
hexkyz
b14dd4fd5f fusee/sept: support mariko fuses 2020-12-31 16:02:47 -08:00
hexkyz
b917d7c886 fusee/sept: update fuse driver code 2020-12-31 16:02:47 -08:00
hexkyz
6263a54be5 fusee: fix sdmmc speed modes 2020-12-31 16:02:46 -08:00
hexkyz
a266e9b11a fusee: update FatFs to R0.14 2020-12-31 16:02:46 -08:00
hexkyz
b5d866f5a0 fusee/sept: isolate common code for mariko preparation (to be revised during C++ rewrite) 2020-12-31 16:02:46 -08:00
1002 changed files with 8155 additions and 67028 deletions

2
.gitignore vendored
View File

@@ -95,5 +95,3 @@ sept/sept-secondary/KEYS.py
**/build_nintendo_nx_arm
**/build_nintendo_nx_x64
**/build_nintendo_nx_x86
stratosphere/test/

View File

@@ -1,9 +1,3 @@
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPro)
endif
include $(DEVKITPRO)/devkitA64/base_tools
TOPTARGETS := all clean dist-no-debug dist
AMSBRANCH := $(shell git symbolic-ref --short HEAD)
AMSHASH := $(shell git rev-parse --short HEAD)
@@ -62,11 +56,18 @@ dist-no-debug: all
mkdir atmosphere-$(AMSVER)/atmosphere
mkdir atmosphere-$(AMSVER)/sept
mkdir atmosphere-$(AMSVER)/switch
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000008
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000000D
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000002B
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000003C
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000042
mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors
mkdir -p atmosphere-$(AMSVER)/atmosphere/config_templates
mkdir -p atmosphere-$(AMSVER)/atmosphere/config
mkdir -p atmosphere-$(AMSVER)/atmosphere/flags
touch atmosphere-$(AMSVER)/atmosphere/flags/clean_stratosphere_for_0.19.0.flag
cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin
cp fusee/fusee-mtc/fusee-mtc.bin atmosphere-$(AMSVER)/atmosphere/fusee-mtc.bin
cp fusee/fusee-secondary/fusee-secondary-experimental.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin
@@ -83,27 +84,19 @@ dist-no-debug: all
cp config_templates/exosphere.ini atmosphere-$(AMSVER)/atmosphere/config_templates/exosphere.ini
cp -r config_templates/kip_patches atmosphere-$(AMSVER)/atmosphere/kip_patches
cp -r config_templates/hbl_html atmosphere-$(AMSVER)/atmosphere/hbl_html
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000000D
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000002B
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000032
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000034
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000036
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000037
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000003C
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042
cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008/exefs.nsp
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000000D/exefs.nsp
cp stratosphere/erpt/erpt.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000002B/exefs.nsp
cp stratosphere/eclct.stub/eclct.stub.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000032/exefs.nsp
cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000034/exefs.nsp
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000036/exefs.nsp
cp stratosphere/ro/ro.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000037/exefs.nsp
cp stratosphere/jpegdec/jpegdec.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000003C/exefs.nsp
cp stratosphere/pgl/pgl.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp
@build_romfs atmosphere-$(AMSVER)/stratosphere_romfs atmosphere-$(AMSVER)/atmosphere/stratosphere.romfs
rm -r atmosphere-$(AMSVER)/stratosphere_romfs
cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000008/exefs.nsp
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/atmosphere/contents/010000000000000D/exefs.nsp
cp stratosphere/erpt/erpt.nsp atmosphere-$(AMSVER)/atmosphere/contents/010000000000002B/exefs.nsp
cp stratosphere/eclct.stub/eclct.stub.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/exefs.nsp
cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034/exefs.nsp
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036/exefs.nsp
cp stratosphere/ro/ro.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/exefs.nsp
cp stratosphere/jpegdec/jpegdec.nsp atmosphere-$(AMSVER)/atmosphere/contents/010000000000003C/exefs.nsp
cp stratosphere/pgl/pgl.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000042/exefs.nsp
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/flags
touch atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/flags/boot2.flag
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/flags
touch atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/flags/boot2.flag
cp troposphere/reboot_to_payload/reboot_to_payload.nro atmosphere-$(AMSVER)/switch/reboot_to_payload.nro
cp troposphere/daybreak/daybreak.nro atmosphere-$(AMSVER)/switch/daybreak.nro
cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../;
@@ -142,7 +135,6 @@ dist: dist-no-debug
cp exosphere/program/sc7fw/sc7fw.elf atmosphere-$(AMSVER)-debug/exosphere-sc7fw.elf
cp exosphere/program/rebootstub/rebootstub.elf atmosphere-$(AMSVER)-debug/exosphere-rebootstub.elf
cp mesosphere/kernel_ldr/kernel_ldr.elf atmosphere-$(AMSVER)-debug/kernel_ldr.elf
cp mesosphere/kernel/kernel.elf atmosphere-$(AMSVER)-debug/kernel.elf
cp stratosphere/ams_mitm/ams_mitm.elf atmosphere-$(AMSVER)-debug/ams_mitm.elf
cp stratosphere/boot/boot.elf atmosphere-$(AMSVER)-debug/boot.elf
cp stratosphere/boot2/boot2.elf atmosphere-$(AMSVER)-debug/boot2.elf

View File

@@ -1,13 +1,9 @@
[eupld]
; Disable uploading error reports to Nintendo
[eupld]
; upload_enabled = u8!0x0
[usb]
; Enable USB 3.0 superspeed for homebrew
; 0 = USB 3.0 support is system default (usually disabled), 1 = USB 3.0 support is enabled.
; usb30_force_enabled = u8!0x0
[ro]
; Control whether RO should ease its validation of NROs.
; (note: this is normally not necessary, and ips patches can be used.)
[ro]
; ease_nro_restriction = u8!0x1
; Atmosphere custom settings
[atmosphere]
@@ -36,23 +32,16 @@
; NOTE: EXPERIMENTAL
; If you do not know what you are doing, do not touch this yet.
; fsmitm_redirect_saves_to_sd = u8!0x0
; Controls whether to enable the deprecated hid mitm
; to fix compatibility with old homebrew.
; 0 = Do not enable, 1 = Enable.
; Please note this setting may be removed in a
; future release of Atmosphere.
; enable_deprecated_hid_mitm = u8!0x0
; Controls whether am sees system settings "DebugModeFlag" as
; enabled or disabled.
; 0 = Disabled (not debug mode), 1 = Enabled (debug mode)
; enable_am_debug_mode = u8!0x0
; Controls whether dns.mitm is enabled
; 0 = Disabled, 1 = Enabled
; enable_dns_mitm = u8!0x1
; Controls whether dns.mitm uses the default redirections in addition to
; whatever is specified in the user's hosts file.
; 0 = Disabled (use hosts file contents), 1 = Enabled (use defaults and hosts file contents)
; add_defaults_to_dns_hosts = u8!0x1
; Controls whether dns.mitm logs to the sd card for debugging
; 0 = Disabled, 1 = Enabled
; enable_dns_mitm_debug_log = u8!0x0
; Controls whether htc is enabled
; 0 = Disabled, 1 = Enabled
; enable_htc = u8!0x0
[hbloader]
; Controls the size of the homebrew heap when running as applet.
; If set to zero, all available applet memory is used as heap.

View File

@@ -1,96 +1,4 @@
# Changelog
## 0.19.2
+ Atmosphère's components were further updated to reflect latest official behaviors as of 12.0.0.
+ Notably, `erpt` was updated to implement the new forced shutdown detection feature.
+ When a forced-shutdown occurs, an erpt_report will be generated and saved to the SD card on the next boot.
+ Atmosphere-libs was updated to use GCC 11 (latest devkitA64/devkitARM releases).
+ Initial inspections show mild-to-moderate optimizer improvements in several important places (kernel is 0x3000 smaller).
+ General system stability improvements to enhance the user's experience.
+ A number of minor issues were fixed, including:
+ A bug was fixed that caused a black screen when attempting to boot firmware versions 2.0.0-4.1.0.
+ A bug was fixed that caused sm to abort when at the session limit, rather than returning error codes.
+ A bug was fixed that allowed for resource exhaustion on 12.0.0, under certain circumstances.
+ Several issues were fixed, and usability and stability were improved.
## 0.19.1
+ An issue was fixed that caused a fatal error when using official `migration` services to transfer data between consoles.
+ An issue was fixed in `ncm` that caused an error when the OS tried to enumerate installed SD card content.
+ Several issues were fixed, and usability and stability were improved.
## 0.19.0
+ Support was added for 12.0.0.
+ `mesosphère` was updated to reflect the latest official kernel behavior.
+ `sm`, `boot2`, `pgl` were updated to reflect the latest official behaviors.
+ **Please Note**: 12.0.0 added a new protocol for IPC ("tipc"), which has been freshly reimplemented in its entirety.
+ It is possible there may be as of yet unfound issues; if there are, please send the appropriate crash reports to SciresM (SciresM#0524 on discord).
+ Homebrew which uses atmosphere extensions (including the mitm API) will need to be re-compiled in order to function on 0.19.0.
+ I apologize for this, but it's unavoidable for technical reasons. If you're affected by this and mad about it, please contact SciresM to complain.
+ `erpt` was partially updated to reflect the latest official behaviors.
+ New features were added to erpt to track the activity of running applets, and to detect when a forced shutdown occurs.
+ These behaviors have been temporarily stubbed, as they are not necessary for 12.0.0 to run (and their outputs won't be saved anywhere).
+ A future atmosphère update will implement these behaviors, in the interest of reflecting official logic as faithfully as we can.
+ Atmosphère no longer uses the /contents/ folder for its own programs.
+ Atmosphère's system modules are now bundled together in the single file "stratosphere.romfs".
+ For those working on developing for atmosphère, executables inside the /contents/ directory will be preferred to those in "stratosphere.romfs".
+ **Please Note**: In order to facilitate this change (and the desired behavior), the first time you boot after extracting a release zip, atmosphère system modules inside /contents/ will be deleted.
+ This will have no impact on user programs (it only removes programs with specific program ids).
+ Improvements were made to mesosphere, including:
+ An extension InfoType was added for getting the current process handle, without having to spawn a thread and do IPC with oneself.
+ An issue was fixed in SvcSetDebugThreadContext.
+ An issue was fixed when doing IPC with user buffers.
+ Support was fixed for toggling the custom setting `usb!usb30_force_enabled` on 9.0.0+.
+ This was broken by Nintendo's introducing a dependency that made USB a requirement to launch before custom settings are parsed.
+ Since the fix, you can now toggle the setting (as you could prior to atmosphère 0.9.4), and it will work as expected.
+ **Please Note**: Enabling USB 3.0 often severely impacts wireless communications.
+ Because of this, the setting will default to off. If you experience issues with it enabled, consider disabling it.
+ A warning was added to daybreak when resetting the console to factory settings.
+ Substantial work was completed towards atmosphere's upcoming implementation of the host target connection protocol.
+ Once completed, users will be able to interact with a Switch running atmosphère via a PC application ("Starlink") currently under development.
+ Planned eventual features for connected consoles include a gdbstub, interacting with memory (for cheat development), streaming gameplay audio and video, and accessing the Switch's SD card filesystem.
+ Switch homebrew will also have access to a (configurable and sandboxed) filesystem on the host PC, while connected.
+ Towards this end, the following was accomplished:
+ The "htc" system module was reimplemented completely.
+ The system module which provides remote access to the SD card was reimplemented completely.
+ This is currently the active focus of atmosphère's development.
+ **Please Note**: Support is not yet completed, and users are disadvised from interacting with the related settings for the time being, unless they particularly know what they're doing.
+ A number of minor issues were fixed, including:
+ A bug was fixed in `dmnt` that could cause a fatal when launching certain games with cheats active.
+ An issue was fixed that could cause an abort in `sm` when using a large number of custom system modules.
+ An issue was fixed that prevented launching gamecards on 1.0.0.
+ Minor issues were fixed in the cheat virtual machine's behavior.
+ Several issues were fixed, and usability and stability were improved.
## 0.18.1
+ A number of minor issues were fixed, including:
+ The new `dns.mitm` module added in 0.18.0 no longer fatal errors when receiving port=nullptr.
+ This fixes youtube ad-blocking, and possibly other usecases.
+ A bug was fixed that caused ams.mitm to incorrectly cache data storages.
+ This potentially broke DLC when using romfs mods, and could have caused other issues (e.g. with custom themes, and maybe other cases).
+ A bug was fixed in power state control module registration.
+ This might fix a weird edge case with system module dependencies on sleep/wake, but probably nobody should notice any differences.
+ A bug was fixed where mesosphere sometimes treated virtual core IDs as though they were physical core IDs.
+ This had zero impact, because for Switch virtual core == physical core, but it could have affected future platforms if it had remained unresolved.
+ Several issues were fixed, and usability and stability were improved.
## 0.18.0
+ A new mitm module was added (`dns.mitm`).
+ This provides a highly configurable mechanism for redirecting DNS resolution requests.
+ By default atmosphère redirects resolution requests for official telemetry servers to a loopback address.
+ Documentation on how to configure `dns.mitm` to meet your more specific needs may be found [here](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/features/dns_mitm.md).
+ The service framework API (`sf`) was refactored to be more accurate to official logic and greatly reduce memory requirements.
+ The comparison of atmosphère module memory usage versus Nintendo's found [here](https://github.com/Atmosphere-NX/Atmosphere/wiki/Memory-Comparisons) was updated to reflect this.
+ **Please Note**: If you are a developer using the libstratosphere service APIs, some updating may be required. Contact SciresM#0524 on discord for assistance if required.
+ A number of deprecations were removed, following a general codebase cleanup:
+ The `sm` extension to not unregister services on connection close was superseded by official opt-in logic in 11.0.0, and has been removed in favor of official logic.
+ This should have zero impact on users.
+ The temporary `hid-mitm` added in 0.9.0 has finally been removed, following over a year of deprecation.
+ There shouldn't be any homebrew in use still affected by this, but the situation will be monitored.
+ If this is somehow still a real issue, an unaffiliated hid mitm sysmodule providing the same functionality can be created and released, separate from atmosphère itself.
+ Several issues were fixed, and usability and stability were improved.
## 0.17.1
+ A number of atmosphère's modules were using more memory than their Nintendo equivalent's in 0.17.0; a number of code generatio tweaks have been applied to fix this across the board.
+ A detailed comparison of atmosphère module memory usage versus Nintendo's was made and can be found [here](https://github.com/Atmosphere-NX/Atmosphere/wiki/Memory-Comparisons).
+ Several minor bugs were fixed, including:
+ A bug was fixed in mesosphère that caused games which attempt to map more memory than the Switch has to fail.
+ This affected "Piczle Lines DX 500 More Puzzles!", and possibly other games.
+ Enabling configuration to "blank" PRODINFO no longer causes a hang on Mariko devices (or any devices with newer format).
+ Several issues were fixed, and usability and stability were improved.
## 0.17.0
+ fusee was heavily rewritten in order to add support for Mariko hardware.
+ **Please Note**: Mariko hardware currently has no (and may not ever have any) software exploits; fusee works when loaded from bootloader context with the right keys in the security engine. No means of getting the system into this state is provided.
@@ -99,7 +7,7 @@
+ This also substantially improves power drain when the system is shut off; consoles powered off from Atmosphere should now drain battery at the same reduced rate as original firmware.
+ A number of minor changes were made, including:
+ A number of inconsistencies in the build system were fixed.
+ For those building atmosphère at home, the `boot` sysmodule will no longer rebuild every time make is invoked.
+ Fow those building atmosphère at home, the `boot` sysmodule will no longer rebuild every time make is invoked.
+ This substantially improves build times during development iteration.
+ `sm` was updated to more accurately reflect how official code manages request deferral.
+ `mesosphère` was updated to more accurately reflect official kernel management of the trace buffer.

View File

@@ -33,8 +33,3 @@ in settings as `#.#.#|AMS #.#.#|?` with `? = S` when running under system eMMC o
### System Settings
set_mitm intercepts the `GetSettingsItemValueSize` and `GetSettingsItemValue` commands for all requesters.
It does so in order to enable user configuration of system settings, which are parsed from `/atmosphere/system_settings.ini` on boot. See [here](../../features/configurations.md) for more information on the system settings format.
## dns_mitm
dns_mitm enables intercepting requests to dns resolution services, to enable redirecting requests for specified hostnames.
For documentation, see [here](../../features/dns_mitm.md).

View File

@@ -1,53 +0,0 @@
# DNS.mitm
As of 0.18.0, atmosphère provides a mechanism for redirecting DNS resolution requests.
By default, atmosphère redirects resolution requests for official telemetry servers, redirecting them to a loopback address.
## Hosts files
DNS.mitm can be configured through the usage of a slightly-extended `hosts` file format, which is parsed only once on system startup.
In particular, hosts files parsed by DNS.mitm have the following extensions to the usual format:
+ `*` is treated as a wildcard character, matching any collection of 0 or more characters wherever it occurs in a hostname.
+ `%` is treated as a stand-in for the value of `nsd!environment_identifier`. This is always `lp1`, on production devices.
If multiple entries in a host file match a domain, the last-defined match is used.
Please note that homebrew may trigger a hosts file re-parse by sending the extension IPC command 65000 ("AtmosphereReloadHostsFile") to a connected `sfdnsres` session.
### Hosts file selection
Atmosphère will try to read hosts from the following file paths, in order, stopping once it successfully performs a file read:
+ (emummc only) `/atmosphere/hosts/emummc_%04lx.txt`, formatted with the emummc's id number (see `emummc.ini`).
+ (emummc only) `/atmosphere/hosts/emummc.txt`.
+ (sysmmc only) `/atmosphere/hosts/sysmmc.txt`.
+ `/atmosphere/hosts/default.txt`
If `/atmosphere/hosts/default.txt` does not exist, atmosphère will create it to contain the defaults.
### Atmosphère defaults
By default, atmosphère's default redirections are parsed **in addition to** the contents of the loaded hosts file.
This is equivalent to thinking of the loaded hosts file as having the atmosphère defaults prepended to it.
This setting is considered desirable, because it minimizes the telemetry risks if a user forgets to update a custom hosts file on a system update which changes the telemetry servers.
This behavior can be opted-out from by setting `atmosphere!add_defaults_to_dns_hosts = u8!0x0` in `system_settings.ini`.
The current default redirections are:
```
# Nintendo telemetry servers
127.0.0.1 receive-%.dg.srv.nintendo.net receive-%.er.srv.nintendo.net
```
## Debugging
On startup (or on hosts file re-parse), DNS.mitm will log both what hosts file it selected and the contents of all redirections it parses to `/atmosphere/logs/dns_mitm_startup.log`.
In addition, if the user sets `atmosphere!enable_dns_mitm_debug_log = u8!0x1` in `system_settings.ini`, DNS.mitm will log all requests to GetHostByName/GetAddrInfo to `/atmosphere/logs/dns_mitm_debug.log`. All redirections will be noted when they occur.
## Opting-out of DNS.mitm entirely
If you wish to disable DNS.mitm entirely, `system_settings.ini` can be edited to set `atmosphere!enable_dns_mitm = u8!0x0`.

View File

@@ -1,32 +1,42 @@
# Planned Features
atmosphère has a number of features that are either works-in-progress or planned. Please note that while time-estimates are given, they are loose, and things may be completed sooner or later than advertised.
The following descriptions were last updated on January 14th, 2021
The following descriptions were last updated on July 7th, 2020.
## ams-on-mariko
* **Description**: Atmosphere cannot run as-is on Mariko hardware. A large number of changes are needed in many components. Although secure monitor support is complete in exosphere, additional work is needed on the bootloader and stratosphere sides as well. Mariko support will also require further design thought; atmosphere's debugging design heavily relies on reboot-to-payload and (more generally) the ability to perform warmboot bootrom hax at will. This is not possible on Mariko, and will require a new design/software support for whatever solution is chosen.
* **Development Status**: Planned.
* **Estimated Time**: Summer 2020
## settings reimplementation
* **Description**: A planned reimplementation of the settings system module, and with it a removal of the settings mitm. This will greatly simplify atmosphère's boot process, and will allow much more flexible control over the various system settings.
* **Development Status**: Undergoing research/initial development by Adubbz.
* **Estimated Time**: Mid 2020
## mesosphere
* **Description**: mesosphère is a reimplementation of the Horizon operating system's Kernel. It aims to provide an open-source reference for Nintendo's code.
* **Development Status**: Under active development by SciresM.
* **Estimated Time**: Mid-to-Late 2020
## tma reimplementation
* **Description** tma ("target manager agent") is a system module that manages communication between the Switch and a client PC. Atmosphere's implementation will allow homebrew on the switch to communicate with a connected PC to do various operations such as exchanging data or interacting with files. It will also serve as the communicator for Atmosphère's planned debugger. This will also include PC-side software for interacting with the Switch.
* **Development Status**: Planned. Switch-side code is fully implemented but needs heavy refactoring/rebasing, as the code was originally authored in 2018.
* **Estimated Time**: 2021-2022.
* **Estimated Time**: Late 2020-2021.
## dmnt.gen2 reimplementation
* **Description**: A reimplementation of the Switch's debug monitor, dmnt will provide an interface for debugging applications or system modules running on the Switch. This will include a gdbstub for debugging actively-running system components or applications.
* **Development Status**: Planned
* **Estimated Time**: 2021-2022
* **Estimated Time**: 2021
## fs reimplementation
* **Description**: Following mesosphère's completion, atmosphère will have reimplemented all components of the BootImagePackage firmware except for the filesystem services system module. Reimplementing fs will allow for fixing Nintendo bugs (such as corruption when using exFAT filesystems and encoding inconsistencies with UTF-8 and Shift-JIS).
* **Development Status**: Planned.
* **Estimated Time**: 2021-2022.
## settings reimplementation
* **Description**: A planned reimplementation of the settings system module, and with it a removal of the settings mitm. This will greatly simplify atmosphère's boot process, and will allow much more flexible control over the various system settings.
* **Development Status**: Pending development by Adubbz.
* **Estimated Time**: Unclear, pending developer availability.
## thermosphère
* **Description**: A general-purpose hypervisor, thermosphère will enable the virtualization of the Switch's operating system; this is planned to enable debugging of the Switch's kernel.
* **Development Status**: Pending development by TuxSH.
* **Estimated Time**: Unclear, pending developer availability.
* **Development Status**: Under semi-active development by TuxSH.
* **Estimated Time**: 2020-2021.
## other planned features
* **Description**: General system stability improvements to enhance the user's experience.
@@ -49,12 +59,4 @@ Please note that this is not an exhaustive list of features present in atmosphè
## exosphere re-write
* **Description**: exosphère, atmosphère's reimplementation of Horizon's Secure Monitor, was the first component authored for the project in early 2018. It is written in C, and in a style very different from the rest of atmosphère's code. In addition, exosphère was written to conform to constraints that no longer apply in an environment where it is not launched from the web browser, and where using a custom firmware image to orchestrate wake-from-sleep is possible. exosphère currently uses all but 1 KB of the space available to it, putting it at risk of breaking as future firmware updates are supported. A re-write will solve these issues.
* **Completion Time**: June 2020
## mesosphere
* **Description**: mesosphère is a reimplementation of the Horizon operating system's Kernel. It aims to provide an open-source reference for Nintendo's code.
* **Estimated Time**: September 2020
## ams-on-mariko
* **Description**: Atmosphere cannot run as-is on Mariko hardware. A large number of changes are needed in many components. Although secure monitor support is complete in exosphere, additional work is needed on the bootloader and stratosphere sides as well. Mariko support will also require further design thought; atmosphere's debugging design heavily relies on reboot-to-payload and (more generally) the ability to perform warmboot bootrom hax at will. This is not possible on Mariko, and will require a new design/software support for whatever solution is chosen.
* **Completion Time**: January 2021
* **Completion Time**: June 2020

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/m4xw/emuMMC
branch = develop
commit = b355ee6a8f376faa615785419c7d73a8814d9d65
parent = b24784f5c13a142bd0cb5d7edb82691c71f4bd00
commit = 5eed18eb527bbaa63aee5323c26de5b0cca6d28e
parent = 021b29d2dbc8ed0469bc822393e58c9f0d174d57
method = rebase
cmdver = 0.4.1

View File

@@ -51,8 +51,6 @@
#include "offsets/1020_exfat.h"
#include "offsets/1100.h"
#include "offsets/1100_exfat.h"
#include "offsets/1200.h"
#include "offsets/1200_exfat.h"
#include "../utils/fatal.h"
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
@@ -115,8 +113,6 @@ DEFINE_OFFSET_STRUCT(_1020);
DEFINE_OFFSET_STRUCT(_1020_EXFAT);
DEFINE_OFFSET_STRUCT(_1100);
DEFINE_OFFSET_STRUCT(_1100_EXFAT);
DEFINE_OFFSET_STRUCT(_1200);
DEFINE_OFFSET_STRUCT(_1200_EXFAT);
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
switch (version) {
@@ -190,10 +186,6 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
return &(GET_OFFSET_STRUCT_NAME(_1100));
case FS_VER_11_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_1100_EXFAT));
case FS_VER_12_0_0:
return &(GET_OFFSET_STRUCT_NAME(_1200));
case FS_VER_12_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_1200_EXFAT));
default:
fatal_abort(Fatal_UnknownVersion);
}

View File

@@ -74,9 +74,6 @@ enum FS_VER
FS_VER_11_0_0,
FS_VER_11_0_0_EXFAT,
FS_VER_12_0_0,
FS_VER_12_0_0_EXFAT,
FS_VER_MAX,
};

View File

@@ -1,59 +0,0 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_1200_H__
#define __FS_1200_H__
// Accessor vtable getters
#define FS_OFFSET_1200_SDMMC_ACCESSOR_GC 0x154FD0
#define FS_OFFSET_1200_SDMMC_ACCESSOR_SD 0x156DE0
#define FS_OFFSET_1200_SDMMC_ACCESSOR_NAND 0x155500
// Hooks
#define FS_OFFSET_1200_SDMMC_WRAPPER_READ 0x150970
#define FS_OFFSET_1200_SDMMC_WRAPPER_WRITE 0x150A30
#define FS_OFFSET_1200_RTLD 0x688
#define FS_OFFSET_1200_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
#define FS_OFFSET_1200_CLKRST_SET_MIN_V_CLK_RATE 0x14FCC0
// Misc funcs
#define FS_OFFSET_1200_LOCK_MUTEX 0x29350
#define FS_OFFSET_1200_UNLOCK_MUTEX 0x293A0
#define FS_OFFSET_1200_SDMMC_WRAPPER_CONTROLLER_OPEN 0x150850
#define FS_OFFSET_1200_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1508E0
// Misc Data
#define FS_OFFSET_1200_SD_MUTEX 0xE3D3E8
#define FS_OFFSET_1200_NAND_MUTEX 0xE38768
#define FS_OFFSET_1200_ACTIVE_PARTITION 0xE387A8
#define FS_OFFSET_1200_SDMMC_DAS_HANDLE 0xE20DB0
// NOPs
#define FS_OFFSET_1200_SD_DAS_INIT 0x27244
// Nintendo Paths
#define FS_OFFSET_1200_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x0006E810, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x0007AEC0, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x00081254, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x00092850, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_1200_H__

View File

@@ -1,59 +0,0 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_1200_EXFAT_H__
#define __FS_1200_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_1200_EXFAT_SDMMC_ACCESSOR_GC 0x154FD0
#define FS_OFFSET_1200_EXFAT_SDMMC_ACCESSOR_SD 0x156DE0
#define FS_OFFSET_1200_EXFAT_SDMMC_ACCESSOR_NAND 0x155500
// Hooks
#define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_READ 0x150970
#define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_WRITE 0x150A30
#define FS_OFFSET_1200_EXFAT_RTLD 0x688
#define FS_OFFSET_1200_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
#define FS_OFFSET_1200_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x14FCC0
// Misc funcs
#define FS_OFFSET_1200_EXFAT_LOCK_MUTEX 0x29350
#define FS_OFFSET_1200_EXFAT_UNLOCK_MUTEX 0x293A0
#define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x150850
#define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1508E0
// Misc Data
#define FS_OFFSET_1200_EXFAT_SD_MUTEX 0xE4B3E8
#define FS_OFFSET_1200_EXFAT_NAND_MUTEX 0xE46768
#define FS_OFFSET_1200_EXFAT_ACTIVE_PARTITION 0xE467A8
#define FS_OFFSET_1200_EXFAT_SDMMC_DAS_HANDLE 0xE2EDB0
// NOPs
#define FS_OFFSET_1200_EXFAT_SD_DAS_INIT 0x27244
// Nintendo Paths
#define FS_OFFSET_1200_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x0006E810, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x0007AEC0, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x00081254, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x00092850, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_1200_EXFAT_H__

View File

@@ -328,13 +328,13 @@ uint64_t sdmmc_wrapper_controller_open(int mmc_id)
if (_this != NULL)
{
// Lock eMMC xfer while SD card is being initialized by FS.
if (mmc_id == FS_SDMMC_SD)
if (_this == sdmmc_accessor_get(FS_SDMMC_SD))
mutex_lock_handler(FS_SDMMC_EMMC); // Recursive Mutex, handler will lock SD as well if custom_driver
result = _this->vtab->sdmmc_accessor_controller_open(_this);
// Unlock eMMC.
if (mmc_id == FS_SDMMC_SD)
if (_this == sdmmc_accessor_get(FS_SDMMC_SD))
mutex_unlock_handler(FS_SDMMC_EMMC);
return result;

View File

@@ -1,4 +1,7 @@
%rename link old_link
*link:
%(old_link) -T %:getenv(TOPDIR /loader_stub.ld) --gc-sections --nmagic
%(old_link) -T %:getenv(TOPDIR /loader_stub.ld) --gc-sections --nmagic -nostdlib -nostartfiles
*startfile:
crti%O%s crtbegin%O%s

View File

@@ -1,4 +1,7 @@
%rename link old_link
*link:
%(old_link) -T %:getenv(TOPDIR /mariko_fatal.ld) --gc-sections --nmagic
%(old_link) -T %:getenv(TOPDIR /mariko_fatal.ld) --gc-sections --nmagic -nostdlib -nostartfiles
*startfile:
crti%O%s crtbegin%O%s

View File

@@ -1,4 +1,4 @@
%rename link old_link
*link:
%(old_link) -T %:getenv(TOPDIR /program.ld) --gc-sections --nmagic
%(old_link) -T %:getenv(TOPDIR /program.ld) --gc-sections --nmagic -nostdlib -nostartfiles

View File

@@ -1,4 +1,7 @@
%rename link old_link
*link:
%(old_link) -T %:getenv(TOPDIR /rebootstub.ld) --gc-sections --nmagic
%(old_link) -T %:getenv(TOPDIR /rebootstub.ld) --gc-sections --nmagic -nostdlib -nostartfiles
*startfile:
crti%O%s crtbegin%O%s

View File

@@ -1,4 +1,7 @@
%rename link old_link
*link:
%(old_link) -T %:getenv(TOPDIR /sc7fw.ld) --gc-sections --nmagic
%(old_link) -T %:getenv(TOPDIR /sc7fw.ld) --gc-sections --nmagic -nostdlib -nostartfiles
*startfile:
crti%O%s crtbegin%O%s

View File

@@ -47,9 +47,9 @@ namespace ams::secmon::smc {
[fuse::DramId_IcosaSamsung4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IcosaHynix4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IcosaMicron4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IowaHynix1y4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_AulaHynix1y4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IcosaSamsung6GB] = pkg1::MemorySize_6GB,
[fuse::DramId_HoagHynix1y4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_CopperHynix4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_CopperMicron4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IowaX1X2Samsung4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IowaSansung4GB] = pkg1::MemorySize_4GB,
@@ -286,10 +286,6 @@ namespace ams::secmon::smc {
/* Get the log configuration. */
args.r[1] = (static_cast<u64>(static_cast<u8>(secmon::GetLogPort())) << 32) | static_cast<u64>(secmon::GetLogBaudRate());
break;
case ConfigItem::ExosphereForceEnableUsb30:
/* Get whether usb 3.0 should be force-enabled. */
args.r[1] = GetSecmonConfiguration().IsUsb30ForceEnabled();
break;
default:
return SmcResult::InvalidArgument;
}

View File

@@ -50,7 +50,6 @@ namespace ams::secmon::smc {
ExosphereEmummcType = 65007,
ExospherePayloadAddress = 65008,
ExosphereLogConfiguration = 65009,
ExosphereForceEnableUsb30 = 65010,
};
SmcResult SmcGetConfigUser(SmcArguments &args);

View File

@@ -1,4 +1,7 @@
%rename link old_link
*link:
%(old_link) -T %:getenv(TOPDIR /sdmmc_test.ld) --gc-sections --nmagic
%(old_link) -T %:getenv(TOPDIR /sdmmc_test.ld) --gc-sections --nmagic -nostdlib -nostartfiles
*startfile:
crti%O%s crtbegin%O%s

View File

@@ -1,4 +1,7 @@
%rename link old_link
*link:
%(old_link) -T %:getenv(TOPDIR /warmboot.ld) --gc-sections --nmagic
%(old_link) -T %:getenv(TOPDIR /warmboot.ld) --gc-sections --nmagic -nostdlib -nostartfiles
*startfile:
crti%O%s crtbegin%O%s

View File

@@ -46,9 +46,6 @@ CFLAGS := \
-std=gnu11 \
-Werror \
-Wall \
-Wno-array-bounds \
-Wno-stringop-overflow \
-Wno-stringop-overread \
-fstrict-volatile-bitfields \
$(ARCH) $(DEFINES)

View File

@@ -53,9 +53,6 @@ CFLAGS := \
-std=gnu11 \
-Werror \
-Wall \
-Wno-array-bounds \
-Wno-stringop-overflow \
-Wno-stringop-overread \
-fstrict-volatile-bitfields \
$(ARCH) $(DEFINES)

View File

@@ -46,9 +46,6 @@ CFLAGS := \
-std=gnu11 \
-Werror \
-Wall \
-Wno-array-bounds \
-Wno-stringop-overflow \
-Wno-stringop-overread \
-fstrict-volatile-bitfields \
$(ARCH) $(DEFINES)

View File

@@ -55,9 +55,6 @@ CFLAGS := \
-std=gnu11 \
-Werror \
-Wall \
-Wno-array-bounds \
-Wno-stringop-overflow \
-Wno-stringop-overread \
-fstrict-volatile-bitfields \
$(ARCH) $(DEFINES)

View File

@@ -91,9 +91,6 @@ typedef enum {
FS_VER_11_0_0,
FS_VER_11_0_0_EXFAT,
FS_VER_12_0_0,
FS_VER_12_0_0_EXFAT,
FS_VER_MAX,
} emummc_fs_ver_t;

View File

@@ -33,7 +33,6 @@
#define EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS (1 << 4u)
#define EXOSPHERE_FLAG_BLANK_PRODINFO (1 << 5u)
#define EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC (1 << 6u)
#define EXOSPHERE_FLAG_FORCE_ENABLE_USB_30 (1 << 7u)
#define EXOSPHERE_LOG_FLAG_INVERTED (1 << 0u)

View File

@@ -426,9 +426,6 @@ static const uint8_t g_fs_hashes[FS_VER_MAX][0x8] = {
"\xE3\x99\x15\x6E\x84\x4E\xB0\xAA", /* FS_VER_11_0_0 */
"\x0B\xA1\x5B\xB3\x04\xB5\x05\x63", /* FS_VER_11_0_0_EXFAT */
"\xDC\x2A\x08\x49\x96\xBB\x3C\x01", /* FS_VER_12_0_0 */
"\xD5\xA5\xBF\x36\x64\x0C\x49\xEA", /* FS_VER_12_0_0_EXFAT */
};
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver) {

View File

@@ -568,7 +568,6 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, proc_id_recv)[] = {0xA9B
*/
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1100, proc_id_send)[] = {0xE0, 0x03, 0x15, 0xAA, 0xA8, 0x02, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0x88, 0x4A, 0x3C, 0x8B, 0x09, 0xFC, 0x60, 0xD3, 0x00, 0x25, 0x00, 0x29};
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_send)[] = {0xA9BF2FEA, 0xF94043EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
/*
stp x10, x11, [sp, #-0x10]!
ldr x11, [sp, #0xE0]
@@ -597,63 +596,6 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_send)[] = {0xA9B
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1100, proc_id_recv)[] = {0x08, 0x03, 0x40, 0xF9, 0xE0, 0x03, 0x18, 0xAA, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0xE8, 0x7F, 0x40, 0xF9, 0x09, 0xFC, 0x60, 0xD3, 0xEA, 0x5B, 0x40, 0xF9};
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_recv)[] = {0xA9BF2FEA, 0xF94073EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
/*
stp x10, x11, [sp, #-0x10]!
ldr x11, [sp, #0x98]
mov w10, #3
lsl x10, x10, #2
ldr x10, [x11, x10]
mov x9, #0x0000ffffffffffff
and x8, x10, x9
mov x9, #0xffff000000000000
and x10, x10, x9
mov x9, #0xfffe000000000000
cmp x10, x9
beq #0x20
stp x8, x9, [sp, #-0x10]!
ldr x8, [x22]
ldr x8, [x8, #0x38]
mov x0, x22
blr x8
ldp x8, x9, [sp],#0x10
mov x8, x0
ldp x10, x11, [sp],#0x10
mov x0, x8
*/
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1200, proc_id_send)[] = {0xE0, 0x03, 0x16, 0xAA, 0xC8, 0x02, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0xA8, 0x4A, 0x3B, 0x8B, 0x09, 0xFC, 0x60, 0xD3, 0x00, 0x25, 0x00, 0x29};
static const instruction_t MAKE_KERNEL_PATCH_NAME(1200, proc_id_send)[] = {0xA9BF2FEA, 0xF9404FEB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002C8, 0xF9401D08, 0xAA1603E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
/*
stp x10, x11, [sp, #-0x10]!
ldr x11, [sp, #0xE0]
mov w10, #3
lsl x10, x10, #2
ldr x10, [x11, x10]
mov x9, #0x0000ffffffffffff
and x8, x10, x9
mov x9, #0xffff000000000000
and x10, x10, x9
mov x9, #0xfffe000000000000
cmp x10, x9
beq #0x20
stp x8, x9, [sp, #-0x10]!
ldr x8, [x28]
ldr x8, [x8, #0x38]
mov x0, x28
blr x8
ldp x8, x9, [sp],#0x10
mov x8, x0
ldp x10, x11, [sp],#0x10
mov x0, x8
*/
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1200, proc_id_recv)[] = {0x88, 0x03, 0x40, 0xF9, 0xE0, 0x03, 0x1C, 0xAA, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0x08, 0x4B, 0x3A, 0x8B, 0x09, 0xFC, 0x60, 0xD3, 0x00, 0x25, 0x00, 0x29};
static const instruction_t MAKE_KERNEL_PATCH_NAME(1200, proc_id_recv)[] = {0xA9BF2FEA, 0xF94073EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400388, 0xF9401D08, 0xAA1C03E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
/* svcControlCodeMemory Patches */
/* b.eq -> nop */
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, svc_control_codememory)[] = {MAKE_NOP};
@@ -663,7 +605,6 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(800, svc_control_codememory)[
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(1200, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, system_memory_increase)[] = {0x52A3C008}; /* MOV W8, #0x1E000000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(600, system_memory_increase)[] = {0x52A3B008}; /* MOV W8, #0x1D800000 */
@@ -672,7 +613,6 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(800, system_memory_increase)[
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, system_memory_increase)[] = {0x52A3B015}; /* MOV W21, #0x1D800000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(1200, system_memory_increase)[] = {0x52A3B015}; /* MOV W21, #0x1D800000 */
/* Hook Definitions. */
static const kernel_patch_t g_kernel_patches_100[] = {
@@ -995,35 +935,6 @@ static const kernel_patch_t g_kernel_patches_1101[] = {
}
};
static const kernel_patch_t g_kernel_patches_1200[] = {
{ /* Send Message Process ID Patch. */
.pattern_size = 0x1C,
.pattern = MAKE_KERNEL_PATTERN_NAME(1200, proc_id_send),
.pattern_hook_offset = 0x0,
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1200, proc_id_send))/sizeof(instruction_t),
.branch_back_offset = 0x10,
.payload = MAKE_KERNEL_PATCH_NAME(1200, proc_id_send)
},
{ /* Receive Message Process ID Patch. */
.pattern_size = 0x1C,
.pattern = MAKE_KERNEL_PATTERN_NAME(1200, proc_id_recv),
.pattern_hook_offset = 0x0,
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1200, proc_id_recv))/sizeof(instruction_t),
.branch_back_offset = 0x10,
.payload = MAKE_KERNEL_PATCH_NAME(1200, proc_id_recv)
},
{ /* svcControlCodeMemory Patch. */
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1200, svc_control_codememory))/sizeof(instruction_t),
.payload = MAKE_KERNEL_PATCH_NAME(1200, svc_control_codememory),
.patch_offset = 0x2FCB4,
},
{ /* System Memory Increase Patch. */
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1200, system_memory_increase))/sizeof(instruction_t),
.payload = MAKE_KERNEL_PATCH_NAME(1200, system_memory_increase),
.patch_offset = 0x4809C,
}
};
#define KERNEL_PATCHES(vers) .num_patches = sizeof(g_kernel_patches_##vers)/sizeof(kernel_patch_t), .patches = g_kernel_patches_##vers,
/* Kernel Infos. */
@@ -1127,15 +1038,6 @@ static const kernel_info_t g_kernel_infos[] = {
.embedded_ini_ptr = 0x180,
.free_code_space_offset = 0x49EE8,
KERNEL_PATCHES(1101)
},
{ /* 12.0.0. */
.hash = {0x8D, 0x4A, 0x1E, 0xFC, 0xCC, 0x6C, 0xFE, 0x6C, 0x45, 0x14, 0x13, 0xA1, 0x7F, 0xF6, 0xDF, 0xFD, 0x7E, 0x5D, 0xD1, 0x38, 0xCE, 0x86, 0x11, 0x8B, 0x58, 0x5F, 0x89, 0x67, 0x84, 0x48, 0xA8, 0x17, },
.hash_offset = 0x1C4,
.hash_size = 0x68000 - 0x1C4,
.embedded_ini_offset = 0x68000,
.embedded_ini_ptr = 0x180,
.free_code_space_offset = 0x48810,
KERNEL_PATCHES(1200)
}
};

View File

@@ -256,24 +256,6 @@ static int stratosphere_ini_handler(void *user, const char *section, const char
return 1;
}
static int system_settings_ini_handler(void *user, const char *section, const char *name, const char *value) {
uint32_t *flags = (uint32_t *)user;
if (strcmp(section, "usb") == 0) {
if (strcmp(name, "usb30_force_enabled") == 0) {
if (strcmp(value, "u8!0x1") == 0) {
*flags |= EXOSPHERE_FLAG_FORCE_ENABLE_USB_30;
} else if (strcmp(value, "u8!0x0") == 0) {
*flags &= ~(EXOSPHERE_FLAG_FORCE_ENABLE_USB_30);
}
} else {
return 0;
}
} else {
return 0;
}
return 1;
}
static bool is_nca_present(const char *nca_name) {
char path[0x100];
snprintf(path, sizeof(path), "system:/contents/registered/%s.nca", nca_name);
@@ -285,10 +267,7 @@ static bool is_nca_present(const char *nca_name) {
static uint32_t nxboot_get_specific_target_firmware(uint32_t target_firmware){
#define CHECK_NCA(NCA_ID, VERSION) do { if (is_nca_present(NCA_ID)) { return ATMOSPHERE_TARGET_FIRMWARE_##VERSION; } } while(0)
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_12_0_0) {
CHECK_NCA("e65114b456f9d0b566a80e53bade2d89", 12_0_1);
CHECK_NCA("bd4185843550fbba125b20787005d1d2", 12_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_11_0_0) {
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_11_0_0) {
CHECK_NCA("56211c7a5ed20a5332f5cdda67121e37", 11_0_1);
CHECK_NCA("594c90bcdbcccad6b062eadba0cd0e7e", 11_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0) {
@@ -391,8 +370,6 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
return ATMOSPHERE_TARGET_FIRMWARE_10_0_0;
} else if (memcmp(package1loader_header->build_timestamp, "20201030", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_11_0_0;
} else if (memcmp(package1loader_header->build_timestamp, "20210129", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_12_0_0;
} else {
fatal_error("[NXBOOT] Unable to identify package1!\n");
}
@@ -560,15 +537,6 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke
/* Apply lcd vendor. */
exo_cfg.lcd_vendor = display_get_lcd_vendor();
/* Read and parse system settings.ini to determine usb 3.0 enable. */
char *settings_ini = calloc(1, 0x20000);
if (read_from_file(settings_ini, 0x1FFFF, "atmosphere/config/system_settings.ini")) {
if (ini_parse_string(settings_ini, system_settings_ini_handler, &exo_cfg.flags[0]) < 0) {
fatal_error("[NXBOOT] Failed to parse system_settings.ini!\n");
}
}
free(settings_ini);
if ((exo_cfg.target_firmware < ATMOSPHERE_TARGET_FIRMWARE_MIN) || (exo_cfg.target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX)) {
fatal_error("[NXBOOT] Invalid Exosphere target firmware!\n");
}
@@ -600,10 +568,6 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_11_0_0 && !(fuse_get_reserved_odm(7) & ~0x00001FFF)) {
kip_patches_set_enable_nogc();
}
/* NOTE: 12.0.0 added a new lotus firmware, but did not burn a fuse. */
/* This is literally undetectable using normal fuses.... */
/* C'est la vie. */
}
}

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = acee57e888aa87ba8976db889dfcf20701cb38a8
parent = dbcb1e15648ef7b050b9b59b40d413038b4888ec
commit = b05ba02f044beb03b3e228a660c0c28d0b1efe0d
parent = f2a6a4a6e60bfe0dea11ba3a0ff56c95a5871a6c
method = merge
cmdver = 0.4.1

View File

@@ -8,19 +8,13 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk
#---------------------------------------------------------------------------------
ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64)
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Wextra -Werror -fno-non-call-exceptions \
-Wno-array-bounds \
-Wno-stringop-overflow \
-Wno-stringop-overread
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Wextra -Werror -fno-non-call-exceptions
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
else ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm)
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -fno-non-call-exceptions \
-Wno-array-bounds \
-Wno-stringop-overflow \
-Wno-stringop-overread
SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -fno-non-call-exceptions
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)

View File

@@ -36,7 +36,7 @@ export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
-Wl,--wrap,_ZSt20__throw_length_errorPKc \
-Wl,--wrap,_ZNSt11logic_errorC2EPKc
export LDFLAGS = -specs=$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/stratosphere.specs -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) $(CXXWRAPS) -Wl,-Map,$(notdir $*.map)
export LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) $(CXXWRAPS) -Wl,-Map,$(notdir $*.map)
export LIBS = -lstratosphere -lnx

View File

@@ -16,10 +16,7 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
#---------------------------------------------------------------------------------
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Wextra -Werror -flto -fno-non-call-exceptions \
-Wno-array-bounds \
-Wno-stringop-overflow \
-Wno-stringop-overread
SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Wextra -Werror -flto -fno-non-call-exceptions
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)

View File

@@ -16,10 +16,7 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
#---------------------------------------------------------------------------------
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Wextra -Werror -fno-non-call-exceptions \
-Wno-array-bounds \
-Wno-stringop-overflow \
-Wno-stringop-overread
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Wextra -Werror -fno-non-call-exceptions
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)

View File

@@ -51,9 +51,9 @@ namespace ams::fuse {
DramId_IcosaSamsung4GB = 0,
DramId_IcosaHynix4GB = 1,
DramId_IcosaMicron4GB = 2,
DramId_IowaHynix1y4GB = 3,
DramId_AulaHynix1y4GB = 3,
DramId_IcosaSamsung6GB = 4,
DramId_HoagHynix1y4GB = 5,
DramId_CopperHynix4GB = 5,
DramId_CopperMicron4GB = 6,
DramId_IowaX1X2Samsung4GB = 7,
DramId_IowaSansung4GB = 8,

View File

@@ -29,7 +29,6 @@ namespace ams::secmon {
SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess = (1u << 4),
SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary = (1u << 5),
SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc = (1u << 6),
SecureMonitorConfigurationFlag_ForceEnableUsb30 = (1u << 7),
SecureMonitorConfigurationFlag_Default = SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel,
};
@@ -102,7 +101,6 @@ namespace ams::secmon {
constexpr bool EnableUserModePerformanceCounterAccess() const { return (this->flags[0] & SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess) != 0; }
constexpr bool ShouldUseBlankCalibrationBinary() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary) != 0; }
constexpr bool AllowWritingToCalibrationBinarySysmmc() const { return (this->flags[0] & SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc) != 0; }
constexpr bool IsUsb30ForceEnabled() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ForceEnableUsb30) != 0; }
constexpr bool IsDevelopmentFunctionEnabled(bool for_kern) const { return for_kern ? this->IsDevelopmentFunctionEnabledForKernel() : this->IsDevelopmentFunctionEnabledForUser(); }
};

View File

@@ -140,8 +140,6 @@ $(OFILES_SRC) : $(HFILES_BIN)
kern_libc_generic.o: CFLAGS += -fno-builtin
kern_k_auto_object.o: CXXFLAGS += -fno-lto
#---------------------------------------------------------------------------------
%_bin.h %.bin.o : %.bin
#---------------------------------------------------------------------------------

View File

@@ -14,7 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <mesosphere/kern_select_assembly_offsets.h>
namespace ams::kern::init {
@@ -32,19 +31,5 @@ namespace ams::kern::init {
u64 setup_function;
u64 exception_stack;
};
static_assert(sizeof(KInitArguments) == INIT_ARGUMENTS_SIZE);
static_assert(__builtin_offsetof(KInitArguments, ttbr0) == INIT_ARGUMENTS_TTBR0);
static_assert(__builtin_offsetof(KInitArguments, ttbr1) == INIT_ARGUMENTS_TTBR1);
static_assert(__builtin_offsetof(KInitArguments, tcr) == INIT_ARGUMENTS_TCR);
static_assert(__builtin_offsetof(KInitArguments, mair) == INIT_ARGUMENTS_MAIR);
static_assert(__builtin_offsetof(KInitArguments, cpuactlr) == INIT_ARGUMENTS_CPUACTLR);
static_assert(__builtin_offsetof(KInitArguments, cpuectlr) == INIT_ARGUMENTS_CPUECTLR);
static_assert(__builtin_offsetof(KInitArguments, sctlr) == INIT_ARGUMENTS_SCTLR);
static_assert(__builtin_offsetof(KInitArguments, sp) == INIT_ARGUMENTS_SP);
static_assert(__builtin_offsetof(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT);
static_assert(__builtin_offsetof(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT);
static_assert(__builtin_offsetof(KInitArguments, setup_function) == INIT_ARGUMENTS_SETUP_FUNCTION);
static_assert(__builtin_offsetof(KInitArguments, exception_stack) == INIT_ARGUMENTS_EXCEPTION_STACK);
}

View File

@@ -38,67 +38,37 @@ namespace ams::kern::arch::arm64::init {
public:
class IPageAllocator {
public:
virtual KPhysicalAddress Allocate(size_t size) = 0;
virtual void Free(KPhysicalAddress phys_addr, size_t size) = 0;
virtual KPhysicalAddress Allocate() { return Null<KPhysicalAddress>; }
virtual void Free(KPhysicalAddress phys_addr) { /* Nothing to do here. */ (void)(phys_addr); }
};
private:
KPhysicalAddress m_l1_tables[2];
u32 m_num_entries[2];
struct NoClear{};
private:
KPhysicalAddress m_l1_table;
public:
KInitialPageTable(KVirtualAddress start_address, KVirtualAddress end_address, IPageAllocator &allocator) {
/* Set tables. */
m_l1_tables[0] = AllocateNewPageTable(allocator);
m_l1_tables[1] = AllocateNewPageTable(allocator);
constexpr ALWAYS_INLINE KInitialPageTable(KPhysicalAddress l1, NoClear) : m_l1_table(l1) { /* ... */ }
/* Set counts. */
m_num_entries[0] = MaxPageTableEntries;
m_num_entries[1] = ((end_address / L1BlockSize) & (MaxPageTableEntries - 1)) - ((start_address / L1BlockSize) & (MaxPageTableEntries - 1)) + 1;
constexpr ALWAYS_INLINE KInitialPageTable(KPhysicalAddress l1) : KInitialPageTable(l1, NoClear{}) {
ClearNewPageTable(m_l1_table);
}
KInitialPageTable() {
/* Set tables. */
m_l1_tables[0] = util::AlignDown(cpu::GetTtbr0El1(), PageSize);
m_l1_tables[1] = util::AlignDown(cpu::GetTtbr1El1(), PageSize);
/* Set counts. */
cpu::TranslationControlRegisterAccessor tcr;
m_num_entries[0] = tcr.GetT0Size() / L1BlockSize;
m_num_entries[1] = tcr.GetT1Size() / L1BlockSize;
/* Check counts. */
MESOSPHERE_INIT_ABORT_UNLESS(0 < m_num_entries[0] && m_num_entries[0] <= MaxPageTableEntries);
MESOSPHERE_INIT_ABORT_UNLESS(0 < m_num_entries[1] && m_num_entries[1] <= MaxPageTableEntries);
}
constexpr ALWAYS_INLINE uintptr_t GetTtbr0L1TableAddress() const {
return GetInteger(m_l1_tables[0]);
}
constexpr ALWAYS_INLINE uintptr_t GetTtbr1L1TableAddress() const {
return GetInteger(m_l1_tables[1]);
constexpr ALWAYS_INLINE uintptr_t GetL1TableAddress() const {
return GetInteger(m_l1_table);
}
private:
constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KVirtualAddress address) const {
const size_t index = (GetInteger(address) >> (BITSIZEOF(address) - 1)) & 1;
L1PageTableEntry *l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[index]));
return l1_table + ((GetInteger(address) / L1BlockSize) & (m_num_entries[index] - 1));
static constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KPhysicalAddress _l1_table, KVirtualAddress address) {
L1PageTableEntry *l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(_l1_table));
return l1_table + ((GetInteger(address) >> 30) & (MaxPageTableEntries - 1));
}
static constexpr ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KVirtualAddress address) {
L2PageTableEntry *l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(entry->GetTable()));
return l2_table + ((GetInteger(address) / L2BlockSize) & (MaxPageTableEntries - 1));
return l2_table + ((GetInteger(address) >> 21) & (MaxPageTableEntries - 1));
}
static constexpr ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KVirtualAddress address) {
L3PageTableEntry *l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(entry->GetTable()));
return l3_table + ((GetInteger(address) / L3BlockSize) & (MaxPageTableEntries - 1));
}
static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(IPageAllocator &allocator) {
auto address = allocator.Allocate(PageSize);
ClearNewPageTable(address);
return address;
return l3_table + ((GetInteger(address) >> 12) & (MaxPageTableEntries - 1));
}
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address) {
@@ -113,7 +83,7 @@ namespace ams::kern::arch::arm64::init {
const KVirtualAddress end_virt_addr = virt_addr + size;
size_t count = 0;
while (virt_addr < end_virt_addr) {
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
/* If an L1 block is mapped or we're empty, advance by L1BlockSize. */
if (l1_entry->IsBlock() || l1_entry->IsEmpty()) {
@@ -167,7 +137,7 @@ namespace ams::kern::arch::arm64::init {
const KVirtualAddress end_virt_addr = virt_addr + size;
size_t count = 0;
while (virt_addr < end_virt_addr) {
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
/* If an L1 block is mapped or we're empty, advance by L1BlockSize. */
if (l1_entry->IsBlock() || l1_entry->IsEmpty()) {
@@ -224,7 +194,7 @@ namespace ams::kern::arch::arm64::init {
}
PageTableEntry *GetMappingEntry(KVirtualAddress virt_addr, size_t block_size) {
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
if (l1_entry->IsBlock()) {
MESOSPHERE_INIT_ABORT_UNLESS(block_size == L1BlockSize);
@@ -331,7 +301,7 @@ namespace ams::kern::arch::arm64::init {
/* Iteratively map pages until the requested region is mapped. */
while (size > 0) {
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
/* Can we make an L1 block? */
if (util::IsAligned(GetInteger(virt_addr), L1BlockSize) && util::IsAligned(GetInteger(phys_addr), L1BlockSize) && size >= L1BlockSize) {
@@ -346,7 +316,7 @@ namespace ams::kern::arch::arm64::init {
/* If we don't already have an L2 table, we need to make a new one. */
if (!l1_entry->IsTable()) {
KPhysicalAddress new_table = AllocateNewPageTable(allocator);
KPhysicalAddress new_table = allocator.Allocate();
ClearNewPageTable(new_table);
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
cpu::DataSynchronizationBarrierInnerShareable();
@@ -380,7 +350,7 @@ namespace ams::kern::arch::arm64::init {
/* If we don't already have an L3 table, we need to make a new one. */
if (!l2_entry->IsTable()) {
KPhysicalAddress new_table = AllocateNewPageTable(allocator);
KPhysicalAddress new_table = allocator.Allocate();
ClearNewPageTable(new_table);
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
cpu::DataSynchronizationBarrierInnerShareable();
@@ -412,7 +382,7 @@ namespace ams::kern::arch::arm64::init {
KPhysicalAddress GetPhysicalAddress(KVirtualAddress virt_addr) const {
/* Get the L1 entry. */
const L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
const L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
if (l1_entry->IsBlock()) {
return l1_entry->GetBlock() + (GetInteger(virt_addr) & (L1BlockSize - 1));
@@ -474,7 +444,7 @@ namespace ams::kern::arch::arm64::init {
};
while (virt_addr < end_virt_addr) {
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
/* If an L1 block is mapped, update. */
if (l1_entry->IsBlock()) {
@@ -515,7 +485,7 @@ namespace ams::kern::arch::arm64::init {
const KVirtualAddress end_virt_addr = virt_addr + size;
while (virt_addr < end_virt_addr) {
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
/* If an L1 block is mapped, the address isn't free. */
if (l1_entry->IsBlock()) {
@@ -564,7 +534,7 @@ namespace ams::kern::arch::arm64::init {
/* Iteratively reprotect pages until the requested region is reprotected. */
while (size > 0) {
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
L1PageTableEntry *l1_entry = GetL1Entry(m_l1_table, virt_addr);
/* Check if an L1 block is present. */
if (l1_entry->IsBlock()) {
@@ -703,18 +673,11 @@ namespace ams::kern::arch::arm64::init {
};
class KInitialPageAllocator final : public KInitialPageTable::IPageAllocator {
private:
static constexpr inline size_t FreeUnitSize = BITSIZEOF(u64) * PageSize;
struct FreeListEntry {
FreeListEntry *next;
size_t size;
};
class KInitialPageAllocator : public KInitialPageTable::IPageAllocator {
public:
struct State {
uintptr_t start_address;
uintptr_t end_address;
FreeListEntry *free_head;
uintptr_t next_address;
uintptr_t free_bitmap;
};
private:
State m_state;
@@ -722,8 +685,8 @@ namespace ams::kern::arch::arm64::init {
constexpr ALWAYS_INLINE KInitialPageAllocator() : m_state{} { /* ... */ }
ALWAYS_INLINE void Initialize(uintptr_t address) {
m_state.start_address = address;
m_state.end_address = address;
m_state.next_address = address + BITSIZEOF(m_state.free_bitmap) * PageSize;
m_state.free_bitmap = ~uintptr_t();
}
ALWAYS_INLINE void InitializeFromState(uintptr_t state_val) {
@@ -734,134 +697,28 @@ namespace ams::kern::arch::arm64::init {
*out = m_state;
m_state = {};
}
private:
bool CanAllocate(size_t align, size_t size) const {
for (auto *cur = m_state.free_head; cur != nullptr; cur = cur->next) {
const uintptr_t cur_last = reinterpret_cast<uintptr_t>(cur) + cur->size - 1;
const uintptr_t alloc_last = util::AlignUp(reinterpret_cast<uintptr_t>(cur), align) + size - 1;
if (alloc_last <= cur_last) {
return true;
}
}
return false;
}
bool TryAllocate(uintptr_t address, size_t size) {
/* Try to allocate the region. */
auto **prev_next = std::addressof(m_state.free_head);
for (auto *cur = m_state.free_head; cur != nullptr; prev_next = std::addressof(cur->next), cur = cur->next) {
const uintptr_t cur_start = reinterpret_cast<uintptr_t>(cur);
const uintptr_t cur_last = cur_start + cur->size - 1;
if (cur_start <= address && address + size - 1 <= cur_last) {
auto *alloc = reinterpret_cast<FreeListEntry *>(address);
/* Perform fragmentation at front. */
if (cur != alloc) {
prev_next = std::addressof(cur->next);
*alloc = {
.next = cur->next,
.size = cur_start + cur->size - address,
};
*cur = {
.next = alloc,
.size = address - cur_start,
};
}
/* Perform fragmentation at tail. */
if (alloc->size != size) {
auto *next = reinterpret_cast<FreeListEntry *>(address + size);
*next = {
.next = alloc->next,
.size = alloc->size - size,
};
*alloc = {
.next = next,
.size = size,
};
}
*prev_next = alloc->next;
return true;
}
}
return false;
}
public:
KPhysicalAddress Allocate(size_t align, size_t size) {
/* Ensure that the free list is non-empty. */
while (!this->CanAllocate(align, size)) {
this->Free(m_state.end_address, FreeUnitSize);
m_state.end_address += FreeUnitSize;
}
/* Allocate a random address. */
const uintptr_t aligned_start = util::AlignUp(m_state.start_address, align);
const uintptr_t aligned_end = util::AlignDown(m_state.end_address, align);
const size_t ind_max = ((aligned_end - aligned_start) / align) - 1;
while (true) {
if (const uintptr_t random_address = aligned_start + (KSystemControl::Init::GenerateRandomRange(0, ind_max) * align); this->TryAllocate(random_address, size)) {
return random_address;
}
}
}
virtual KPhysicalAddress Allocate(size_t size) override {
return this->Allocate(size, size);
}
virtual void Free(KPhysicalAddress phys_addr, size_t size) override {
auto **prev_next = std::addressof(m_state.free_head);
auto *new_chunk = reinterpret_cast<FreeListEntry *>(GetInteger(phys_addr));
if (auto *cur = m_state.free_head; cur != nullptr) {
const uintptr_t new_start = reinterpret_cast<uintptr_t>(new_chunk);
const uintptr_t new_end = GetInteger(phys_addr) + size;
while (true) {
/* Attempt coalescing. */
const uintptr_t cur_start = reinterpret_cast<uintptr_t>(cur);
const uintptr_t cur_end = cur_start + cur->size;
if (new_start < new_end) {
if (new_end < cur_start) {
*new_chunk = {
.next = cur,
.size = size,
};
break;
} else if (new_end == cur_start) {
*new_chunk = {
.next = cur->next,
.size = cur->size + size,
};
break;
}
} else if (cur_end == new_start) {
cur->size += size;
return;
}
prev_next = std::addressof(cur->next);
if (cur->next != nullptr) {
cur = cur->next;
} else {
*new_chunk = {
.next = nullptr,
.size = size,
};
cur->next = new_chunk;
return;
}
}
virtual KPhysicalAddress Allocate() override {
MESOSPHERE_INIT_ABORT_UNLESS(m_state.next_address != Null<uintptr_t>);
uintptr_t allocated = m_state.next_address;
if (m_state.free_bitmap != 0) {
u64 index;
uintptr_t mask;
do {
index = KSystemControl::Init::GenerateRandomRange(0, BITSIZEOF(m_state.free_bitmap) - 1);
mask = (static_cast<uintptr_t>(1) << index);
} while ((m_state.free_bitmap & mask) == 0);
m_state.free_bitmap &= ~mask;
allocated = m_state.next_address - ((BITSIZEOF(m_state.free_bitmap) - index) * PageSize);
} else {
*new_chunk = {
.next = nullptr,
.size = size,
};
m_state.next_address += PageSize;
}
*prev_next = new_chunk;
ClearPhysicalMemory(allocated, PageSize);
return allocated;
}
/* No need to override free. The default does nothing, and so would we. */
};
}

View File

@@ -1,157 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
/* TODO: Different header for this? */
#define AMS_KERN_NUM_SUPERVISOR_CALLS 0xC0
/* ams::kern::KThread::StackParameters, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp */
#define THREAD_STACK_PARAMETERS_SIZE 0x30
#define THREAD_STACK_PARAMETERS_SVC_PERMISSION 0x00
#define THREAD_STACK_PARAMETERS_CONTEXT 0x18
#define THREAD_STACK_PARAMETERS_CUR_THREAD 0x20
#define THREAD_STACK_PARAMETERS_DISABLE_COUNT 0x28
#define THREAD_STACK_PARAMETERS_DPC_FLAGS 0x2A
#define THREAD_STACK_PARAMETERS_CURRENT_SVC_ID 0x2B
#define THREAD_STACK_PARAMETERS_IS_CALLING_SVC 0x2C
#define THREAD_STACK_PARAMETERS_IS_IN_EXCEPTION_HANDLER 0x2D
#define THREAD_STACK_PARAMETERS_IS_PINNED 0x2E
/* ams::kern::arch::arm64::KThreadContext, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_thread_context.hpp */
#define THREAD_CONTEXT_SIZE 0x290
#define THREAD_CONTEXT_CPU_REGISTERS 0x000
#define THREAD_CONTEXT_X19 0x000
#define THREAD_CONTEXT_X20 0x008
#define THREAD_CONTEXT_X21 0x010
#define THREAD_CONTEXT_X22 0x018
#define THREAD_CONTEXT_X23 0x020
#define THREAD_CONTEXT_X24 0x028
#define THREAD_CONTEXT_X25 0x030
#define THREAD_CONTEXT_X26 0x038
#define THREAD_CONTEXT_X27 0x040
#define THREAD_CONTEXT_X28 0x048
#define THREAD_CONTEXT_X29 0x050
#define THREAD_CONTEXT_LR 0x058
#define THREAD_CONTEXT_SP 0x060
#define THREAD_CONTEXT_CPACR 0x068
#define THREAD_CONTEXT_FPCR 0x070
#define THREAD_CONTEXT_FPSR 0x078
#define THREAD_CONTEXT_FPU_REGISTERS 0x080
#define THREAD_CONTEXT_LOCKED 0x280
#define THREAD_CONTEXT_X19_X20 THREAD_CONTEXT_X19
#define THREAD_CONTEXT_X21_X22 THREAD_CONTEXT_X21
#define THREAD_CONTEXT_X23_X24 THREAD_CONTEXT_X23
#define THREAD_CONTEXT_X25_X26 THREAD_CONTEXT_X25
#define THREAD_CONTEXT_X27_X28 THREAD_CONTEXT_X27
#define THREAD_CONTEXT_X29_X30 THREAD_CONTEXT_X29
#define THREAD_CONTEXT_LR_SP THREAD_CONTEXT_LR
#define THREAD_CONTEXT_SP_CPACR THREAD_CONTEXT_SP
#define THREAD_CONTEXT_FPCR_FPSR THREAD_CONTEXT_FPCR
/* ams::kern::arch::arm64::KExceptionContext, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_exception_context.hpp */
#define EXCEPTION_CONTEXT_SIZE 0x120
#define EXCEPTION_CONTEXT_X0 0x000
#define EXCEPTION_CONTEXT_X1 0x008
#define EXCEPTION_CONTEXT_X2 0x010
#define EXCEPTION_CONTEXT_X3 0x018
#define EXCEPTION_CONTEXT_X4 0x020
#define EXCEPTION_CONTEXT_X5 0x028
#define EXCEPTION_CONTEXT_X6 0x030
#define EXCEPTION_CONTEXT_X7 0x038
#define EXCEPTION_CONTEXT_X8 0x040
#define EXCEPTION_CONTEXT_X9 0x048
#define EXCEPTION_CONTEXT_X10 0x050
#define EXCEPTION_CONTEXT_X11 0x058
#define EXCEPTION_CONTEXT_X12 0x060
#define EXCEPTION_CONTEXT_X13 0x068
#define EXCEPTION_CONTEXT_X14 0x070
#define EXCEPTION_CONTEXT_X15 0x078
#define EXCEPTION_CONTEXT_X16 0x080
#define EXCEPTION_CONTEXT_X17 0x088
#define EXCEPTION_CONTEXT_X18 0x090
#define EXCEPTION_CONTEXT_X19 0x098
#define EXCEPTION_CONTEXT_X20 0x0A0
#define EXCEPTION_CONTEXT_X21 0x0A8
#define EXCEPTION_CONTEXT_X22 0x0B0
#define EXCEPTION_CONTEXT_X23 0x0B8
#define EXCEPTION_CONTEXT_X24 0x0C0
#define EXCEPTION_CONTEXT_X25 0x0C8
#define EXCEPTION_CONTEXT_X26 0x0D0
#define EXCEPTION_CONTEXT_X27 0x0D8
#define EXCEPTION_CONTEXT_X28 0x0E0
#define EXCEPTION_CONTEXT_X29 0x0E8
#define EXCEPTION_CONTEXT_X30 0x0F0
#define EXCEPTION_CONTEXT_SP 0x0F8
#define EXCEPTION_CONTEXT_PC 0x100
#define EXCEPTION_CONTEXT_PSR 0x108
#define EXCEPTION_CONTEXT_TPIDR 0x110
#define EXCEPTION_CONTEXT_X0_X1 EXCEPTION_CONTEXT_X0
#define EXCEPTION_CONTEXT_X2_X3 EXCEPTION_CONTEXT_X2
#define EXCEPTION_CONTEXT_X4_X5 EXCEPTION_CONTEXT_X4
#define EXCEPTION_CONTEXT_X6_X7 EXCEPTION_CONTEXT_X6
#define EXCEPTION_CONTEXT_X8_X9 EXCEPTION_CONTEXT_X8
#define EXCEPTION_CONTEXT_X10_X11 EXCEPTION_CONTEXT_X10
#define EXCEPTION_CONTEXT_X12_X13 EXCEPTION_CONTEXT_X12
#define EXCEPTION_CONTEXT_X14_X15 EXCEPTION_CONTEXT_X14
#define EXCEPTION_CONTEXT_X16_X17 EXCEPTION_CONTEXT_X16
#define EXCEPTION_CONTEXT_X18_X19 EXCEPTION_CONTEXT_X18
#define EXCEPTION_CONTEXT_X20_X21 EXCEPTION_CONTEXT_X20
#define EXCEPTION_CONTEXT_X22_X23 EXCEPTION_CONTEXT_X22
#define EXCEPTION_CONTEXT_X24_X25 EXCEPTION_CONTEXT_X24
#define EXCEPTION_CONTEXT_X26_X27 EXCEPTION_CONTEXT_X26
#define EXCEPTION_CONTEXT_X28_X29 EXCEPTION_CONTEXT_X28
#define EXCEPTION_CONTEXT_X30_SP EXCEPTION_CONTEXT_X30
#define EXCEPTION_CONTEXT_PC_PSR EXCEPTION_CONTEXT_PC
#define EXCEPTION_CONTEXT_X9_X10 EXCEPTION_CONTEXT_X9
#define EXCEPTION_CONTEXT_X19_X20 EXCEPTION_CONTEXT_X19
#define EXCEPTION_CONTEXT_X21_X22 EXCEPTION_CONTEXT_X21
#define EXCEPTION_CONTEXT_X23_X24 EXCEPTION_CONTEXT_X23
#define EXCEPTION_CONTEXT_X25_X26 EXCEPTION_CONTEXT_X25
#define EXCEPTION_CONTEXT_X27_X28 EXCEPTION_CONTEXT_X27
#define EXCEPTION_CONTEXT_X29_X30 EXCEPTION_CONTEXT_X29
#define EXCEPTION_CONTEXT_SP_PC EXCEPTION_CONTEXT_SP
#define EXCEPTION_CONTEXT_PSR_TPIDR EXCEPTION_CONTEXT_PSR
/* ams::svc::arch::arm64::ThreadLocalRegion, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libvapours/include/vapours/svc/arch/arm64/svc_thread_local_region.hpp */
#define THREAD_LOCAL_REGION_MESSAGE_BUFFER 0x000
#define THREAD_LOCAL_REGION_DISABLE_COUNT 0x100
#define THREAD_LOCAL_REGION_INTERRUPT_FLAG 0x102
#define THREAD_LOCAL_REGION_SIZE 0x200
/* ams::kern::init::KInitArguments, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_arguments.hpp */
#define INIT_ARGUMENTS_SIZE 0x60
#define INIT_ARGUMENTS_TTBR0 0x00
#define INIT_ARGUMENTS_TTBR1 0x08
#define INIT_ARGUMENTS_TCR 0x10
#define INIT_ARGUMENTS_MAIR 0x18
#define INIT_ARGUMENTS_CPUACTLR 0x20
#define INIT_ARGUMENTS_CPUECTLR 0x28
#define INIT_ARGUMENTS_SCTLR 0x30
#define INIT_ARGUMENTS_SP 0x38
#define INIT_ARGUMENTS_ENTRYPOINT 0x40
#define INIT_ARGUMENTS_ARGUMENT 0x48
#define INIT_ARGUMENTS_SETUP_FUNCTION 0x50
#define INIT_ARGUMENTS_EXCEPTION_STACK 0x58
/* ams::kern::KScheduler (::SchedulingState), https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp */
/* NOTE: Due to constraints on ldarb relative offsets, KSCHEDULER_NEEDS_SCHEDULING cannot trivially be changed, and will require assembly edits. */
#define KSCHEDULER_NEEDS_SCHEDULING 0x00
#define KSCHEDULER_INTERRUPT_TASK_THREAD_RUNNABLE 0x01
#define KSCHEDULER_HIGHEST_PRIORITY_THREAD 0x10
#define KSCHEDULER_IDLE_THREAD_STACK 0x18

View File

@@ -232,7 +232,7 @@ namespace ams::kern::arch::arm64::cpu {
}
ALWAYS_INLINE void SetExceptionThreadStackTop(uintptr_t top) {
cpu::SetCntvCvalEl0(top);
SetTpidrEl1(top);
}
ALWAYS_INLINE void SwitchThreadLocalRegion(uintptr_t tlr) {

View File

@@ -74,7 +74,6 @@ namespace ams::kern::arch::arm64::cpu {
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntkCtlEl1, cntkctl_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntpCtlEl0, cntp_ctl_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntpCvalEl0, cntp_cval_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntvCvalEl0, cntv_cval_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Daif, daif)
@@ -198,11 +197,6 @@ namespace ams::kern::arch::arm64::cpu {
public:
MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(TranslationControl, tcr_el1)
constexpr ALWAYS_INLINE size_t GetT0Size() const {
const size_t shift_value = this->GetBits(0, 6);
return size_t(1) << (size_t(64) - shift_value);
}
constexpr ALWAYS_INLINE size_t GetT1Size() const {
const size_t shift_value = this->GetBits(16, 6);
return size_t(1) << (size_t(64) - shift_value);

View File

@@ -43,42 +43,6 @@ namespace ams::kern::arch::arm64 {
}
}
};
static_assert(sizeof(KExceptionContext) == EXCEPTION_CONTEXT_SIZE);
static_assert(__builtin_offsetof(KExceptionContext, x[ 0]) == EXCEPTION_CONTEXT_X0);
static_assert(__builtin_offsetof(KExceptionContext, x[ 1]) == EXCEPTION_CONTEXT_X1);
static_assert(__builtin_offsetof(KExceptionContext, x[ 2]) == EXCEPTION_CONTEXT_X2);
static_assert(__builtin_offsetof(KExceptionContext, x[ 3]) == EXCEPTION_CONTEXT_X3);
static_assert(__builtin_offsetof(KExceptionContext, x[ 4]) == EXCEPTION_CONTEXT_X4);
static_assert(__builtin_offsetof(KExceptionContext, x[ 5]) == EXCEPTION_CONTEXT_X5);
static_assert(__builtin_offsetof(KExceptionContext, x[ 6]) == EXCEPTION_CONTEXT_X6);
static_assert(__builtin_offsetof(KExceptionContext, x[ 7]) == EXCEPTION_CONTEXT_X7);
static_assert(__builtin_offsetof(KExceptionContext, x[ 8]) == EXCEPTION_CONTEXT_X8);
static_assert(__builtin_offsetof(KExceptionContext, x[ 9]) == EXCEPTION_CONTEXT_X9);
static_assert(__builtin_offsetof(KExceptionContext, x[10]) == EXCEPTION_CONTEXT_X10);
static_assert(__builtin_offsetof(KExceptionContext, x[11]) == EXCEPTION_CONTEXT_X11);
static_assert(__builtin_offsetof(KExceptionContext, x[12]) == EXCEPTION_CONTEXT_X12);
static_assert(__builtin_offsetof(KExceptionContext, x[13]) == EXCEPTION_CONTEXT_X13);
static_assert(__builtin_offsetof(KExceptionContext, x[14]) == EXCEPTION_CONTEXT_X14);
static_assert(__builtin_offsetof(KExceptionContext, x[15]) == EXCEPTION_CONTEXT_X15);
static_assert(__builtin_offsetof(KExceptionContext, x[16]) == EXCEPTION_CONTEXT_X16);
static_assert(__builtin_offsetof(KExceptionContext, x[17]) == EXCEPTION_CONTEXT_X17);
static_assert(__builtin_offsetof(KExceptionContext, x[18]) == EXCEPTION_CONTEXT_X18);
static_assert(__builtin_offsetof(KExceptionContext, x[19]) == EXCEPTION_CONTEXT_X19);
static_assert(__builtin_offsetof(KExceptionContext, x[20]) == EXCEPTION_CONTEXT_X20);
static_assert(__builtin_offsetof(KExceptionContext, x[21]) == EXCEPTION_CONTEXT_X21);
static_assert(__builtin_offsetof(KExceptionContext, x[22]) == EXCEPTION_CONTEXT_X22);
static_assert(__builtin_offsetof(KExceptionContext, x[23]) == EXCEPTION_CONTEXT_X23);
static_assert(__builtin_offsetof(KExceptionContext, x[24]) == EXCEPTION_CONTEXT_X24);
static_assert(__builtin_offsetof(KExceptionContext, x[25]) == EXCEPTION_CONTEXT_X25);
static_assert(__builtin_offsetof(KExceptionContext, x[26]) == EXCEPTION_CONTEXT_X26);
static_assert(__builtin_offsetof(KExceptionContext, x[27]) == EXCEPTION_CONTEXT_X27);
static_assert(__builtin_offsetof(KExceptionContext, x[28]) == EXCEPTION_CONTEXT_X28);
static_assert(__builtin_offsetof(KExceptionContext, x[29]) == EXCEPTION_CONTEXT_X29);
static_assert(__builtin_offsetof(KExceptionContext, x[30]) == EXCEPTION_CONTEXT_X30);
static_assert(__builtin_offsetof(KExceptionContext, sp) == EXCEPTION_CONTEXT_SP);
static_assert(__builtin_offsetof(KExceptionContext, pc) == EXCEPTION_CONTEXT_PC);
static_assert(__builtin_offsetof(KExceptionContext, psr) == EXCEPTION_CONTEXT_PSR);
static_assert(__builtin_offsetof(KExceptionContext, tpidr) == EXCEPTION_CONTEXT_TPIDR);
static_assert(sizeof(KExceptionContext) == 0x120);
}

View File

@@ -85,6 +85,7 @@ namespace ams::kern::arch::arm64 {
NOINLINE Result BindHandler(KInterruptHandler *handler, s32 irq, s32 core_id, s32 priority, bool manual_clear, bool level);
NOINLINE Result UnbindHandler(s32 irq, s32 core);
NOINLINE Result ClearInterrupt(s32 irq);
NOINLINE Result ClearInterrupt(s32 irq, s32 core_id);
ALWAYS_INLINE void SendInterProcessorInterrupt(s32 irq, u64 core_mask) {

View File

@@ -176,7 +176,7 @@ namespace ams::kern::arch::arm64 {
}
NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit);
NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager);
Result Finalize();
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);

View File

@@ -30,16 +30,12 @@ namespace ams::kern::arch::arm64 {
m_page_table.Activate(id);
}
Result Initialize(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit) {
return m_page_table.InitializeForProcess(id, as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, mem_block_slab_manager, block_info_manager, pt_manager, resource_limit);
Result Initialize(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager) {
return m_page_table.InitializeForProcess(id, as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, mem_block_slab_manager, block_info_manager, pt_manager);
}
void Finalize() { m_page_table.Finalize(); }
ALWAYS_INLINE KScopedLightLock AcquireDeviceMapLock() {
return m_page_table.AcquireDeviceMapLock();
}
Result SetMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission perm) {
return m_page_table.SetMemoryPermission(addr, size, perm);
}
@@ -140,42 +136,26 @@ namespace ams::kern::arch::arm64 {
return m_page_table.ReadDebugMemory(buffer, address, size);
}
Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size) {
return m_page_table.ReadDebugIoMemory(buffer, address, size);
}
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size) {
return m_page_table.WriteDebugMemory(address, buffer, size);
}
Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size) {
return m_page_table.WriteDebugIoMemory(address, buffer, size);
}
Result LockForMapDeviceAddressSpace(KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
return m_page_table.LockForMapDeviceAddressSpace(address, size, perm, is_aligned);
}
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size) {
return m_page_table.LockForUnmapDeviceAddressSpace(address, size);
Result LockForDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
return m_page_table.LockForDeviceAddressSpace(out, address, size, perm, is_aligned);
}
Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size) {
return m_page_table.UnlockForDeviceAddressSpace(address, size);
}
Result MakePageGroupForUnmapDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size) {
return m_page_table.MakePageGroupForUnmapDeviceAddressSpace(out, address, size);
}
Result UnlockForDeviceAddressSpacePartialMap(KProcessAddress address, size_t size, size_t mapped_size) {
return m_page_table.UnlockForDeviceAddressSpacePartialMap(address, size, mapped_size);
}
Result OpenMemoryRangeForMapDeviceAddressSpace(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
return m_page_table.OpenMemoryRangeForMapDeviceAddressSpace(out, address, size, perm, is_aligned);
}
Result OpenMemoryRangeForUnmapDeviceAddressSpace(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size) {
return m_page_table.OpenMemoryRangeForUnmapDeviceAddressSpace(out, address, size);
}
Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size) {
return m_page_table.LockForIpcUserBuffer(out, address, size);
}
@@ -200,10 +180,6 @@ namespace ams::kern::arch::arm64 {
return m_page_table.UnlockForCodeMemory(address, size, pg);
}
Result OpenMemoryRangeForProcessCacheOperation(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size) {
return m_page_table.OpenMemoryRangeForProcessCacheOperation(out, address, size);
}
Result CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) {
return m_page_table.CopyMemoryFromLinearToUser(dst_addr, size, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr);
}
@@ -232,8 +208,8 @@ namespace ams::kern::arch::arm64 {
return m_page_table.SetupForIpc(out_dst_addr, size, src_addr, src_page_table.m_page_table, test_perm, dst_state, send);
}
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state) {
return m_page_table.CleanupForIpcServer(address, size, dst_state);
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state, KProcess *server_process) {
return m_page_table.CleanupForIpcServer(address, size, dst_state, server_process);
}
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state) {
@@ -256,10 +232,6 @@ namespace ams::kern::arch::arm64 {
return m_page_table.UnmapPhysicalMemoryUnsafe(address, size);
}
Result UnmapProcessMemory(KProcessAddress dst_address, size_t size, KProcessPageTable &src_page_table, KProcessAddress src_address) {
return m_page_table.UnmapProcessMemory(dst_address, size, src_page_table.m_page_table, src_address);
}
void DumpMemoryBlocks() const {
return m_page_table.DumpMemoryBlocks();
}
@@ -318,10 +290,6 @@ namespace ams::kern::arch::arm64 {
KBlockInfoManager *GetBlockInfoManager() {
return m_page_table.GetBlockInfoManager();
}
KPageTableBase &GetBasePageTable() {
return m_page_table;
}
};
}

View File

@@ -79,38 +79,8 @@ namespace ams::kern::arch::arm64 {
const u128 *GetFpuRegisters() const { return m_fpu_registers; }
public:
static void OnThreadTerminating(const KThread *thread);
public:
static consteval bool ValidateOffsets();
};
consteval bool KThreadContext::ValidateOffsets() {
static_assert(sizeof(KThreadContext) == THREAD_CONTEXT_SIZE);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.registers) == THREAD_CONTEXT_CPU_REGISTERS);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x19) == THREAD_CONTEXT_X19);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x20) == THREAD_CONTEXT_X20);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x21) == THREAD_CONTEXT_X21);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x22) == THREAD_CONTEXT_X22);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x23) == THREAD_CONTEXT_X23);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x24) == THREAD_CONTEXT_X24);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x25) == THREAD_CONTEXT_X25);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x26) == THREAD_CONTEXT_X26);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x27) == THREAD_CONTEXT_X27);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x28) == THREAD_CONTEXT_X28);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x29) == THREAD_CONTEXT_X29);
static_assert(__builtin_offsetof(KThreadContext, m_lr) == THREAD_CONTEXT_LR);
static_assert(__builtin_offsetof(KThreadContext, m_sp) == THREAD_CONTEXT_SP);
static_assert(__builtin_offsetof(KThreadContext, m_cpacr) == THREAD_CONTEXT_CPACR);
static_assert(__builtin_offsetof(KThreadContext, m_fpcr) == THREAD_CONTEXT_FPCR);
static_assert(__builtin_offsetof(KThreadContext, m_fpsr) == THREAD_CONTEXT_FPSR);
static_assert(__builtin_offsetof(KThreadContext, m_fpu_registers) == THREAD_CONTEXT_FPU_REGISTERS);
static_assert(__builtin_offsetof(KThreadContext, m_locked) == THREAD_CONTEXT_LOCKED);
return true;
}
static_assert(KThreadContext::ValidateOffsets());
void GetUserContext(ams::svc::ThreadContext *out, const KThread *thread);
}

View File

@@ -69,8 +69,8 @@ namespace ams::kern::board::nintendo::nx {
Result Attach(ams::svc::DeviceName device_name, u64 space_address, u64 space_size);
Result Detach(ams::svc::DeviceName device_name);
Result Map(size_t *out_mapped_size, KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings);
Result Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address);
Result Map(size_t *out_mapped_size, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings);
Result Unmap(const KPageGroup &pg, KDeviceVirtualAddress device_address);
void Unmap(KDeviceVirtualAddress device_address, size_t size) {
return this->UnmapImpl(device_address, size, false);
@@ -78,11 +78,12 @@ namespace ams::kern::board::nintendo::nx {
private:
Result MapDevicePage(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, KPhysicalAddress phys_addr, u64 size, KDeviceVirtualAddress address, ams::svc::MemoryPermission device_perm);
Result MapImpl(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned);
Result MapImpl(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm);
void UnmapImpl(KDeviceVirtualAddress address, u64 size, bool force);
bool IsFree(KDeviceVirtualAddress address, u64 size) const;
bool Compare(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address) const;
Result MakePageGroup(KPageGroup *out, KDeviceVirtualAddress address, u64 size) const;
bool Compare(const KPageGroup &pg, KDeviceVirtualAddress device_address) const;
public:
static void Initialize();

View File

@@ -25,7 +25,6 @@ namespace ams::kern::board::nintendo::nx {
/* Initialization. */
static size_t GetIntendedMemorySize();
static KPhysicalAddress GetKernelPhysicalBaseAddress(uintptr_t base_address);
static KPhysicalAddress GetInitialProcessBinaryPhysicalAddress();
static bool ShouldIncreaseThreadResourceLimit();
static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
static size_t GetApplicationPoolSize();

View File

@@ -27,7 +27,7 @@ namespace ams::kern::init {
u32 rw_end_offset;
u32 bss_offset;
u32 bss_end_offset;
u32 resource_offset;
u32 ini_load_offset;
u32 dynamic_offset;
u32 init_array_offset;
u32 init_array_end_offset;

View File

@@ -17,7 +17,6 @@
#include <vapours.hpp>
#include <mesosphere/kern_build_config.hpp>
#include <mesosphere/svc/kern_svc_results.hpp>
#include <mesosphere/kern_select_assembly_offsets.h>
namespace ams::kern {

View File

@@ -29,14 +29,11 @@ namespace ams::kern {
u32 reserved;
};
NOINLINE size_t CopyInitialProcessBinaryToKernelMemory();
NOINLINE void CopyInitialProcessBinaryToKernelMemory();
NOINLINE void CreateAndRunInitialProcesses();
u64 GetInitialProcessIdMin();
u64 GetInitialProcessIdMax();
KVirtualAddress GetInitialProcessBinaryAddress();
size_t GetInitialProcessesSecureMemorySize();
void LoadInitialProcessBinaryHeaderDeprecated(KPhysicalAddress pool_end);
}

View File

@@ -69,12 +69,11 @@ namespace ams::kern {
private:
MESOSPHERE_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
private:
KAutoObject *m_next_closed_object;
std::atomic<u32> m_ref_count;
public:
static KAutoObject *Create(KAutoObject *ptr);
public:
constexpr ALWAYS_INLINE explicit KAutoObject() : m_next_closed_object(nullptr), m_ref_count(0) { MESOSPHERE_ASSERT_THIS(); }
constexpr ALWAYS_INLINE explicit KAutoObject() : m_ref_count(0) { MESOSPHERE_ASSERT_THIS(); }
virtual ~KAutoObject() { MESOSPHERE_ASSERT_THIS(); }
/* Destroy is responsible for destroying the auto object's resources when ref_count hits zero. */
@@ -86,7 +85,7 @@ namespace ams::kern {
virtual KProcess *GetOwner() const { return nullptr; }
u32 GetReferenceCount() const {
return m_ref_count.load();
return m_ref_count;
}
ALWAYS_INLINE bool IsDerivedFrom(const TypeObj &rhs) const {
@@ -121,16 +120,36 @@ namespace ams::kern {
}
}
bool Open();
void Close();
private:
/* NOTE: This has to be defined *after* KThread is defined. */
/* Nintendo seems to handle this by defining Open/Close() in a cpp, but we'd like them to remain in headers. */
/* Implementation for this will be inside kern_k_thread.hpp, so it can be ALWAYS_INLINE. */
void ScheduleDestruction();
public:
/* Getter, for KThread. */
ALWAYS_INLINE KAutoObject *GetNextClosedObject() { return m_next_closed_object; }
ALWAYS_INLINE bool Open() {
MESOSPHERE_ASSERT_THIS();
/* Atomically increment the reference count, only if it's positive. */
u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire);
do {
if (AMS_UNLIKELY(cur_ref_count == 0)) {
MESOSPHERE_AUDIT(cur_ref_count != 0);
return false;
}
MESOSPHERE_ABORT_UNLESS(cur_ref_count < cur_ref_count + 1);
} while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count + 1, std::memory_order_relaxed));
return true;
}
ALWAYS_INLINE void Close() {
MESOSPHERE_ASSERT_THIS();
/* Atomically decrement the reference count, not allowing it to become negative. */
u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire);
do {
MESOSPHERE_ABORT_UNLESS(cur_ref_count > 0);
} while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count - 1, std::memory_order_relaxed));
/* If ref count hits zero, destroy the object. */
if (cur_ref_count - 1 == 0) {
this->Destroy();
}
}
};
class KAutoObjectWithListContainer;
@@ -179,7 +198,7 @@ namespace ams::kern {
}
}
ALWAYS_INLINE ~KScopedAutoObject() {
~KScopedAutoObject() {
if (m_obj != nullptr) {
m_obj->Close();
}

View File

@@ -47,7 +47,6 @@ namespace ams::kern {
ALWAYS_INLINE s32 GetMaxSessions() const { return m_max_sessions; }
bool IsLight() const;
bool IsServerClosed() const;
/* Overridden virtual functions. */
virtual void Destroy() override;

View File

@@ -23,7 +23,7 @@ namespace ams::kern {
class KCodeMemory final : public KAutoObjectWithSlabHeapAndContainer<KCodeMemory, KAutoObjectWithList> {
MESOSPHERE_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject);
private:
util::TypedStorage<KPageGroup> m_page_group;
TYPED_STORAGE(KPageGroup) m_page_group;
KProcess *m_owner;
KProcessAddress m_address;
KLightLock m_lock;

View File

@@ -36,7 +36,7 @@ namespace ams::kern {
void Signal(uintptr_t cv_key, s32 count);
Result Wait(KProcessAddress addr, uintptr_t key, u32 value, s64 timeout);
private:
void SignalImpl(KThread *thread);
KThread *SignalImpl(KThread *thread);
};
ALWAYS_INLINE void BeforeUpdatePriority(KConditionVariable::ThreadTree *tree, KThread *thread) {

View File

@@ -49,9 +49,9 @@ namespace ams::kern {
constexpr KVirtualAddress GetAddress() const { return m_address; }
constexpr size_t GetSize() const { return m_size; }
constexpr size_t GetUsed() const { return m_used.load(); }
constexpr size_t GetPeak() const { return m_peak.load(); }
constexpr size_t GetCount() const { return m_count.load(); }
constexpr size_t GetUsed() const { return m_used; }
constexpr size_t GetPeak() const { return m_peak; }
constexpr size_t GetCount() const { return m_count; }
constexpr bool IsInRange(KVirtualAddress addr) const {
return this->GetAddress() <= addr && addr <= this->GetAddress() + this->GetSize() - 1;
@@ -65,7 +65,7 @@ namespace ams::kern {
/* Free blocks to memory. */
u8 *cur = GetPointer<u8>(m_address + m_size);
for (size_t i = 0; i < sz / sizeof(T); i++) {
for (size_t i = 0; i < m_count; i++) {
cur -= sizeof(T);
this->GetImpl()->Free(cur);
}
@@ -84,13 +84,13 @@ namespace ams::kern {
this->Initialize(page_allocator);
/* Allocate until we have the correct number of objects. */
while (m_count.load() < num_objects) {
while (m_count < num_objects) {
auto *allocated = reinterpret_cast<T *>(m_page_allocator->Allocate());
MESOSPHERE_ABORT_UNLESS(allocated != nullptr);
for (size_t i = 0; i < sizeof(PageBuffer) / sizeof(T); i++) {
this->GetImpl()->Free(allocated + i);
}
m_count.fetch_add(sizeof(PageBuffer) / sizeof(T));
m_count += sizeof(PageBuffer) / sizeof(T);
}
}
@@ -106,18 +106,18 @@ namespace ams::kern {
for (size_t i = 1; i < sizeof(PageBuffer) / sizeof(T); i++) {
this->GetImpl()->Free(allocated + i);
}
m_count.fetch_add(sizeof(PageBuffer) / sizeof(T));
m_count += sizeof(PageBuffer) / sizeof(T);
}
}
}
if (AMS_LIKELY(allocated != nullptr)) {
/* Construct the object. */
std::construct_at(allocated);
new (allocated) T();
/* Update our tracking. */
size_t used = m_used.fetch_add(1) + 1;
size_t peak = m_peak.load();
size_t used = ++m_used;
size_t peak = m_peak;
while (peak < used) {
if (m_peak.compare_exchange_weak(peak, used, std::memory_order_relaxed)) {
break;
@@ -130,7 +130,7 @@ namespace ams::kern {
void Free(T *t) {
this->GetImpl()->Free(t);
m_used.fetch_sub(1);
--m_used;
}
};

View File

@@ -53,29 +53,46 @@ namespace ams::kern {
return pack.Get<HandleEncoded>();
}
union EntryInfo {
struct {
u16 linear_id;
u16 type;
} info;
s32 next_free_index;
class Entry {
private:
union {
struct {
u16 linear_id;
u16 type;
} info;
Entry *next_free_entry;
} m_meta;
KAutoObject *m_object;
public:
constexpr Entry() : m_meta(), m_object(nullptr) { /* ... */ }
constexpr ALWAYS_INLINE u16 GetLinearId() const { return info.linear_id; }
constexpr ALWAYS_INLINE u16 GetType() const { return info.type; }
constexpr ALWAYS_INLINE s32 GetNextFreeIndex() const { return next_free_index; }
constexpr ALWAYS_INLINE void SetFree(Entry *next) {
m_object = nullptr;
m_meta.next_free_entry = next;
}
constexpr ALWAYS_INLINE void SetUsed(KAutoObject *obj, u16 linear_id, u16 type) {
m_object = obj;
m_meta.info = { linear_id, type };
}
constexpr ALWAYS_INLINE KAutoObject *GetObject() const { return m_object; }
constexpr ALWAYS_INLINE Entry *GetNextFreeEntry() const { return m_meta.next_free_entry; }
constexpr ALWAYS_INLINE u16 GetLinearId() const { return m_meta.info.linear_id; }
constexpr ALWAYS_INLINE u16 GetType() const { return m_meta.info.type; }
};
private:
EntryInfo m_entry_infos[MaxTableSize];
KAutoObject *m_objects[MaxTableSize];
s32 m_free_head_index;
mutable KSpinLock m_lock;
Entry *m_table;
Entry *m_free_head;
Entry m_entries[MaxTableSize];
u16 m_table_size;
u16 m_max_count;
u16 m_next_linear_id;
u16 m_count;
mutable KSpinLock m_lock;
public:
constexpr KHandleTable() :
m_entry_infos(), m_objects(), m_free_head_index(-1), m_table_size(0), m_max_count(0), m_next_linear_id(MinLinearId), m_count(0), m_lock()
m_lock(), m_table(nullptr), m_free_head(nullptr), m_entries(), m_table_size(0), m_max_count(0), m_next_linear_id(MinLinearId), m_count(0)
{ MESOSPHERE_ASSERT_THIS(); }
constexpr NOINLINE Result Initialize(s32 size) {
@@ -84,18 +101,19 @@ namespace ams::kern {
R_UNLESS(size <= static_cast<s32>(MaxTableSize), svc::ResultOutOfMemory());
/* Initialize all fields. */
m_max_count = 0;
m_table_size = (size <= 0) ? MaxTableSize : size;
m_next_linear_id = MinLinearId;
m_count = 0;
m_free_head_index = -1;
m_table = m_entries;
m_table_size = (size <= 0) ? MaxTableSize : size;
m_next_linear_id = MinLinearId;
m_count = 0;
m_max_count = 0;
/* Free all entries. */
for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
m_objects[i] = nullptr;
m_entry_infos[i].next_free_index = i - 1;
m_free_head_index = i;
for (size_t i = 0; i < static_cast<size_t>(m_table_size - 1); i++) {
m_entries[i].SetFree(std::addressof(m_entries[i + 1]));
}
m_entries[m_table_size - 1].SetFree(nullptr);
m_free_head = std::addressof(m_entries[0]);
return ResultSuccess();
}
@@ -116,7 +134,7 @@ namespace ams::kern {
if constexpr (std::is_same<T, KAutoObject>::value) {
return this->GetObjectImpl(handle);
} else {
if (auto *obj = this->GetObjectImpl(handle); AMS_LIKELY(obj != nullptr)) {
if (auto *obj = this->GetObjectImpl(handle); obj != nullptr) {
return obj->DynamicCast<T*>();
} else {
return nullptr;
@@ -131,15 +149,11 @@ namespace ams::kern {
/* Handle pseudo-handles. */
if constexpr (std::derived_from<KProcess, T>) {
if (handle == ams::svc::PseudoHandle::CurrentProcess) {
auto * const cur_process = GetCurrentProcessPointer();
AMS_ASSUME(cur_process != nullptr);
return cur_process;
return GetCurrentProcessPointer();
}
} else if constexpr (std::derived_from<KThread, T>) {
if (handle == ams::svc::PseudoHandle::CurrentThread) {
auto * const cur_thread = GetCurrentThreadPointer();
AMS_ASSUME(cur_thread != nullptr);
return cur_thread;
return GetCurrentThreadPointer();
}
}
@@ -163,11 +177,8 @@ namespace ams::kern {
ALWAYS_INLINE KScopedAutoObject<KAutoObject> GetObjectForIpc(ams::svc::Handle handle, KThread *cur_thread) const {
/* Handle pseudo-handles. */
AMS_ASSUME(cur_thread != nullptr);
if (handle == ams::svc::PseudoHandle::CurrentProcess) {
auto * const cur_process = static_cast<KAutoObject *>(static_cast<void *>(cur_thread->GetOwnerProcess()));
AMS_ASSUME(cur_process != nullptr);
return cur_process;
return static_cast<KAutoObject *>(static_cast<void *>(cur_thread->GetOwnerProcess()));
}
if (handle == ams::svc::PseudoHandle::CurrentThread) {
return static_cast<KAutoObject *>(cur_thread);
@@ -245,29 +256,27 @@ namespace ams::kern {
NOINLINE Result Add(ams::svc::Handle *out_handle, KAutoObject *obj, u16 type);
NOINLINE void Register(ams::svc::Handle handle, KAutoObject *obj, u16 type);
constexpr ALWAYS_INLINE s32 AllocateEntry() {
constexpr ALWAYS_INLINE Entry *AllocateEntry() {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(m_count < m_table_size);
const auto index = m_free_head_index;
Entry *entry = m_free_head;
m_free_head = entry->GetNextFreeEntry();
m_free_head_index = m_entry_infos[index].GetNextFreeIndex();
m_count++;
m_max_count = std::max(m_max_count, m_count);
m_max_count = std::max(m_max_count, ++m_count);
return index;
return entry;
}
constexpr ALWAYS_INLINE void FreeEntry(s32 index) {
constexpr ALWAYS_INLINE void FreeEntry(Entry *entry) {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(m_count > 0);
m_objects[index] = nullptr;
m_entry_infos[index].next_free_index = m_free_head_index;
entry->SetFree(m_free_head);
m_free_head = entry;
m_free_head_index = index;
--m_count;
m_count--;
}
constexpr ALWAYS_INLINE u16 AllocateLinearId() {
@@ -278,7 +287,13 @@ namespace ams::kern {
return id;
}
constexpr ALWAYS_INLINE bool IsValidHandle(ams::svc::Handle handle) const {
constexpr ALWAYS_INLINE size_t GetEntryIndex(Entry *entry) {
const size_t index = entry - m_table;
MESOSPHERE_ASSERT(index < m_table_size);
return index;
}
constexpr ALWAYS_INLINE Entry *FindEntry(ams::svc::Handle handle) const {
MESOSPHERE_ASSERT_THIS();
/* Unpack the handle. */
@@ -288,41 +303,40 @@ namespace ams::kern {
const auto linear_id = handle_pack.Get<HandleLinearId>();
const auto reserved = handle_pack.Get<HandleReserved>();
MESOSPHERE_ASSERT(reserved == 0);
MESOSPHERE_UNUSED(reserved);
/* Validate our indexing information. */
if (AMS_UNLIKELY(raw_value == 0)) {
return false;
if (raw_value == 0) {
return nullptr;
}
if (AMS_UNLIKELY(linear_id == 0)) {
return false;
if (linear_id == 0) {
return nullptr;
}
if (AMS_UNLIKELY(index >= m_table_size)) {
return false;
}
/* Check that there's an object, and our serial id is correct. */
if (AMS_UNLIKELY(m_objects[index] == nullptr)) {
return false;
}
if (AMS_UNLIKELY(m_entry_infos[index].GetLinearId() != linear_id)) {
return false;
}
return true;
}
constexpr NOINLINE KAutoObject *GetObjectImpl(ams::svc::Handle handle) const {
MESOSPHERE_ASSERT_THIS();
/* Handles must not have reserved bits set. */
const auto handle_pack = GetHandleBitPack(handle);
if (AMS_UNLIKELY(handle_pack.Get<HandleReserved>() != 0)) {
if (index >= m_table_size) {
return nullptr;
}
if (AMS_LIKELY(this->IsValidHandle(handle))) {
return m_objects[handle_pack.Get<HandleIndex>()];
/* Get the entry, and ensure our serial id is correct. */
Entry *entry = std::addressof(m_table[index]);
if (entry->GetObject() == nullptr) {
return nullptr;
}
if (entry->GetLinearId() != linear_id) {
return nullptr;
}
return entry;
}
constexpr ALWAYS_INLINE KAutoObject *GetObjectImpl(ams::svc::Handle handle) const {
MESOSPHERE_ASSERT_THIS();
/* Handles must not have reserved bits set. */
if (GetHandleBitPack(handle).Get<HandleReserved>() != 0) {
return nullptr;
}
if (Entry *entry = this->FindEntry(handle); entry != nullptr) {
return entry->GetObject();
} else {
return nullptr;
}
@@ -332,17 +346,18 @@ namespace ams::kern {
MESOSPHERE_ASSERT_THIS();
/* Index must be in bounds. */
if (AMS_UNLIKELY(index >= m_table_size)) {
if (index >= m_table_size || m_table == nullptr) {
return nullptr;
}
/* Ensure entry has an object. */
if (KAutoObject *obj = m_objects[index]; obj != nullptr) {
*out_handle = EncodeHandle(index, m_entry_infos[index].GetLinearId());
return obj;
} else {
Entry *entry = std::addressof(m_table[index]);
if (entry->GetObject() == nullptr) {
return nullptr;
}
*out_handle = EncodeHandle(index, entry->GetLinearId());
return entry->GetObject();
}
};

View File

@@ -70,7 +70,6 @@ namespace ams::kern {
constexpr bool Is64Bit() const { return (m_flags & (1 << 3)); }
constexpr bool Is64BitAddressSpace() const { return (m_flags & (1 << 4)); }
constexpr bool UsesSecureMemory() const { return (m_flags & (1 << 5)); }
constexpr bool IsImmortal() const { return (m_flags & (1 << 6)); }
constexpr u32 GetRxAddress() const { return m_rx_address; }
constexpr u32 GetRxSize() const { return m_rx_size; }
@@ -91,49 +90,45 @@ namespace ams::kern {
class KInitialProcessReader {
private:
KInitialProcessHeader m_kip_header;
KInitialProcessHeader *m_kip_header;
public:
constexpr KInitialProcessReader() : m_kip_header() { /* ... */ }
constexpr const u32 *GetCapabilities() const { return m_kip_header.GetCapabilities(); }
constexpr size_t GetNumCapabilities() const { return m_kip_header.GetNumCapabilities(); }
constexpr const u32 *GetCapabilities() const { return m_kip_header->GetCapabilities(); }
constexpr size_t GetNumCapabilities() const { return m_kip_header->GetNumCapabilities(); }
constexpr size_t GetBinarySize() const {
return m_kip_header.GetRxCompressedSize() + m_kip_header.GetRoCompressedSize() + m_kip_header.GetRwCompressedSize();
return sizeof(*m_kip_header) + m_kip_header->GetRxCompressedSize() + m_kip_header->GetRoCompressedSize() + m_kip_header->GetRwCompressedSize();
}
constexpr size_t GetSize() const {
if (const size_t bss_size = m_kip_header.GetBssSize(); bss_size != 0) {
return util::AlignUp(m_kip_header.GetBssAddress() + m_kip_header.GetBssSize(), PageSize);
if (const size_t bss_size = m_kip_header->GetBssSize(); bss_size != 0) {
return m_kip_header->GetBssAddress() + m_kip_header->GetBssSize();
} else {
return util::AlignUp(m_kip_header.GetRwAddress() + m_kip_header.GetRwSize(), PageSize);
return m_kip_header->GetRwAddress() + m_kip_header->GetRwSize();
}
}
constexpr u8 GetPriority() const { return m_kip_header.GetPriority(); }
constexpr u8 GetIdealCoreId() const { return m_kip_header.GetIdealCoreId(); }
constexpr u32 GetAffinityMask() const { return m_kip_header.GetAffinityMask(); }
constexpr u32 GetStackSize() const { return m_kip_header.GetStackSize(); }
constexpr u8 GetPriority() const { return m_kip_header->GetPriority(); }
constexpr u8 GetIdealCoreId() const { return m_kip_header->GetIdealCoreId(); }
constexpr u32 GetAffinityMask() const { return m_kip_header->GetAffinityMask(); }
constexpr u32 GetStackSize() const { return m_kip_header->GetStackSize(); }
constexpr bool Is64Bit() const { return m_kip_header.Is64Bit(); }
constexpr bool Is64BitAddressSpace() const { return m_kip_header.Is64BitAddressSpace(); }
constexpr bool UsesSecureMemory() const { return m_kip_header.UsesSecureMemory(); }
constexpr bool IsImmortal() const { return m_kip_header.IsImmortal(); }
constexpr bool Is64Bit() const { return m_kip_header->Is64Bit(); }
constexpr bool Is64BitAddressSpace() const { return m_kip_header->Is64BitAddressSpace(); }
constexpr bool UsesSecureMemory() const { return m_kip_header->UsesSecureMemory(); }
KVirtualAddress Attach(KVirtualAddress bin) {
/* Copy the header. */
m_kip_header = *GetPointer<const KInitialProcessHeader>(bin);
/* Check that it's valid. */
if (m_kip_header.IsValid()) {
return bin + sizeof(KInitialProcessHeader);
bool Attach(u8 *bin) {
if (KInitialProcessHeader *header = reinterpret_cast<KInitialProcessHeader *>(bin); header->IsValid()) {
m_kip_header = header;
return true;
} else {
return Null<KVirtualAddress>;
return false;
}
}
Result MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const;
Result Load(KProcessAddress address, const ams::svc::CreateProcessParameter &params, KProcessAddress src) const;
Result Load(KProcessAddress address, const ams::svc::CreateProcessParameter &params) const;
Result SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter &params) const;
};

View File

@@ -28,10 +28,9 @@ namespace ams::kern {
MESOSPHERE_AUTOOBJECT_TRAITS(KInterruptEvent, KReadableEvent);
private:
s32 m_interrupt_id;
s32 m_core_id;
bool m_is_initialized;
public:
constexpr KInterruptEvent() : m_interrupt_id(-1), m_core_id(-1), m_is_initialized(false) { /* ... */ }
constexpr KInterruptEvent() : m_interrupt_id(-1), m_is_initialized(false) { /* ... */ }
virtual ~KInterruptEvent() { /* ... */ }
Result Initialize(int32_t interrupt_name, ams::svc::InterruptType type);
@@ -59,9 +58,9 @@ namespace ams::kern {
virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override;
virtual void DoTask() override;
void Unregister(s32 interrupt_id, s32 core_id);
void Unregister(s32 interrupt_id);
public:
static Result Register(s32 interrupt_id, s32 core_id, bool level, KInterruptEvent *event);
static Result Register(s32 interrupt_id, bool level, KInterruptEvent *event);
};
}

View File

@@ -24,59 +24,40 @@ namespace ams::kern {
class KLightConditionVariable {
private:
KThread::WaiterList m_wait_list;
KThreadQueue m_thread_queue;
public:
constexpr ALWAYS_INLINE KLightConditionVariable() : m_wait_list() { /* ... */ }
constexpr ALWAYS_INLINE KLightConditionVariable() : m_thread_queue() { /* ... */ }
private:
void WaitImpl(KLightLock *lock, s64 timeout, bool allow_terminating_thread) {
void WaitImpl(KLightLock *lock, s64 timeout) {
KThread *owner = GetCurrentThreadPointer();
KHardwareTimer *timer;
/* Sleep the thread. */
{
KScopedSchedulerLockAndSleep lk(&timer, owner, timeout);
lock->Unlock();
if (!allow_terminating_thread && owner->IsTerminationRequested()) {
if (!m_thread_queue.SleepThread(owner)) {
lk.CancelSleep();
return;
}
lock->Unlock();
/* Set the thread as waiting. */
GetCurrentThread().SetState(KThread::ThreadState_Waiting);
/* Add the thread to the queue. */
m_wait_list.push_back(GetCurrentThread());
}
/* Remove the thread from the wait list. */
{
KScopedSchedulerLock sl;
m_wait_list.erase(m_wait_list.iterator_to(GetCurrentThread()));
}
/* Cancel the task that the sleep setup. */
if (timer != nullptr) {
timer->CancelTask(owner);
}
/* Re-acquire the lock. */
lock->Lock();
}
public:
void Wait(KLightLock *lock, s64 timeout = -1ll, bool allow_terminating_thread = true) {
this->WaitImpl(lock, timeout, allow_terminating_thread);
void Wait(KLightLock *lock, s64 timeout = -1ll) {
this->WaitImpl(lock, timeout);
lock->Lock();
}
void Broadcast() {
KScopedSchedulerLock lk;
/* Signal all threads. */
for (auto &thread : m_wait_list) {
thread.SetState(KThread::ThreadState_Runnable);
while (m_thread_queue.WakeupFrontThread() != nullptr) {
/* We want to signal all threads, and so should continue waking up until there's nothing to wake. */
}
}

View File

@@ -50,7 +50,7 @@ namespace ams::kern {
}
}
ALWAYS_INLINE void Unlock() {
void Unlock() {
MESOSPHERE_ASSERT_THIS();
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer());
@@ -65,8 +65,8 @@ namespace ams::kern {
void LockSlowPath(uintptr_t owner, uintptr_t cur_thread);
void UnlockSlowPath(uintptr_t cur_thread);
ALWAYS_INLINE bool IsLocked() const { return m_tag.load() != 0; }
ALWAYS_INLINE bool IsLockedByCurrentThread() const { return (m_tag.load() | 0x1ul) == (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer()) | 0x1ul); }
bool IsLocked() const { return m_tag != 0; }
bool IsLockedByCurrentThread() const { return (m_tag | 0x1ul) == (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer()) | 0x1ul); }
};
using KScopedLightLock = KScopedLock<KLightLock>;

View File

@@ -0,0 +1,236 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_typed_address.hpp>
#include <mesosphere/kern_slab_helpers.hpp>
namespace ams::kern {
class KLinkedListNode : public util::IntrusiveListBaseNode<KLinkedListNode>, public KSlabAllocated<KLinkedListNode> {
private:
void *m_item;
public:
constexpr KLinkedListNode() : util::IntrusiveListBaseNode<KLinkedListNode>(), m_item(nullptr) { MESOSPHERE_ASSERT_THIS(); }
constexpr void Initialize(void *it) {
MESOSPHERE_ASSERT_THIS();
m_item = it;
}
constexpr void *GetItem() const {
return m_item;
}
};
static_assert(sizeof(KLinkedListNode) == sizeof(util::IntrusiveListNode) + sizeof(void *));
template<typename T>
class KLinkedList : private util::IntrusiveListBaseTraits<KLinkedListNode>::ListType {
private:
using BaseList = util::IntrusiveListBaseTraits<KLinkedListNode>::ListType;
public:
template<bool Const>
class Iterator;
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = value_type *;
using const_pointer = const value_type *;
using reference = value_type &;
using const_reference = const value_type &;
using iterator = Iterator<false>;
using const_iterator = Iterator<true>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
template<bool Const>
class Iterator {
private:
using BaseIterator = BaseList::Iterator<Const>;
friend class KLinkedList;
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename KLinkedList::value_type;
using difference_type = typename KLinkedList::difference_type;
using pointer = typename std::conditional<Const, KLinkedList::const_pointer, KLinkedList::pointer>::type;
using reference = typename std::conditional<Const, KLinkedList::const_reference, KLinkedList::reference>::type;
private:
BaseIterator m_base_it;
public:
explicit Iterator(BaseIterator it) : m_base_it(it) { /* ... */ }
pointer GetItem() const {
return static_cast<pointer>(m_base_it->GetItem());
}
bool operator==(const Iterator &rhs) const {
return m_base_it == rhs.m_base_it;
}
bool operator!=(const Iterator &rhs) const {
return !(*this == rhs);
}
pointer operator->() const {
return this->GetItem();
}
reference operator*() const {
return *this->GetItem();
}
Iterator &operator++() {
++m_base_it;
return *this;
}
Iterator &operator--() {
--m_base_it;
return *this;
}
Iterator operator++(int) {
const Iterator it{*this};
++(*this);
return it;
}
Iterator operator--(int) {
const Iterator it{*this};
--(*this);
return it;
}
operator Iterator<true>() const {
return Iterator<true>(m_base_it);
}
};
public:
constexpr KLinkedList() : BaseList() { /* ... */ }
~KLinkedList() {
/* Erase all elements. */
for (auto it = this->begin(); it != this->end(); it = this->erase(it)) {
/* ... */
}
/* Ensure we succeeded. */
MESOSPHERE_ASSERT(this->empty());
}
/* Iterator accessors. */
iterator begin() {
return iterator(BaseList::begin());
}
const_iterator begin() const {
return const_iterator(BaseList::begin());
}
iterator end() {
return iterator(BaseList::end());
}
const_iterator end() const {
return const_iterator(BaseList::end());
}
const_iterator cbegin() const {
return this->begin();
}
const_iterator cend() const {
return this->end();
}
reverse_iterator rbegin() {
return reverse_iterator(this->end());
}
const_reverse_iterator rbegin() const {
return const_reverse_iterator(this->end());
}
reverse_iterator rend() {
return reverse_iterator(this->begin());
}
const_reverse_iterator rend() const {
return const_reverse_iterator(this->begin());
}
const_reverse_iterator crbegin() const {
return this->rbegin();
}
const_reverse_iterator crend() const {
return this->rend();
}
/* Content management. */
using BaseList::empty;
using BaseList::size;
reference back() {
return *(--this->end());
}
const_reference back() const {
return *(--this->end());
}
reference front() {
return *this->begin();
}
const_reference front() const {
return *this->begin();
}
iterator insert(const_iterator pos, reference ref) {
KLinkedListNode *node = KLinkedListNode::Allocate();
MESOSPHERE_ABORT_UNLESS(node != nullptr);
node->Initialize(std::addressof(ref));
return iterator(BaseList::insert(pos.m_base_it, *node));
}
void push_back(reference ref) {
this->insert(this->end(), ref);
}
void push_front(reference ref) {
this->insert(this->begin(), ref);
}
void pop_back() {
this->erase(--this->end());
}
void pop_front() {
this->erase(this->begin());
}
iterator erase(const iterator pos) {
KLinkedListNode *freed_node = std::addressof(*pos.m_base_it);
iterator ret = iterator(BaseList::erase(pos.m_base_it));
KLinkedListNode::Free(freed_node);
return ret;
}
};
}

View File

@@ -160,7 +160,7 @@ namespace ams::kern {
};
constexpr KMemoryPermission ConvertToKMemoryPermission(ams::svc::MemoryPermission perm) {
return static_cast<KMemoryPermission>((util::ToUnderlying(perm) & KMemoryPermission_UserMask) | KMemoryPermission_KernelRead | ((util::ToUnderlying(perm) & KMemoryPermission_UserWrite) << KMemoryPermission_KernelShift) | (perm == ams::svc::MemoryPermission_None ? KMemoryPermission_NotMapped : KMemoryPermission_None));
return static_cast<KMemoryPermission>((perm & KMemoryPermission_UserMask) | KMemoryPermission_KernelRead | ((perm & KMemoryPermission_UserWrite) << KMemoryPermission_KernelShift) | (perm == ams::svc::MemoryPermission_None ? KMemoryPermission_NotMapped : KMemoryPermission_None));
}
enum KMemoryAttribute : u8 {

View File

@@ -27,8 +27,18 @@ namespace ams::kern {
KMemoryBlock *m_blocks[MaxBlocks];
size_t m_index;
KMemoryBlockSlabManager *m_slab_manager;
private:
ALWAYS_INLINE Result Initialize(size_t num_blocks) {
public:
constexpr explicit KMemoryBlockManagerUpdateAllocator(KMemoryBlockSlabManager *sm) : m_blocks(), m_index(MaxBlocks), m_slab_manager(sm) { /* ... */ }
~KMemoryBlockManagerUpdateAllocator() {
for (const auto &block : m_blocks) {
if (block != nullptr) {
m_slab_manager->Free(block);
}
}
}
Result Initialize(size_t num_blocks) {
/* Check num blocks. */
MESOSPHERE_ASSERT(num_blocks <= MaxBlocks);
@@ -43,18 +53,6 @@ namespace ams::kern {
return ResultSuccess();
}
public:
KMemoryBlockManagerUpdateAllocator(Result *out_result, KMemoryBlockSlabManager *sm, size_t num_blocks = MaxBlocks) : m_blocks(), m_index(MaxBlocks), m_slab_manager(sm) {
*out_result = this->Initialize(num_blocks);
}
~KMemoryBlockManagerUpdateAllocator() {
for (const auto &block : m_blocks) {
if (block != nullptr) {
m_slab_manager->Free(block);
}
}
}
KMemoryBlock *Allocate() {
MESOSPHERE_ABORT_UNLESS(m_index < MaxBlocks);

View File

@@ -44,8 +44,9 @@ namespace ams::kern {
constexpr size_t KernelInitialPageHeapSize = 128_KB;
constexpr size_t KernelSlabHeapDataSize = 5_MB;
constexpr size_t KernelSlabHeapGapsSizeMax = 2_MB - 64_KB;
constexpr size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSizeMax;
constexpr size_t KernelSlabHeapGapsSize = 2_MB - 64_KB;
constexpr size_t KernelSlabHeapGapsSizeDeprecated = 2_MB;
constexpr size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSize;
/* NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860. */
constexpr size_t KernelSlabHeapAdditionalSize = 0x68000;
@@ -175,14 +176,7 @@ namespace ams::kern {
return std::make_tuple(total_size, kernel_size);
}
static void InitializeLinearMemoryAddresses(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start) {
/* Set static differences. */
s_linear_phys_to_virt_diff = GetInteger(linear_virtual_start) - GetInteger(aligned_linear_phys_start);
s_linear_virt_to_phys_diff = GetInteger(aligned_linear_phys_start) - GetInteger(linear_virtual_start);
}
static void InitializeLinearMemoryRegionTrees();
static void InitializeLinearMemoryRegionTrees(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start);
static size_t GetResourceRegionSizeForInit();
static NOINLINE auto GetKernelRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel); }

View File

@@ -75,7 +75,7 @@ namespace ams::kern {
KVirtualAddress AllocateBlock(s32 index, bool random) { return m_heap.AllocateBlock(index, random); }
void Free(KVirtualAddress addr, size_t num_pages) { m_heap.Free(addr, num_pages); }
void SetInitialUsedHeapSize(size_t reserved_size) { m_heap.SetInitialUsedSize(reserved_size); }
void UpdateUsedHeapSize() { m_heap.UpdateUsedSize(); }
void InitializeOptimizedMemory() { std::memset(GetVoidPointer(m_management_region), 0, CalculateOptimizedProcessOverheadSize(m_heap.GetSize())); }
@@ -168,10 +168,6 @@ namespace ams::kern {
return m_managers[KMemoryLayout::GetVirtualLinearRegion(address).GetAttributes()];
}
const Impl &GetManager(KVirtualAddress address) const {
return m_managers[KMemoryLayout::GetVirtualLinearRegion(address).GetAttributes()];
}
constexpr Impl *GetFirstManager(Pool pool, Direction dir) {
return dir == Direction_FromBack ? m_pool_managers_tail[pool] : m_pool_managers_head[pool];
}
@@ -201,10 +197,6 @@ namespace ams::kern {
NOINLINE Result AllocateAndOpen(KPageGroup *out, size_t num_pages, u32 option);
NOINLINE Result AllocateAndOpenForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern);
Pool GetPool(KVirtualAddress address) const {
return this->GetManager(address).GetPool();
}
void Open(KVirtualAddress address, size_t num_pages) {
/* Repeatedly open references until we've done so for all pages. */
while (num_pages) {

View File

@@ -21,8 +21,7 @@ namespace ams::kern {
enum KMemoryRegionType : u32 {};
enum KMemoryRegionAttr : typename std::underlying_type<KMemoryRegionType>::type {
KMemoryRegionAttr_CarveoutProtected = 0x02000000,
KMemoryRegionAttr_Uncached = 0x04000000,
KMemoryRegionAttr_CarveoutProtected = 0x04000000,
KMemoryRegionAttr_DidKernelMap = 0x08000000,
KMemoryRegionAttr_ShouldKernelMap = 0x10000000,
KMemoryRegionAttr_UserReadOnly = 0x20000000,
@@ -66,41 +65,11 @@ namespace ams::kern {
consteval operator KMemoryRegionType() const { return static_cast<KMemoryRegionType>(m_value); }
consteval ValueType GetValue() const { return m_value; }
consteval const KMemoryRegionTypeValue Finalize() {
AMS_ASSUME(!m_finalized);
consteval const KMemoryRegionTypeValue &Finalize() { m_finalized = true; return *this; }
consteval const KMemoryRegionTypeValue &SetSparseOnly() { m_sparse_only = true; return *this; }
consteval const KMemoryRegionTypeValue &SetDenseOnly() { m_dense_only = true; return *this; }
KMemoryRegionTypeValue new_type = *this;
new_type.m_finalized = true;
return new_type;
}
consteval const KMemoryRegionTypeValue SetSparseOnly() {
AMS_ASSUME(!m_finalized);
AMS_ASSUME(!m_sparse_only);
AMS_ASSUME(!m_dense_only);
KMemoryRegionTypeValue new_type = *this;
new_type.m_sparse_only = true;
return new_type;
}
consteval const KMemoryRegionTypeValue SetDenseOnly() {
AMS_ASSUME(!m_finalized);
AMS_ASSUME(!m_sparse_only);
AMS_ASSUME(!m_dense_only);
KMemoryRegionTypeValue new_type = *this;
new_type.m_dense_only = true;
return new_type;
}
consteval KMemoryRegionTypeValue SetAttribute(KMemoryRegionAttr attr) {
AMS_ASSUME(!m_finalized);
KMemoryRegionTypeValue new_type = *this;
new_type.m_value |= attr;
return new_type;
}
consteval KMemoryRegionTypeValue &SetAttribute(KMemoryRegionAttr attr) { AMS_ASSUME(!m_finalized); m_value |= attr; return *this; }
consteval KMemoryRegionTypeValue DeriveInitial(size_t i, size_t next = BITSIZEOF(ValueType)) const {
AMS_ASSUME(!m_finalized);
@@ -247,10 +216,6 @@ namespace ams::kern {
static_assert(KMemoryRegionType_VirtualDramKernelPtHeap .GetValue() == 0x2A);
static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
/* UNUSED: .DeriveSparse(2, 2, 0); */
constexpr inline const auto KMemoryRegionType_VirtualDramUnknownDebug = KMemoryRegionType_Dram.DeriveSparse(2, 2, 1);
static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x52));
constexpr inline const auto KMemoryRegionType_VirtualDramKernelInitPt = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
constexpr inline const auto KMemoryRegionType_VirtualDramPoolManagement = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
constexpr inline const auto KMemoryRegionType_VirtualDramUserPool = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
@@ -327,8 +292,6 @@ namespace ams::kern {
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
} else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
return KMemoryRegionType_VirtualDramKernelPtHeap;
} else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) {
return KMemoryRegionType_VirtualDramUnknownDebug;
} else {
return KMemoryRegionType_Dram;
}

View File

@@ -47,9 +47,6 @@ namespace ams::kern {
Derived *derived = obj->DynamicCast<Derived *>();
R_UNLESS(derived != nullptr, svc::ResultNotFound());
/* Check that the object is closed. */
R_UNLESS(derived->IsServerClosed(), svc::ResultInvalidState());
return Delete(obj.GetPointerUnsafe(), name);
}

View File

@@ -125,7 +125,7 @@ namespace ams::kern {
private:
KVirtualAddress m_heap_address;
size_t m_heap_size;
size_t m_initial_used_size;
size_t m_used_size;
size_t m_num_blocks;
Block m_blocks[NumMemoryBlockPageShifts];
private:
@@ -134,7 +134,7 @@ namespace ams::kern {
void FreeBlock(KVirtualAddress block, s32 index);
public:
KPageHeap() : m_heap_address(), m_heap_size(), m_initial_used_size(), m_num_blocks(), m_blocks() { /* ... */ }
KPageHeap() : m_heap_address(), m_heap_size(), m_used_size(), m_num_blocks(), m_blocks() { /* ... */ }
constexpr KVirtualAddress GetAddress() const { return m_heap_address; }
constexpr size_t GetSize() const { return m_heap_size; }
@@ -149,13 +149,8 @@ namespace ams::kern {
size_t GetFreeSize() const { return this->GetNumFreePages() * PageSize; }
void DumpFreeList() const;
void SetInitialUsedSize(size_t reserved_size) {
/* Check that the reserved size is valid. */
const size_t free_size = this->GetNumFreePages() * PageSize;
MESOSPHERE_ABORT_UNLESS(m_heap_size >= free_size + reserved_size);
/* Set the initial used size. */
m_initial_used_size = m_heap_size - free_size - reserved_size;
void UpdateUsedSize() {
m_used_size = m_heap_size - (this->GetNumFreePages() * PageSize);
}
KVirtualAddress AllocateBlock(s32 index, bool random);

View File

@@ -47,21 +47,12 @@ namespace ams::kern {
static_assert(std::is_trivial<KPageProperties>::value);
static_assert(sizeof(KPageProperties) == sizeof(u32));
class KResourceLimit;
class KPageTableBase {
NON_COPYABLE(KPageTableBase);
NON_MOVEABLE(KPageTableBase);
public:
using TraversalEntry = KPageTableImpl::TraversalEntry;
using TraversalContext = KPageTableImpl::TraversalContext;
struct MemoryRange {
KVirtualAddress address;
size_t size;
void Close();
};
protected:
enum MemoryFillValue {
MemoryFillValue_Zero = 0,
@@ -159,10 +150,8 @@ namespace ams::kern {
size_t m_max_heap_size{};
size_t m_mapped_physical_memory_size{};
size_t m_mapped_unsafe_physical_memory{};
size_t m_mapped_ipc_server_memory{};
mutable KLightLock m_general_lock{};
mutable KLightLock m_map_physical_memory_lock{};
KLightLock m_device_map_lock{};
KPageTableImpl m_impl{};
KMemoryBlockManager m_memory_block_manager{};
u32 m_allocate_option{};
@@ -172,7 +161,6 @@ namespace ams::kern {
bool m_enable_device_address_space_merge{};
KMemoryBlockSlabManager *m_memory_block_slab_manager{};
KBlockInfoManager *m_block_info_manager{};
KResourceLimit *m_resource_limit{};
const KMemoryRegion *m_cached_physical_linear_region{};
const KMemoryRegion *m_cached_physical_heap_region{};
const KMemoryRegion *m_cached_virtual_heap_region{};
@@ -183,7 +171,7 @@ namespace ams::kern {
constexpr KPageTableBase() { /* ... */ }
NOINLINE Result InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end);
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KResourceLimit *resource_limit);
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager);
void Finalize();
@@ -207,10 +195,6 @@ namespace ams::kern {
return this->CanContain(addr, size, KMemoryState_AliasCode);
}
ALWAYS_INLINE KScopedLightLock AcquireDeviceMapLock() {
return KScopedLightLock(m_device_map_lock);
}
KProcessAddress GetRegionAddress(KMemoryState state) const;
size_t GetRegionSize(KMemoryState state) const;
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const;
@@ -219,54 +203,54 @@ namespace ams::kern {
virtual Result Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, const KPageGroup &page_group, const KPageProperties properties, OperationType operation, bool reuse_ll) = 0;
virtual void FinalizeUpdate(PageLinkedList *page_list) = 0;
ALWAYS_INLINE KPageTableImpl &GetImpl() { return m_impl; }
ALWAYS_INLINE const KPageTableImpl &GetImpl() const { return m_impl; }
KPageTableImpl &GetImpl() { return m_impl; }
const KPageTableImpl &GetImpl() const { return m_impl; }
ALWAYS_INLINE bool IsLockedByCurrentThread() const { return m_general_lock.IsLockedByCurrentThread(); }
bool IsLockedByCurrentThread() const { return m_general_lock.IsLockedByCurrentThread(); }
ALWAYS_INLINE bool IsLinearMappedPhysicalAddress(KPhysicalAddress phys_addr) {
bool IsLinearMappedPhysicalAddress(KPhysicalAddress phys_addr) {
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
return KMemoryLayout::IsLinearMappedPhysicalAddress(m_cached_physical_linear_region, phys_addr);
}
ALWAYS_INLINE bool IsLinearMappedPhysicalAddress(KPhysicalAddress phys_addr, size_t size) {
bool IsLinearMappedPhysicalAddress(KPhysicalAddress phys_addr, size_t size) {
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
return KMemoryLayout::IsLinearMappedPhysicalAddress(m_cached_physical_linear_region, phys_addr, size);
}
ALWAYS_INLINE bool IsHeapPhysicalAddress(KPhysicalAddress phys_addr) {
bool IsHeapPhysicalAddress(KPhysicalAddress phys_addr) {
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
return KMemoryLayout::IsHeapPhysicalAddress(m_cached_physical_heap_region, phys_addr);
}
ALWAYS_INLINE bool IsHeapPhysicalAddress(KPhysicalAddress phys_addr, size_t size) {
bool IsHeapPhysicalAddress(KPhysicalAddress phys_addr, size_t size) {
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
return KMemoryLayout::IsHeapPhysicalAddress(m_cached_physical_heap_region, phys_addr, size);
}
ALWAYS_INLINE bool IsHeapPhysicalAddressForFinalize(KPhysicalAddress phys_addr) {
bool IsHeapPhysicalAddressForFinalize(KPhysicalAddress phys_addr) {
MESOSPHERE_ASSERT(!this->IsLockedByCurrentThread());
return KMemoryLayout::IsHeapPhysicalAddress(m_cached_physical_heap_region, phys_addr);
}
ALWAYS_INLINE bool IsHeapVirtualAddress(KVirtualAddress virt_addr) {
bool IsHeapVirtualAddress(KVirtualAddress virt_addr) {
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
return KMemoryLayout::IsHeapVirtualAddress(m_cached_virtual_heap_region, virt_addr);
}
ALWAYS_INLINE bool IsHeapVirtualAddress(KVirtualAddress virt_addr, size_t size) {
bool IsHeapVirtualAddress(KVirtualAddress virt_addr, size_t size) {
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
return KMemoryLayout::IsHeapVirtualAddress(m_cached_virtual_heap_region, virt_addr, size);
}
ALWAYS_INLINE bool ContainsPages(KProcessAddress addr, size_t num_pages) const {
bool ContainsPages(KProcessAddress addr, size_t num_pages) const {
return (m_address_space_start <= addr) && (num_pages <= (m_address_space_end - m_address_space_start) / PageSize) && (addr + num_pages * PageSize - 1 <= m_address_space_end - 1);
}
private:
@@ -302,35 +286,16 @@ namespace ams::kern {
Result MakePageGroup(KPageGroup &pg, KProcessAddress addr, size_t num_pages);
bool IsValidPageGroup(const KPageGroup &pg, KProcessAddress addr, size_t num_pages);
Result GetContiguousMemoryRangeWithState(MemoryRange *out, KProcessAddress address, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr);
NOINLINE Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
Result MapIoImpl(KProcessAddress *out, PageLinkedList *page_list, KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
Result ReadIoMemoryImpl(void *buffer, KPhysicalAddress phys_addr, size_t size);
Result WriteIoMemoryImpl(KPhysicalAddress phys_addr, const void *buffer, size_t size);
Result SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state);
Result SetupForIpcServer(KProcessAddress *out_addr, size_t size, KProcessAddress src_addr, KMemoryPermission test_perm, KMemoryState dst_state, KPageTableBase &src_page_table, bool send);
void CleanupForIpcClientOnServerSetupFailure(PageLinkedList *page_list, KProcessAddress address, size_t size, KMemoryPermission prot_perm);
size_t GetSize(KMemoryState state) const;
ALWAYS_INLINE bool GetPhysicalAddressLocked(KPhysicalAddress *out, KProcessAddress virt_addr) const {
/* Validate pre-conditions. */
MESOSPHERE_AUDIT(this->IsLockedByCurrentThread());
return this->GetImpl().GetPhysicalAddress(out, virt_addr);
}
public:
bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const {
/* Validate pre-conditions. */
MESOSPHERE_AUDIT(!this->IsLockedByCurrentThread());
/* Acquire exclusive access to the table while doing address translation. */
KScopedLightLock lk(m_general_lock);
return this->GetPhysicalAddressLocked(out, virt_addr);
return this->GetImpl().GetPhysicalAddress(out, virt_addr);
}
KBlockInfoManager *GetBlockInfoManager() const { return m_block_info_manager; }
@@ -376,19 +341,13 @@ namespace ams::kern {
Result InvalidateProcessDataCache(KProcessAddress address, size_t size);
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size);
Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size);
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size);
Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size);
Result LockForMapDeviceAddressSpace(KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned);
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size);
Result LockForDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned);
Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size);
Result UnlockForDeviceAddressSpacePartialMap(KProcessAddress address, size_t size, size_t mapped_size);
Result OpenMemoryRangeForMapDeviceAddressSpace(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned);
Result OpenMemoryRangeForUnmapDeviceAddressSpace(MemoryRange *out, KProcessAddress address, size_t size);
Result MakePageGroupForUnmapDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size);
Result UnlockForDeviceAddressSpacePartialMap(KProcessAddress address, size_t size, size_t mapped_size);
Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size);
Result UnlockForIpcUserBuffer(KProcessAddress address, size_t size);
@@ -398,8 +357,6 @@ namespace ams::kern {
Result LockForCodeMemory(KPageGroup *out, KProcessAddress address, size_t size);
Result UnlockForCodeMemory(KProcessAddress address, size_t size, const KPageGroup &pg);
Result OpenMemoryRangeForProcessCacheOperation(MemoryRange *out, KProcessAddress address, size_t size);
Result CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
Result CopyMemoryFromLinearToKernel(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
Result CopyMemoryFromUserToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr);
@@ -408,7 +365,7 @@ namespace ams::kern {
Result CopyMemoryFromHeapToHeapWithoutCheckDestination(KPageTableBase &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
Result SetupForIpc(KProcessAddress *out_dst_addr, size_t size, KProcessAddress src_addr, KPageTableBase &src_page_table, KMemoryPermission test_perm, KMemoryState dst_state, bool send);
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state);
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state, KProcess *server_process);
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state);
Result MapPhysicalMemory(KProcessAddress address, size_t size);
@@ -417,8 +374,6 @@ namespace ams::kern {
Result MapPhysicalMemoryUnsafe(KProcessAddress address, size_t size);
Result UnmapPhysicalMemoryUnsafe(KProcessAddress address, size_t size);
Result UnmapProcessMemory(KProcessAddress dst_address, size_t size, KPageTableBase &src_pt, KProcessAddress src_address);
void DumpMemoryBlocksLocked() const {
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
m_memory_block_manager.DumpBlocks();

View File

@@ -53,11 +53,6 @@ namespace ams::kern {
uintptr_t GetName() const { return m_name; }
bool IsLight() const { return m_is_light; }
bool IsServerClosed() const {
KScopedSchedulerLock sl;
return m_state == State::ServerClosed;
}
Result EnqueueSession(KServerSession *session);
Result EnqueueSession(KLightServerSession *session);

View File

@@ -77,7 +77,8 @@ namespace ams::kern {
bool m_is_initialized{};
bool m_is_application{};
char m_name[13]{};
std::atomic<u16> m_num_running_threads{};
std::atomic<u16> m_num_threads{};
u16 m_peak_num_threads{};
u32 m_flags{};
KMemoryManager::Pool m_memory_pool{};
s64 m_schedule_count{};
@@ -98,9 +99,7 @@ namespace ams::kern {
SharedMemoryInfoList m_shared_memory_list{};
BetaList m_beta_list{};
bool m_is_suspended{};
bool m_is_immortal{};
bool m_is_jit_debug{};
bool m_is_handle_table_initialized{};
ams::svc::DebugEvent m_jit_debug_event_type{};
ams::svc::DebugException m_jit_debug_exception_type{};
uintptr_t m_jit_debug_params[4]{};
@@ -109,6 +108,7 @@ namespace ams::kern {
KThread *m_running_threads[cpu::NumCores]{};
u64 m_running_thread_idle_counts[cpu::NumCores]{};
KThread *m_pinned_threads[cpu::NumCores]{};
std::atomic<s32> m_num_created_threads{};
std::atomic<s64> m_cpu_time{};
std::atomic<s64> m_num_process_switches{};
std::atomic<s64> m_num_thread_switches{};
@@ -124,18 +124,17 @@ namespace ams::kern {
private:
Result Initialize(const ams::svc::CreateProcessParameter &params);
Result StartTermination();
void StartTermination();
void FinishTermination();
ALWAYS_INLINE void PinThread(s32 core_id, KThread *thread) {
void PinThread(s32 core_id, KThread *thread) {
MESOSPHERE_ASSERT(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores));
MESOSPHERE_ASSERT(thread != nullptr);
MESOSPHERE_ASSERT(m_pinned_threads[core_id] == nullptr);
m_pinned_threads[core_id] = thread;
}
ALWAYS_INLINE void UnpinThread(s32 core_id, KThread *thread) {
MESOSPHERE_UNUSED(thread);
void UnpinThread(s32 core_id, KThread *thread) {
MESOSPHERE_ASSERT(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores));
MESOSPHERE_ASSERT(thread != nullptr);
MESOSPHERE_ASSERT(m_pinned_threads[core_id] == thread);
@@ -145,7 +144,7 @@ namespace ams::kern {
KProcess() { /* ... */ }
virtual ~KProcess() { /* ... */ }
Result Initialize(const ams::svc::CreateProcessParameter &params, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool, bool immortal);
Result Initialize(const ams::svc::CreateProcessParameter &params, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool);
Result Initialize(const ams::svc::CreateProcessParameter &params, svc::KUserPointer<const u32 *> caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool);
void Exit();
@@ -285,8 +284,8 @@ namespace ams::kern {
constexpr s64 GetScheduledCount() const { return m_schedule_count; }
void IncrementScheduledCount() { ++m_schedule_count; }
void IncrementRunningThreadCount();
void DecrementRunningThreadCount();
void IncrementThreadCount();
void DecrementThreadCount();
size_t GetTotalSystemResourceSize() const { return m_system_resource_num_pages * PageSize; }
size_t GetUsedSystemResourceSize() const {
@@ -340,7 +339,6 @@ namespace ams::kern {
void PinCurrentThread();
void UnpinCurrentThread();
void UnpinThread(KThread *thread);
Result SignalToAddress(KProcessAddress address) {
return m_cond_var.SignalToAddress(address);
@@ -406,23 +404,6 @@ namespace ams::kern {
this->NotifyAvailable();
}
}
ALWAYS_INLINE Result InitializeHandleTable(s32 size) {
/* Try to initialize the handle table. */
R_TRY(m_handle_table.Initialize(size));
/* We succeeded, so note that we did. */
m_is_handle_table_initialized = true;
return ResultSuccess();
}
ALWAYS_INLINE void FinalizeHandleTable() {
/* Finalize the table. */
m_handle_table.Finalize();
/* Note that the table is finalized. */
m_is_handle_table_initialized = false;
}
};
}

View File

@@ -38,7 +38,7 @@ namespace ams::kern {
static_assert(ams::svc::HighestThreadPriority <= HighestCoreMigrationAllowedPriority);
struct SchedulingState {
std::atomic<u8> needs_scheduling;
std::atomic<bool> needs_scheduling;
bool interrupt_task_thread_runnable;
bool should_count_idle;
u64 idle_count;
@@ -181,7 +181,7 @@ namespace ams::kern {
KScopedInterruptDisable intr_disable;
ON_SCOPE_EXIT { GetCurrentThread().EnableDispatch(); };
if (m_state.needs_scheduling.load()) {
if (m_state.needs_scheduling) {
Schedule();
}
}
@@ -194,20 +194,8 @@ namespace ams::kern {
static bool s_scheduler_update_needed;
static KSchedulerPriorityQueue s_priority_queue;
static LockType s_scheduler_lock;
public:
static consteval bool ValidateAssemblyOffsets();
};
consteval bool KScheduler::ValidateAssemblyOffsets() {
static_assert(__builtin_offsetof(KScheduler, m_state.needs_scheduling) == KSCHEDULER_NEEDS_SCHEDULING);
static_assert(__builtin_offsetof(KScheduler, m_state.interrupt_task_thread_runnable) == KSCHEDULER_INTERRUPT_TASK_THREAD_RUNNABLE);
static_assert(__builtin_offsetof(KScheduler, m_state.highest_priority_thread) == KSCHEDULER_HIGHEST_PRIORITY_THREAD);
static_assert(__builtin_offsetof(KScheduler, m_state.idle_thread_stack) == KSCHEDULER_IDLE_THREAD_STACK);
return true;
}
static_assert(KScheduler::ValidateAssemblyOffsets());
class KScopedSchedulerLock : KScopedLock<KScheduler::LockType> {
public:
explicit ALWAYS_INLINE KScopedSchedulerLock() : KScopedLock(KScheduler::s_scheduler_lock) { /* ... */ }

View File

@@ -53,7 +53,7 @@ namespace ams::kern {
void Dump();
private:
ALWAYS_INLINE bool IsSignaledImpl() const;
bool IsSignaledImpl() const;
void CleanupRequests();
};

View File

@@ -37,22 +37,14 @@ namespace ams::kern {
private:
KServerSession m_server;
KClientSession m_client;
std::atomic<std::underlying_type<State>::type> m_atomic_state;
State m_state;
KClientPort *m_port;
uintptr_t m_name;
KProcess *m_process;
bool m_initialized;
private:
ALWAYS_INLINE void SetState(State state) {
m_atomic_state = static_cast<u8>(state);
}
ALWAYS_INLINE State GetState() const {
return static_cast<State>(m_atomic_state.load());
}
public:
constexpr KSession()
: m_server(), m_client(), m_atomic_state(static_cast<std::underlying_type<State>::type>(State::Invalid)), m_port(), m_name(), m_process(), m_initialized()
: m_server(), m_client(), m_state(State::Invalid), m_port(), m_name(), m_process(), m_initialized()
{
/* ... */
}
@@ -70,8 +62,8 @@ namespace ams::kern {
void OnServerClosed();
void OnClientClosed();
bool IsServerClosed() const { return this->GetState() != State::Normal; }
bool IsClientClosed() const { return this->GetState() != State::Normal; }
bool IsServerClosed() const { return m_state != State::Normal; }
bool IsClientClosed() const { return m_state != State::Normal; }
Result OnRequest(KSessionRequest *request) { return m_server.OnRequest(request); }

View File

@@ -36,8 +36,8 @@ namespace ams::kern {
}
constexpr void Open() {
++m_reference_count;
MESOSPHERE_ASSERT(m_reference_count > 0);
const size_t ref_count = ++m_reference_count;
MESOSPHERE_ASSERT(ref_count > 0);
}
constexpr bool Close() {

View File

@@ -216,7 +216,7 @@ namespace ams::kern {
T *Allocate() {
T *obj = reinterpret_cast<T *>(this->AllocateImpl());
if (AMS_LIKELY(obj != nullptr)) {
std::construct_at(obj);
new (obj) T();
}
return obj;
}

View File

@@ -16,6 +16,7 @@
#pragma once
#include <mesosphere/kern_k_auto_object.hpp>
#include <mesosphere/kern_slab_helpers.hpp>
#include <mesosphere/kern_k_linked_list.hpp>
namespace ams::kern {
@@ -45,7 +46,7 @@ namespace ams::kern {
static Result Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout);
public:
virtual void Finalize() override;
virtual bool IsSignaled() const { AMS_INFINITE_LOOP(); }
virtual bool IsSignaled() const = 0;
virtual void DumpWaiters();
};

View File

@@ -77,34 +77,22 @@ namespace ams::kern {
};
enum DpcFlag : u32 {
DpcFlag_Terminating = (1 << 0),
DpcFlag_Terminated = (1 << 1),
DpcFlag_PerformDestruction = (1 << 2),
DpcFlag_Terminating = (1 << 0),
DpcFlag_Terminated = (1 << 1),
};
struct StackParameters {
alignas(0x10) u8 svc_permission[0x18];
KThreadContext *context;
KThread *cur_thread;
s16 disable_count;
alignas(0x10) u8 svc_permission[0x10];
std::atomic<u8> dpc_flags;
u8 current_svc_id;
bool is_calling_svc;
bool is_in_exception_handler;
bool is_pinned;
s32 disable_count;
KThreadContext *context;
KThread *cur_thread;
};
static_assert(alignof(StackParameters) == 0x10);
static_assert(sizeof(StackParameters) == THREAD_STACK_PARAMETERS_SIZE);
static_assert(__builtin_offsetof(StackParameters, svc_permission) == THREAD_STACK_PARAMETERS_SVC_PERMISSION);
static_assert(__builtin_offsetof(StackParameters, context) == THREAD_STACK_PARAMETERS_CONTEXT);
static_assert(__builtin_offsetof(StackParameters, cur_thread) == THREAD_STACK_PARAMETERS_CUR_THREAD);
static_assert(__builtin_offsetof(StackParameters, disable_count) == THREAD_STACK_PARAMETERS_DISABLE_COUNT);
static_assert(__builtin_offsetof(StackParameters, dpc_flags) == THREAD_STACK_PARAMETERS_DPC_FLAGS);
static_assert(__builtin_offsetof(StackParameters, current_svc_id) == THREAD_STACK_PARAMETERS_CURRENT_SVC_ID);
static_assert(__builtin_offsetof(StackParameters, is_calling_svc) == THREAD_STACK_PARAMETERS_IS_CALLING_SVC);
static_assert(__builtin_offsetof(StackParameters, is_in_exception_handler) == THREAD_STACK_PARAMETERS_IS_IN_EXCEPTION_HANDLER);
static_assert(__builtin_offsetof(StackParameters, is_pinned) == THREAD_STACK_PARAMETERS_IS_PINNED);
struct QueueEntry {
private:
@@ -136,7 +124,7 @@ namespace ams::kern {
static_assert(sizeof(SyncObjectBuffer::m_sync_objects) == sizeof(SyncObjectBuffer::m_handles));
struct ConditionVariableComparator {
struct RedBlackKeyType {
struct LightCompareType {
uintptr_t m_cv_key;
s32 m_priority;
@@ -149,7 +137,7 @@ namespace ams::kern {
}
};
template<typename T> requires (std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>)
template<typename T> requires (std::same_as<T, KThread> || std::same_as<T, LightCompareType>)
static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KThread &rhs) {
const uintptr_t l_key = lhs.GetConditionVariableKey();
const uintptr_t r_key = rhs.GetConditionVariableKey();
@@ -165,8 +153,8 @@ namespace ams::kern {
}
}
};
static_assert(ams::util::HasRedBlackKeyType<ConditionVariableComparator>);
static_assert(std::same_as<ams::util::RedBlackKeyType<ConditionVariableComparator, void>, ConditionVariableComparator::RedBlackKeyType>);
static_assert(ams::util::HasLightCompareType<ConditionVariableComparator>);
static_assert(std::same_as<ams::util::LightCompareType<ConditionVariableComparator, void>, ConditionVariableComparator::LightCompareType>);
private:
static inline std::atomic<u64> s_next_thread_id = 0;
private:
@@ -204,14 +192,12 @@ namespace ams::kern {
WaiterList m_pinned_waiter_list{};
KThread *m_lock_owner{};
uintptr_t m_debug_params[3]{};
KAutoObject *m_closed_object{};
u32 m_address_key_value{};
u32 m_suspend_request_flags{};
u32 m_suspend_allowed_flags{};
Result m_wait_result;
Result m_debug_exception_result;
s32 m_base_priority{};
s32 m_base_priority_on_unpin{};
s32 m_physical_ideal_core_id{};
s32 m_virtual_ideal_core_id{};
s32 m_num_kernel_waiters{};
@@ -221,7 +207,7 @@ namespace ams::kern {
s32 m_original_physical_ideal_core_id{};
s32 m_num_core_migration_disables{};
ThreadState m_thread_state{};
std::atomic<u8> m_termination_requested{};
std::atomic<bool> m_termination_requested{};
bool m_wait_cancelled{};
bool m_cancellable{};
bool m_signaled{};
@@ -265,7 +251,7 @@ namespace ams::kern {
return *(reinterpret_cast<StackParameters *>(m_kernel_stack_top) - 1);
}
public:
ALWAYS_INLINE s16 GetDisableDispatchCount() const {
ALWAYS_INLINE s32 GetDisableDispatchCount() const {
MESOSPHERE_ASSERT_THIS();
return this->GetStackParameters().disable_count;
}
@@ -326,15 +312,15 @@ namespace ams::kern {
}
ALWAYS_INLINE void RegisterDpc(DpcFlag flag) {
this->GetStackParameters().dpc_flags.fetch_or(flag);
this->GetStackParameters().dpc_flags |= flag;
}
ALWAYS_INLINE void ClearDpc(DpcFlag flag) {
this->GetStackParameters().dpc_flags.fetch_and(~flag);
this->GetStackParameters().dpc_flags &= ~flag;
}
ALWAYS_INLINE u8 GetDpc() const {
return this->GetStackParameters().dpc_flags.load();
return this->GetStackParameters().dpc_flags;
}
ALWAYS_INLINE bool HasDpc() const {
@@ -342,15 +328,13 @@ namespace ams::kern {
return this->GetDpc() != 0;
}
private:
void UpdateState();
void Suspend();
ALWAYS_INLINE void AddWaiterImpl(KThread *thread);
ALWAYS_INLINE void RemoveWaiterImpl(KThread *thread);
ALWAYS_INLINE static void RestorePriority(KThread *thread);
void StartTermination();
void FinishTermination();
void IncreaseBasePriority(s32 priority);
public:
constexpr u64 GetThreadId() const { return m_thread_id; }
@@ -487,45 +471,12 @@ namespace ams::kern {
constexpr void *GetThreadLocalRegionHeapAddress() const { return m_tls_heap_address; }
constexpr KSynchronizationObject **GetSynchronizationObjectBuffer() { return std::addressof(m_sync_object_buffer.m_sync_objects[0]); }
constexpr ams::svc::Handle *GetHandleBuffer() { return std::addressof(m_sync_object_buffer.m_handles[sizeof(m_sync_object_buffer.m_sync_objects) / (sizeof(ams::svc::Handle)) - ams::svc::ArgumentHandleCountMax]); }
constexpr ams::svc::Handle *GetHandleBuffer() { return std::addressof(m_sync_object_buffer.m_handles[sizeof(m_sync_object_buffer.m_sync_objects) / sizeof(ams::svc::Handle) - ams::svc::ArgumentHandleCountMax]); }
u16 GetUserDisableCount() const { return static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->disable_count; }
void SetInterruptFlag() const { static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->interrupt_flag = 1; }
void ClearInterruptFlag() const { static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->interrupt_flag = 0; }
ALWAYS_INLINE KAutoObject *GetClosedObject() { return m_closed_object; }
ALWAYS_INLINE void SetClosedObject(KAutoObject *object) {
MESOSPHERE_ASSERT(object != nullptr);
/* Set the object to destroy. */
m_closed_object = object;
/* Schedule destruction DPC. */
if ((this->GetStackParameters().dpc_flags.load(std::memory_order_relaxed) & DpcFlag_PerformDestruction) == 0) {
this->RegisterDpc(DpcFlag_PerformDestruction);
}
}
ALWAYS_INLINE void DestroyClosedObjects() {
/* Destroy all objects that have been closed. */
if (KAutoObject *cur = m_closed_object; cur != nullptr) {
do {
/* Set our closed object as the next to close. */
m_closed_object = cur->GetNextClosedObject();
/* Destroy the current object. */
cur->Destroy();
/* Advance. */
cur = m_closed_object;
} while (cur != nullptr);
/* Clear the pending DPC. */
this->ClearDpc(DpcFlag_PerformDestruction);
}
}
constexpr void SetDebugAttached() { m_debug_attached = true; }
constexpr bool IsAttachedToDebugger() const { return m_debug_attached; }
@@ -535,7 +486,7 @@ namespace ams::kern {
MESOSPHERE_UNUSED(core_id);
}
s64 GetCpuTime() const { return m_cpu_time.load(); }
s64 GetCpuTime() const { return m_cpu_time; }
s64 GetCpuTime(s32 core_id) const {
MESOSPHERE_ABORT_UNLESS(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores));
@@ -546,7 +497,7 @@ namespace ams::kern {
constexpr u32 GetSuspendFlags() const { return m_suspend_allowed_flags & m_suspend_request_flags; }
constexpr bool IsSuspended() const { return this->GetSuspendFlags() != 0; }
constexpr bool IsSuspendRequested(SuspendType type) const { return (m_suspend_request_flags & (1u << (util::ToUnderlying(ThreadState_SuspendShift) + util::ToUnderlying(type)))) != 0; }
constexpr bool IsSuspendRequested(SuspendType type) const { return (m_suspend_request_flags & (1u << (ThreadState_SuspendShift + type))) != 0; }
constexpr bool IsSuspendRequested() const { return m_suspend_request_flags != 0; }
void RequestSuspend(SuspendType type);
void Resume(SuspendType type);
@@ -570,7 +521,7 @@ namespace ams::kern {
Result Run();
void Exit();
Result Terminate();
void Terminate();
ThreadState RequestTerminate();
Result Sleep(s64 timeout);
@@ -579,7 +530,7 @@ namespace ams::kern {
ALWAYS_INLINE void *GetKernelStackTop() const { return m_kernel_stack_top; }
ALWAYS_INLINE bool IsTerminationRequested() const {
return m_termination_requested.load() || this->GetRawState() == ThreadState_Terminated;
return m_termination_requested || this->GetRawState() == ThreadState_Terminated;
}
size_t GetKernelStackUsage() const;
@@ -638,14 +589,4 @@ namespace ams::kern {
return GetCurrentThread().GetCurrentCore();
}
ALWAYS_INLINE void KAutoObject::ScheduleDestruction() {
MESOSPHERE_ASSERT_THIS();
/* Set our object to destroy. */
m_next_closed_object = GetCurrentThread().GetClosedObject();
/* Set ourselves as the thread's next object to destroy. */
GetCurrentThread().SetClosedObject(this);
}
}

View File

@@ -105,10 +105,4 @@ namespace ams::kern {
}
};
/* Miscellaneous sanity checking. */
static_assert(ams::svc::ThreadLocalRegionSize == THREAD_LOCAL_REGION_SIZE);
static_assert(__builtin_offsetof(ams::svc::ThreadLocalRegion, message_buffer) == THREAD_LOCAL_REGION_MESSAGE_BUFFER);
static_assert(__builtin_offsetof(ams::svc::ThreadLocalRegion, disable_count) == THREAD_LOCAL_REGION_DISABLE_COUNT);
static_assert(__builtin_offsetof(ams::svc::ThreadLocalRegion, interrupt_flag) == THREAD_LOCAL_REGION_INTERRUPT_FLAG);
}

View File

@@ -23,7 +23,7 @@ namespace ams::kern {
class KTransferMemory final : public KAutoObjectWithSlabHeapAndContainer<KTransferMemory, KAutoObjectWithList> {
MESOSPHERE_AUTOOBJECT_TRAITS(KTransferMemory, KAutoObject);
private:
util::TypedStorage<KPageGroup> m_page_group;
TYPED_STORAGE(KPageGroup) m_page_group;
KProcess *m_owner;
KProcessAddress m_address;
KLightLock m_lock;

View File

@@ -40,10 +40,8 @@ namespace ams::kern {
MESOSPHERE_PANIC(__VA_ARGS__); \
} \
})
#elif defined(MESOSPHERE_PRESERVE_ASSERTION_EXPRESSIONS)
#define MESOSPHERE_ASSERT_IMPL(expr, ...) do { static_cast<void>(expr); } while (0)
#else
#define MESOSPHERE_ASSERT_IMPL(expr, ...) static_cast<void>(0)
#define MESOSPHERE_ASSERT_IMPL(expr, ...) do { static_cast<void>(expr); } while (0)
#endif
#define MESOSPHERE_ASSERT(expr) MESOSPHERE_ASSERT_IMPL(expr, "Assertion failed: %s\n", #expr)
@@ -58,10 +56,8 @@ namespace ams::kern {
#ifdef MESOSPHERE_BUILD_FOR_AUDITING
#define MESOSPHERE_AUDIT(expr) MESOSPHERE_ASSERT(expr)
#elif defined(MESOSPHERE_PRESERVE_AUDIT_EXPRESSIONS)
#define MESOSPHERE_AUDIT(expr) do { static_cast<void>(expr); } while (0)
#else
#define MESOSPHERE_AUDIT(expr) static_cast<void>(0)
#define MESOSPHERE_AUDIT(expr) do { static_cast<void>(expr); } while (0)
#endif
#define MESOSPHERE_TODO(arg) ({ constexpr const char *__mesosphere_todo = arg; static_cast<void>(__mesosphere_todo); MESOSPHERE_PANIC("TODO (%s): %s\n", __PRETTY_FUNCTION__, __mesosphere_todo); })

View File

@@ -1,26 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifdef ATMOSPHERE_ARCH_ARM64
#include <mesosphere/arch/arm64/kern_assembly_offsets.h>
#else
#error "Unknown architecture for CPU"
#endif

View File

@@ -45,21 +45,7 @@
namespace ams::kern {
namespace cpu {
static constexpr inline size_t NumVirtualCores = BITSIZEOF(u64);
static constexpr inline u64 VirtualCoreMask = [] {
u64 mask = 0;
for (size_t i = 0; i < NumVirtualCores; ++i) {
mask |= (UINT64_C(1) << i);
}
return mask;
}();
}
static_assert(cpu::NumCores <= cpu::NumVirtualCores);
static_assert(util::size(cpu::VirtualToPhysicalCoreMap) == cpu::NumVirtualCores);
static_assert(cpu::NumCores <= static_cast<s32>(BITSIZEOF(u64)));
static_assert(util::size(cpu::VirtualToPhysicalCoreMap) == BITSIZEOF(u64));
}

View File

@@ -54,12 +54,12 @@ namespace ams::kern::svc {
public:
using T = typename std::remove_const<typename std::remove_pointer<_T>::type>::type;
public:
static ALWAYS_INLINE Result CopyFromUserspace(void *dst, const void *src, size_t size) {
static Result CopyFromUserspace(void *dst, const void *src, size_t size) {
R_UNLESS(UserspaceAccess::CopyMemoryFromUser(dst, src, size), svc::ResultInvalidPointer());
return ResultSuccess();
}
static ALWAYS_INLINE Result CopyToUserspace(void *dst, const void *src, size_t size) {
static Result CopyToUserspace(void *dst, const void *src, size_t size) {
R_UNLESS(UserspaceAccess::CopyMemoryToUser(dst, src, size), svc::ResultInvalidPointer());
return ResultSuccess();
}
@@ -70,12 +70,12 @@ namespace ams::kern::svc {
public:
using T = typename std::remove_const<typename std::remove_pointer<_T>::type>::type;
public:
static ALWAYS_INLINE Result CopyFromUserspace(void *dst, const void *src, size_t size) {
static Result CopyFromUserspace(void *dst, const void *src, size_t size) {
R_UNLESS(UserspaceAccess::CopyMemoryFromUserAligned32Bit(dst, src, size), svc::ResultInvalidPointer());
return ResultSuccess();
}
static ALWAYS_INLINE Result CopyToUserspace(void *dst, const void *src, size_t size) {
static Result CopyToUserspace(void *dst, const void *src, size_t size) {
R_UNLESS(UserspaceAccess::CopyMemoryToUserAligned32Bit(dst, src, size), svc::ResultInvalidPointer());
return ResultSuccess();
}
@@ -86,12 +86,12 @@ namespace ams::kern::svc {
public:
using T = typename std::remove_const<typename std::remove_pointer<_T>::type>::type;
public:
static ALWAYS_INLINE Result CopyFromUserspace(void *dst, const void *src, size_t size) {
static Result CopyFromUserspace(void *dst, const void *src, size_t size) {
R_UNLESS(UserspaceAccess::CopyMemoryFromUserAligned64Bit(dst, src, size), svc::ResultInvalidPointer());
return ResultSuccess();
}
static ALWAYS_INLINE Result CopyToUserspace(void *dst, const void *src, size_t size) {
static Result CopyToUserspace(void *dst, const void *src, size_t size) {
R_UNLESS(UserspaceAccess::CopyMemoryToUserAligned64Bit(dst, src, size), svc::ResultInvalidPointer());
return ResultSuccess();
}
@@ -110,26 +110,26 @@ namespace ams::kern::svc {
private:
CT *m_ptr;
private:
ALWAYS_INLINE Result CopyToImpl(void *p, size_t size) const {
Result CopyToImpl(void *p, size_t size) const {
return Traits::CopyFromUserspace(p, m_ptr, size);
}
ALWAYS_INLINE Result CopyFromImpl(const void *p, size_t size) const {
Result CopyFromImpl(const void *p, size_t size) const {
return Traits::CopyToUserspace(m_ptr, p, size);
}
protected:
ALWAYS_INLINE Result CopyTo(T *p) const { return this->CopyToImpl(p, sizeof(*p)); }
ALWAYS_INLINE Result CopyFrom(const T *p) const { return this->CopyFromImpl(p, sizeof(*p)); }
Result CopyTo(T *p) const { return this->CopyToImpl(p, sizeof(*p)); }
Result CopyFrom(const T *p) const { return this->CopyFromImpl(p, sizeof(*p)); }
ALWAYS_INLINE Result CopyArrayElementTo(T *p, size_t index) const { return Traits::CopyFromUserspace(p, m_ptr + index, sizeof(*p)); }
ALWAYS_INLINE Result CopyArrayElementFrom(const T *p, size_t index) const { return Traits::CopyToUserspace(m_ptr + index, p, sizeof(*p)); }
Result CopyArrayElementTo(T *p, size_t index) const { return Traits::CopyFromUserspace(p, m_ptr + index, sizeof(*p)); }
Result CopyArrayElementFrom(const T *p, size_t index) const { return Traits::CopyToUserspace(m_ptr + index, p, sizeof(*p)); }
ALWAYS_INLINE Result CopyArrayTo(T *arr, size_t count) const { return this->CopyToImpl(arr, sizeof(*arr) * count); }
ALWAYS_INLINE Result CopyArrayFrom(const T *arr, size_t count) const { return this->CopyFromImpl(arr, sizeof(*arr) * count); }
Result CopyArrayTo(T *arr, size_t count) const { return this->CopyToImpl(arr, sizeof(*arr) * count); }
Result CopyArrayFrom(const T *arr, size_t count) const { return this->CopyFromImpl(arr, sizeof(*arr) * count); }
constexpr ALWAYS_INLINE bool IsNull() const { return m_ptr == nullptr; }
constexpr bool IsNull() const { return m_ptr == nullptr; }
constexpr ALWAYS_INLINE CT *GetUnsafePointer() const { return m_ptr; }
constexpr CT *GetUnsafePointer() const { return m_ptr; }
};
template<>
@@ -142,19 +142,19 @@ namespace ams::kern::svc {
private:
const char *ptr;
protected:
ALWAYS_INLINE Result CopyStringTo(char *dst, size_t size) const {
Result CopyStringTo(char *dst, size_t size) const {
static_assert(sizeof(char) == 1);
R_UNLESS(UserspaceAccess::CopyStringFromUser(dst, this->ptr, size) > 0, svc::ResultInvalidPointer());
return ResultSuccess();
}
ALWAYS_INLINE Result CopyArrayElementTo(char *dst, size_t index) const {
Result CopyArrayElementTo(char *dst, size_t index) const {
return Traits::CopyFromUserspace(dst, this->ptr + index, sizeof(*dst));
}
constexpr ALWAYS_INLINE bool IsNull() const { return this->ptr == nullptr; }
constexpr bool IsNull() const { return this->ptr == nullptr; }
constexpr ALWAYS_INLINE const char *GetUnsafePointer() const { return this->ptr; }
constexpr const char *GetUnsafePointer() const { return this->ptr; }
};
}

View File

@@ -20,7 +20,7 @@
namespace ams::kern::svc {
static constexpr size_t NumSupervisorCalls = AMS_KERN_NUM_SUPERVISOR_CALLS;
static constexpr size_t NumSupervisorCalls = 0x80;
#define AMS_KERN_SVC_DECLARE_ENUM_ID(ID, RETURN_TYPE, NAME, ...) \
SvcId_##NAME = ID,

View File

@@ -109,7 +109,7 @@ namespace ams::kern::arch::arm64::cpu {
/* Wait for a request to come in. */
{
KScopedLightLock lk(m_cv_lock);
while ((m_target_cores.load() & (1ul << core_id)) == 0) {
while ((m_target_cores & (1ul << core_id)) == 0) {
m_cv.Wait(std::addressof(m_cv_lock));
}
}
@@ -120,7 +120,7 @@ namespace ams::kern::arch::arm64::cpu {
/* Broadcast, if there's nothing pending. */
{
KScopedLightLock lk(m_cv_lock);
if (m_target_cores.load() == 0) {
if (m_target_cores == 0) {
m_cv.Broadcast();
}
}
@@ -163,7 +163,7 @@ namespace ams::kern::arch::arm64::cpu {
if ((op == Operation::InstructionMemoryBarrier) || (Kernel::GetState() == Kernel::State::Initializing)) {
/* Check that there's no on-going operation. */
MESOSPHERE_ABORT_UNLESS(m_operation == Operation::Idle);
MESOSPHERE_ABORT_UNLESS(m_target_cores.load() == 0);
MESOSPHERE_ABORT_UNLESS(m_target_cores == 0);
/* Set operation. */
m_operation = op;
@@ -171,13 +171,12 @@ namespace ams::kern::arch::arm64::cpu {
/* For certain operations, we want to send an interrupt. */
m_target_cores = other_cores_mask;
const u64 target_mask = m_target_cores.load();
const u64 target_mask = m_target_cores;
DataSynchronizationBarrier();
Kernel::GetInterruptManager().SendInterProcessorInterrupt(KInterruptName_CacheOperation, target_mask);
this->ProcessOperation();
while (m_target_cores.load() != 0) {
while (m_target_cores != 0) {
cpu::Yield();
}
@@ -189,7 +188,7 @@ namespace ams::kern::arch::arm64::cpu {
/* Check that there's no on-going operation. */
MESOSPHERE_ABORT_UNLESS(m_operation == Operation::Idle);
MESOSPHERE_ABORT_UNLESS(m_target_cores.load() == 0);
MESOSPHERE_ABORT_UNLESS(m_target_cores == 0);
/* Set operation. */
m_operation = op;
@@ -199,7 +198,7 @@ namespace ams::kern::arch::arm64::cpu {
/* Use the condvar. */
m_cv.Broadcast();
while (m_target_cores.load() != 0) {
while (m_target_cores != 0) {
m_cv.Wait(std::addressof(m_cv_lock));
}
@@ -283,16 +282,6 @@ namespace ams::kern::arch::arm64::cpu {
}
}
void StoreDataCacheBySetWay(int level) {
PerformCacheOperationBySetWayImpl<false>(level, StoreDataCacheLineBySetWayImpl);
cpu::DataSynchronizationBarrier();
}
void FlushDataCacheBySetWay(int level) {
PerformCacheOperationBySetWayImpl<false>(level, FlushDataCacheLineBySetWayImpl);
cpu::DataSynchronizationBarrier();
}
void KCacheHelperInterruptHandler::ProcessOperation() {
switch (m_operation) {
case Operation::Idle:
@@ -301,10 +290,12 @@ namespace ams::kern::arch::arm64::cpu {
InstructionMemoryBarrier();
break;
case Operation::StoreDataCache:
StoreDataCacheBySetWay(0);
PerformCacheOperationBySetWayLocal<false>(StoreDataCacheLineBySetWayImpl);
DataSynchronizationBarrier();
break;
case Operation::FlushDataCache:
FlushDataCacheBySetWay(0);
PerformCacheOperationBySetWayLocal<false>(FlushDataCacheLineBySetWayImpl);
DataSynchronizationBarrier();
break;
}
@@ -382,20 +373,7 @@ namespace ams::kern::arch::arm64::cpu {
}
void FlushEntireDataCache() {
KScopedCoreMigrationDisable dm;
CacheLineIdRegisterAccessor clidr_el1;
const int levels_of_coherency = clidr_el1.GetLevelsOfCoherency();
/* Store cache from L2 up to the level of coherence (if there's an L3 cache or greater). */
for (int level = 2; level < levels_of_coherency; ++level) {
StoreDataCacheBySetWay(level - 1);
}
/* Flush cache from the level of coherence down to L2. */
for (int level = levels_of_coherency; level > 1; --level) {
FlushDataCacheBySetWay(level - 1);
}
return PerformCacheOperationBySetWayShared<false>(FlushDataCacheLineBySetWayImpl);
}
Result InvalidateDataCache(void *addr, size_t size) {

View File

@@ -521,11 +521,6 @@ namespace ams::kern::arch::arm64 {
{
KScopedInterruptEnable ei;
/* Terminate the thread, if we should. */
if (GetCurrentThread().IsTerminationRequested()) {
GetCurrentThread().Exit();
}
HandleUserException(context, esr, far, afsr0, afsr1, data);
}
} else {

View File

@@ -208,8 +208,6 @@ namespace ams::kern::arch::arm64 {
}
Result KInterruptManager::BindHandler(KInterruptHandler *handler, s32 irq, s32 core_id, s32 priority, bool manual_clear, bool level) {
MESOSPHERE_UNUSED(core_id);
R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange());
KScopedInterruptDisable di;
@@ -224,8 +222,6 @@ namespace ams::kern::arch::arm64 {
}
Result KInterruptManager::UnbindHandler(s32 irq, s32 core_id) {
MESOSPHERE_UNUSED(core_id);
R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange());
KScopedInterruptDisable di;
@@ -239,9 +235,15 @@ namespace ams::kern::arch::arm64 {
}
}
Result KInterruptManager::ClearInterrupt(s32 irq, s32 core_id) {
MESOSPHERE_UNUSED(core_id);
Result KInterruptManager::ClearInterrupt(s32 irq) {
R_UNLESS(KInterruptController::IsGlobal(irq), svc::ResultOutOfRange());
KScopedInterruptDisable di;
KScopedSpinLock lk(this->GetGlobalInterruptLock());
return this->ClearGlobal(irq);
}
Result KInterruptManager::ClearInterrupt(s32 irq, s32 core_id) {
R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange());
KScopedInterruptDisable di;

View File

@@ -181,7 +181,7 @@ namespace ams::kern::arch::arm64 {
return ResultSuccess();
}
Result KPageTable::InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit) {
Result KPageTable::InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager) {
/* The input ID isn't actually used. */
MESOSPHERE_UNUSED(id);
@@ -202,7 +202,7 @@ namespace ams::kern::arch::arm64 {
const size_t as_width = GetAddressSpaceWidth(as_type);
const KProcessAddress as_start = 0;
const KProcessAddress as_end = (1ul << as_width);
R_TRY(KPageTableBase::InitializeForProcess(as_type, enable_aslr, enable_das_merge, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, mem_block_slab_manager, block_info_manager, resource_limit));
R_TRY(KPageTableBase::InitializeForProcess(as_type, enable_aslr, enable_das_merge, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, mem_block_slab_manager, block_info_manager));
/* We succeeded! */
table_guard.Cancel();
@@ -556,13 +556,13 @@ namespace ams::kern::arch::arm64 {
/* If we're not forcing an unmap, separate pages immediately. */
if (!force) {
const size_t size = num_pages * PageSize;
R_TRY(this->SeparatePages(virt_addr, std::min(util::GetAlignment(GetInteger(virt_addr)), size), page_list, reuse_ll));
R_TRY(this->SeparatePages(virt_addr, std::min(GetInteger(virt_addr) & -GetInteger(virt_addr), size), page_list, reuse_ll));
if (num_pages > 1) {
const auto end_page = virt_addr + size;
const auto last_page = end_page - PageSize;
auto merge_guard = SCOPE_GUARD { this->MergePages(virt_addr, page_list); };
R_TRY(this->SeparatePages(last_page, std::min(util::GetAlignment(GetInteger(end_page)), size), page_list, reuse_ll));
R_TRY(this->SeparatePages(last_page, std::min(GetInteger(end_page) & -GetInteger(end_page), size), page_list, reuse_ll));
merge_guard.Cancel();
}
}
@@ -1194,13 +1194,13 @@ namespace ams::kern::arch::arm64 {
/* Separate pages before we change permissions. */
const size_t size = num_pages * PageSize;
R_TRY(this->SeparatePages(virt_addr, std::min(util::GetAlignment(GetInteger(virt_addr)), size), page_list, reuse_ll));
R_TRY(this->SeparatePages(virt_addr, std::min(GetInteger(virt_addr) & -GetInteger(virt_addr), size), page_list, reuse_ll));
if (num_pages > 1) {
const auto end_page = virt_addr + size;
const auto last_page = end_page - PageSize;
auto merge_guard = SCOPE_GUARD { this->MergePages(virt_addr, page_list); };
R_TRY(this->SeparatePages(last_page, std::min(util::GetAlignment(GetInteger(end_page)), size), page_list, reuse_ll));
R_TRY(this->SeparatePages(last_page, std::min(GetInteger(end_page) & -GetInteger(end_page), size), page_list, reuse_ll));
merge_guard.Cancel();
}

View File

@@ -14,7 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere/kern_build_config.hpp>
#include <mesosphere/kern_select_assembly_offsets.h>
#if defined(MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP)
@@ -33,28 +32,28 @@
\
/* Save x0/x1/sp to the context. */ \
ldr x1, [sp, #(8 * 0)]; \
str x1, [x0, #(EXCEPTION_CONTEXT_X0)]; \
str x1, [x0, #(8 * 0)]; \
ldr x1, [sp, #(8 * 1)]; \
str x1, [x0, #(EXCEPTION_CONTEXT_X1)]; \
str x1, [x0, #(8 * 1)]; \
\
/* Save all other registers to the context. */ \
stp x2, x3, [x0, #(EXCEPTION_CONTEXT_X2_X3)]; \
stp x4, x5, [x0, #(EXCEPTION_CONTEXT_X4_X5)]; \
stp x6, x7, [x0, #(EXCEPTION_CONTEXT_X6_X7)]; \
stp x8, x9, [x0, #(EXCEPTION_CONTEXT_X8_X9)]; \
stp x10, x11, [x0, #(EXCEPTION_CONTEXT_X10_X11)]; \
stp x12, x13, [x0, #(EXCEPTION_CONTEXT_X12_X13)]; \
stp x14, x15, [x0, #(EXCEPTION_CONTEXT_X14_X15)]; \
stp x16, x17, [x0, #(EXCEPTION_CONTEXT_X16_X17)]; \
stp x18, x19, [x0, #(EXCEPTION_CONTEXT_X18_X19)]; \
stp x20, x21, [x0, #(EXCEPTION_CONTEXT_X20_X21)]; \
stp x22, x23, [x0, #(EXCEPTION_CONTEXT_X22_X23)]; \
stp x24, x25, [x0, #(EXCEPTION_CONTEXT_X24_X25)]; \
stp x26, x27, [x0, #(EXCEPTION_CONTEXT_X26_X27)]; \
stp x28, x29, [x0, #(EXCEPTION_CONTEXT_X28_X29)]; \
stp x2, x3, [x0, #(8 * 2)]; \
stp x4, x5, [x0, #(8 * 4)]; \
stp x6, x7, [x0, #(8 * 6)]; \
stp x8, x9, [x0, #(8 * 8)]; \
stp x10, x11, [x0, #(8 * 10)]; \
stp x12, x13, [x0, #(8 * 12)]; \
stp x14, x15, [x0, #(8 * 14)]; \
stp x16, x17, [x0, #(8 * 16)]; \
stp x18, x19, [x0, #(8 * 18)]; \
stp x20, x21, [x0, #(8 * 20)]; \
stp x22, x23, [x0, #(8 * 22)]; \
stp x24, x25, [x0, #(8 * 24)]; \
stp x26, x27, [x0, #(8 * 26)]; \
stp x28, x29, [x0, #(8 * 28)]; \
\
add x1, sp, #16; \
stp x30, x1, [x0, #(EXCEPTION_CONTEXT_X30_SP)]; \
stp x30, x1, [x0, #(8 * 30)]; \
\
/* Restore x0/x1. */ \
ldp x0, x1, [sp], #16;

View File

@@ -758,6 +758,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory32BitEPvPKvm:
mov x8, x30
1: /* Read the word from normal memory. */
mov x30, x8
ldtr w9, [x5]
/* Set our return address so that on read failure we continue. */
@@ -768,7 +769,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory32BitEPvPKvm:
dsb sy
2: /* Continue. */
mov x30, x8
nop
/* Advance. */
add x4, x4, #4
@@ -800,6 +801,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory16BitEPvPKvm:
mov x8, x30
1: /* Read the word from normal memory. */
mov x30, x8
ldtrh w9, [x5]
/* Set our return address so that on read failure we continue. */
@@ -810,7 +812,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory16BitEPvPKvm:
dsb sy
2: /* Continue. */
mov x30, x8
nop
/* Advance. */
add x4, x4, #2
@@ -842,6 +844,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17WriteIoMemory8BitEPvPKvm:
mov x8, x30
1: /* Read the word from normal memory. */
mov x30, x8
ldtrb w9, [x5]
/* Set our return address so that on read failure we continue. */
@@ -852,7 +855,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17WriteIoMemory8BitEPvPKvm:
dsb sy
2: /* Continue. */
mov x30, x8
nop
/* Advance. */
add x4, x4, #1

View File

@@ -13,7 +13,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere/kern_select_assembly_offsets.h>
/* ams::kern::svc::CallReturnFromException64(Result result) */
.section .text._ZN3ams4kern3svc25CallReturnFromException64Ev, "ax", %progbits
@@ -21,15 +20,15 @@
.type _ZN3ams4kern3svc25CallReturnFromException64Ev, %function
_ZN3ams4kern3svc25CallReturnFromException64Ev:
/* Save registers the SVC entry handler didn't. */
stp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
stp x14, x15, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
stp x16, x17, [sp, #(EXCEPTION_CONTEXT_X16_X17)]
str x19, [sp, #(EXCEPTION_CONTEXT_X19)]
stp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)]
stp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)]
stp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)]
stp x26, x26, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
stp x12, x13, [sp, #(8 * 12)]
stp x14, x15, [sp, #(8 * 14)]
stp x16, x17, [sp, #(8 * 16)]
str x19, [sp, #(8 * 19)]
stp x20, x21, [sp, #(8 * 20)]
stp x22, x23, [sp, #(8 * 22)]
stp x24, x25, [sp, #(8 * 24)]
stp x26, x26, [sp, #(8 * 26)]
stp x28, x29, [sp, #(8 * 28)]
/* Call ams::kern::arch::arm64::ReturnFromException(result). */
bl _ZN3ams4kern4arch5arm6419ReturnFromExceptionENS_6ResultE
@@ -63,7 +62,7 @@ _ZN3ams4kern3svc14RestoreContextEm:
0: /* We should handle DPC. */
/* Check the dpc flags. */
ldrb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_DPC_FLAGS)]
ldrb w8, [sp, #(0x120 + 0x10)]
cbz w8, 1f
/* We have DPC to do! */
@@ -83,32 +82,32 @@ _ZN3ams4kern3svc14RestoreContextEm:
1: /* We're done with DPC, and should return from the svc. */
/* Clear our in-SVC note. */
strb wzr, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_CALLING_SVC)]
strb wzr, [sp, #(0x120 + 0x12)]
/* Restore registers. */
ldp x30, x8, [sp, #(EXCEPTION_CONTEXT_X30_SP)]
ldp x9, x10, [sp, #(EXCEPTION_CONTEXT_PC_PSR)]
ldr x11, [sp, #(EXCEPTION_CONTEXT_TPIDR)]
ldp x30, x8, [sp, #(8 * 30)]
ldp x9, x10, [sp, #(8 * 32)]
ldr x11, [sp, #(8 * 34)]
msr sp_el0, x8
msr elr_el1, x9
msr spsr_el1, x10
msr tpidr_el0, x11
ldp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
ldp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
ldp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
ldp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
ldp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)]
ldp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)]
ldp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
ldp x14, x15, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
ldp x16, x17, [sp, #(EXCEPTION_CONTEXT_X16_X17)]
ldp x18, x19, [sp, #(EXCEPTION_CONTEXT_X18_X19)]
ldp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)]
ldp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)]
ldp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)]
ldp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
ldp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
ldp x0, x1, [sp, #(8 * 0)]
ldp x2, x3, [sp, #(8 * 2)]
ldp x4, x5, [sp, #(8 * 4)]
ldp x6, x7, [sp, #(8 * 6)]
ldp x8, x9, [sp, #(8 * 8)]
ldp x10, x11, [sp, #(8 * 10)]
ldp x12, x13, [sp, #(8 * 12)]
ldp x14, x15, [sp, #(8 * 14)]
ldp x16, x17, [sp, #(8 * 16)]
ldp x18, x19, [sp, #(8 * 18)]
ldp x20, x21, [sp, #(8 * 20)]
ldp x22, x23, [sp, #(8 * 22)]
ldp x24, x25, [sp, #(8 * 24)]
ldp x26, x27, [sp, #(8 * 26)]
ldp x28, x29, [sp, #(8 * 28)]
/* Return. */
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
add sp, sp, #0x120
eret

View File

@@ -14,7 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere/kern_build_config.hpp>
#include <mesosphere/kern_select_assembly_offsets.h>
/* ams::kern::arch::arm64::SvcHandler64() */
.section .text._ZN3ams4kern4arch5arm6412SvcHandler64Ev, "ax", %progbits
@@ -22,45 +21,45 @@
.type _ZN3ams4kern4arch5arm6412SvcHandler64Ev, %function
_ZN3ams4kern4arch5arm6412SvcHandler64Ev:
/* Create a KExceptionContext for the exception. */
sub sp, sp, #(EXCEPTION_CONTEXT_SIZE)
sub sp, sp, #0x120
/* Save registers needed for ReturnFromException */
stp x9, x10, [sp, #(EXCEPTION_CONTEXT_X9_X10)]
str x11, [sp, #(EXCEPTION_CONTEXT_X11)]
str x18, [sp, #(EXCEPTION_CONTEXT_X18)]
stp x9, x10, [sp, #(8 * 9)]
str x11, [sp, #(8 * 11)]
str x18, [sp, #(8 * 18)]
mrs x8, sp_el0
mrs x9, elr_el1
mrs x10, spsr_el1
mrs x11, tpidr_el0
ldr x18, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CUR_THREAD)]
ldr x18, [sp, #(0x120 + 0x28)]
/* Save callee-saved registers. */
stp x19, x20, [sp, #(EXCEPTION_CONTEXT_X19_X20)]
stp x21, x22, [sp, #(EXCEPTION_CONTEXT_X21_X22)]
stp x23, x24, [sp, #(EXCEPTION_CONTEXT_X23_X24)]
stp x25, x26, [sp, #(EXCEPTION_CONTEXT_X25_X26)]
stp x27, x28, [sp, #(EXCEPTION_CONTEXT_X27_X28)]
stp x19, x20, [sp, #(8 * 19)]
stp x21, x22, [sp, #(8 * 21)]
stp x23, x24, [sp, #(8 * 23)]
stp x25, x26, [sp, #(8 * 25)]
stp x27, x28, [sp, #(8 * 27)]
/* Save miscellaneous registers. */
stp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
stp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
stp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
stp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
stp x29, x30, [sp, #(EXCEPTION_CONTEXT_X29_X30)]
stp x8, x9, [sp, #(EXCEPTION_CONTEXT_SP_PC)]
stp x10, x11, [sp, #(EXCEPTION_CONTEXT_PSR_TPIDR)]
stp x0, x1, [sp, #(8 * 0)]
stp x2, x3, [sp, #(8 * 2)]
stp x4, x5, [sp, #(8 * 4)]
stp x6, x7, [sp, #(8 * 6)]
stp x29, x30, [sp, #(8 * 29)]
stp x8, x9, [sp, #(8 * 31)]
stp x10, x11, [sp, #(8 * 33)]
/* Check if the SVC index is out of range. */
mrs x8, esr_el1
and x8, x8, #0xFF
cmp x8, #(AMS_KERN_NUM_SUPERVISOR_CALLS)
cmp x8, #0x80
b.ge 3f
/* Check the specific SVC permission bit for allowal. */
mov x9, sp
add x9, x9, x8, lsr#3
ldrb w9, [x9, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_SVC_PERMISSION)]
ldrb w9, [x9, #0x120]
and x10, x8, #0x7
lsr x10, x9, x10
tst x10, #1
@@ -68,11 +67,11 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
/* Check if our disable count allows us to call SVCs. */
mrs x10, tpidrro_el0
ldrh w10, [x10, #(THREAD_LOCAL_REGION_DISABLE_COUNT)]
ldrh w10, [x10, #0x100]
cbz w10, 1f
/* It might not, so check the stack params to see if we must not allow the SVC. */
ldrb w10, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_PINNED)]
ldrb w10, [sp, #(0x120 + 0x14)]
cbz w10, 3f
1: /* We can call the SVC. */
@@ -82,8 +81,8 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
/* Note that we're calling the SVC. */
mov w10, #1
strb w10, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_CALLING_SVC)]
strb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CURRENT_SVC_ID)]
strb w10, [sp, #(0x120 + 0x12)]
strb w8, [sp, #(0x120 + 0x11)]
/* If we should, trace the svc entry. */
#if defined(MESOSPHERE_BUILD_FOR_TRACING)
@@ -110,7 +109,7 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
2: /* We completed the SVC, and we should handle DPC. */
/* Check the dpc flags. */
ldrb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_DPC_FLAGS)]
ldrb w8, [sp, #(0x120 + 0x10)]
cbz w8, 4f
/* We have DPC to do! */
@@ -130,57 +129,57 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
3: /* Invalid SVC. */
/* Setup the context to call into HandleException. */
stp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
stp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
stp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
stp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X8_X9)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X10_X11)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X16_X17)]
str x19, [sp, #(EXCEPTION_CONTEXT_X19)]
stp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)]
stp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)]
stp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)]
stp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
stp x0, x1, [sp, #(8 * 0)]
stp x2, x3, [sp, #(8 * 2)]
stp x4, x5, [sp, #(8 * 4)]
stp x6, x7, [sp, #(8 * 6)]
stp xzr, xzr, [sp, #(8 * 8)]
stp xzr, xzr, [sp, #(8 * 10)]
stp xzr, xzr, [sp, #(8 * 12)]
stp xzr, xzr, [sp, #(8 * 14)]
stp xzr, xzr, [sp, #(8 * 16)]
str x19, [sp, #(8 * 19)]
stp x20, x21, [sp, #(8 * 20)]
stp x22, x23, [sp, #(8 * 22)]
stp x24, x25, [sp, #(8 * 24)]
stp x26, x27, [sp, #(8 * 26)]
stp x28, x29, [sp, #(8 * 28)]
/* Call ams::kern::arch::arm64::HandleException(ams::kern::arch::arm64::KExceptionContext *) */
mov x0, sp
bl _ZN3ams4kern4arch5arm6415HandleExceptionEPNS2_17KExceptionContextE
/* Restore registers. */
ldp x30, x8, [sp, #(EXCEPTION_CONTEXT_X30_SP)]
ldp x9, x10, [sp, #(EXCEPTION_CONTEXT_PC_PSR)]
ldr x11, [sp, #(EXCEPTION_CONTEXT_TPIDR)]
ldp x30, x8, [sp, #(8 * 30)]
ldp x9, x10, [sp, #(8 * 32)]
ldr x11, [sp, #(8 * 34)]
msr sp_el0, x8
msr elr_el1, x9
msr spsr_el1, x10
msr tpidr_el0, x11
ldp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
ldp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
ldp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
ldp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
ldp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)]
ldp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)]
ldp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
ldp x14, x15, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
ldp x16, x17, [sp, #(EXCEPTION_CONTEXT_X16_X17)]
ldp x18, x19, [sp, #(EXCEPTION_CONTEXT_X18_X19)]
ldp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)]
ldp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)]
ldp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)]
ldp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
ldp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
ldp x0, x1, [sp, #(8 * 0)]
ldp x2, x3, [sp, #(8 * 2)]
ldp x4, x5, [sp, #(8 * 4)]
ldp x6, x7, [sp, #(8 * 6)]
ldp x8, x9, [sp, #(8 * 8)]
ldp x10, x11, [sp, #(8 * 10)]
ldp x12, x13, [sp, #(8 * 12)]
ldp x14, x15, [sp, #(8 * 14)]
ldp x16, x17, [sp, #(8 * 16)]
ldp x18, x19, [sp, #(8 * 18)]
ldp x20, x21, [sp, #(8 * 20)]
ldp x22, x23, [sp, #(8 * 22)]
ldp x24, x25, [sp, #(8 * 24)]
ldp x26, x27, [sp, #(8 * 26)]
ldp x28, x29, [sp, #(8 * 28)]
/* Return. */
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
add sp, sp, #0x120
eret
4: /* Return from SVC. */
/* Clear our in-SVC note. */
strb wzr, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_CALLING_SVC)]
strb wzr, [sp, #(0x120 + 0x12)]
/* If we should, trace the svc exit. */
#if defined(MESOSPHERE_BUILD_FOR_TRACING)
@@ -199,10 +198,10 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
#endif
/* Restore registers. */
ldp x30, x8, [sp, #(EXCEPTION_CONTEXT_X30_SP)]
ldp x9, x10, [sp, #(EXCEPTION_CONTEXT_PC_PSR)]
ldr x11, [sp, #(EXCEPTION_CONTEXT_TPIDR)]
ldr x18, [sp, #(EXCEPTION_CONTEXT_X18)]
ldp x30, x8, [sp, #(8 * 30)]
ldp x9, x10, [sp, #(8 * 32)]
ldr x11, [sp, #(8 * 34)]
ldr x18, [sp, #(8 * 18)]
msr sp_el0, x8
msr elr_el1, x9
msr spsr_el1, x10
@@ -221,7 +220,7 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
mov x17, xzr
/* Return. */
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
add sp, sp, #0x120
eret
/* ams::kern::arch::arm64::SvcHandler32() */
@@ -240,36 +239,36 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
mov w7, w7
/* Create a KExceptionContext for the exception. */
sub sp, sp, #(EXCEPTION_CONTEXT_SIZE)
sub sp, sp, #0x120
/* Save system registers */
mrs x17, elr_el1
mrs x20, spsr_el1
mrs x19, tpidr_el0
ldr x18, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CUR_THREAD)]
stp x17, x20, [sp, #(EXCEPTION_CONTEXT_PC_PSR)]
str x19, [sp, #(EXCEPTION_CONTEXT_TPIDR)]
ldr x18, [sp, #(0x120 + 0x28)]
stp x17, x20, [sp, #(8 * 32)]
str x19, [sp, #(8 * 34)]
/* Save registers. */
stp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
stp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
stp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
stp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
stp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)]
stp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)]
stp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
stp x14, xzr, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
stp x0, x1, [sp, #(8 * 0)]
stp x2, x3, [sp, #(8 * 2)]
stp x4, x5, [sp, #(8 * 4)]
stp x6, x7, [sp, #(8 * 6)]
stp x8, x9, [sp, #(8 * 8)]
stp x10, x11, [sp, #(8 * 10)]
stp x12, x13, [sp, #(8 * 12)]
stp x14, xzr, [sp, #(8 * 14)]
/* Check if the SVC index is out of range. */
mrs x16, esr_el1
and x16, x16, #0xFF
cmp x16, #(AMS_KERN_NUM_SUPERVISOR_CALLS)
cmp x16, #0x80
b.ge 3f
/* Check the specific SVC permission bit for allowal. */
mov x20, sp
add x20, x20, x16, lsr#3
ldrb w20, [x20, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_SVC_PERMISSION)]
ldrb w20, [x20, #0x120]
and x17, x16, #0x7
lsr x17, x20, x17
tst x17, #1
@@ -277,11 +276,11 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
/* Check if our disable count allows us to call SVCs. */
mrs x15, tpidrro_el0
ldrh w15, [x15, #(THREAD_LOCAL_REGION_DISABLE_COUNT)]
ldrh w15, [x15, #0x100]
cbz w15, 1f
/* It might not, so check the stack params to see if we must not allow the SVC. */
ldrb w15, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_PINNED)]
ldrb w15, [sp, #(0x120 + 0x14)]
cbz w15, 3f
1: /* We can call the SVC. */
@@ -291,8 +290,8 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
/* Note that we're calling the SVC. */
mov w15, #1
strb w15, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_CALLING_SVC)]
strb w16, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CURRENT_SVC_ID)]
strb w15, [sp, #(0x120 + 0x12)]
strb w16, [sp, #(0x120 + 0x11)]
/* If we should, trace the svc entry. */
#if defined(MESOSPHERE_BUILD_FOR_TRACING)
@@ -319,7 +318,7 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
2: /* We completed the SVC, and we should handle DPC. */
/* Check the dpc flags. */
ldrb w16, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_DPC_FLAGS)]
ldrb w16, [sp, #(0x120 + 0x10)]
cbz w16, 4f
/* We have DPC to do! */
@@ -339,45 +338,45 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
3: /* Invalid SVC. */
/* Setup the context to call into HandleException. */
stp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
stp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
stp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
stp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X16_X17)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X18_X19)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X20_X21)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X22_X23)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X24_X25)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X30_SP)]
stp x0, x1, [sp, #(8 * 0)]
stp x2, x3, [sp, #(8 * 2)]
stp x4, x5, [sp, #(8 * 4)]
stp x6, x7, [sp, #(8 * 6)]
stp xzr, xzr, [sp, #(8 * 16)]
stp xzr, xzr, [sp, #(8 * 18)]
stp xzr, xzr, [sp, #(8 * 20)]
stp xzr, xzr, [sp, #(8 * 22)]
stp xzr, xzr, [sp, #(8 * 24)]
stp xzr, xzr, [sp, #(8 * 26)]
stp xzr, xzr, [sp, #(8 * 28)]
stp xzr, xzr, [sp, #(8 * 30)]
/* Call ams::kern::arch::arm64::HandleException(ams::kern::arch::arm64::KExceptionContext *) */
mov x0, sp
bl _ZN3ams4kern4arch5arm6415HandleExceptionEPNS2_17KExceptionContextE
/* Restore registers. */
ldp x17, x20, [sp, #(EXCEPTION_CONTEXT_PC_PSR)]
ldr x19, [sp, #(EXCEPTION_CONTEXT_TPIDR)]
ldp x17, x20, [sp, #(8 * 32)]
ldr x19, [sp, #(8 * 34)]
msr elr_el1, x17
msr spsr_el1, x20
msr tpidr_el0, x19
ldp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)]
ldp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)]
ldp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)]
ldp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)]
ldp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)]
ldp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)]
ldp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
ldp x14, x15, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
ldp x0, x1, [sp, #(8 * 0)]
ldp x2, x3, [sp, #(8 * 2)]
ldp x4, x5, [sp, #(8 * 4)]
ldp x6, x7, [sp, #(8 * 6)]
ldp x8, x9, [sp, #(8 * 8)]
ldp x10, x11, [sp, #(8 * 10)]
ldp x12, x13, [sp, #(8 * 12)]
ldp x14, x15, [sp, #(8 * 14)]
/* Return. */
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
add sp, sp, #0x120
eret
4: /* Return from SVC. */
/* Clear our in-SVC note. */
strb wzr, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_CALLING_SVC)]
strb wzr, [sp, #(0x120 + 0x12)]
/* If we should, trace the svc exit. */
#if defined(MESOSPHERE_BUILD_FOR_TRACING)
@@ -396,16 +395,16 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
#endif
/* Restore registers. */
ldp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)]
ldp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)]
ldp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)]
ldp x14, xzr, [sp, #(EXCEPTION_CONTEXT_X14_X15)]
ldp x17, x20, [sp, #(EXCEPTION_CONTEXT_PC_PSR)]
ldr x19, [sp, #(EXCEPTION_CONTEXT_TPIDR)]
ldp x8, x9, [sp, #(8 * 8)]
ldp x10, x11, [sp, #(8 * 10)]
ldp x12, x13, [sp, #(8 * 12)]
ldp x14, xzr, [sp, #(8 * 14)]
ldp x17, x20, [sp, #(8 * 32)]
ldr x19, [sp, #(8 * 34)]
msr elr_el1, x17
msr spsr_el1, x20
msr tpidr_el0, x19
/* Return. */
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
add sp, sp, #0x120
eret

View File

@@ -216,12 +216,6 @@ namespace ams::kern::board::nintendo::nx {
return (m_value & (1u << n));
}
template<Bit... Bits>
constexpr ALWAYS_INLINE u32 SelectBits() const {
constexpr u32 Mask = ((1u << Bits) | ...);
return m_value & Mask;
}
constexpr ALWAYS_INLINE bool GetBit(Bit n) const {
return this->SelectBit(n) != 0;
}
@@ -248,14 +242,12 @@ namespace ams::kern::board::nintendo::nx {
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBit(Bit_NonSecure); }
constexpr ALWAYS_INLINE bool IsWriteable() const { return this->GetBit(Bit_Writeable); }
constexpr ALWAYS_INLINE bool IsReadable() const { return this->GetBit(Bit_Readable); }
constexpr ALWAYS_INLINE bool IsValid() const { return this->SelectBits<Bit_Readable, Bit_Writeable>(); }
constexpr ALWAYS_INLINE bool IsValid() const { return this->IsWriteable() || this->IsReadable(); }
constexpr ALWAYS_INLINE u32 GetAttributes() const { return this->SelectBits<Bit_Readable, Bit_Writeable, Bit_NonSecure>(); }
constexpr ALWAYS_INLINE u32 GetAttributes() const { return this->SelectBit(Bit_NonSecure) | this->SelectBit(Bit_Writeable) | this->SelectBit(Bit_Readable); }
constexpr ALWAYS_INLINE KPhysicalAddress GetPhysicalAddress() const { return (static_cast<u64>(m_value) << DevicePageBits) & PhysicalAddressMask; }
ALWAYS_INLINE void InvalidateAttributes() { this->SetValue(m_value & ~(0xCu << 28)); }
ALWAYS_INLINE void Invalidate() { this->SetValue(0); }
};
@@ -534,7 +526,7 @@ namespace ams::kern::board::nintendo::nx {
#if defined(MESOSPHERE_ENABLE_MEMORY_CONTROLLER_INTERRUPT)
{
/* Clear the interrupt when we're done. */
ON_SCOPE_EXIT { Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_MemoryController, GetCurrentCoreId()); };
ON_SCOPE_EXIT { Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_MemoryController); };
/* Get and clear the interrupt status. */
u32 int_status, err_status, err_adr;
@@ -591,15 +583,15 @@ namespace ams::kern::board::nintendo::nx {
constinit KMemoryControllerInterruptTask g_mc_interrupt_task;
/* Memory controller utilities. */
ALWAYS_INLINE void SmmuSynchronizationBarrier() {
void SmmuSynchronizationBarrier() {
ReadMcRegister(MC_SMMU_CONFIG);
}
ALWAYS_INLINE void InvalidatePtc() {
void InvalidatePtc() {
WriteMcRegister(MC_SMMU_PTC_FLUSH_0, 0);
}
ALWAYS_INLINE void InvalidatePtc(KPhysicalAddress address) {
void InvalidatePtc(KPhysicalAddress address) {
WriteMcRegister(MC_SMMU_PTC_FLUSH_1, (static_cast<u64>(GetInteger(address)) >> 32));
WriteMcRegister(MC_SMMU_PTC_FLUSH_0, (GetInteger(address) & 0xFFFFFFF0u) | 1u);
}
@@ -614,15 +606,15 @@ namespace ams::kern::board::nintendo::nx {
return ((match_asid ? 1u : 0u) << 31) | ((asid & 0x7F) << 24) | (((address & 0xFFC00000u) >> DevicePageBits)) | (match);
}
ALWAYS_INLINE void InvalidateTlb() {
void InvalidateTlb() {
return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(false, 0, 0, TlbFlushVaMatch_All));
}
ALWAYS_INLINE void InvalidateTlb(u8 asid) {
void InvalidateTlb(u8 asid) {
return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, 0, TlbFlushVaMatch_All));
}
ALWAYS_INLINE void InvalidateTlbSection(u8 asid, KDeviceVirtualAddress address) {
void InvalidateTlbSection(u8 asid, KDeviceVirtualAddress address) {
return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, address, TlbFlushVaMatch_Section));
}
@@ -855,7 +847,7 @@ namespace ams::kern::board::nintendo::nx {
}
/* Forcibly unmap all pages. */
this->UnmapImpl(0, (1ul << DeviceVirtualAddressBits), false);
this->UnmapImpl(0, (1ul << DeviceVirtualAddressBits), true);
/* Release all asids. */
for (size_t i = 0; i < TableCount; ++i) {
@@ -1125,11 +1117,12 @@ namespace ams::kern::board::nintendo::nx {
return ResultSuccess();
}
Result KDevicePageTable::MapImpl(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned) {
Result KDevicePageTable::MapImpl(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm) {
/* Clear the output size. */
*out_mapped_size = 0;
/* Get the size, and validate the address. */
const u64 size = pg.GetNumPages() * PageSize;
MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0);
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
@@ -1137,33 +1130,28 @@ namespace ams::kern::board::nintendo::nx {
R_UNLESS(this->IsFree(device_address, size), svc::ResultInvalidCurrentMemory());
/* Ensure that if we fail, we unmap anything we mapped. */
auto unmap_guard = SCOPE_GUARD { this->UnmapImpl(device_address, size, false); };
auto unmap_guard = SCOPE_GUARD { this->UnmapImpl(device_address, size, true); };
/* Iterate, mapping device pages. */
KDeviceVirtualAddress cur_addr = device_address;
while (true) {
/* Get the current contiguous range. */
KPageTableBase::MemoryRange contig_range = {};
R_TRY(page_table->OpenMemoryRangeForMapDeviceAddressSpace(std::addressof(contig_range), process_address + *out_mapped_size, size - *out_mapped_size, ConvertToKMemoryPermission(device_perm), is_aligned));
for (auto it = pg.begin(); it != pg.end(); ++it) {
/* Require that we be able to map the device page. */
R_UNLESS(IsHeapVirtualAddress(it->GetAddress()), svc::ResultInvalidCurrentMemory());
/* Ensure we close the range when we're done. */
ON_SCOPE_EXIT { contig_range.Close(); };
/* Get the physical address for the page. */
const KPhysicalAddress phys_addr = GetHeapPhysicalAddress(it->GetAddress());
/* Map the device page. */
const u64 block_size = it->GetSize();
size_t mapped_size = 0;
R_TRY(this->MapDevicePage(std::addressof(mapped_size), num_pt, max_pt, GetHeapPhysicalAddress(contig_range.address), contig_range.size, cur_addr, device_perm));
R_TRY(this->MapDevicePage(std::addressof(mapped_size), num_pt, max_pt, phys_addr, block_size, cur_addr, device_perm));
/* Advance. */
cur_addr += contig_range.size;
cur_addr += block_size;
*out_mapped_size += mapped_size;
/* If we didn't map as much as we wanted, break. */
if (mapped_size < contig_range.size) {
break;
}
/* Similarly, if we're done, break. */
if (*out_mapped_size >= size) {
if (mapped_size < block_size) {
break;
}
}
@@ -1175,7 +1163,6 @@ namespace ams::kern::board::nintendo::nx {
}
void KDevicePageTable::UnmapImpl(KDeviceVirtualAddress address, u64 size, bool force) {
MESOSPHERE_UNUSED(force);
MESOSPHERE_ASSERT((address & ~DeviceVirtualAddressMask) == 0);
MESOSPHERE_ASSERT(((address + size - 1) & ~DeviceVirtualAddressMask) == 0);
@@ -1198,6 +1185,8 @@ namespace ams::kern::board::nintendo::nx {
/* Check if there's nothing mapped at l1. */
if (l1 == nullptr || !l1[l1_index].IsValid()) {
MESOSPHERE_ASSERT(force);
const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index;
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize);
@@ -1211,12 +1200,30 @@ namespace ams::kern::board::nintendo::nx {
const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index;
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize);
size_t num_closed = 0;
bool invalidated_tlb = false;
/* Invalidate the attributes of all entries. */
for (size_t i = 0; i < map_count; ++i) {
if (l2[l2_index + i].IsValid()) {
l2[l2_index + i].InvalidateAttributes();
/* Get the physical address. */
const KPhysicalAddress phys_addr = l2[l2_index + i].GetPhysicalAddress();
MESOSPHERE_ASSERT(IsHeapPhysicalAddress(phys_addr));
/* Invalidate the entry. */
l2[l2_index + i].Invalidate();
++num_closed;
/* Try to add the page to the group. */
if (R_FAILED(pg.AddBlock(GetHeapVirtualAddress(phys_addr), DevicePageSize / PageSize))) {
/* If we can't add it for deferred close, close it now. */
cpu::StoreDataCache(std::addressof(l2[l2_index + i]), sizeof(PageTableEntry));
InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l2[l2_index + i]))));
SmmuSynchronizationBarrier();
/* Close the page's reference. */
mm.Close(GetHeapVirtualAddress(phys_addr), 1);
}
} else {
MESOSPHERE_ASSERT(force);
}
}
cpu::StoreDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry));
@@ -1227,38 +1234,6 @@ namespace ams::kern::board::nintendo::nx {
}
SmmuSynchronizationBarrier();
/* Close the memory manager's references to the pages. */
{
KPhysicalAddress contig_phys_addr = Null<KPhysicalAddress>;
size_t contig_count = 0;
for (size_t i = 0; i < map_count; ++i) {
/* Get the physical address. */
const KPhysicalAddress phys_addr = l2[l2_index + i].GetPhysicalAddress();
MESOSPHERE_ASSERT(IsHeapPhysicalAddress(phys_addr));
/* Fully invalidate the entry. */
l2[l2_index + i].Invalidate();
if (contig_count == 0) {
/* Ensure that our address/count is valid. */
contig_phys_addr = phys_addr;
contig_count = contig_phys_addr != Null<KPhysicalAddress> ? 1 : 0;
} else if (phys_addr == Null<KPhysicalAddress> || phys_addr != (contig_phys_addr + (contig_count * DevicePageSize))) {
/* If we're no longer contiguous, close the range we've been building. */
mm.Close(GetHeapVirtualAddress(contig_phys_addr), (contig_count * DevicePageSize) / PageSize);
contig_phys_addr = phys_addr;
contig_count = contig_phys_addr != Null<KPhysicalAddress> ? 1 : 0;
} else {
++contig_count;
}
}
if (contig_count > 0) {
mm.Close(GetHeapVirtualAddress(contig_phys_addr), (contig_count * DevicePageSize) / PageSize);
}
}
/* Close the pages. */
if (ptm.Close(KVirtualAddress(l2), num_closed)) {
/* Invalidate the l1 entry. */
@@ -1267,12 +1242,22 @@ namespace ams::kern::board::nintendo::nx {
/* Synchronize. */
InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l1[l1_index]))));
InvalidateTlbSection(m_table_asids[l0_index], address);
SmmuSynchronizationBarrier();
/* We invalidated the tlb. */
invalidated_tlb = true;
/* Free the l2 page. */
ptm.Free(KVirtualAddress(l2));
}
/* Invalidate the tlb if we haven't already. */
if (!invalidated_tlb) {
InvalidateTlbSection(m_table_asids[l0_index], address);
SmmuSynchronizationBarrier();
}
/* Advance. */
address += map_count * DevicePageSize;
remaining -= map_count * DevicePageSize;
@@ -1301,158 +1286,114 @@ namespace ams::kern::board::nintendo::nx {
remaining -= DeviceLargePageSize;
}
}
/* Close references to the pages in the group. */
pg.Close();
}
bool KDevicePageTable::Compare(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address) const {
MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0);
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
/* We need to traverse the ranges that make up our mapping, to make sure they're all good. Start by getting a contiguous range. */
KPageTableBase::MemoryRange contig_range = {};
if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), process_address, size))) {
return false;
}
/* Ensure that we close the range when we're done. */
bool range_open = true;
ON_SCOPE_EXIT { if (range_open) { contig_range.Close(); } };
Result KDevicePageTable::MakePageGroup(KPageGroup *out, KDeviceVirtualAddress address, u64 size) const {
MESOSPHERE_ASSERT((address & ~DeviceVirtualAddressMask) == 0);
MESOSPHERE_ASSERT(((address + size - 1) & ~DeviceVirtualAddressMask) == 0);
/* Walk the directory. */
KProcessAddress cur_process_address = process_address;
size_t remaining_size = size;
KPhysicalAddress cur_phys_address = GetHeapPhysicalAddress(contig_range.address);
size_t remaining_in_range = contig_range.size;
bool first = true;
u32 first_attr = 0;
while (remaining_size > 0) {
/* Convert the device address to a series of indices. */
const size_t l0_index = (device_address / DeviceRegionSize);
const size_t l1_index = (device_address % DeviceRegionSize) / DeviceLargePageSize;
const size_t l2_index = (device_address % DeviceLargePageSize) / DevicePageSize;
u64 remaining = size;
bool first = true;
u32 attr = 0;
while (remaining > 0) {
const size_t l0_index = (address / DeviceRegionSize);
const size_t l1_index = (address % DeviceRegionSize) / DeviceLargePageSize;
const size_t l2_index = (address % DeviceLargePageSize) / DevicePageSize;
/* Get and validate l1. */
const PageDirectoryEntry *l1 = GetPointer<PageDirectoryEntry>(m_tables[l0_index]);
if (!(l1 != nullptr && l1[l1_index].IsValid())) {
return false;
}
R_UNLESS(l1 != nullptr, svc::ResultInvalidCurrentMemory());
R_UNLESS(l1[l1_index].IsValid(), svc::ResultInvalidCurrentMemory());
if (l1[l1_index].IsTable()) {
/* We're acting on an l2 entry. */
const PageTableEntry *l2 = GetPointer<PageTableEntry>(GetPageTableVirtualAddress(l1[l1_index].GetPhysicalAddress()));
/* Determine the number of pages to check. */
const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index;
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining_size / DevicePageSize);
const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize);
/* Check each page. */
for (size_t i = 0; i < map_count; ++i) {
/* Ensure the l2 entry is valid. */
if (!l2[l2_index + i].IsValid()) {
return false;
R_UNLESS(l2[l2_index + i].IsValid(), svc::ResultInvalidCurrentMemory());
/* Get the physical address. */
const KPhysicalAddress phys_addr = l2[l2_index + i].GetPhysicalAddress();
MESOSPHERE_ASSERT(IsHeapPhysicalAddress(phys_addr));
/* Add to the group. */
R_TRY(out->AddBlock(GetHeapVirtualAddress(phys_addr), DevicePageSize / PageSize));
/* If this is our first entry, get the attribute. */
if (first) {
attr = l2[l2_index + i].GetAttributes();
first = false;
} else {
/* Validate the attributes match the first entry. */
R_UNLESS(l2[l2_index + i].GetAttributes() == attr, svc::ResultInvalidCurrentMemory());
}
/* Check that the attributes match the first attributes we encountered. */
const u32 cur_attr = l2[l2_index + i].GetAttributes();
if (!first && cur_attr != first_attr) {
return false;
}
/* If there's nothing remaining in the range, refresh the range. */
if (remaining_in_range == 0) {
contig_range.Close();
range_open = false;
if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), cur_process_address, remaining_size))) {
return false;
}
range_open = true;
cur_phys_address = GetHeapPhysicalAddress(contig_range.address);
remaining_in_range = contig_range.size;
}
/* Check that the physical address is expected. */
if (l2[l2_index + i].GetPhysicalAddress() != cur_phys_address) {
return false;
}
/* Advance. */
cur_phys_address += DevicePageSize;
cur_process_address += DevicePageSize;
remaining_size -= DevicePageSize;
remaining_in_range -= DevicePageSize;
first = false;
first_attr = cur_attr;
}
/* Advance the device address. */
device_address += map_count * DevicePageSize;
} else {
/* We're acting on an l1 entry. */
if (!(l2_index == 0 && remaining_size >= DeviceLargePageSize)) {
return false;
}
/* Check that the attributes match the first attributes we encountered. */
const u32 cur_attr = l1[l1_index].GetAttributes();
if (!first && cur_attr != first_attr) {
return false;
}
/* If there's nothing remaining in the range, refresh the range. */
if (remaining_in_range == 0) {
contig_range.Close();
range_open = false;
if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), cur_process_address, remaining_size))) {
return false;
}
range_open = true;
cur_phys_address = GetHeapPhysicalAddress(contig_range.address);
remaining_in_range = contig_range.size;
}
/* Check that the physical address is expected, and there's enough in the range. */
if (remaining_in_range < DeviceLargePageSize || l1[l1_index].GetPhysicalAddress() != cur_phys_address) {
return false;
}
/* Advance. */
cur_phys_address += DeviceLargePageSize;
cur_process_address += DeviceLargePageSize;
remaining_size -= DeviceLargePageSize;
remaining_in_range -= DeviceLargePageSize;
address += DevicePageSize * map_count;
remaining -= DevicePageSize * map_count;
} else {
/* We're acting on an l1 entry. */
R_UNLESS(l2_index == 0, svc::ResultInvalidCurrentMemory());
R_UNLESS(remaining >= DeviceLargePageSize, svc::ResultInvalidCurrentMemory());
first = false;
first_attr = cur_attr;
/* Get the physical address. */
const KPhysicalAddress phys_addr = l1[l1_index].GetPhysicalAddress();
MESOSPHERE_ASSERT(IsHeapPhysicalAddress(phys_addr));
/* Advance the device address. */
device_address += DeviceLargePageSize;
/* Add to the group. */
R_TRY(out->AddBlock(GetHeapVirtualAddress(phys_addr), DeviceLargePageSize / PageSize));
/* If this is our first entry, get the attribute. */
if (first) {
attr = l1[l1_index].GetAttributes();
first = false;
} else {
/* Validate the attributes match the first entry. */
R_UNLESS(l1[l1_index].GetAttributes() == attr, svc::ResultInvalidCurrentMemory());
}
/* Advance. */
address += DeviceLargePageSize;
remaining -= DeviceLargePageSize;
}
}
/* The range is valid! */
return true;
return ResultSuccess();
}
Result KDevicePageTable::Map(size_t *out_mapped_size, KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings) {
bool KDevicePageTable::Compare(const KPageGroup &compare_pg, KDeviceVirtualAddress device_address) const {
/* Check whether the page group we expect for the virtual address matches the page group we're validating. */
KPageGroup calc_pg(std::addressof(Kernel::GetBlockInfoManager()));
return (R_SUCCEEDED(this->MakePageGroup(std::addressof(calc_pg), device_address, compare_pg.GetNumPages() * PageSize))) &&
calc_pg.IsEquivalentTo(compare_pg);
}
Result KDevicePageTable::Map(size_t *out_mapped_size, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings) {
/* Clear the output size. */
*out_mapped_size = 0;
/* Map the pages. */
s32 num_pt = 0;
return this->MapImpl(out_mapped_size, num_pt, refresh_mappings ? 1 : std::numeric_limits<s32>::max(), page_table, process_address, size, device_address, device_perm, refresh_mappings);
return this->MapImpl(out_mapped_size, num_pt, refresh_mappings ? 1 : std::numeric_limits<s32>::max(), pg, device_address, device_perm);
}
Result KDevicePageTable::Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address) {
Result KDevicePageTable::Unmap(const KPageGroup &pg, KDeviceVirtualAddress device_address) {
/* Validate address/size. */
const size_t size = pg.GetNumPages() * PageSize;
MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0);
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
/* Ensure the page group is correct. */
R_UNLESS(this->Compare(page_table, process_address, size, device_address), svc::ResultInvalidCurrentMemory());
R_UNLESS(this->Compare(pg, device_address), svc::ResultInvalidCurrentMemory());
/* Unmap the pages. */
this->UnmapImpl(device_address, size, false);

Some files were not shown because too many files have changed in this diff Show More