Compare commits

..

101 Commits

Author SHA1 Message Date
Michael Scire
21c0f75a29 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "6cc765fca"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "6cc765fca"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-12-08 18:41:44 -07:00
Michael Scire
3cb5d5f957 ams: add enum recognition for 21.1.0 2025-12-08 18:41:01 -07:00
Michael Scire
00d1cdb533 loader: fix valid-nso-set checks to be accurate (closes #2660) 2025-11-22 15:57:35 -07:00
Michael Scire
d9fc6e99eb kern: eshop actually requires an extra mb 2025-11-15 17:35:47 -07:00
Michael Scire
c08a13a546 loader: add USB 3.0 patches for 21.0.0 2025-11-15 17:03:49 -07:00
Michael Scire
b5b6189c85 kern: fix comparison typo 2025-11-15 16:51:15 -07:00
Michael Scire
28a378ca0d ro: fix loading of aligned-header NROs 2025-11-15 16:47:57 -07:00
Michael Scire
540d00e097 kern: 21.0.0 requires an even smaller memory pool... 2025-11-15 16:47:44 -07:00
Michael Scire
bfe98bc5b8 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "6e2c09c79"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "6e2c09c79"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-11-15 12:58:41 -07:00
Michael Scire
4928bcb003 git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "3c57b20ba"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "3c57b20ba"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-11-15 12:57:18 -07:00
Michael Scire
d61ee942d9 docs: add changelog for 1.10.0 2025-11-15 12:55:47 -07:00
Michael Scire
f59e6a936b emummc: update for 21.0.0 2025-11-15 12:31:07 -07:00
Michael Scire
129c61c256 loader: fix sd-cmpt 2025-11-15 12:31:07 -07:00
Michael Scire
db71eefd9f loader: update for 20.0.0/21.0.0 2025-11-15 12:31:07 -07:00
Michael Scire
4b32a2b964 pgl/pm: add GetProcessId command 2025-11-15 12:31:07 -07:00
Michael Scire
0fb9481e59 kern: fix debug build for [[nodiscard]] changes 2025-11-15 12:31:07 -07:00
Michael Scire
c05d91f44a kern: fix whoops introduced by nodiscard refactor 2025-11-15 12:31:07 -07:00
Michael Scire
e1d82a13f3 erpt: implement new 21.0.0 commands 2025-11-15 12:31:07 -07:00
Michael Scire
4f1201a022 erpt: fix ids, failed to copy the new categories 2025-11-15 12:31:07 -07:00
Michael Scire
4201bbff63 fatal: add new HashedTraceContext command 2025-11-15 12:31:07 -07:00
Michael Scire
94c36a3255 erpt: add new IDs for 21.0.0 2025-11-15 12:31:07 -07:00
Michael Scire
6b0ef21b83 kern: RESERVED_2F now set by HandleFpuException 2025-11-15 12:31:07 -07:00
Michael Scire
ac382f69e7 kern: exception flags are now atomic.
This is a really weird one, because they didn't actually update the
code which updates these flags in asm, these still use ldrb/orr/strb.
But every access to these via c++ is now an atomic ldxrb/stxrb loop.
Maybe they just forgot to update the asm?
2025-11-15 12:31:07 -07:00
Michael Scire
2a44550dbe kern: pass u32 directly to CopyMemoryToUserSize32Bit 2025-11-15 12:31:07 -07:00
Michael Scire
3bc1951820 ams: mark ams::Result [[nodiscard]] (partially complete).
NOTE: This work is not yet fully complete; kernel is done, but
it was taking an exceedingly long time to get through libstratosphere.
Thus, I've temporarily added -Wno-error=unused-result for libstratosphere/stratosphere.

All warnings should be fixed to do the same thing Nintendo does as relevant, but this
is taking a phenomenally long time and is not actually the most important work to do,
so it can be put off for some time to prioritize other tasks for 21.0.0 support.
2025-11-15 12:31:07 -07:00
Michael Scire
418fde40a8 kern: Nintendo now also devirtualizes KAutoObject::DynamicCast 2025-11-15 12:31:07 -07:00
Michael Scire
e36051359c kern: write cpu tick differential to tls +0x108 on thread switch 2025-11-15 12:31:07 -07:00
Michael Scire
18bb1fdea0 fusee/exo/ams: update with new keydata/version enums 2025-11-15 12:31:07 -07:00
Michael Scire
c8e39a54d2 fs.mitm: add another game which needs stolen heap for layeredfs 2025-10-07 23:12:07 -07:00
Michael Scire
11a46e4579 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "583ae0fbf"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "583ae0fbf"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-10-07 17:34:00 -07:00
Michael Scire
652519da2e fssystem: fix support for parsing newer-format BKTR NCAs
Apparently, at some point they started allowing maxlayers=3, which caused this code to not work.

Looking at latest FS, they always reference DataStorage instead of level+2 for the final level.

This fixes parsing update romfs for newer games, e.g. Super Mario Galaxy 2.
2025-10-07 17:30:12 -07:00
Michael Scire
de9b02007b git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "efd3d931a"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "efd3d931a"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-09-29 18:45:20 -07:00
Michael Scire
982f0e4fd4 ams: bump version, add enum support for 20.5.0 2025-09-29 18:44:40 -07:00
Michael Scire
d7936d3fa4 exo: improve offset-table fix (save 8 bytes) 2025-09-02 19:50:08 -07:00
Michael Scire
1c0ea680b6 docs: add note about deadlock fix 2025-09-02 18:37:24 -07:00
Michael Scire
b8ed942ae4 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "bbd085442"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "bbd085442"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-09-02 18:36:29 -07:00
Michael Scire
98bc030b37 ams.mitm: fix deadlock when building multiple romfs simultaneously (closes #1972) 2025-09-02 18:35:42 -07:00
Michael Scire
081e76a2b5 ams: bump version, add enum support for 20.4.0 2025-09-02 18:29:51 -07:00
Michael Scire
e8de1e3c34 exo: fix register access tables to page start 2025-09-02 18:29:50 -07:00
comex
41b28bb0c4 build: portability fixes
- Invoke Python scripts with `python3` if `python` is not available.

  Despite SciresM preferring Python 2, the scripts used in the build all
  worked in Python 3 already, so this is just a Makefile change.

- Export `MAKE` to work around a GNU bug.

  See the comment for details.

- `rmdir --ignore-fail-on-non-empty` -> `rmdir 2>/dev/null`

  macOS `rmdir` doesn't support `--ignore-fail-on-non-empty`.

  This is a slight downgrade in functionality, because now we ignore all
  errors from `rmdir` rather than just 'Directory not empty'.  I could
  have avoided this with a more complicated fix, but the benefit strikes
  me as not worth the complexity.  Let me know if you disagree.

- Append `$(DEVKITPRO)/tools/bin/` to `$PATH` when invoking
  `build_romfs`.

  This avoids the need to add devkitPro directories to `$PATH` when
  building Atmosphere.

  If you already have `build_romfs` in your PATH, then that will still
  take precedence.  (This seemed like the nicer option, though I don't
  have strong opinions.)
2025-08-16 16:22:32 -07:00
comex
3197b1e25b nanovg: disable some compiler warnings
Disable all warnings seen on devkitA64 GCC 15.1.0:

- Several false-positive `-Wmisleading-indentation` warnings (the
  indentation is not actually misleading)

- One `-Wuse-after-free` warning, which looks alarming and represents
  very dubious design, but is ultimately harmless (a freed pointer is
  passed to a function that doesn't use it).

- Some `-Wunused-function` warnings in `simd/neon.h`
2025-08-08 14:16:03 -07:00
comex
822cbbbc8b daybreak: fix strncpy compiler warning
GCC warned that the output string would not be nul-terminated if the
input string was too long.  Fix this by subtracting 1 from the size
argument, as is done for other `strncpy` calls in the file.  (It would
probably be better to avoid `strncpy` entirely, but this is just a
simple fix.)
2025-08-08 14:16:03 -07:00
comex
4237f52ee2 haze: fix duplicate-macro warnings
haze was including both `<switch.h>` and `vapours/types.hpp` which both
define `R_SUCCEEDED` and `R_FAILED`, producing compiler warnings.

The intent is that `vapours/types.hpp` only gets included when targeting
not-Switch and/or not-EL0.  But the check didn't account for
Troposphère.  Fix that.
2025-08-08 14:16:03 -07:00
Michael Scire
8b8e4438e8 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "bc7a0fc11"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "bc7a0fc11"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-07-29 15:17:41 -07:00
Michael Scire
debfff9f62 ams: bump version, support 20.3.0 2025-07-29 15:16:51 -07:00
Michael Scire
c77acb32be fs.mitm: steal some heap when building romfs for kotor2 (closes #2564) 2025-07-22 00:36:51 -07:00
Michael Scire
af859d9e65 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "af10bca1b"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "af10bca1b"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-07-16 10:23:50 -07:00
Michael Scire
a487efad6b ams: bump version, add 1.9.2 changelog 2025-07-16 10:23:05 -07:00
Michael Scire
7e0eb10e32 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "4e3615355"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "4e3615355"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-07-14 18:24:52 -07:00
Michael Scire
4a3e2b5c57 ams: add enum version support for 20.1.x/20.2.0 2025-07-14 18:24:09 -07:00
lsp199308
d8a37b4b71 loader: add usb 3.0 enable patches for 20.1.0 (#2556)
* loader: add usb 3.0 enable patches for 20.1.0
2025-06-03 01:04:52 -07:00
Michael Scire
b11850b3a3 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "0f72b2ceb"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "0f72b2ceb"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-05-28 19:34:34 -07:00
Michael Scire
77603bf7e5 docs: add basic changelog for 1.9.1 2025-05-28 19:33:49 -07:00
Marcus Carter
6b01ebca9e Clarify that code type 0xC4 uses a 64-bit value in cheats.md by formatting the key values as such
Changes the formatting of the key values at `Code Type 0xC4: Begin Extended Keypress Conditional Block` in cheats.md so that it is perfectly clear that those values are 64-bit values rather than 32-bit or 28-bit like `Code Type 0x8: Begin Keypress Conditional Block`, and also for the fact that the formatting matches the rest of the document and is thus cleaner.
2025-05-28 14:47:45 -07:00
Michael Scire
17be65b4b9 git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "a8e5f1a18"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "a8e5f1a18"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-05-28 12:29:54 -07:00
Michael Scire
409c3cf9e1 emummc: note 20.1.0 support in README 2025-05-28 12:29:17 -07:00
Michael Scire
f4e1d0bf9f kern: move spendsgir static assert 2025-05-28 12:18:51 -07:00
Michael Scire
ae65b5df0c fusee/emummc: add support for FS 20.1.0 2025-05-28 12:02:56 -07:00
Michael Scire
0a299a3d40 erpt: update IDs for 20.1.0 2025-05-28 11:48:04 -07:00
Michael Scire
801438953d kern: save/restore spendsgir in KInterruptController::Save/RestoreCoreLocal 2025-05-28 10:54:52 -07:00
Michael Scire
3fbc59cce1 kern: wait 100us after synchronizing cores before saving interrupt state on sleep 2025-05-28 10:48:42 -07:00
Michael Scire
f646d9c8f9 kern: use KLightLock for KCoreBarrierInterruptHandler 2025-05-28 10:44:31 -07:00
Michael Scire
69cc653e7f Add version enums for 20.1.0 2025-05-28 10:32:26 -07:00
Michael Scire
6da88f8f3e docs: add banner to readme 2025-05-27 22:24:41 -07:00
Michael Scire
1d3f3c6e56 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "9e8cbe3fa"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "9e8cbe3fa"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-05-09 12:11:13 -07:00
Michael Scire
4d4f0ba968 svc: bump supported kernel version 2025-05-09 12:05:01 -07:00
Michael Scire
cc4531e3bf git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "7522f1f60"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "7522f1f60"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2025-05-09 12:02:17 -07:00
Michael Scire
0e2ef545f9 fusee: commit mtc table combined bins, to remove need for running py script outside of makefile 2025-05-09 12:00:44 -07:00
Michael Scire
f1ca7db562 boot: use --embed-dir for fusee embed 2025-05-09 11:58:56 -07:00
Michael Scire
d5567b5363 pm: update for fsp-pr RegisterProgram api change 2025-05-09 11:55:21 -07:00
Michael Scire
f9165c472e docs: add gcc15 to changelog 2025-05-09 11:55:21 -07:00
Michael Scire
b2dd3b7dce boot: use #embed for fusee 2025-05-09 11:55:21 -07:00
Michael Scire
66acab02db exo: use #embed for loader stub 2025-05-09 11:55:21 -07:00
Michael Scire
2c50ef717a fusee: use embed in mtc/sdram param scripts 2025-05-09 11:55:21 -07:00
Michael Scire
d305d48a7e ams: basic support for compiling with gcc 15 2025-05-09 11:55:21 -07:00
Michael Scire
cb032006d5 fusee: fix off-by-one in nogc patches for exFAT firm 2025-05-09 11:55:21 -07:00
Michael Scire
8da6bc59a7 docs: add provisional changelog for ams 1.9.0 2025-05-09 11:55:21 -07:00
Michael Scire
b7ec64ea16 fs.mitm: add and use memlet module to temporarily steal applet memory while building romfs images.
Starting in 20.0.0, the browser needs more applet memory to function, so we can't steal as much any more.
Thus, we now steal 14 MB on 20.0.0+ instead of 40MB.

However, since this reduces memory available for custom system modules, we are adjusting to compensate.
ams.mitm's heap size has been reduced from 32MB to 12MB (recovering 20MB).
In addition, fs.mitm now uses a new mechanism for stealing memory from the applet pool while romfs is being built.

On net, we are compromising:
    * Custom sysmodules lose memory available to them.
        On 19.0.0/AMS 1.8.0, there was 30 MB available for custom sysmodules.
        Stealing 14 MB instead of 40 MB, we lose 26 MB of that. Reducing ams.mitm's usage will gain us back 20.
        Nintendo also appears to...use 4 extra MB, in 20.0.0, from my test homebrew.
        So on 20.0.0/AMS 1.9.0, there should be 20 MB available for custom sysmodules.
        On the bright side, on <20.0.0/AMS 1.9.0, I guess there will be 50 MB available for custom sysmodules now?
    * totk mods will lose the ability to...put every file in the romfs on sd card. There will be some unknown maximum filecount for totk mods.
        On the bright side, implementing the transient memory stealing should improve compatibility for some mods which strictly add files?
2025-05-09 11:55:21 -07:00
Michael Scire
bc44ffe70d emummc: fix offsets for 20.0.0-exfat 2025-05-09 11:55:21 -07:00
Michael Scire
a6847ca70e ams: add enum support for 20.0.1/18.0.1 2025-05-09 11:55:21 -07:00
Michael Scire
3af8757c3b erpt: initial support (incomplete) for 20.0.0 2025-05-09 11:55:21 -07:00
Michael Scire
f55cf42433 ldr/pm: update for 20.0.0 abi changes 2025-05-09 11:55:21 -07:00
Michael Scire
07df13e2a0 strat: update for fsp-ldr 20.0.0 changes 2025-05-09 11:55:21 -07:00
Michael Scire
791edf87a0 ncm: update to implement new ContentMetaDatabase function for 20.0.0 2025-05-09 11:55:21 -07:00
Michael Scire
b1ca5b4049 kern: plutoo is an intellectual, I am a fool, fix chicanery 2025-05-09 11:55:21 -07:00
Michael Scire
4580a352c0 kern: use callback to note pte updates in KPageTableImpl 2025-05-09 11:55:21 -07:00
Michael Scire
28296e2aac kern: refactor FindFreeArea region search logic per 20.0.0 changes 2025-05-09 11:55:21 -07:00
Michael Scire
b80f0944ab kern: update instruction cache invalidation logic in KPageTableBase to reflect 20.0.0 changes 2025-05-09 11:55:21 -07:00
Michael Scire
96d4546498 kern: reorder resource manager implementation 2025-05-09 11:55:21 -07:00
Michael Scire
86e4bed056 kern: support null resource limit in KSecureSystemResource 2025-05-09 11:55:21 -07:00
Michael Scire
2e204ccbaf kern: update synchronous exception handlers to assume FAR validity on TLB conflict 2025-05-09 11:55:21 -07:00
Michael Scire
b27999a116 kern: adjust system registers during exception handling on MTE-violation or kernel address fault 2025-05-09 11:55:21 -07:00
Michael Scire
98e5bd4411 kern: update UserspaceAccess functions for 20.0.0 changes 2025-05-09 11:55:21 -07:00
Michael Scire
4c5c5c85e3 kern: update crt0 to reflect 20.0.0 changes 2025-05-09 11:55:21 -07:00
Michael Scire
3e19e4d004 kern: update KAddressSpaceInfo to reflect 20.0.0 changes 2025-05-09 11:55:21 -07:00
Michael Scire
66fcf33a2c kern: invert meaning of KTargetSystem/KSystemControl bools 2025-05-09 11:55:21 -07:00
Michael Scire
d147f6f93b erpt: update ids for 20.0.0 2025-05-09 11:55:21 -07:00
Michael Scire
3dd5c98f52 readme: sept has not been in the project for many years 2025-05-09 11:55:21 -07:00
Michael Scire
b9b01bbbd1 loader: add usb 3.0 enable patches for 20.0.0 2025-05-09 11:55:21 -07:00
Michael Scire
6352397203 emummc: add offsets for 20.0.0 (untested) 2025-05-09 11:55:21 -07:00
Michael Scire
ef5334c3ca fusee/exo/ams: update with new keydata/version enums 2025-05-09 11:55:21 -07:00
256 changed files with 3739 additions and 1569 deletions

View File

@@ -4,6 +4,7 @@
![License](https://img.shields.io/badge/License-GPLv2-blue.svg)
[![Chat on Discord](https://img.shields.io/badge/Discord-5865f2?logo=discord&logoColor=white)](https://discordapp.com/invite/ZdqEhed)
![Made with Notepad++](img/np++.png?raw=true)
Atmosphère is a work-in-progress customized firmware for the Nintendo Switch.
@@ -13,7 +14,6 @@ Components
Atmosphère consists of multiple components, each of which replaces/modifies a different component of the system:
* Fusée: First-stage Loader, responsible for loading and validating stage 2 (custom TrustZone) plus package2 (Kernel/FIRM sysmodules), and patching them as needed. This replaces all functionality normally in Package1loader/NX Bootloader.
* Sept: Payload used to enable support for runtime key derivation on 7.0.0.
* Exosphère: Customized TrustZone, to run a customized Secure Monitor
* Thermosphère: EL2 EmuNAND support, i.e. backing up and using virtualized/redirected NAND images
* Stratosphère: Custom Sysmodule(s), both Rosalina style to extend the kernel/provide new features, and of the loader reimplementation style to hook important system actions

View File

@@ -50,6 +50,7 @@ dist: dist-no-debug
cp $(CURRENT_DIRECTORY)/stratosphere/sm/$(ATMOSPHERE_OUT_DIR)/sm.elf $(DIST_DIR)/sm.elf
cp $(CURRENT_DIRECTORY)/stratosphere/spl/$(ATMOSPHERE_OUT_DIR)/spl.elf $(DIST_DIR)/spl.elf
cp $(CURRENT_DIRECTORY)/stratosphere/TioServer/$(ATMOSPHERE_OUT_DIR)/TioServer.elf $(DIST_DIR)/TioServer.elf
cp $(CURRENT_DIRECTORY)/stratosphere/memlet/$(ATMOSPHERE_OUT_DIR)/memlet.elf $(DIST_DIR)/memlet.elf
cp $(CURRENT_DIRECTORY)/troposphere/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf
cp $(CURRENT_DIRECTORY)/troposphere/haze/haze.elf $(DIST_DIR)/haze.elf
cp $(CURRENT_DIRECTORY)/troposphere/reboot_to_payload/reboot_to_payload.elf $(DIST_DIR)/reboot_to_payload.elf
@@ -87,6 +88,7 @@ dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
#mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003c
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000421
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000b240
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000d609
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000d623
@@ -104,7 +106,8 @@ dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
cp stratosphere/htc/$(ATMOSPHERE_OUT_DIR)/htc.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000b240/exefs.nsp
cp stratosphere/dmnt.gen2/$(ATMOSPHERE_OUT_DIR)/dmnt.gen2.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000d609/exefs.nsp
cp stratosphere/TioServer/$(ATMOSPHERE_OUT_DIR)/TioServer.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000d623/exefs.nsp
@build_romfs $(DIST_DIR)/stratosphere_romfs $(DIST_DIR)/atmosphere/stratosphere.romfs
cp stratosphere/memlet/$(ATMOSPHERE_OUT_DIR)/memlet.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000421/exefs.nsp
@PATH="$(DEVKITPRO)/tools/bin:$$PATH" build_romfs $(DIST_DIR)/stratosphere_romfs $(DIST_DIR)/atmosphere/stratosphere.romfs
rm -r $(DIST_DIR)/stratosphere_romfs
cp troposphere/reboot_to_payload/reboot_to_payload.nro $(DIST_DIR)/switch/reboot_to_payload.nro
cp troposphere/daybreak/daybreak.nro $(DIST_DIR)/switch/daybreak.nro
@@ -114,7 +117,7 @@ dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
cp fusee/$(ATMOSPHERE_BOOT_OUT_DIR)/fusee.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin
package3: emummc fusee stratosphere mesosphere exosphere troposphere
@python fusee/build_package3.py $(CURRENT_DIRECTORY) $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BOOT_OUT_DIR) $(ATMOSPHERE_GIT_HASH) $(ATMOSPHERE_MAJOR_VERSION) $(ATMOSPHERE_MINOR_VERSION) $(ATMOSPHERE_MICRO_VERSION) 0 $(ATMOSPHERE_SUPPORTED_HOS_MAJOR_VERSION) $(ATMOSPHERE_SUPPORTED_HOS_MINOR_VERSION) $(ATMOSPHERE_SUPPORTED_HOS_MICRO_VERSION) 0
$(SILENTCMD)$(PYTHON) fusee/build_package3.py $(CURRENT_DIRECTORY) $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BOOT_OUT_DIR) $(ATMOSPHERE_GIT_HASH) $(ATMOSPHERE_MAJOR_VERSION) $(ATMOSPHERE_MINOR_VERSION) $(ATMOSPHERE_MICRO_VERSION) 0 $(ATMOSPHERE_SUPPORTED_HOS_MAJOR_VERSION) $(ATMOSPHERE_SUPPORTED_HOS_MINOR_VERSION) $(ATMOSPHERE_SUPPORTED_HOS_MICRO_VERSION) 0
@echo "Built package3!"
emummc:

View File

@@ -1,4 +1,74 @@
# Changelog
## 1.10.0
+ Basic support was added for 21.0.0.
+ The console should boot and atmosphère should be fully functional.
+ **Please note**: All homebrew software may need to be re-compiled with the latest libnx (>= 4.10.0), or else it may crash/experience memory corruption.
+ Nintendo broke the userland<->kernel TLS ABI in 21.0.0, by writing to previously reserved space.
+ Homebrew used this reserved space for its TLS slots, which means any homebrew software using TLS slots will experience memory corruption when running under Atmosphere 1.10.0.
+ This doesn't appear to impact everything, but a large portion of tested homebrew crashes (often on exit), and so will need re-compile for the new ABI.
+ For those technically inclined, while TLS slots are rarely used by developers, they're used to implement features like e.g. C++ exceptions under the hood, and so anything using those crashes, etc.
+ To help make this transition easier, hbmenu now shows a warning when selecting homebrew compiled with an older, incompatible ABI version.
+ I apologize for the hassle in general.
+ libnx has been updated so that its reserved space matches Nintendo's now -- this particular issue can never occur again, even if Nintendo touches more reserved space.
+ `exosphère` was updated to reflect the latest official secure monitor behavior.
+ `mesosphère` was updated to reflect the latest official kernel behavior.
+ `loader` was updated to reflect the latest official behavior.
+ `pm` was updated to reflect the latest official behavior.
+ `erpt` was updated to reflect the latest official behavior.
+ `pgl` was updated to reflect the latest official behavior.
+ `fatal` was updated to reflect the latest official behavior.
+ Support was added for launching another game-which-has-too-many-files with romfs mods.
+ I rely on user reports for adding support/fixing these, and some of these games can be pretty obscure!
+ If you are affected by this, you will see "Data abort (0x101)" when trying to launch the game with mods.
+ Please reach out to `sciresm` on discord if this occurs to share your error report binary.
+ Although some games may be impossible to fix, I believe I can get almost everything working, so please let me try to help you (and improve atmosphère's support!) if you run into this!
+ General system stability improvements to enhance the user's experience.
## 1.9.5
+ Basic support was added for 20.5.0.
+ General system stability improvements to enhance the user's experience.
## 1.9.4
+ Basic support was added for 20.4.0.
+ An issue was fixed in `exosphère`'s register accessilibity tables (thanks @CTCaer).
+ I believe this had no impact on official code, though it would have prevented some homebrew from interacting correctly with the MC0/MC1 registers.
+ An issue was fixed that could cause a deadlock when building multiple romfs images simultaneously (thanks @Ereza).
+ This fixes support for certain mods, e.g. system language translations overriding content for both overlayDisp and qlaunch.
+ General system stability improvements to enhance the user's experience.
## 1.9.3
+ Basic support was added for 20.3.0.
+ Compatibility was fixed for loading mods with KOTOR 2 (star wars).
+ General system stability improvements to enhance the user's experience.
## 1.9.2
+ Basic support was added for 20.2.0.
+ USB 3.0 support force-enable was fixed for 20.1.0+.
+ General system stability improvements to enhance the user's experience.
## 1.9.1
+ Basic support was added for 20.1.0.
+ General system stability improvements to enhance the user's experience.
## 1.9.0
+ Basic support was added for 20.0.0.
+ The console should boot and atmosphère should be fully functional. However, not all modules have been fully updated to reflect the latest changes.
+ There shouldn't be anything user visible resulting from this, but it will be addressed in a future atmosphère update.
+ The same action item from 18.0.0 remains, and I believe in my heart of hearts that it will be addressed eventually. Someone has told me they're working on it.
+ There aren't (to my knowledge) outstanding 19.0.0 items any more.
+ **Please note**: As a result of changes made to nintendo's software in 20.0.0, there is roughly 10MB less memory available for custom system modules.
+ We can only steal a maximum of 14MB from the applet pool, down from 40MB.
+ To compensate for this, `ams.mitm`'s heap usage has been reduced by 20MB.
+ To facilitate this, a new helper module (`memlet`) was added, so that memory may be temporarily stolen during the romfs building process.
+ Hopefully, this results in relatively little breakage, however it is possible that user mods which replace extremely large numbers of files in The Legend of Zelda: Tears of the Kingdom may no longer function.
+ If you are affected by this, you will see "Data abort (0x101)" when trying to launch the game with mods.
+ Please reach out to `sciresm` on discord if this occurs to share your error report binary. However, some issues may be impossible to fix.
+ I apologize sincerely if the issue is impossible to resolve, but I have been forced unavoidably to make compromises here, and I think this is the best balance to be struck.
+ `exosphère` was updated to reflect the latest official secure monitor behavior.
+ `mesosphère` was updated to reflect the latest official kernel behavior.
+ `loader` was updated to reflect the latest official behavior.
+ `pm` was updated to reflect the latest official behavior.
+ `ncm` was partially updated to reflect the latest official behavior.
+ `erpt` was updated to reflect the latest official behavior.
+ Atmosphère was updated to use GCC 15/newlib (latest devkitA64/devkitARM releases).
+ A number of improvements were made to the dmnt cheat engine.
+ New instructions were added, and instructions were updated for improved/new functionality.
+ Please see the documents for details -- thanks @tomvita!
+ General system stability improvements to enhance the user's experience.
## 1.8.0
+ Basic support was added for 19.0.0.
+ The console should boot and atmosphère should be fully functional. However, not all modules have been fully updated to reflect the latest changes.

View File

@@ -423,41 +423,41 @@ Note that for multiple button combinations, the bitmasks should be OR'd together
#### Keypad Values
Note: This is the direct output of `hidKeysDown()`.
+ 000000001: A
+ 000000002: B
+ 000000004: X
+ 000000008: Y
+ 000000010: Left Stick Pressed
+ 000000020: Right Stick Pressed
+ 000000040: L
+ 000000080: R
+ 000000100: ZL
+ 000000200: ZR
+ 000000400: Plus
+ 000000800: Minus
+ 000001000: Left
+ 000002000: Up
+ 000004000: Right
+ 000008000: Down
+ 000010000: Left Stick Left
+ 000020000: Left Stick Up
+ 000040000: Left Stick Right
+ 000080000: Left Stick Down
+ 000100000: Right Stick Left
+ 000200000: Right Stick Up
+ 000400000: Right Stick Right
+ 000800000: Right Stick Down
+ 001000000: SL Left Joy-Con
+ 002000000: SR Left Joy-Con
+ 004000000: SL Right Joy-Con
+ 008000000: SR Right Joy-Con
+ 010000000: Top button on Poké Ball Plus (Palma) controller
+ 020000000: Verification
+ 040000000: B button on Left NES/HVC controller in Handheld mode
+ 080000000: Left C button in N64 controller
+ 100000000: Up C button in N64 controller
+ 200000000: Right C button in N64 controller
+ 400000000: Down C button in N64 controller
+ 00000000 00000001: A
+ 00000000 00000002: B
+ 00000000 00000004: X
+ 00000000 00000008: Y
+ 00000000 00000010: Left Stick Pressed
+ 00000000 00000020: Right Stick Pressed
+ 00000000 00000040: L
+ 00000000 00000080: R
+ 00000000 00000100: ZL
+ 00000000 00000200: ZR
+ 00000000 00000400: Plus
+ 00000000 00000800: Minus
+ 00000000 00001000: Left
+ 00000000 00002000: Up
+ 00000000 00004000: Right
+ 00000000 00008000: Down
+ 00000000 00010000: Left Stick Left
+ 00000000 00020000: Left Stick Up
+ 00000000 00040000: Left Stick Right
+ 00000000 00080000: Left Stick Down
+ 00000000 00100000: Right Stick Left
+ 00000000 00200000: Right Stick Up
+ 00000000 00400000: Right Stick Right
+ 00000000 00800000: Right Stick Down
+ 00000000 01000000: SL Left Joy-Con
+ 00000000 02000000: SR Left Joy-Con
+ 00000000 04000000: SL Right Joy-Con
+ 00000000 08000000: SR Right Joy-Con
+ 00000000 10000000: Top button on Poké Ball Plus (Palma) controller
+ 00000000 20000000: Verification
+ 00000000 40000000: B button on Left NES/HVC controller in Handheld mode
+ 00000000 80000000: Left C button in N64 controller
+ 00000001 00000000: Up C button in N64 controller
+ 00000002 00000000: Right C button in N64 controller
+ 00000004 00000000: Down C button in N64 controller
### Code Type 0xF0: Double Extended-Width Instruction
Code Type 0xF0 signals to the VM to treat the upper three nybbles of the first dword as instruction type, instead of just the upper nybble.

4
emummc/.gitrepo vendored
View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/m4xw/emummc
branch = develop
commit = d248ea6f700c3e6987549e30a1e2eeb609ce9f8c
parent = 9112461620330ba73a74926edd4c08b3cc0310f0
commit = 3c57b20ba3820ec87d7dd239d6fcf9ba97510606
parent = d61ee942d9b34cadd80464d5d549c5e2e5bf1689
method = merge
cmdver = 0.4.1

2
emummc/README.md vendored
View File

@@ -2,7 +2,7 @@
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
### Supported Horizon Versions
**1.0.0 - 19.0.0**
**1.0.0 - 21.0.0**
## Features
* Arbitrary SDMMC backend selection

View File

@@ -75,6 +75,12 @@
#include "offsets/1810_exfat.h"
#include "offsets/1900.h"
#include "offsets/1900_exfat.h"
#include "offsets/2000.h"
#include "offsets/2000_exfat.h"
#include "offsets/2010.h"
#include "offsets/2010_exfat.h"
#include "offsets/2100.h"
#include "offsets/2100_exfat.h"
#include "../utils/fatal.h"
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
@@ -161,6 +167,12 @@ DEFINE_OFFSET_STRUCT(_1810);
DEFINE_OFFSET_STRUCT(_1810_EXFAT);
DEFINE_OFFSET_STRUCT(_1900);
DEFINE_OFFSET_STRUCT(_1900_EXFAT);
DEFINE_OFFSET_STRUCT(_2000);
DEFINE_OFFSET_STRUCT(_2000_EXFAT);
DEFINE_OFFSET_STRUCT(_2010);
DEFINE_OFFSET_STRUCT(_2010_EXFAT);
DEFINE_OFFSET_STRUCT(_2100);
DEFINE_OFFSET_STRUCT(_2100_EXFAT);
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
switch (version) {
@@ -282,6 +294,18 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
return &(GET_OFFSET_STRUCT_NAME(_1900));
case FS_VER_19_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_1900_EXFAT));
case FS_VER_20_0_0:
return &(GET_OFFSET_STRUCT_NAME(_2000));
case FS_VER_20_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_2000_EXFAT));
case FS_VER_20_1_0:
return &(GET_OFFSET_STRUCT_NAME(_2010));
case FS_VER_20_1_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_2010_EXFAT));
case FS_VER_21_0_0:
return &(GET_OFFSET_STRUCT_NAME(_2100));
case FS_VER_21_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_2100_EXFAT));
default:
fatal_abort(Fatal_UnknownVersion);
}

View File

@@ -110,6 +110,15 @@ enum FS_VER
FS_VER_19_0_0,
FS_VER_19_0_0_EXFAT,
FS_VER_20_0_0,
FS_VER_20_0_0_EXFAT,
FS_VER_20_1_0,
FS_VER_20_1_0_EXFAT,
FS_VER_21_0_0,
FS_VER_21_0_0_EXFAT,
FS_VER_MAX,
};

59
emummc/source/FS/offsets/2000.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_2000_H__
#define __FS_2000_H__
// Accessor vtable getters
#define FS_OFFSET_2000_SDMMC_ACCESSOR_GC 0x1A7DB0
#define FS_OFFSET_2000_SDMMC_ACCESSOR_SD 0x1AA130
#define FS_OFFSET_2000_SDMMC_ACCESSOR_NAND 0x1A8560
// Hooks
#define FS_OFFSET_2000_SDMMC_WRAPPER_READ 0x1A3C20
#define FS_OFFSET_2000_SDMMC_WRAPPER_WRITE 0x1A3C80
#define FS_OFFSET_2000_RTLD 0x2B594
#define FS_OFFSET_2000_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2000_CLKRST_SET_MIN_V_CLK_RATE 0x1C6150
// Misc funcs
#define FS_OFFSET_2000_LOCK_MUTEX 0x19CD80
#define FS_OFFSET_2000_UNLOCK_MUTEX 0x19CDD0
#define FS_OFFSET_2000_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1A3BE0
#define FS_OFFSET_2000_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1A3C00
// Misc Data
#define FS_OFFSET_2000_SD_MUTEX 0xFF5408
#define FS_OFFSET_2000_NAND_MUTEX 0xFF0CF0
#define FS_OFFSET_2000_ACTIVE_PARTITION 0xFF0D30
#define FS_OFFSET_2000_SDMMC_DAS_HANDLE 0xFD2B08
// NOPs
#define FS_OFFSET_2000_SD_DAS_INIT 0x289F4
// Nintendo Paths
#define FS_OFFSET_2000_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x0006DB14, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x0007CE1C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x00084A08, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0009AE48, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_2000_H__

59
emummc/source/FS/offsets/2000_exfat.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_2000_EXFAT_H__
#define __FS_2000_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_2000_EXFAT_SDMMC_ACCESSOR_GC 0x1B36D0
#define FS_OFFSET_2000_EXFAT_SDMMC_ACCESSOR_SD 0x1B5A50
#define FS_OFFSET_2000_EXFAT_SDMMC_ACCESSOR_NAND 0x1B3E80
// Hooks
#define FS_OFFSET_2000_EXFAT_SDMMC_WRAPPER_READ 0x1AF540
#define FS_OFFSET_2000_EXFAT_SDMMC_WRAPPER_WRITE 0x1AF5A0
#define FS_OFFSET_2000_EXFAT_RTLD 0x2B594
#define FS_OFFSET_2000_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2000_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1D1A70
// Misc funcs
#define FS_OFFSET_2000_EXFAT_LOCK_MUTEX 0x1A86A0
#define FS_OFFSET_2000_EXFAT_UNLOCK_MUTEX 0x1A86F0
#define FS_OFFSET_2000_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1AF500
#define FS_OFFSET_2000_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1AF520
// Misc Data
#define FS_OFFSET_2000_EXFAT_SD_MUTEX 0x1006408
#define FS_OFFSET_2000_EXFAT_NAND_MUTEX 0x1001CF0
#define FS_OFFSET_2000_EXFAT_ACTIVE_PARTITION 0x1001D30
#define FS_OFFSET_2000_EXFAT_SDMMC_DAS_HANDLE 0xFDFB08
// NOPs
#define FS_OFFSET_2000_EXFAT_SD_DAS_INIT 0x289F4
// Nintendo Paths
#define FS_OFFSET_2000_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x0006DB14, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x0007CE1C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x00084A08, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0009AE48, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_2000_EXFAT_H__

59
emummc/source/FS/offsets/2010.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_2010_H__
#define __FS_2010_H__
// Accessor vtable getters
#define FS_OFFSET_2010_SDMMC_ACCESSOR_GC 0x1A7DB0
#define FS_OFFSET_2010_SDMMC_ACCESSOR_SD 0x1AA130
#define FS_OFFSET_2010_SDMMC_ACCESSOR_NAND 0x1A8560
// Hooks
#define FS_OFFSET_2010_SDMMC_WRAPPER_READ 0x1A3C20
#define FS_OFFSET_2010_SDMMC_WRAPPER_WRITE 0x1A3C80
#define FS_OFFSET_2010_RTLD 0x2B594
#define FS_OFFSET_2010_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2010_CLKRST_SET_MIN_V_CLK_RATE 0x1C6150
// Misc funcs
#define FS_OFFSET_2010_LOCK_MUTEX 0x19CD80
#define FS_OFFSET_2010_UNLOCK_MUTEX 0x19CDD0
#define FS_OFFSET_2010_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1A3BE0
#define FS_OFFSET_2010_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1A3C00
// Misc Data
#define FS_OFFSET_2010_SD_MUTEX 0xFF5408
#define FS_OFFSET_2010_NAND_MUTEX 0xFF0CF0
#define FS_OFFSET_2010_ACTIVE_PARTITION 0xFF0D30
#define FS_OFFSET_2010_SDMMC_DAS_HANDLE 0xFD2B08
// NOPs
#define FS_OFFSET_2010_SD_DAS_INIT 0x289F4
// Nintendo Paths
#define FS_OFFSET_2010_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x0006DB14, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x0007CE1C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x00084A08, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0009AE48, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_2010_H__

59
emummc/source/FS/offsets/2010_exfat.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_2010_EXFAT_H__
#define __FS_2010_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_2010_EXFAT_SDMMC_ACCESSOR_GC 0x1B36D0
#define FS_OFFSET_2010_EXFAT_SDMMC_ACCESSOR_SD 0x1B5A50
#define FS_OFFSET_2010_EXFAT_SDMMC_ACCESSOR_NAND 0x1B3E80
// Hooks
#define FS_OFFSET_2010_EXFAT_SDMMC_WRAPPER_READ 0x1AF540
#define FS_OFFSET_2010_EXFAT_SDMMC_WRAPPER_WRITE 0x1AF5A0
#define FS_OFFSET_2010_EXFAT_RTLD 0x2B594
#define FS_OFFSET_2010_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2010_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1D1A70
// Misc funcs
#define FS_OFFSET_2010_EXFAT_LOCK_MUTEX 0x1A86A0
#define FS_OFFSET_2010_EXFAT_UNLOCK_MUTEX 0x1A86F0
#define FS_OFFSET_2010_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1AF500
#define FS_OFFSET_2010_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1AF520
// Misc Data
#define FS_OFFSET_2010_EXFAT_SD_MUTEX 0x1006408
#define FS_OFFSET_2010_EXFAT_NAND_MUTEX 0x1001CF0
#define FS_OFFSET_2010_EXFAT_ACTIVE_PARTITION 0x1001D30
#define FS_OFFSET_2010_EXFAT_SDMMC_DAS_HANDLE 0xFDFB08
// NOPs
#define FS_OFFSET_2010_EXFAT_SD_DAS_INIT 0x289F4
// Nintendo Paths
#define FS_OFFSET_2010_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x0006DB14, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x0007CE1C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x00084A08, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0009AE48, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_2010_EXFAT_H__

59
emummc/source/FS/offsets/2100.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_2100_H__
#define __FS_2100_H__
// Accessor vtable getters
#define FS_OFFSET_2100_SDMMC_ACCESSOR_GC 0x1AC970
#define FS_OFFSET_2100_SDMMC_ACCESSOR_SD 0x1AE980
#define FS_OFFSET_2100_SDMMC_ACCESSOR_NAND 0x1ACFA0
// Hooks
#define FS_OFFSET_2100_SDMMC_WRAPPER_READ 0x1A8850
#define FS_OFFSET_2100_SDMMC_WRAPPER_WRITE 0x1A88B0
#define FS_OFFSET_2100_RTLD 0x2E1C0
#define FS_OFFSET_2100_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2100_CLKRST_SET_MIN_V_CLK_RATE 0x1CB9B0
// Misc funcs
#define FS_OFFSET_2100_LOCK_MUTEX 0x1A17D0
#define FS_OFFSET_2100_UNLOCK_MUTEX 0x1A1830
#define FS_OFFSET_2100_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1A8810
#define FS_OFFSET_2100_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1A8830
// Misc Data
#define FS_OFFSET_2100_SD_MUTEX 0xFEE408
#define FS_OFFSET_2100_NAND_MUTEX 0xFE9CF0
#define FS_OFFSET_2100_ACTIVE_PARTITION 0xFE9D30
#define FS_OFFSET_2100_SDMMC_DAS_HANDLE 0xFCBB18
// NOPs
#define FS_OFFSET_2100_SD_DAS_INIT 0x2B5C8
// Nintendo Paths
#define FS_OFFSET_2100_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x000718CC, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x000824F4, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008AF18, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x000A0B8C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_2100_H__

59
emummc/source/FS/offsets/2100_exfat.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_2100_EXFAT_EXFAT_H__
#define __FS_2100_EXFAT_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_2100_EXFAT_SDMMC_ACCESSOR_GC 0x1B7AD0
#define FS_OFFSET_2100_EXFAT_SDMMC_ACCESSOR_SD 0x1B9AE0
#define FS_OFFSET_2100_EXFAT_SDMMC_ACCESSOR_NAND 0x1B8100
// Hooks
#define FS_OFFSET_2100_EXFAT_SDMMC_WRAPPER_READ 0x1B39B0
#define FS_OFFSET_2100_EXFAT_SDMMC_WRAPPER_WRITE 0x1B3A10
#define FS_OFFSET_2100_EXFAT_RTLD 0x2E1C0
#define FS_OFFSET_2100_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2100_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1D6B10
// Misc funcs
#define FS_OFFSET_2100_EXFAT_LOCK_MUTEX 0x1AC930
#define FS_OFFSET_2100_EXFAT_UNLOCK_MUTEX 0x1AC990
#define FS_OFFSET_2100_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1B3970
#define FS_OFFSET_2100_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1B3990
// Misc Data
#define FS_OFFSET_2100_EXFAT_SD_MUTEX 0xFFF408
#define FS_OFFSET_2100_EXFAT_NAND_MUTEX 0xFFACF0
#define FS_OFFSET_2100_EXFAT_ACTIVE_PARTITION 0xFFAD30
#define FS_OFFSET_2100_EXFAT_SDMMC_DAS_HANDLE 0xFD8B18
// NOPs
#define FS_OFFSET_2100_EXFAT_SD_DAS_INIT 0x2B5C8
// Nintendo Paths
#define FS_OFFSET_2100_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x000718CC, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x000824F4, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008AF18, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x000A0B8C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_2100_EXFAT_EXFAT_H__

View File

@@ -70,6 +70,6 @@ clean:
@$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk clean
@$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))"
@rm -fr $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
@for i in $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR); do [ -d $$i ] && rmdir --ignore-fail-on-non-empty $$i || true; done
@for i in $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR); do [ -d $$i ] && rmdir $$i 2>/dev/null || true; done
.PHONY: all clean check_lib check_boot_lib check_loader_stub check_program check_mariko_fatal check_warmboot

View File

@@ -119,7 +119,7 @@ DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
$(OUTPUT).lz4 : $(OUTPUT).bin
@python $(CURRENT_DIRECTORY)/split_program.py $(OUTPUT).bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
$(SILENTCMD)$(PYTHON) $(CURRENT_DIRECTORY)/split_program.py $(OUTPUT).bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
@echo built ... $(notdir $@)
$(OUTPUT).bin : $(OUTPUT).elf

View File

@@ -85,10 +85,10 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
/* We can get away with only including latest because exosphere supports newer-than-expected master key in engine. */
/* TODO: Update on next change of keys. */
/* Mariko Development Master Kek Source. */
.byte 0x65, 0x7B, 0x11, 0x46, 0x0E, 0xC2, 0x22, 0x5D, 0xB9, 0xF1, 0xF5, 0x00, 0xF9, 0x3E, 0x1F, 0x70
.byte 0x11, 0x1C, 0x13, 0x90, 0xD9, 0x5E, 0xB0, 0xA2, 0xE3, 0xD0, 0x0E, 0x5D, 0xC4, 0xFB, 0x9E, 0xDB
/* Mariko Production Master Kek Source. */
.byte 0x31, 0xBE, 0x25, 0xFB, 0xDB, 0xB4, 0xEE, 0x49, 0x5C, 0x77, 0x05, 0xC2, 0x36, 0x9F, 0x34, 0x80
.byte 0xEB, 0xF3, 0x5B, 0x2D, 0x4A, 0x2D, 0xCE, 0x45, 0x3A, 0x6F, 0x61, 0x38, 0x0B, 0x00, 0x3B, 0x46
/* Development Master Key Vectors. */
.byte 0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE /* Zeroes encrypted with Master Key 00. */
@@ -110,6 +110,8 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0x39, 0x1E, 0x7E, 0xF8, 0x7E, 0x73, 0xEA, 0x6F, 0xAF, 0x00, 0x3A, 0xB4, 0xAA, 0xB8, 0xB7, 0x59 /* Master key 0F encrypted with Master key 10. */
.byte 0x0C, 0x75, 0x39, 0x15, 0x53, 0xEA, 0x81, 0x11, 0xA3, 0xE0, 0xDC, 0x3D, 0x0E, 0x76, 0xC6, 0xB8 /* Master key 10 encrypted with Master key 11. */
.byte 0x90, 0x64, 0xF9, 0x08, 0x29, 0x88, 0xD4, 0xDC, 0x73, 0xA4, 0xA1, 0x13, 0x9E, 0x59, 0x85, 0xA0 /* Master key 11 encrypted with Master key 12. */
.byte 0x94, 0x46, 0x3B, 0xFA, 0x7D, 0xB9, 0xE2, 0x94, 0xC2, 0x9D, 0xB9, 0xA4, 0xB2, 0x56, 0xCA, 0xFE /* Master key 12 encrypted with Master key 13. */
.byte 0x74, 0xB2, 0x5F, 0xA0, 0x4B, 0x74, 0x6D, 0x47, 0x5B, 0xA9, 0xF5, 0x26, 0x46, 0xD7, 0x4B, 0x6E /* Master key 13 encrypted with Master key 14. */
/* Production Master Key Vectors. */
.byte 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D /* Zeroes encrypted with Master Key 00. */
@@ -131,6 +133,8 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD /* Master key 0F encrypted with Master key 10. */
.byte 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 /* Master key 10 encrypted with Master key 11. */
.byte 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 /* Master key 11 encrypted with Master key 12. */
.byte 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 /* Master key 12 encrypted with Master key 13. */
.byte 0xF7, 0x92, 0xC0, 0xEC, 0xF3, 0xA4, 0x8C, 0xB7, 0x0D, 0xB3, 0xF3, 0xAB, 0x10, 0x9B, 0x18, 0xBA /* Master key 13 encrypted with Master key 14. */
/* Device Master Key Source Sources. */
.byte 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D /* 4.0.0 Device Master Key Source Source. */
@@ -149,6 +153,8 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0xDA, 0xB9, 0xD6, 0x77, 0x52, 0x2D, 0x1F, 0x78, 0x73, 0xC9, 0x98, 0x5B, 0x06, 0xFE, 0xA0, 0x52 /* 17.0.0 Device Master Key Source Source. */
.byte 0x14, 0xF5, 0xA5, 0xD0, 0x73, 0x6D, 0x44, 0x80, 0x5F, 0x31, 0x5A, 0x8F, 0x1E, 0xD4, 0x0D, 0x63 /* 18.0.0 Device Master Key Source Source. */
.byte 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 /* 19.0.0 Device Master Key Source Source. */
.byte 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 /* 20.0.0 Device Master Key Source Source. */
.byte 0xF9, 0x62, 0x05, 0x99, 0xE0, 0xB9, 0xA6, 0x9B, 0x9D, 0xAA, 0xB4, 0x12, 0x0B, 0x0F, 0xF5, 0x8F /* 21.0.0 Device Master Key Source Source. */
/* Development Device Master Kek Sources. */
.byte 0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34 /* 4.0.0 Device Master Kek Source. */
@@ -167,6 +173,8 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0x4E, 0xCE, 0x7B, 0x2A, 0xEA, 0x2E, 0x3D, 0x16, 0xD5, 0x2A, 0xDE, 0xF6, 0xF8, 0x6A, 0x7D, 0x43 /* 17.0.0 Device Master Kek Source. */
.byte 0x3B, 0x00, 0x89, 0xD7, 0xA9, 0x9E, 0xB7, 0x70, 0x86, 0x00, 0xC3, 0x49, 0x52, 0x8C, 0xA4, 0xAF /* 18.0.0 Device Master Kek Source. */
.byte 0xAE, 0x78, 0x36, 0xB6, 0x91, 0xEB, 0xAF, 0x9C, 0x18, 0xF1, 0xC0, 0xD5, 0x8A, 0x0C, 0x7C, 0xA1 /* 19.0.0 Device Master Kek Source. */
.byte 0x09, 0x12, 0x4F, 0x26, 0x90, 0xB9, 0xA6, 0xF5, 0xA5, 0x18, 0x74, 0xB6, 0x8D, 0x80, 0x59, 0x3D /* 20.0.0 Device Master Kek Source. */
.byte 0x7A, 0x4C, 0x38, 0xB7, 0x03, 0x6B, 0x1E, 0x81, 0x20, 0x53, 0x14, 0x99, 0xA4, 0x21, 0x92, 0x9F /* 21.0.0 Device Master Kek Source. */
/* Production Device Master Kek Sources. */
.byte 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D /* 4.0.0 Device Master Kek Source. */
@@ -185,3 +193,5 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0x21, 0xD6, 0x35, 0xF1, 0x0F, 0x7A, 0xF0, 0x5D, 0xDF, 0x79, 0x1C, 0x7A, 0xE4, 0x32, 0x82, 0x9E /* 17.0.0 Device Master Kek Source. */
.byte 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B /* 18.0.0 Device Master Kek Source. */
.byte 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F /* 19.0.0 Device Master Kek Source. */
.byte 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 /* 20.0.0 Device Master Kek Source. */
.byte 0x92, 0xBF, 0x37, 0x80, 0x0E, 0x79, 0x56, 0x8C, 0x57, 0x75, 0x72, 0x0A, 0x48, 0xD8, 0x15, 0x39 /* 21.0.0 Device Master Kek Source. */

View File

@@ -94,7 +94,7 @@ namespace ams::secmon::boot {
}
/* Check that the key generation is one that we can use. */
static_assert(pkg1::KeyGeneration_Count == 19);
static_assert(pkg1::KeyGeneration_Count == 21);
if (key_generation >= pkg1::KeyGeneration_Count) {
return false;
}

View File

@@ -101,10 +101,10 @@ namespace ams::secmon::smc {
#include "secmon_define_mc01_access_table.inc"
constexpr const AccessTableEntry AccessTables[] = {
{ PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
{ McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
{ PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
{ McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
};
constexpr bool IsAccessAllowed(const AccessTableEntry &entry, uintptr_t address) {

View File

@@ -43,6 +43,6 @@ clean:
@$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/loader_stub -f $(CURRENT_DIRECTORY)/loader_stub/loader_stub.mk clean
@$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/program -f $(CURRENT_DIRECTORY)/program/program.mk clean
@rm -fr $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
@for i in $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR); do [ -d $$i ] && rmdir --ignore-fail-on-non-empty $$i || true; done
@for i in $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR); do [ -d $$i ] && rmdir $$i 2>/dev/null || true; done
.PHONY: all clean check_lib check_loader_stub check_program

View File

@@ -84,7 +84,7 @@ DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
$(OUTPUT).lz4 : $(OUTPUT).bin
@python $(CURRENT_DIRECTORY)/lz4_compress.py $(OUTPUT).bin $(OUTPUT).lz4
$(SILENTCMD)$(PYTHON) $(CURRENT_DIRECTORY)/lz4_compress.py $(OUTPUT).bin $(OUTPUT).lz4
@echo built ... $(notdir $@)
$(OUTPUT).bin : $(OUTPUT).elf

View File

@@ -23,17 +23,17 @@ namespace ams::nxboot {
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSource[se::AesBlockSize] = {
/* TODO: Update on next change of keys. */
0x31, 0xBE, 0x25, 0xFB, 0xDB, 0xB4, 0xEE, 0x49, 0x5C, 0x77, 0x05, 0xC2, 0x36, 0x9F, 0x34, 0x80
0xEB, 0xF3, 0x5B, 0x2D, 0x4A, 0x2D, 0xCE, 0x45, 0x3A, 0x6F, 0x61, 0x38, 0x0B, 0x00, 0x3B, 0x46
};
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = {
/* TODO: Update on next change of keys. */
0x65, 0x7B, 0x11, 0x46, 0x0E, 0xC2, 0x22, 0x5D, 0xB9, 0xF1, 0xF5, 0x00, 0xF9, 0x3E, 0x1F, 0x70
0x11, 0x1C, 0x13, 0x90, 0xD9, 0x5E, 0xB0, 0xA2, 0xE3, 0xD0, 0x0E, 0x5D, 0xC4, 0xFB, 0x9E, 0xDB
};
alignas(se::AesBlockSize) constexpr inline const u8 EristaMasterKekSource[se::AesBlockSize] = {
/* TODO: Update on next change of keys. */
0xD7, 0x63, 0x74, 0x46, 0x4E, 0xBA, 0x78, 0x0A, 0x7C, 0x9D, 0xB3, 0xE8, 0x7A, 0x3D, 0x71, 0xE3
0x66, 0xC8, 0xCB, 0x3D, 0xEC, 0xF4, 0x59, 0x73, 0x54, 0x88, 0xE1, 0x2E, 0xE6, 0x3D, 0x68, 0x46
};
alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = {
@@ -73,6 +73,8 @@ namespace ams::nxboot {
{ 0xDA, 0xB9, 0xD6, 0x77, 0x52, 0x2D, 0x1F, 0x78, 0x73, 0xC9, 0x98, 0x5B, 0x06, 0xFE, 0xA0, 0x52 }, /* 17.0.0 Device Master Key Source Source. */
{ 0x14, 0xF5, 0xA5, 0xD0, 0x73, 0x6D, 0x44, 0x80, 0x5F, 0x31, 0x5A, 0x8F, 0x1E, 0xD4, 0x0D, 0x63 }, /* 18.0.0 Device Master Key Source Source. */
{ 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 }, /* 19.0.0 Device Master Key Source Source. */
{ 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 }, /* 20.0.0 Device Master Key Source Source. */
{ 0xF9, 0x62, 0x05, 0x99, 0xE0, 0xB9, 0xA6, 0x9B, 0x9D, 0xAA, 0xB4, 0x12, 0x0B, 0x0F, 0xF5, 0x8F }, /* 21.0.0 Device Master Key Source Source. */
};
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
@@ -92,6 +94,8 @@ namespace ams::nxboot {
{ 0x21, 0xD6, 0x35, 0xF1, 0x0F, 0x7A, 0xF0, 0x5D, 0xDF, 0x79, 0x1C, 0x7A, 0xE4, 0x32, 0x82, 0x9E }, /* 17.0.0 Device Master Kek Source. */
{ 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B }, /* 18.0.0 Device Master Kek Source. */
{ 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F }, /* 19.0.0 Device Master Kek Source. */
{ 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 }, /* 20.0.0 Device Master Kek Source. */
{ 0x92, 0xBF, 0x37, 0x80, 0x0E, 0x79, 0x56, 0x8C, 0x57, 0x75, 0x72, 0x0A, 0x48, 0xD8, 0x15, 0x39 }, /* 21.0.0 Device Master Kek Source. */
};
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
@@ -111,6 +115,8 @@ namespace ams::nxboot {
{ 0x4E, 0xCE, 0x7B, 0x2A, 0xEA, 0x2E, 0x3D, 0x16, 0xD5, 0x2A, 0xDE, 0xF6, 0xF8, 0x6A, 0x7D, 0x43 }, /* 17.0.0 Device Master Kek Source. */
{ 0x3B, 0x00, 0x89, 0xD7, 0xA9, 0x9E, 0xB7, 0x70, 0x86, 0x00, 0xC3, 0x49, 0x52, 0x8C, 0xA4, 0xAF }, /* 18.0.0 Device Master Kek Source. */
{ 0xAE, 0x78, 0x36, 0xB6, 0x91, 0xEB, 0xAF, 0x9C, 0x18, 0xF1, 0xC0, 0xD5, 0x8A, 0x0C, 0x7C, 0xA1 }, /* 19.0.0 Device Master Kek Source. */
{ 0x09, 0x12, 0x4F, 0x26, 0x90, 0xB9, 0xA6, 0xF5, 0xA5, 0x18, 0x74, 0xB6, 0x8D, 0x80, 0x59, 0x3D }, /* 20.0.0 Device Master Kek Source. */
{ 0x7A, 0x4C, 0x38, 0xB7, 0x03, 0x6B, 0x1E, 0x81, 0x20, 0x53, 0x14, 0x99, 0xA4, 0x21, 0x92, 0x9F }, /* 21.0.0 Device Master Kek Source. */
};
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySources[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
@@ -133,6 +139,8 @@ namespace ams::nxboot {
{ 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD }, /* Master key 0F encrypted with Master key 10. */
{ 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 }, /* Master key 10 encrypted with Master key 11. */
{ 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 }, /* Master key 11 encrypted with Master key 12. */
{ 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 }, /* Master key 12 encrypted with Master key 13. */
{ 0xF7, 0x92, 0xC0, 0xEC, 0xF3, 0xA4, 0x8C, 0xB7, 0x0D, 0xB3, 0xF3, 0xAB, 0x10, 0x9B, 0x18, 0xBA }, /* Master key 13 encrypted with Master key 14. */
};
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySourcesDev[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
@@ -155,6 +163,8 @@ namespace ams::nxboot {
{ 0x39, 0x1E, 0x7E, 0xF8, 0x7E, 0x73, 0xEA, 0x6F, 0xAF, 0x00, 0x3A, 0xB4, 0xAA, 0xB8, 0xB7, 0x59 }, /* Master key 0F encrypted with Master key 10. */
{ 0x0C, 0x75, 0x39, 0x15, 0x53, 0xEA, 0x81, 0x11, 0xA3, 0xE0, 0xDC, 0x3D, 0x0E, 0x76, 0xC6, 0xB8 }, /* Master key 10 encrypted with Master key 11. */
{ 0x90, 0x64, 0xF9, 0x08, 0x29, 0x88, 0xD4, 0xDC, 0x73, 0xA4, 0xA1, 0x13, 0x9E, 0x59, 0x85, 0xA0 }, /* Master key 11 encrypted with Master key 12. */
{ 0x94, 0x46, 0x3B, 0xFA, 0x7D, 0xB9, 0xE2, 0x94, 0xC2, 0x9D, 0xB9, 0xA4, 0xB2, 0x56, 0xCA, 0xFE }, /* Master key 12 encrypted with Master key 13. */
{ 0x74, 0xB2, 0x5F, 0xA0, 0x4B, 0x74, 0x6D, 0x47, 0x5B, 0xA9, 0xF5, 0x26, 0x46, 0xD7, 0x4B, 0x6E }, /* Master key 13 encrypted with Master key 14. */
};
alignas(se::AesBlockSize) constinit u8 MasterKeys[pkg1::OldMasterKeyCount][se::AesBlockSize] = {};

View File

@@ -80,7 +80,7 @@ namespace ams::nxboot {
}
/* Check that the key generation is one that we can use. */
static_assert(pkg1::KeyGeneration_Count == 19);
static_assert(pkg1::KeyGeneration_Count == 21);
if (key_generation >= pkg1::KeyGeneration_Count) {
return false;
}

View File

@@ -263,6 +263,10 @@ namespace ams::nxboot {
return ams::TargetFirmware_18_0_0;
} else if (std::memcmp(package1 + 0x10, "20240808", 8) == 0) {
return ams::TargetFirmware_19_0_0;
} else if (std::memcmp(package1 + 0x10, "20250206", 8) == 0) {
return ams::TargetFirmware_20_0_0;
} else if (std::memcmp(package1 + 0x10, "20251009", 8) == 0) {
return ams::TargetFirmware_21_0_0;
}
break;
default:
@@ -407,8 +411,9 @@ namespace ams::nxboot {
/* If we should, save the current warmboot firmware. */
UpdateWarmbootPath(expected_fuses);
if (!IsFileExist(warmboot_path)) {
fs::CreateDirectory("sdmc:/warmboot_mariko");
fs::CreateFile(warmboot_path, warmboot_src_size);
/* Try to create the directory/file, allowing them to fail (if already exist). */
static_cast<void>(fs::CreateDirectory("sdmc:/warmboot_mariko"));
static_cast<void>(fs::CreateFile(warmboot_path, warmboot_src_size));
Result result;
fs::FileHandle file;

View File

@@ -180,6 +180,15 @@ namespace ams::nxboot {
FsVersion_19_0_0,
FsVersion_19_0_0_Exfat,
FsVersion_20_0_0,
FsVersion_20_0_0_Exfat,
FsVersion_20_1_0,
FsVersion_20_1_0_Exfat,
FsVersion_21_0_0,
FsVersion_21_0_0_Exfat,
FsVersion_Count,
};
@@ -272,6 +281,15 @@ namespace ams::nxboot {
{ 0xD9, 0x4C, 0x68, 0x15, 0xF8, 0xF5, 0x0A, 0x20 }, /* FsVersion_19_0_0 */
{ 0xED, 0xA8, 0x78, 0x68, 0xA4, 0x49, 0x07, 0x50 }, /* FsVersion_19_0_0_Exfat */
{ 0x63, 0x54, 0x96, 0x9E, 0x60, 0xA7, 0x97, 0x7B }, /* FsVersion_20_0_0 */
{ 0x47, 0x41, 0x07, 0x10, 0x65, 0x4F, 0xA4, 0x3F }, /* FsVersion_20_0_0_Exfat */
{ 0xED, 0x34, 0xB4, 0x50, 0x58, 0x4A, 0x5B, 0x43 }, /* FsVersion_20_1_0 */
{ 0xA5, 0x1A, 0xA4, 0x92, 0x6C, 0x41, 0x87, 0x59 }, /* FsVersion_20_1_0_Exfat */
{ 0xEE, 0x4B, 0x30, 0x12, 0xA6, 0x84, 0x02, 0x25 }, /* FsVersion_21_0_0 */
{ 0x6E, 0x2B, 0xD9, 0xBA, 0xA3, 0xB9, 0x10, 0xF1 }, /* FsVersion_21_0_0_Exfat */
};
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
@@ -661,6 +679,28 @@ namespace ams::nxboot {
AddPatch(fs_meta, 0x1A16A5, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x17A9A0, NogcPatch1, sizeof(NogcPatch1));
break;
case FsVersion_20_0_0:
case FsVersion_20_1_0:
AddPatch(fs_meta, 0x1A7E25, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x1A8025, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x17C250, NogcPatch1, sizeof(NogcPatch1));
break;
case FsVersion_20_0_0_Exfat:
case FsVersion_20_1_0_Exfat:
AddPatch(fs_meta, 0x1B3745, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x1B3945, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x187B70, NogcPatch1, sizeof(NogcPatch1));
break;
case FsVersion_21_0_0:
AddPatch(fs_meta, 0x1AC9ED, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x1ACA05 , NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x17FBE0, NogcPatch1, sizeof(NogcPatch1));
break;
case FsVersion_21_0_0_Exfat:
AddPatch(fs_meta, 0x1B7B4D, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x1B7B65, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x18AD40, NogcPatch1, sizeof(NogcPatch1));
break;
default:
break;
}

BIN
img/np++.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = 989fb7be0c68bf229fe6789428b6c448b6de142a
parent = be19749841e581de4cc5d38f39f4de5fa4046c52
commit = 6cc765fcaa5f83b9cd6dc5b424bae31a0f33b29f
parent = 3cb5d5f957020d07f5bdb3fb89521f29bea5d79d
method = merge
cmdver = 0.4.1

View File

@@ -297,6 +297,23 @@ FIND_SOURCE_FILES=$(foreach dir,$1,$(filter-out $(notdir $(wildcard $(dir)/*.arc
ATMOSPHERE_GCH_IDENTIFIER := $(ATMOSPHERE_FULL_NAME)
#---------------------------------------------------------------------------------
# Python. The scripts should work with Python 2 or 3, but 2 is preferred.
#---------------------------------------------------------------------------------
PYTHON = $(shell command -v python >/dev/null && echo python || echo python3)
#---------------------------------------------------------------------------------
# Export MAKE:
# GCC's LTO driver invokes Make internally. This invocation respects both $(MAKE)
# and $(MAKEFLAGS), but only if they're in the environment. By default, MAKEFLAGS
# is in the environment while MAKE isn't, so GCC will always use the default
# `make` command, yet it inherits MAKEFLAGS from the copy of Make the user
# invoked, which might have incompatible flags. In practice this is an issue on
# macOS when running e.g. `gmake -j32 -Otarget`. This behavior is arguably a bug
# in GCC and/or Make, but we can work around it by exporting MAKE.
#---------------------------------------------------------------------------------
export MAKE
#---------------------------------------------------------------------------------
# Rules for compiling pre-compiled headers
#---------------------------------------------------------------------------------

View File

@@ -26,7 +26,7 @@ ATMOSPHERE_OPTIMIZATION_FLAG := -O2
endif
export DEFINES = $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_STRATOSPHERE -D_GNU_SOURCE
export SETTINGS = $(ATMOSPHERE_SETTINGS) $(ATMOSPHERE_OPTIMIZATION_FLAG) -Wextra -Werror -Wno-missing-field-initializers
export SETTINGS = $(ATMOSPHERE_SETTINGS) $(ATMOSPHERE_OPTIMIZATION_FLAG) -Wextra -Werror -Wno-missing-field-initializers -Wno-error=unused-result
export CFLAGS = $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
export CXXFLAGS = $(CFLAGS) $(ATMOSPHERE_CXXFLAGS)
export ASFLAGS = $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES)

View File

@@ -39,6 +39,8 @@ namespace ams::pkg1 {
KeyGeneration_17_0_0 = 0x10,
KeyGeneration_18_0_0 = 0x11,
KeyGeneration_19_0_0 = 0x12,
KeyGeneration_20_0_0 = 0x13,
KeyGeneration_21_0_0 = 0x14,
KeyGeneration_Count,

View File

@@ -24,7 +24,7 @@ namespace ams::pkg2 {
constexpr inline int PayloadCount = 3;
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x18 in Nintendo's code. */
constexpr inline int CurrentBootloaderVersion = 0x16;
constexpr inline int CurrentBootloaderVersion = 0x18;
struct Package2Meta {
using Magic = util::FourCC<'P','K','2','1'>;

View File

@@ -104,7 +104,7 @@ clean:
@echo clean $(ATMOSPHERE_BUILD_NAME) ...
@rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR)
@rm -fr $(foreach hdr,$(GCH_DIRS),$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER))
@for i in $(GCH_DIRS); do [ -d $$i ] && rmdir --ignore-fail-on-non-empty $$i || true; done
@for i in $(GCH_DIRS); do [ -d $$i ] && rmdir $$i 2>/dev/null || true; done
$(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(GCH_DIRS):
@[ -d $@ ] || mkdir -p $@

View File

@@ -177,6 +177,8 @@ namespace ams::fuse {
}
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
TargetFirmware_21_0_0,
TargetFirmware_20_0_0,
TargetFirmware_19_0_0,
TargetFirmware_17_0_0,
TargetFirmware_16_0_0,

View File

@@ -116,7 +116,9 @@ namespace ams::kern::arch::arm {
u32 ipriorityr[NumLocalInterrupts / 4];
u32 itargetsr[NumLocalInterrupts / 4];
u32 icfgr[NumLocalInterrupts / 16];
u32 spendsgir[4];
};
static_assert(sizeof(LocalState{}.spendsgir) == sizeof(GicDistributor{}.spendsgir));
struct GlobalState {
u32 isenabler[NumGlobalInterrupts / 32];

View File

@@ -83,9 +83,9 @@ 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 void UnbindHandler(s32 irq, s32 core);
NOINLINE Result ClearInterrupt(s32 irq, s32 core_id);
NOINLINE void ClearInterrupt(s32 irq, s32 core_id);
ALWAYS_INLINE void SendInterProcessorInterrupt(s32 irq, u64 core_mask) {
m_interrupt_controller.SendInterProcessorInterrupt(irq, core_mask);
@@ -99,10 +99,10 @@ namespace ams::kern::arch::arm64 {
private:
Result BindGlobal(KInterruptHandler *handler, s32 irq, s32 core_id, s32 priority, bool manual_clear, bool level);
Result BindLocal(KInterruptHandler *handler, s32 irq, s32 priority, bool manual_clear);
Result UnbindGlobal(s32 irq);
Result UnbindLocal(s32 irq);
Result ClearGlobal(s32 irq);
Result ClearLocal(s32 irq);
void UnbindGlobal(s32 irq);
void UnbindLocal(s32 irq);
void ClearGlobal(s32 irq);
void ClearLocal(s32 irq);
private:
[[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledState() {
u64 intr_state;

View File

@@ -197,9 +197,14 @@ namespace ams::kern::arch::arm64 {
cpu::SwitchProcess(s_ttbr0_entries[proc_idx + 1], proc_id);
}
NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
NOINLINE void InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index);
Result Finalize();
void Finalize();
static void NoteUpdatedCallback(const void *pt) {
/* Note the update. */
static_cast<const KPageTable *>(pt)->NoteUpdated();
}
private:
Result Unmap(KProcessAddress virt_addr, size_t num_pages, PageLinkedList *page_list, bool force, bool reuse_ll);

View File

@@ -49,6 +49,8 @@ namespace ams::kern::arch::arm64 {
EntryLevel level;
bool is_contiguous;
};
using EntryUpdatedCallback = void (*)(const void *);
private:
static constexpr size_t PageBits = util::CountTrailingZeros(PageSize);
static constexpr size_t NumLevels = 3;
@@ -144,8 +146,8 @@ namespace ams::kern::arch::arm64 {
bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const;
static bool MergePages(KVirtualAddress *out, TraversalContext *context);
void SeparatePages(TraversalEntry *entry, TraversalContext *context, KProcessAddress address, PageTableEntry *pte) const;
static bool MergePages(KVirtualAddress *out, TraversalContext *context, EntryUpdatedCallback on_entry_updated, const void *pt);
void SeparatePages(TraversalEntry *entry, TraversalContext *context, KProcessAddress address, PageTableEntry *pte, EntryUpdatedCallback on_entry_updated, const void *pt) const;
KProcessAddress GetAddressForContext(const TraversalContext *context) const {
KProcessAddress addr = m_is_kernel ? static_cast<uintptr_t>(-GetBlockSize(EntryLevel_L1)) * m_num_entries : 0;

View File

@@ -165,7 +165,7 @@ namespace ams::kern::arch::arm64 {
constexpr explicit KThreadContext(util::ConstantInitializeTag) : m_callee_saved(), m_lr(), m_sp(), m_fpcr(), m_fpsr(), m_callee_saved_fpu(), m_locked() { /* ... */ }
explicit KThreadContext() { /* ... */ }
Result Initialize(KVirtualAddress u_pc, KVirtualAddress k_sp, KVirtualAddress u_sp, uintptr_t arg, bool is_user, bool is_64_bit, bool is_main);
void Initialize(KVirtualAddress u_pc, KVirtualAddress k_sp, KVirtualAddress u_sp, uintptr_t arg, bool is_user, bool is_64_bit, bool is_main);
void SetArguments(uintptr_t arg0, uintptr_t arg1);

View File

@@ -22,49 +22,139 @@ namespace ams::kern::arch::arm64 {
class UserspaceAccess {
private:
static bool CopyMemoryFromUserSize32BitWithSupervisorAccessImpl(void *dst, const void *src);
class Impl {
public:
static bool CopyMemoryFromUser(void *dst, const void *src, size_t size);
static bool CopyMemoryFromUserAligned32Bit(void *dst, const void *src, size_t size);
static bool CopyMemoryFromUserAligned64Bit(void *dst, const void *src, size_t size);
static bool CopyMemoryFromUserSize64Bit(void *dst, const void *src);
static bool CopyMemoryFromUserSize32Bit(void *dst, const void *src);
static bool CopyMemoryFromUserSize32BitWithSupervisorAccess(void *dst, const void *src);
static s32 CopyStringFromUser(void *dst, const void *src, size_t size);
static bool CopyMemoryToUser(void *dst, const void *src, size_t size);
static bool CopyMemoryToUserAligned32Bit(void *dst, const void *src, size_t size);
static bool CopyMemoryToUserAligned64Bit(void *dst, const void *src, size_t size);
static bool CopyMemoryToUserSize32Bit(void *dst, u32 value);
static s32 CopyStringToUser(void *dst, const void *src, size_t size);
static bool UpdateLockAtomic(u32 *out, u32 *address, u32 if_zero, u32 new_orr_mask);
static bool UpdateIfEqualAtomic(s32 *out, s32 *address, s32 compare_value, s32 new_value);
static bool DecrementIfLessThanAtomic(s32 *out, s32 *address, s32 compare);
static bool StoreDataCache(uintptr_t start, uintptr_t end);
static bool FlushDataCache(uintptr_t start, uintptr_t end);
static bool InvalidateDataCache(uintptr_t start, uintptr_t end);
static bool ReadIoMemory32Bit(void *dst, const void *src, size_t size);
static bool ReadIoMemory16Bit(void *dst, const void *src, size_t size);
static bool ReadIoMemory8Bit(void *dst, const void *src, size_t size);
static bool WriteIoMemory32Bit(void *dst, const void *src, size_t size);
static bool WriteIoMemory16Bit(void *dst, const void *src, size_t size);
static bool WriteIoMemory8Bit(void *dst, const void *src, size_t size);
};
public:
static bool CopyMemoryFromUser(void *dst, const void *src, size_t size) {
return Impl::CopyMemoryFromUser(dst, src, size);
}
static bool CopyMemoryFromUserAligned32Bit(void *dst, const void *src, size_t size) {
return Impl::CopyMemoryFromUserAligned32Bit(dst, src, size);
}
static bool CopyMemoryFromUserAligned64Bit(void *dst, const void *src, size_t size) {
return Impl::CopyMemoryFromUserAligned64Bit(dst, src, size);
}
static bool CopyMemoryFromUserSize64Bit(void *dst, const void *src) {
return Impl::CopyMemoryFromUserSize64Bit(dst, src);
}
static bool CopyMemoryFromUserSize32Bit(void *dst, const void *src) {
return Impl::CopyMemoryFromUserSize32Bit(dst, src);
}
static bool CopyMemoryFromUserSize32BitWithSupervisorAccess(void *dst, const void *src) {
/* Check that the address is within the valid userspace range. */
if (const uintptr_t src_uptr = reinterpret_cast<uintptr_t>(src); src_uptr < ams::svc::AddressNullGuard32Size || (src_uptr + sizeof(u32) - 1) >= ams::svc::AddressMemoryRegion39Size) {
return false;
}
return CopyMemoryFromUserSize32BitWithSupervisorAccessImpl(dst, src);
return Impl::CopyMemoryFromUserSize32BitWithSupervisorAccess(dst, src);
}
static bool CopyMemoryFromUser(void *dst, const void *src, size_t size);
static bool CopyMemoryFromUserAligned32Bit(void *dst, const void *src, size_t size);
static bool CopyMemoryFromUserAligned64Bit(void *dst, const void *src, size_t size);
static bool CopyMemoryFromUserSize64Bit(void *dst, const void *src);
static bool CopyMemoryFromUserSize32Bit(void *dst, const void *src);
static s32 CopyStringFromUser(void *dst, const void *src, size_t size);
static s32 CopyStringFromUser(void *dst, const void *src, size_t size) {
return Impl::CopyStringFromUser(dst, src, size);
}
static bool CopyMemoryToUser(void *dst, const void *src, size_t size);
static bool CopyMemoryToUserAligned32Bit(void *dst, const void *src, size_t size);
static bool CopyMemoryToUserAligned64Bit(void *dst, const void *src, size_t size);
static bool CopyMemoryToUserSize32Bit(void *dst, const void *src);
static s32 CopyStringToUser(void *dst, const void *src, size_t size);
static bool CopyMemoryToUser(void *dst, const void *src, size_t size) {
return Impl::CopyMemoryToUser(dst, src, size);
}
static bool ClearMemory(void *dst, size_t size);
static bool ClearMemoryAligned32Bit(void *dst, size_t size);
static bool ClearMemoryAligned64Bit(void *dst, size_t size);
static bool ClearMemorySize32Bit(void *dst);
static bool CopyMemoryToUserAligned32Bit(void *dst, const void *src, size_t size) {
return Impl::CopyMemoryToUserAligned32Bit(dst, src, size);
}
static bool UpdateLockAtomic(u32 *out, u32 *address, u32 if_zero, u32 new_orr_mask);
static bool UpdateIfEqualAtomic(s32 *out, s32 *address, s32 compare_value, s32 new_value);
static bool DecrementIfLessThanAtomic(s32 *out, s32 *address, s32 compare);
static bool CopyMemoryToUserAligned64Bit(void *dst, const void *src, size_t size) {
return Impl::CopyMemoryToUserAligned64Bit(dst, src, size);
}
static bool StoreDataCache(uintptr_t start, uintptr_t end);
static bool FlushDataCache(uintptr_t start, uintptr_t end);
static bool InvalidateDataCache(uintptr_t start, uintptr_t end);
static bool CopyMemoryToUserSize32Bit(void *dst, u32 value) {
return Impl::CopyMemoryToUserSize32Bit(dst, value);
}
static bool ReadIoMemory32Bit(void *dst, const void *src, size_t size);
static bool ReadIoMemory16Bit(void *dst, const void *src, size_t size);
static bool ReadIoMemory8Bit(void *dst, const void *src, size_t size);
static bool WriteIoMemory32Bit(void *dst, const void *src, size_t size);
static bool WriteIoMemory16Bit(void *dst, const void *src, size_t size);
static bool WriteIoMemory8Bit(void *dst, const void *src, size_t size);
static s32 CopyStringToUser(void *dst, const void *src, size_t size) {
return Impl::CopyStringToUser(dst, src, size);
}
static bool UpdateLockAtomic(u32 *out, u32 *address, u32 if_zero, u32 new_orr_mask) {
return Impl::UpdateLockAtomic(out, address, if_zero, new_orr_mask);
}
static bool UpdateIfEqualAtomic(s32 *out, s32 *address, s32 compare_value, s32 new_value) {
return Impl::UpdateIfEqualAtomic(out, address, compare_value, new_value);
}
static bool DecrementIfLessThanAtomic(s32 *out, s32 *address, s32 compare) {
return Impl::DecrementIfLessThanAtomic(out, address, compare);
}
static bool StoreDataCache(uintptr_t start, uintptr_t end) {
return Impl::StoreDataCache(start, end);
}
static bool FlushDataCache(uintptr_t start, uintptr_t end) {
return Impl::FlushDataCache(start, end);
}
static bool InvalidateDataCache(uintptr_t start, uintptr_t end) {
return Impl::InvalidateDataCache(start, end);
}
static bool ReadIoMemory32Bit(void *dst, const void *src, size_t size) {
return Impl::ReadIoMemory32Bit(dst, src, size);
}
static bool ReadIoMemory16Bit(void *dst, const void *src, size_t size) {
return Impl::ReadIoMemory16Bit(dst, src, size);
}
static bool ReadIoMemory8Bit(void *dst, const void *src, size_t size) {
return Impl::ReadIoMemory8Bit(dst, src, size);
}
static bool WriteIoMemory32Bit(void *dst, const void *src, size_t size) {
return Impl::WriteIoMemory32Bit(dst, src, size);
}
static bool WriteIoMemory16Bit(void *dst, const void *src, size_t size) {
return Impl::WriteIoMemory16Bit(dst, src, size);
}
static bool WriteIoMemory8Bit(void *dst, const void *src, size_t size) {
return Impl::WriteIoMemory8Bit(dst, src, size);
}
};

View File

@@ -47,13 +47,6 @@
/* re-enabled by toggling this define. */
//#define MESOSPHERE_ENABLE_PROCESS_CREATION_TIME
/* NOTE: This enables fast class token storage using a class member. */
/* This saves a virtual call when doing KAutoObject->DynCast<>(), */
/* at the cost of storing class tokens inside the class object. */
/* However, as of (10/16/2021) KAutoObject has an unused class member */
/* of the right side, and so this does not actually cost any space. */
#define MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST
/* NOTE: This enables usage of KDebug handles as parameter for svc::GetInfo */
/* calls which require a process parameter. This enables a debugger to obtain */
/* address space/layout information, for example. However, it changes abi, and so */

View File

@@ -37,7 +37,7 @@ namespace ams::kern {
size_t m_size;
Type m_type;
public:
static uintptr_t GetAddressSpaceStart(ams::svc::CreateProcessFlag flags, Type type);
static uintptr_t GetAddressSpaceStart(ams::svc::CreateProcessFlag flags, Type type, size_t code_size);
static size_t GetAddressSpaceSize(ams::svc::CreateProcessFlag flags, Type type);
static void SetAddressSpaceSize(size_t width, Type type, size_t size);

View File

@@ -121,14 +121,9 @@ namespace ams::kern {
private:
KAutoObject *m_next_closed_object;
ReferenceCount m_ref_count;
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST)
ClassTokenType m_class_token;
#endif
public:
constexpr ALWAYS_INLINE explicit KAutoObject(util::ConstantInitializeTag) : m_next_closed_object(nullptr), m_ref_count(0)
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST)
, m_class_token(0)
#endif
constexpr ALWAYS_INLINE explicit KAutoObject(util::ConstantInitializeTag) : m_next_closed_object(nullptr), m_ref_count(0), m_class_token(0)
{
MESOSPHERE_ASSERT_THIS();
}
@@ -151,19 +146,11 @@ namespace ams::kern {
}
ALWAYS_INLINE bool IsDerivedFrom(const TypeObj &rhs) const {
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST)
return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.GetClassToken());
#else
return this->GetTypeObj().IsDerivedFrom(rhs);
#endif
return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.GetClassToken());
}
ALWAYS_INLINE bool IsDerivedFrom(const KAutoObject &rhs) const {
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST)
return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.m_class_token);
#else
return this->IsDerivedFrom(rhs.GetTypeObj());
#endif
return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.m_class_token);
}
template<typename Derived>
@@ -218,12 +205,10 @@ namespace ams::kern {
KAutoObject &auto_object = *static_cast<KAutoObject *>(obj);
/* If we should, set our class token. */
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST)
{
constexpr auto Token = Derived::GetStaticTypeObj().GetClassToken();
auto_object.m_class_token = Token;
}
#endif
/* Initialize reference count to 1. */
auto_object.m_ref_count = 1;

View File

@@ -93,9 +93,9 @@ namespace ams::kern {
static Result ProcessDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
public:
static Result OnDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
static Result OnExitProcess(KProcess *process);
static Result OnTerminateProcess(KProcess *process);
static Result OnExitThread(KThread *thread);
static void OnExitProcess(KProcess *process);
static void OnTerminateProcess(KProcess *process);
static void OnExitThread(KThread *thread);
static KEventInfo *CreateDebugEvent(ams::svc::DebugEvent event, u64 thread_id, const uintptr_t *params, size_t num_params);
};

View File

@@ -50,8 +50,8 @@ namespace ams::kern {
KReadableEvent &GetReadableEvent() { return m_readable_event; }
Result Signal();
Result Clear();
void Signal();
void Clear();
ALWAYS_INLINE void OnReadableEventDestroyed() { m_readable_event_destroyed = true; }
};

View File

@@ -105,7 +105,7 @@ namespace ams::kern {
constexpr ALWAYS_INLINE size_t GetCount() const { return m_count; }
constexpr ALWAYS_INLINE size_t GetMaxCount() const { return m_max_count; }
MESOSPHERE_NOINLINE_IF_DEBUG Result Finalize();
MESOSPHERE_NOINLINE_IF_DEBUG void Finalize();
MESOSPHERE_NOINLINE_IF_DEBUG bool Remove(ams::svc::Handle handle);
template<typename T = KAutoObject>

View File

@@ -38,13 +38,11 @@ namespace ams::kern {
Result Reset();
Result Clear() {
void Clear() {
MESOSPHERE_ASSERT_THIS();
/* Try to perform a reset, succeeding unconditionally. */
this->Reset();
R_SUCCEED();
/* Try to perform a reset, ignoring whether it succeeds. */
static_cast<void>(this->Reset());
}
bool IsInitialized() const { return m_is_initialized; }

View File

@@ -99,6 +99,7 @@ namespace ams::kern {
Result Initialize(KProcessAddress st, KProcessAddress nd, KMemoryBlockSlabManager *slab_manager);
void Finalize(KMemoryBlockSlabManager *slab_manager);
static bool GetRegionForFindFreeArea(KProcessAddress *out_start, KProcessAddress *out_end, KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages);
KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const;
void Update(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, KMemoryBlockDisableMergeAttribute clear_disable_attr);

View File

@@ -226,7 +226,7 @@ namespace ams::kern {
explicit KPageTableBase() { /* ... */ }
NOINLINE Result InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end);
NOINLINE void InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end);
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit);
void Finalize();

View File

@@ -269,7 +269,7 @@ namespace ams::kern {
void RemoveIoRegion(KIoRegion *io_region);
Result CreateThreadLocalRegion(KProcessAddress *out);
Result DeleteThreadLocalRegion(KProcessAddress addr);
void DeleteThreadLocalRegion(KProcessAddress addr);
void *GetThreadLocalRegionPointer(KProcessAddress addr);
constexpr KProcessAddress GetProcessLocalRegionAddress() const { return m_plr_address; }

View File

@@ -35,16 +35,14 @@ namespace ams::kern {
constexpr KEvent *GetParent() const { return m_parent; }
Result Signal();
void Signal();
Result Reset();
Result Clear() {
void Clear() {
MESOSPHERE_ASSERT_THIS();
/* Try to perform a reset, succeeding unconditionally. */
this->Reset();
R_SUCCEED();
/* Try to perform a reset, ignoring whether it succeeds. */
static_cast<void>(this->Reset());
}
virtual bool IsSignaled() const override;

View File

@@ -41,7 +41,7 @@ namespace ams::kern {
/* Nintendo uses std::mt19937_t for randomness. */
/* To save space (and because mt19337_t isn't secure anyway), */
/* We will use TinyMT. */
static constinit inline bool s_initialized_random_generator;
static constinit inline bool s_uninitialized_random_generator{true};
static constinit inline util::TinyMT s_random_generator{util::ConstantInitialize};
static constinit inline KSpinLock s_random_lock;
public:

View File

@@ -94,7 +94,11 @@ namespace ams::kern {
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
ALWAYS_INLINE size_t CalculateRequiredSecureMemorySize() const {
return CalculateRequiredSecureMemorySize(m_resource_size, m_resource_pool);
if (m_resource_limit != nullptr) {
return CalculateRequiredSecureMemorySize(m_resource_size, m_resource_pool);
} else {
return 0;
}
}
ALWAYS_INLINE size_t GetSize() const { return m_resource_size; }

View File

@@ -25,35 +25,35 @@ namespace ams::kern {
friend class KSystemControl;
private:
struct KTargetSystemData {
bool is_debug_mode;
bool enable_debug_logging;
bool enable_user_exception_handlers;
bool enable_debug_memory_fill;
bool enable_user_pmu_access;
bool enable_kernel_debugging;
bool enable_dynamic_resource_limits;
bool is_not_debug_mode;
bool disable_debug_logging;
bool disable_user_exception_handlers;
bool disable_debug_memory_fill;
bool disable_user_pmu_access;
bool disable_kernel_debugging;
bool disable_dynamic_resource_limits;
};
private:
static inline constinit bool s_is_initialized = false;
static inline constinit bool s_is_uninitialized = true;
static inline constinit const volatile KTargetSystemData s_data = {
.is_debug_mode = true,
.enable_debug_logging = true,
.enable_user_exception_handlers = true,
.enable_debug_memory_fill = true,
.enable_user_pmu_access = true,
.enable_kernel_debugging = true,
.enable_dynamic_resource_limits = false,
.is_not_debug_mode = false,
.disable_debug_logging = false,
.disable_user_exception_handlers = false,
.disable_debug_memory_fill = false,
.disable_user_pmu_access = false,
.disable_kernel_debugging = false,
.disable_dynamic_resource_limits = true,
};
private:
static ALWAYS_INLINE void SetInitialized() { s_is_initialized = true; }
static ALWAYS_INLINE void SetInitialized() { s_is_uninitialized = false; }
public:
static ALWAYS_INLINE bool IsDebugMode() { return s_is_initialized && s_data.is_debug_mode; }
static ALWAYS_INLINE bool IsDebugLoggingEnabled() { return s_is_initialized && s_data.enable_debug_logging; }
static ALWAYS_INLINE bool IsUserExceptionHandlersEnabled() { return s_is_initialized && s_data.enable_user_exception_handlers; }
static ALWAYS_INLINE bool IsDebugMemoryFillEnabled() { return s_is_initialized && s_data.enable_debug_memory_fill; }
static ALWAYS_INLINE bool IsUserPmuAccessEnabled() { return s_is_initialized && s_data.enable_user_pmu_access; }
static ALWAYS_INLINE bool IsKernelDebuggingEnabled() { return s_is_initialized && s_data.enable_kernel_debugging; }
static ALWAYS_INLINE bool IsDynamicResourceLimitsEnabled() { return s_is_initialized && s_data.enable_dynamic_resource_limits; }
static ALWAYS_INLINE bool IsDebugMode() { return !(s_is_uninitialized | s_data.is_not_debug_mode); }
static ALWAYS_INLINE bool IsDebugLoggingEnabled() { return !(s_is_uninitialized | s_data.disable_debug_logging); }
static ALWAYS_INLINE bool IsUserExceptionHandlersEnabled() { return !(s_is_uninitialized | s_data.disable_user_exception_handlers); }
static ALWAYS_INLINE bool IsDebugMemoryFillEnabled() { return !(s_is_uninitialized | s_data.disable_debug_memory_fill); }
static ALWAYS_INLINE bool IsUserPmuAccessEnabled() { return !(s_is_uninitialized | s_data.disable_user_pmu_access); }
static ALWAYS_INLINE bool IsKernelDebuggingEnabled() { return !(s_is_uninitialized | s_data.disable_kernel_debugging); }
static ALWAYS_INLINE bool IsDynamicResourceLimitsEnabled() { return !(s_is_uninitialized | s_data.disable_dynamic_resource_limits); }
};
}

View File

@@ -105,7 +105,7 @@ namespace ams::kern {
util::Atomic<u8> dpc_flags;
u8 current_svc_id;
u8 reserved_2c;
u8 exception_flags;
util::Atomic<u8> exception_flags;
bool is_pinned;
u8 reserved_2f;
u8 reserved_30[0x10];
@@ -417,17 +417,17 @@ namespace ams::kern {
private:
ALWAYS_INLINE void SetExceptionFlag(ExceptionFlag flag) {
MESOSPHERE_ASSERT_THIS();
this->GetStackParameters().exception_flags |= flag;
this->GetStackParameters().exception_flags.FetchOr<std::memory_order_relaxed>(flag);
}
ALWAYS_INLINE void ClearExceptionFlag(ExceptionFlag flag) {
MESOSPHERE_ASSERT_THIS();
this->GetStackParameters().exception_flags &= ~flag;
this->GetStackParameters().exception_flags.FetchAnd<std::memory_order_relaxed>(~flag);
}
ALWAYS_INLINE bool IsExceptionFlagSet(ExceptionFlag flag) const {
MESOSPHERE_ASSERT_THIS();
return this->GetStackParameters().exception_flags & flag;
return this->GetStackParameters().exception_flags.Load<std::memory_order_relaxed>() & flag;
}
public:
/* ALWAYS_INLINE void SetCallingSvc() { return this->SetExceptionFlag(ExceptionFlag_IsCallingSvc); } */
@@ -523,7 +523,7 @@ namespace ams::kern {
Result GetCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask);
Result SetCoreMask(int32_t ideal_core, u64 affinity_mask);
Result GetPhysicalCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask);
void GetPhysicalCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask);
constexpr ThreadState GetState() const { return static_cast<ThreadState>(m_thread_state & ThreadState_Mask); }
constexpr ThreadState GetRawState() const { return m_thread_state; }
@@ -717,7 +717,7 @@ namespace ams::kern {
}
void SetBasePriority(s32 priority);
Result SetPriorityToIdle();
void SetPriorityToIdle();
Result Run();
void Exit();
@@ -725,7 +725,7 @@ namespace ams::kern {
Result Terminate();
ThreadState RequestTerminate();
Result Sleep(s64 timeout);
void Sleep(s64 timeout);
ALWAYS_INLINE void *GetStackTop() const { return reinterpret_cast<StackParameters *>(m_kernel_stack_top) - 1; }
ALWAYS_INLINE void *GetKernelStackTop() const { return m_kernel_stack_top; }

View File

@@ -77,7 +77,7 @@ namespace ams::kern {
}
public:
Result Initialize(KProcess *process);
Result Finalize();
void Finalize();
KProcessAddress Reserve();
void Release(KProcessAddress addr);

View File

@@ -86,7 +86,7 @@ clean:
@echo clean $(ATMOSPHERE_BUILD_NAME) ...
@rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR)
@rm -fr $(foreach hdr,$(GCH_DIRS),$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER))
@for i in $(GCH_DIRS); do [ -d $$i ] && rmdir --ignore-fail-on-non-empty $$i || true; done
@for i in $(GCH_DIRS); do [ -d $$i ] && rmdir $$i 2>/dev/null || true; done
$(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(GCH_DIRS):
@[ -d $@ ] || mkdir -p $@

View File

@@ -113,6 +113,11 @@ namespace ams::kern::arch::arm {
constexpr size_t Offset = 0;
state->icfgr[i] = m_gicd->icfgr[i + Offset];
}
/* Save spendsgir. */
for (size_t i = 0; i < util::size(state->spendsgir); ++i) {
state->spendsgir[i] = m_gicd->spendsgir[i];
}
}
void KInterruptController::SaveGlobal(GlobalState *state) const {
@@ -168,6 +173,11 @@ namespace ams::kern::arch::arm {
m_gicd->icenabler[i + Offset] = 0xFFFFFFFF;
m_gicd->isenabler[i + Offset] = state->isenabler[i];
}
/* Restore spendsgir. */
for (size_t i = 0; i < util::size(state->spendsgir); ++i) {
m_gicd->spendsgir[i] = state->spendsgir[i];
}
}
void KInterruptController::RestoreGlobal(const GlobalState *state) const {

View File

@@ -112,7 +112,7 @@ namespace ams::kern::arch::arm64::cpu {
class KCoreBarrierInterruptHandler : public KInterruptHandler {
private:
util::Atomic<u64> m_target_cores;
KSpinLock m_lock;
KLightLock m_lock;
public:
constexpr KCoreBarrierInterruptHandler() : KInterruptHandler(), m_target_cores(0), m_lock() { /* ... */ }
@@ -123,11 +123,8 @@ namespace ams::kern::arch::arm64::cpu {
}
void SynchronizeCores(u64 core_mask) {
/* Disable dispatch while we synchronize. */
KScopedDisableDispatch dd;
/* Acquire exclusive access to ourselves. */
KScopedSpinLock lk(m_lock);
KScopedLightLock lk(m_lock);
/* If necessary, force synchronization with other cores. */
if (const u64 other_cores_mask = core_mask & ~(1ul << GetCurrentCoreId()); other_cores_mask != 0) {
@@ -218,7 +215,7 @@ namespace ams::kern::arch::arm64::cpu {
KThread::Register(new_thread);
/* Run the thread. */
new_thread->Run();
MESOSPHERE_R_ABORT_UNLESS(new_thread->Run());
}
virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override {
@@ -511,16 +508,16 @@ namespace ams::kern::arch::arm64::cpu {
g_cache_operation_handler.Initialize(core_id);
/* Bind all handlers to the relevant interrupts. */
Kernel::GetInterruptManager().BindHandler(std::addressof(g_cache_operation_handler), KInterruptName_CacheOperation, core_id, KInterruptController::PriorityLevel_High, false, false);
Kernel::GetInterruptManager().BindHandler(std::addressof(g_thread_termination_handler), KInterruptName_ThreadTerminate, core_id, KInterruptController::PriorityLevel_Scheduler, false, false);
Kernel::GetInterruptManager().BindHandler(std::addressof(g_core_barrier_handler), KInterruptName_CoreBarrier, core_id, KInterruptController::PriorityLevel_Scheduler, false, false);
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(std::addressof(g_cache_operation_handler), KInterruptName_CacheOperation, core_id, KInterruptController::PriorityLevel_High, false, false));
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(std::addressof(g_thread_termination_handler), KInterruptName_ThreadTerminate, core_id, KInterruptController::PriorityLevel_Scheduler, false, false));
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(std::addressof(g_core_barrier_handler), KInterruptName_CoreBarrier, core_id, KInterruptController::PriorityLevel_Scheduler, false, false));
/* If we should, enable user access to the performance counter registers. */
if (KTargetSystem::IsUserPmuAccessEnabled()) { SetPmUserEnrEl0(1ul); }
/* If we should, enable the kernel performance counter interrupt handler. */
#if defined(MESOSPHERE_ENABLE_PERFORMANCE_COUNTER)
Kernel::GetInterruptManager().BindHandler(std::addressof(g_performance_counter_handler[core_id]), KInterruptName_PerformanceCounter, core_id, KInterruptController::PriorityLevel_Timer, false, false);
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(std::addressof(g_performance_counter_handler[core_id]), KInterruptName_PerformanceCounter, core_id, KInterruptController::PriorityLevel_Timer, false, false));
#endif
}

View File

@@ -109,12 +109,31 @@ namespace ams::kern::arch::arm64 {
return insn;
}
void HandleUserException(KExceptionContext *context, u64 esr, u64 far, u64 afsr0, u64 afsr1, u32 data) {
void HandleUserException(KExceptionContext *context, u64 raw_esr, u64 raw_far, u64 afsr0, u64 afsr1, u32 data) {
/* Pre-process exception registers as needed. */
u64 esr = raw_esr;
u64 far = raw_far;
const u64 ec = (esr >> 26) & 0x3F;
if (ec == EsrEc_InstructionAbortEl0 || ec == EsrEc_DataAbortEl0) {
/* Adjust registers if a synchronous external abort has occurred with far not valid. */
/* Mask 0x03F = Low 6 bits IFSC == 0x10: "Synchronous External abort, */
/* not on translation table walk or hardware update of translation table. */
/* Mask 0x400 = FnV = "FAR Not Valid" */
/* TODO: How would we perform this check using named register accesses? */
if ((esr & 0x43F) == 0x410) {
/* Clear the faulting register on memory tagging exception. */
far = 0;
} else {
/* If the faulting address is a kernel address, set ISFC = 4. */
if (far >= ams::svc::AddressMemoryRegion39Size) {
esr = (esr & 0xFFFFFFC0) | 4;
}
}
}
KProcess &cur_process = GetCurrentProcess();
bool should_process_user_exception = KTargetSystem::IsUserExceptionHandlersEnabled();
const u64 ec = (esr >> 26) & 0x3F;
/* In the event that we return from this exception, we want SPSR.SS set so that we advance an instruction if single-stepping. */
#if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP)
context->psr |= (1ul << 21);
@@ -165,7 +184,7 @@ namespace ams::kern::arch::arm64 {
}
/* Save the debug parameters to the current thread. */
GetCurrentThread().SaveDebugParams(far, esr, data);
GetCurrentThread().SaveDebugParams(raw_far, raw_esr, data);
/* Get the exception type. */
u32 type;
@@ -387,7 +406,6 @@ namespace ams::kern::arch::arm64 {
ams::svc::aarch32::ExceptionInfo info32;
} info = {};
const bool is_aarch64 = (e_ctx->psr & 0x10) == 0;
if (is_aarch64) {
/* We're 64-bit. */
@@ -432,9 +450,28 @@ namespace ams::kern::arch::arm64 {
uintptr_t far, esr, data;
GetCurrentThread().RestoreDebugParams(std::addressof(far), std::addressof(esr), std::addressof(data));
/* Pre-process exception registers as needed. */
const u64 ec = (esr >> 26) & 0x3F;
if (ec == EsrEc_InstructionAbortEl0 || ec == EsrEc_DataAbortEl0) {
/* Adjust registers if a synchronous external abort has occurred with far not valid. */
/* Mask 0x03F = Low 6 bits IFSC == 0x10: "Synchronous External abort, */
/* not on translation table walk or hardware update of translation table. */
/* Mask 0x400 = FnV = "FAR Not Valid" */
/* TODO: How would we perform this check using named register accesses? */
if ((esr & 0x43F) == 0x410) {
/* Clear the faulting register on memory tagging exception. */
far = 0;
} else {
/* If the faulting address is a kernel address, set ISFC = 4. */
if (far >= ams::svc::AddressMemoryRegion39Size) {
esr = (esr & 0xFFFFFFC0) | 4;
}
}
}
/* Collect additional information based on the ec. */
uintptr_t params[3] = {};
switch ((esr >> 26) & 0x3F) {
switch (ec) {
case EsrEc_Unknown:
case EsrEc_IllegalExecution:
case EsrEc_BkptInstruction:

View File

@@ -25,7 +25,7 @@ namespace ams::kern::arch::arm64 {
m_maximum_time = static_cast<s64>(std::min<u64>(std::numeric_limits<s64>::max(), cpu::CounterTimerPhysicalTimerCompareValueRegisterAccessor().GetCompareValue()));
/* Bind the interrupt task for this core. */
Kernel::GetInterruptManager().BindHandler(this, KInterruptName_NonSecurePhysicalTimer, GetCurrentCoreId(), KInterruptController::PriorityLevel_Timer, true, true);
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(this, KInterruptName_NonSecurePhysicalTimer, GetCurrentCoreId(), KInterruptController::PriorityLevel_Timer, true, true));
}
void KHardwareTimer::Finalize() {

View File

@@ -126,7 +126,7 @@ namespace ams::kern::arch::arm64 {
if (entry.handler != nullptr) {
/* Set manual clear needed if relevant. */
if (entry.manually_cleared) {
m_interrupt_controller.SetPriorityLevel(irq, KInterruptController::PriorityLevel_Low);
m_interrupt_controller.Disable(irq);
entry.needs_clear = true;
}
@@ -242,40 +242,40 @@ namespace ams::kern::arch::arm64 {
}
}
Result KInterruptManager::UnbindHandler(s32 irq, s32 core_id) {
void KInterruptManager::UnbindHandler(s32 irq, s32 core_id) {
MESOSPHERE_UNUSED(core_id);
R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange());
MESOSPHERE_ASSERT(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq));
if (KInterruptController::IsGlobal(irq)) {
KScopedInterruptDisable di;
KScopedSpinLock lk(this->GetGlobalInterruptLock());
R_RETURN(this->UnbindGlobal(irq));
} else {
return this->UnbindGlobal(irq);
} else if (KInterruptController::IsLocal(irq)) {
MESOSPHERE_ASSERT(core_id == GetCurrentCoreId());
KScopedInterruptDisable di;
R_RETURN(this->UnbindLocal(irq));
return this->UnbindLocal(irq);
}
}
Result KInterruptManager::ClearInterrupt(s32 irq, s32 core_id) {
void KInterruptManager::ClearInterrupt(s32 irq, s32 core_id) {
MESOSPHERE_UNUSED(core_id);
R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange());
MESOSPHERE_ASSERT(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq));
if (KInterruptController::IsGlobal(irq)) {
KScopedInterruptDisable di;
KScopedSpinLock lk(this->GetGlobalInterruptLock());
R_RETURN(this->ClearGlobal(irq));
} else {
return this->ClearGlobal(irq);
} else if (KInterruptController::IsLocal(irq)) {
MESOSPHERE_ASSERT(core_id == GetCurrentCoreId());
KScopedInterruptDisable di;
R_RETURN(this->ClearLocal(irq));
return this->ClearLocal(irq);
}
}
@@ -332,7 +332,7 @@ namespace ams::kern::arch::arm64 {
R_SUCCEED();
}
Result KInterruptManager::UnbindGlobal(s32 irq) {
void KInterruptManager::UnbindGlobal(s32 irq) {
for (size_t core_id = 0; core_id < cpu::NumCores; core_id++) {
m_interrupt_controller.ClearTarget(irq, static_cast<s32>(core_id));
}
@@ -340,50 +340,35 @@ namespace ams::kern::arch::arm64 {
m_interrupt_controller.Disable(irq);
GetGlobalInterruptEntry(irq).handler = nullptr;
R_SUCCEED();
}
Result KInterruptManager::UnbindLocal(s32 irq) {
auto &entry = this->GetLocalInterruptEntry(irq);
R_UNLESS(entry.handler != nullptr, svc::ResultInvalidState());
void KInterruptManager::UnbindLocal(s32 irq) {
m_interrupt_controller.SetPriorityLevel(irq, KInterruptController::PriorityLevel_Low);
m_interrupt_controller.Disable(irq);
entry.handler = nullptr;
R_SUCCEED();
this->GetLocalInterruptEntry(irq).handler = nullptr;
}
Result KInterruptManager::ClearGlobal(s32 irq) {
/* We can't clear an entry with no handler. */
void KInterruptManager::ClearGlobal(s32 irq) {
/* Get the entry. */
auto &entry = GetGlobalInterruptEntry(irq);
R_UNLESS(entry.handler != nullptr, svc::ResultInvalidState());
/* If auto-cleared, we can succeed immediately. */
R_SUCCEED_IF(!entry.manually_cleared);
R_SUCCEED_IF(!entry.needs_clear);
/* Clear and enable. */
entry.needs_clear = false;
m_interrupt_controller.Enable(irq);
R_SUCCEED();
/* If not auto-cleared, clear and enable. */
if (entry.manually_cleared && entry.needs_clear) {
entry.needs_clear = false;
m_interrupt_controller.Enable(irq);
}
}
Result KInterruptManager::ClearLocal(s32 irq) {
/* We can't clear an entry with no handler. */
void KInterruptManager::ClearLocal(s32 irq) {
/* Get the entry. */
auto &entry = this->GetLocalInterruptEntry(irq);
R_UNLESS(entry.handler != nullptr, svc::ResultInvalidState());
/* If auto-cleared, we can succeed immediately. */
R_SUCCEED_IF(!entry.manually_cleared);
R_SUCCEED_IF(!entry.needs_clear);
/* Clear and set priority. */
entry.needs_clear = false;
m_interrupt_controller.SetPriorityLevel(irq, entry.priority);
R_SUCCEED();
/* If not auto-cleared, clear and enable. */
if (entry.manually_cleared && entry.needs_clear) {
entry.needs_clear = false;
m_interrupt_controller.Enable(irq);
}
}
}

View File

@@ -119,15 +119,13 @@ namespace ams::kern::arch::arm64 {
MESOSPHERE_UNUSED(core_id);
}
Result KPageTable::InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end) {
void KPageTable::InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end) {
/* Initialize basic fields. */
m_asid = 0;
m_manager = Kernel::GetSystemSystemResource().GetPageTableManagerPointer();
/* Initialize the base page table. */
MESOSPHERE_R_ABORT_UNLESS(KPageTableBase::InitializeForKernel(true, table, start, end));
R_SUCCEED();
KPageTableBase::InitializeForKernel(true, table, start, end);
}
Result KPageTable::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index) {
@@ -153,7 +151,7 @@ namespace ams::kern::arch::arm64 {
R_SUCCEED();
}
Result KPageTable::Finalize() {
void KPageTable::Finalize() {
/* Only process tables should be finalized. */
MESOSPHERE_ASSERT(!this->IsKernel());
@@ -271,8 +269,6 @@ namespace ams::kern::arch::arm64 {
/* Perform inherited finalization. */
KPageTableBase::Finalize();
}
R_SUCCEED();
}
Result KPageTable::OperateImpl(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll) {
@@ -752,13 +748,10 @@ namespace ams::kern::arch::arm64 {
while (true) {
/* Try to merge. */
KVirtualAddress freed_table = Null<KVirtualAddress>;
if (!impl.MergePages(std::addressof(freed_table), context)) {
if (!impl.MergePages(std::addressof(freed_table), context, &KPageTable::NoteUpdatedCallback, this)) {
break;
}
/* Note that we updated. */
this->NoteUpdated();
/* Free the page. */
if (freed_table != Null<KVirtualAddress>) {
ClearPageTable(freed_table);
@@ -816,8 +809,7 @@ namespace ams::kern::arch::arm64 {
}
/* Separate. */
impl.SeparatePages(entry, context, virt_addr, GetPointer<PageTableEntry>(table));
this->NoteUpdated();
impl.SeparatePages(entry, context, virt_addr, GetPointer<PageTableEntry>(table), &KPageTable::NoteUpdatedCallback, this);
}
R_SUCCEED();
@@ -946,7 +938,7 @@ namespace ams::kern::arch::arm64 {
/* If we should flush entries, do so. */
if ((apply_option & ApplyOption_FlushDataCache) != 0) {
if (IsHeapPhysicalAddress(next_entry.phys_addr)) {
cpu::FlushDataCache(GetVoidPointer(GetHeapVirtualAddress(next_entry.phys_addr)), next_entry.block_size);
MESOSPHERE_R_ABORT_UNLESS(cpu::FlushDataCache(GetVoidPointer(GetHeapVirtualAddress(next_entry.phys_addr)), next_entry.block_size));
}
}
@@ -1025,6 +1017,9 @@ namespace ams::kern::arch::arm64 {
/* Finally, apply the changes as directed, flushing the mappings before they're applied (if we should). */
ApplyEntryTemplate(entry_template, flush_mapping ? ApplyOption_FlushDataCache : ApplyOption_None);
/* Wait for pending stores to complete. */
cpu::DataSynchronizationBarrierInnerShareableStore();
}
/* We've succeeded, now perform what coalescing we can. */

View File

@@ -219,7 +219,7 @@ namespace ams::kern::arch::arm64 {
return is_block;
}
bool KPageTableImpl::MergePages(KVirtualAddress *out, TraversalContext *context) {
bool KPageTableImpl::MergePages(KVirtualAddress *out, TraversalContext *context, EntryUpdatedCallback on_entry_updated, const void *pt) {
/* We want to upgrade the pages by one step. */
if (context->is_contiguous) {
/* We can't merge an L1 table. */
@@ -251,6 +251,7 @@ namespace ams::kern::arch::arm64 {
const auto sw_reserved_bits = PageTableEntry::EncodeSoftwareReservedBits(head_pte->IsHeadMergeDisabled(), head_pte->IsHeadAndBodyMergeDisabled(), tail_pte->IsTailMergeDisabled());
*context->level_entries[context->level + 1] = PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, PageTableEntry(entry_template), sw_reserved_bits, false, false);
on_entry_updated(pt);
/* Update our context. */
context->is_contiguous = false;
@@ -285,6 +286,7 @@ namespace ams::kern::arch::arm64 {
for (size_t i = 0; i < BlocksPerContiguousBlock; ++i) {
pte[i] = PageTableEntry(PageTableEntry::BlockTag{}, phys_addr + (i << (PageBits + LevelBits * context->level)), PageTableEntry(entry_template), sw_reserved_bits, true, context->level == EntryLevel_L3);
}
on_entry_updated(pt);
/* Update our context. */
context->level_entries[context->level] = pte;
@@ -294,7 +296,7 @@ namespace ams::kern::arch::arm64 {
return true;
}
void KPageTableImpl::SeparatePages(TraversalEntry *entry, TraversalContext *context, KProcessAddress address, PageTableEntry *pte) const {
void KPageTableImpl::SeparatePages(TraversalEntry *entry, TraversalContext *context, KProcessAddress address, PageTableEntry *pte, EntryUpdatedCallback on_entry_updated, const void *pt) const {
/* We want to downgrade the pages by one step. */
if (context->is_contiguous) {
/* We want to downgrade a contiguous mapping to a non-contiguous mapping. */
@@ -305,6 +307,7 @@ namespace ams::kern::arch::arm64 {
for (size_t i = 0; i < BlocksPerContiguousBlock; ++i) {
pte[i] = PageTableEntry(PageTableEntry::BlockTag{}, block + (i << (PageBits + LevelBits * context->level)), PageTableEntry(first->GetEntryTemplateForSeparateContiguous(i)), PageTableEntry::SeparateContiguousTag{});
}
on_entry_updated(pt);
context->is_contiguous = false;
@@ -325,12 +328,12 @@ namespace ams::kern::arch::arm64 {
/* Update the block entry to be a table entry. */
*context->level_entries[context->level + 1] = PageTableEntry(PageTableEntry::TableTag{}, KPageTable::GetPageTablePhysicalAddress(KVirtualAddress(pte)), m_is_kernel, true, BlocksPerTable);
on_entry_updated(pt);
context->level_entries[context->level] = pte + this->GetLevelIndex(address, context->level);
}
entry->sw_reserved_bits = 0;
entry->sw_reserved_bits = context->level_entries[context->level]->GetSoftwareReservedBits();
entry->attr = 0;
entry->phys_addr = this->GetBlock(context->level_entries[context->level], context->level) + this->GetOffset(address, context->level);
entry->block_size = static_cast<size_t>(1) << (PageBits + LevelBits * context->level + 4 * context->is_contiguous);

View File

@@ -37,7 +37,7 @@ namespace ams::kern::arch::arm64 {
KScopedInterruptEnable ei;
const uintptr_t params[2] = { GetCurrentThread().GetId(), GetInteger(GetCurrentThread().GetThreadLocalRegionAddress()) };
KDebug::OnDebugEvent(ams::svc::DebugEvent_CreateThread, params, util::size(params));
static_cast<void>(KDebug::OnDebugEvent(ams::svc::DebugEvent_CreateThread, params, util::size(params)));
}
/* Handle any pending dpc. */
@@ -116,7 +116,7 @@ namespace ams::kern::arch::arm64 {
}
Result KThreadContext::Initialize(KVirtualAddress u_pc, KVirtualAddress k_sp, KVirtualAddress u_sp, uintptr_t arg, bool is_user, bool is_64_bit, bool is_main) {
void KThreadContext::Initialize(KVirtualAddress u_pc, KVirtualAddress k_sp, KVirtualAddress u_sp, uintptr_t arg, bool is_user, bool is_64_bit, bool is_main) {
MESOSPHERE_ASSERT(k_sp != Null<KVirtualAddress>);
/* Ensure that the stack pointers are aligned. */
@@ -157,8 +157,6 @@ namespace ams::kern::arch::arm64 {
/* Lock the context, if we're a main thread. */
m_locked = is_main;
R_SUCCEED();
}
void KThreadContext::SetArguments(uintptr_t arg0, uintptr_t arg1) {

View File

@@ -24,12 +24,12 @@ _ZN3ams4kern4arch5arm6432UserspaceAccessFunctionAreaBeginEv:
/* ================ All Userspace Access Functions after this line. ================ */
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUser(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess18CopyMemoryFromUserEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess18CopyMemoryFromUserEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess18CopyMemoryFromUserEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryFromUser(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyMemoryFromUserEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyMemoryFromUserEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyMemoryFromUserEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess18CopyMemoryFromUserEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyMemoryFromUserEPvPKvm:
/* Check if there's anything to copy. */
cmp x2, #0
b.eq 2f
@@ -48,12 +48,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18CopyMemoryFromUserEPvPKvm:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUserAligned32Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned32BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned32BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned32BitEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryFromUserAligned32Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned32BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned32BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned32BitEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned32BitEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned32BitEPvPKvm:
/* Check if there are 0x40 bytes to copy */
cmp x2, #0x3F
b.ls 1f
@@ -72,7 +72,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned32BitEPvPKvm:
add x0, x0, #0x40
add x1, x1, #0x40
sub x2, x2, #0x40
b _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned32BitEPvPKvm
b _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned32BitEPvPKvm
1: /* We have less than 0x40 bytes to copy. */
cmp x2, #0
@@ -87,12 +87,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned32BitEPvPKvm:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUserAligned64Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned64BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned64BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned64BitEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryFromUserAligned64Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned64BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned64BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned64BitEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned64BitEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned64BitEPvPKvm:
/* Check if there are 0x40 bytes to copy */
cmp x2, #0x3F
b.ls 1f
@@ -111,7 +111,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned64BitEPvPKvm:
add x0, x0, #0x40
add x1, x1, #0x40
sub x2, x2, #0x40
b _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned64BitEPvPKvm
b _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned64BitEPvPKvm
1: /* We have less than 0x40 bytes to copy. */
cmp x2, #0
@@ -126,12 +126,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned64BitEPvPKvm:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUserSize64Bit(void *dst, const void *src) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv
.type _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryFromUserSize64Bit(void *dst, const void *src) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize64BitEPvPKv, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize64BitEPvPKv
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize64BitEPvPKv, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize64BitEPvPKv:
/* Just load and store a u64. */
ldtr x2, [x1]
str x2, [x0]
@@ -140,12 +140,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUserSize32Bit(void *dst, const void *src) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv
.type _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryFromUserSize32Bit(void *dst, const void *src) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize32BitEPvPKv, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize32BitEPvPKv
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize32BitEPvPKv, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize32BitEPvPKv:
/* Just load and store a u32. */
ldtr w2, [x1]
str w2, [x0]
@@ -154,12 +154,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUserSize32BitWithSupervisorAccessImpl(void *dst, const void *src) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess51CopyMemoryFromUserSize32BitWithSupervisorAccessImplEPvPKv, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess51CopyMemoryFromUserSize32BitWithSupervisorAccessImplEPvPKv
.type _ZN3ams4kern4arch5arm6415UserspaceAccess51CopyMemoryFromUserSize32BitWithSupervisorAccessImplEPvPKv, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryFromUserSize32BitWithSupervisorAccess(void *dst, const void *src) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl47CopyMemoryFromUserSize32BitWithSupervisorAccessEPvPKv, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl47CopyMemoryFromUserSize32BitWithSupervisorAccessEPvPKv
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl47CopyMemoryFromUserSize32BitWithSupervisorAccessEPvPKv, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess51CopyMemoryFromUserSize32BitWithSupervisorAccessImplEPvPKv:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl47CopyMemoryFromUserSize32BitWithSupervisorAccessEPvPKv:
/* Just load and store a u32. */
/* NOTE: This is done with supervisor access permissions. */
ldr w2, [x1]
@@ -169,12 +169,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess51CopyMemoryFromUserSize32BitWithSupervi
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::CopyStringFromUser(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess18CopyStringFromUserEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess18CopyStringFromUserEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess18CopyStringFromUserEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyStringFromUser(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyStringFromUserEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyStringFromUserEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyStringFromUserEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess18CopyStringFromUserEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyStringFromUserEPvPKvm:
/* Check if there's anything to copy. */
cmp x2, #0
b.eq 3f
@@ -204,12 +204,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18CopyStringFromUserEPvPKvm:
mov x0, #0
ret
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryToUser(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess16CopyMemoryToUserEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess16CopyMemoryToUserEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess16CopyMemoryToUserEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryToUser(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyMemoryToUserEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyMemoryToUserEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyMemoryToUserEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess16CopyMemoryToUserEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyMemoryToUserEPvPKvm:
/* Check if there's anything to copy. */
cmp x2, #0
b.eq 2f
@@ -228,12 +228,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess16CopyMemoryToUserEPvPKvm:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryToUserAligned32Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned32BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned32BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned32BitEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryToUserAligned32Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned32BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned32BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned32BitEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned32BitEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned32BitEPvPKvm:
/* Check if there are 0x40 bytes to copy */
cmp x2, #0x3F
b.ls 1f
@@ -252,7 +252,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned32BitEPvPKvm:
add x0, x0, #0x40
add x1, x1, #0x40
sub x2, x2, #0x40
b _ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned32BitEPvPKvm
b _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned32BitEPvPKvm
1: /* We have less than 0x40 bytes to copy. */
cmp x2, #0
@@ -267,12 +267,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned32BitEPvPKvm:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryToUserAligned64Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned64BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned64BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned64BitEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryToUserAligned64Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned64BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned64BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned64BitEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned64BitEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned64BitEPvPKvm:
/* Check if there are 0x40 bytes to copy */
cmp x2, #0x3F
b.ls 1f
@@ -291,7 +291,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned64BitEPvPKvm:
add x0, x0, #0x40
add x1, x1, #0x40
sub x2, x2, #0x40
b _ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned64BitEPvPKvm
b _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned64BitEPvPKvm
1: /* We have less than 0x40 bytes to copy. */
cmp x2, #0
@@ -306,26 +306,25 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess28CopyMemoryToUserAligned64BitEPvPKvm:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryToUserSize32Bit(void *dst, const void *src) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess25CopyMemoryToUserSize32BitEPvPKv, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess25CopyMemoryToUserSize32BitEPvPKv
.type _ZN3ams4kern4arch5arm6415UserspaceAccess25CopyMemoryToUserSize32BitEPvPKv, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryToUserSize32Bit(void *dst, u32 value) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25CopyMemoryToUserSize32BitEPvj, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25CopyMemoryToUserSize32BitEPvj
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25CopyMemoryToUserSize32BitEPvj, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess25CopyMemoryToUserSize32BitEPvPKv:
/* Just load and store a u32. */
ldr w2, [x1]
sttr w2, [x0]
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25CopyMemoryToUserSize32BitEPvj:
/* Just store a u32. */
sttr w1, [x0]
/* We're done. */
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::CopyStringToUser(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess16CopyStringToUserEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess16CopyStringToUserEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess16CopyStringToUserEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyStringToUser(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyStringToUserEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyStringToUserEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyStringToUserEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess16CopyStringToUserEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyStringToUserEPvPKvm:
/* Check if there's anything to copy. */
cmp x2, #0
b.eq 3f
@@ -355,114 +354,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess16CopyStringToUserEPvPKvm:
mov x0, #0
ret
/* ams::kern::arch::arm64::UserspaceAccess::ClearMemory(void *dst, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess11ClearMemoryEPvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess11ClearMemoryEPvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess11ClearMemoryEPvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::UpdateLockAtomic(u32 *out, u32 *address, u32 if_zero, u32 new_orr_mask) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16UpdateLockAtomicEPjS5_jj, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16UpdateLockAtomicEPjS5_jj
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16UpdateLockAtomicEPjS5_jj, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess11ClearMemoryEPvm:
/* Check if there's anything to clear. */
cmp x1, #0
b.eq 2f
/* Keep track of the last address. */
add x2, x0, x1
1: /* We're copying memory byte-by-byte. */
sttrb wzr, [x0]
add x0, x0, #1
cmp x0, x2
b.ne 1b
2: /* We're done. */
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::ClearMemoryAligned32Bit(void *dst, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess23ClearMemoryAligned32BitEPvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess23ClearMemoryAligned32BitEPvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess23ClearMemoryAligned32BitEPvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess23ClearMemoryAligned32BitEPvm:
/* Check if there are 0x40 bytes to clear. */
cmp x1, #0x3F
b.ls 2f
sttr xzr, [x0, #0x00]
sttr xzr, [x0, #0x08]
sttr xzr, [x0, #0x10]
sttr xzr, [x0, #0x18]
sttr xzr, [x0, #0x20]
sttr xzr, [x0, #0x28]
sttr xzr, [x0, #0x30]
sttr xzr, [x0, #0x38]
add x0, x0, #0x40
sub x1, x1, #0x40
b _ZN3ams4kern4arch5arm6415UserspaceAccess23ClearMemoryAligned32BitEPvm
1: /* We have less than 0x40 bytes to clear. */
cmp x1, #0
b.eq 2f
sttr wzr, [x0]
add x0, x0, #4
sub x1, x1, #4
b 1b
2: /* We're done. */
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::ClearMemoryAligned64Bit(void *dst, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess23ClearMemoryAligned64BitEPvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess23ClearMemoryAligned64BitEPvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess23ClearMemoryAligned64BitEPvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess23ClearMemoryAligned64BitEPvm:
/* Check if there are 0x40 bytes to clear. */
cmp x1, #0x3F
b.ls 2f
sttr xzr, [x0, #0x00]
sttr xzr, [x0, #0x08]
sttr xzr, [x0, #0x10]
sttr xzr, [x0, #0x18]
sttr xzr, [x0, #0x20]
sttr xzr, [x0, #0x28]
sttr xzr, [x0, #0x30]
sttr xzr, [x0, #0x38]
add x0, x0, #0x40
sub x1, x1, #0x40
b _ZN3ams4kern4arch5arm6415UserspaceAccess23ClearMemoryAligned64BitEPvm
1: /* We have less than 0x40 bytes to clear. */
cmp x1, #0
b.eq 2f
sttr xzr, [x0]
add x0, x0, #8
sub x1, x1, #8
b 1b
2: /* We're done. */
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::ClearMemorySize32Bit(void *dst) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess20ClearMemorySize32BitEPv, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess20ClearMemorySize32BitEPv
.type _ZN3ams4kern4arch5arm6415UserspaceAccess20ClearMemorySize32BitEPv, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess20ClearMemorySize32BitEPv:
/* Just store a zero. */
sttr wzr, [x0]
/* We're done. */
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::UpdateLockAtomic(u32 *out, u32 *address, u32 if_zero, u32 new_orr_mask) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess16UpdateLockAtomicEPjS4_jj, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess16UpdateLockAtomicEPjS4_jj
.type _ZN3ams4kern4arch5arm6415UserspaceAccess16UpdateLockAtomicEPjS4_jj, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess16UpdateLockAtomicEPjS4_jj:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16UpdateLockAtomicEPjS5_jj:
/* Load the value from the address. */
ldaxr w4, [x1]
@@ -477,7 +374,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess16UpdateLockAtomicEPjS4_jj:
stlxr w6, w5, [x1]
/* If we failed to store, try again. */
cbnz w6, _ZN3ams4kern4arch5arm6415UserspaceAccess16UpdateLockAtomicEPjS4_jj
cbnz w6, _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16UpdateLockAtomicEPjS5_jj
/* We're done. */
str w4, [x0]
@@ -485,12 +382,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess16UpdateLockAtomicEPjS4_jj:
ret
/* ams::kern::arch::arm64::UserspaceAccess::UpdateIfEqualAtomic(s32 *out, s32 *address, s32 compare_value, s32 new_value) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess19UpdateIfEqualAtomicEPiS4_ii, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess19UpdateIfEqualAtomicEPiS4_ii
.type _ZN3ams4kern4arch5arm6415UserspaceAccess19UpdateIfEqualAtomicEPiS4_ii, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::UpdateIfEqualAtomic(s32 *out, s32 *address, s32 compare_value, s32 new_value) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19UpdateIfEqualAtomicEPiS5_ii, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19UpdateIfEqualAtomicEPiS5_ii
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19UpdateIfEqualAtomicEPiS5_ii, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess19UpdateIfEqualAtomicEPiS4_ii:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19UpdateIfEqualAtomicEPiS5_ii:
/* Load the value from the address. */
ldaxr w4, [x1]
@@ -508,19 +405,19 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess19UpdateIfEqualAtomicEPiS4_ii:
stlxr w5, w3, [x1]
/* If we failed to store, try again. */
cbnz w5, _ZN3ams4kern4arch5arm6415UserspaceAccess19UpdateIfEqualAtomicEPiS4_ii
cbnz w5, _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19UpdateIfEqualAtomicEPiS5_ii
2: /* We're done. */
str w4, [x0]
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::DecrementIfLessThanAtomic(s32 *out, s32 *address, s32 compare) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess25DecrementIfLessThanAtomicEPiS4_i, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess25DecrementIfLessThanAtomicEPiS4_i
.type _ZN3ams4kern4arch5arm6415UserspaceAccess25DecrementIfLessThanAtomicEPiS4_i, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::DecrementIfLessThanAtomic(s32 *out, s32 *address, s32 compare) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25DecrementIfLessThanAtomicEPiS5_i, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25DecrementIfLessThanAtomicEPiS5_i
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25DecrementIfLessThanAtomicEPiS5_i, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess25DecrementIfLessThanAtomicEPiS4_i:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25DecrementIfLessThanAtomicEPiS5_i:
/* Load the value from the address. */
ldaxr w3, [x1]
@@ -539,19 +436,19 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess25DecrementIfLessThanAtomicEPiS4_i:
stlxr w5, w4, [x1]
/* If we failed to store, try again. */
cbnz w5, _ZN3ams4kern4arch5arm6415UserspaceAccess25DecrementIfLessThanAtomicEPiS4_i
cbnz w5, _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25DecrementIfLessThanAtomicEPiS5_i
2: /* We're done. */
str w3, [x0]
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::StoreDataCache(uintptr_t start, uintptr_t end) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess14StoreDataCacheEmm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess14StoreDataCacheEmm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess14StoreDataCacheEmm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::StoreDataCache(uintptr_t start, uintptr_t end) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14StoreDataCacheEmm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14StoreDataCacheEmm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14StoreDataCacheEmm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess14StoreDataCacheEmm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14StoreDataCacheEmm:
/* Check if we have any work to do. */
cmp x1, x0
b.eq 2f
@@ -566,12 +463,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess14StoreDataCacheEmm:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::FlushDataCache(uintptr_t start, uintptr_t end) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess14FlushDataCacheEmm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess14FlushDataCacheEmm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess14FlushDataCacheEmm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::FlushDataCache(uintptr_t start, uintptr_t end) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14FlushDataCacheEmm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14FlushDataCacheEmm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14FlushDataCacheEmm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess14FlushDataCacheEmm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14FlushDataCacheEmm:
/* Check if we have any work to do. */
cmp x1, x0
b.eq 2f
@@ -586,12 +483,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess14FlushDataCacheEmm:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::InvalidateDataCache(uintptr_t start, uintptr_t end) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess19InvalidateDataCacheEmm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess19InvalidateDataCacheEmm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess19InvalidateDataCacheEmm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::InvalidateDataCache(uintptr_t start, uintptr_t end) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19InvalidateDataCacheEmm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19InvalidateDataCacheEmm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19InvalidateDataCacheEmm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess19InvalidateDataCacheEmm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19InvalidateDataCacheEmm:
/* Check if we have any work to do. */
cmp x1, x0
b.eq 2f
@@ -606,12 +503,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess19InvalidateDataCacheEmm:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::ReadIoMemory32Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory32BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory32BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory32BitEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::ReadIoMemory32Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory32BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory32BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory32BitEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory32BitEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory32BitEPvPKvm:
/* Check if we have any work to do. */
cmp x2, #0
b.eq 3f
@@ -656,12 +553,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory32BitEPvPKvm:
mov w9, #0xFFFFFFFF
b 2b
/* ams::kern::arch::arm64::UserspaceAccess::ReadIoMemory16Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory16BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory16BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory16BitEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::ReadIoMemory16Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory16BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory16BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory16BitEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory16BitEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory16BitEPvPKvm:
/* Check if we have any work to do. */
cmp x2, #0
b.eq 3f
@@ -706,12 +603,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory16BitEPvPKvm:
mov w9, #0xFFFFFFFF
b 2b
/* ams::kern::arch::arm64::UserspaceAccess::ReadIoMemory8Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess16ReadIoMemory8BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess16ReadIoMemory8BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess16ReadIoMemory8BitEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::ReadIoMemory8Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16ReadIoMemory8BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16ReadIoMemory8BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16ReadIoMemory8BitEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess16ReadIoMemory8BitEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16ReadIoMemory8BitEPvPKvm:
/* Check if we have any work to do. */
cmp x2, #0
b.eq 3f
@@ -756,12 +653,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess16ReadIoMemory8BitEPvPKvm:
mov w9, #0xFFFFFFFF
b 2b
/* ams::kern::arch::arm64::UserspaceAccess::WriteIoMemory32Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory32BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory32BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory32BitEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::WriteIoMemory32Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory32BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory32BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory32BitEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory32BitEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory32BitEPvPKvm:
/* Check if we have any work to do. */
cmp x2, #0
b.eq 3f
@@ -801,12 +698,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory32BitEPvPKvm:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::WriteIoMemory16Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory16BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory16BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory16BitEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::WriteIoMemory16Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory16BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory16BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory16BitEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory16BitEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory16BitEPvPKvm:
/* Check if we have any work to do. */
cmp x2, #0
b.eq 3f
@@ -846,12 +743,12 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory16BitEPvPKvm:
mov x0, #1
ret
/* ams::kern::arch::arm64::UserspaceAccess::WriteIoMemory8Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess17WriteIoMemory8BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess17WriteIoMemory8BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess17WriteIoMemory8BitEPvPKvm, %function
/* ams::kern::arch::arm64::UserspaceAccess::Impl::WriteIoMemory8Bit(void *dst, const void *src, size_t size) */
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17WriteIoMemory8BitEPvPKvm, "ax", %progbits
.global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17WriteIoMemory8BitEPvPKvm
.type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17WriteIoMemory8BitEPvPKvm, %function
.balign 0x10
_ZN3ams4kern4arch5arm6415UserspaceAccess17WriteIoMemory8BitEPvPKvm:
_ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17WriteIoMemory8BitEPvPKvm:
/* Check if we have any work to do. */
cmp x2, #0
b.eq 3f

View File

@@ -660,8 +660,7 @@ namespace ams::kern::board::nintendo::nx {
ptm.Open(table_virt_addr, 1);
/* Save the page. Note that it is a pre-condition that the page is cleared, when allocated from the system page table manager. */
/* NOTE: Nintendo does not check the result of StoreDataCache. */
cpu::StoreDataCache(GetVoidPointer(table_virt_addr), PageDirectorySize);
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(GetVoidPointer(table_virt_addr), PageDirectorySize));
g_reserved_table_phys_addr = table_phys_addr;
/* Reserve an asid to correspond to no device. */
@@ -710,7 +709,7 @@ namespace ams::kern::board::nintendo::nx {
/* Install interrupt handler. */
#if defined(MESOSPHERE_ENABLE_MEMORY_CONTROLLER_INTERRUPT)
{
Kernel::GetInterruptManager().BindHandler(std::addressof(g_mc_interrupt_task), KInterruptName_MemoryController, GetCurrentCoreId(), KInterruptController::PriorityLevel_High, true, true);
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(std::addressof(g_mc_interrupt_task), KInterruptName_MemoryController, GetCurrentCoreId(), KInterruptController::PriorityLevel_High, true, true));
}
#endif
}
@@ -806,7 +805,7 @@ namespace ams::kern::board::nintendo::nx {
MESOSPHERE_ASSERT(IsValidPhysicalAddress(GetPageTablePhysicalAddress(table_vaddr)));
ptm.Open(table_vaddr, 1);
cpu::StoreDataCache(GetVoidPointer(table_vaddr), PageDirectorySize);
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(GetVoidPointer(table_vaddr), PageDirectorySize));
m_tables[i] = table_vaddr;
}
@@ -1042,7 +1041,7 @@ namespace ams::kern::board::nintendo::nx {
if (l2_index == 0 && util::IsAligned(GetInteger(phys_addr), DeviceLargePageSize) && remaining >= DeviceLargePageSize) {
/* Set the large page. */
l1[l1_index].SetLargePage(read, write, true, phys_addr);
cpu::StoreDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry));
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry)));
/* Synchronize. */
InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l1[l1_index]))));
@@ -1062,11 +1061,11 @@ namespace ams::kern::board::nintendo::nx {
const KVirtualAddress table_vaddr = ptm.Allocate();
R_UNLESS(table_vaddr != Null<KVirtualAddress>, svc::ResultOutOfMemory());
MESOSPHERE_ASSERT(IsValidPhysicalAddress(GetPageTablePhysicalAddress(table_vaddr)));
cpu::StoreDataCache(GetVoidPointer(table_vaddr), PageTableSize);
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(GetVoidPointer(table_vaddr), PageTableSize));
/* Set the l1 table. */
l1[l1_index].SetTable(true, true, true, GetPageTablePhysicalAddress(table_vaddr));
cpu::StoreDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry));
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry)));
/* Synchronize. */
InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l1[l1_index]))));
@@ -1093,7 +1092,7 @@ namespace ams::kern::board::nintendo::nx {
/* Add a reference to the l2 page (from the l2 entry page). */
ptm.Open(KVirtualAddress(l2), 1);
}
cpu::StoreDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry));
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry)));
/* Invalidate the page table cache. */
for (size_t i = util::AlignDown(l2_index, 4); i <= util::AlignDown(l2_index + map_count - 1, 4); i += 4) {
@@ -1199,7 +1198,7 @@ namespace ams::kern::board::nintendo::nx {
++num_closed;
}
}
cpu::StoreDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry));
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry)));
/* Invalidate the page table cache. */
for (size_t i = util::AlignDown(l2_index, 4); i <= util::AlignDown(l2_index + map_count - 1, 4); i += 4) {
@@ -1243,7 +1242,7 @@ namespace ams::kern::board::nintendo::nx {
if (ptm.Close(KVirtualAddress(l2), num_closed)) {
/* Invalidate the l1 entry. */
l1[l1_index].Invalidate();
cpu::StoreDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry));
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry)));
/* Synchronize. */
InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l1[l1_index]))));
@@ -1266,7 +1265,7 @@ namespace ams::kern::board::nintendo::nx {
/* Invalidate the entry. */
l1[l1_index].Invalidate();
cpu::StoreDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry));
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry)));
/* Synchronize. */
InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l1[l1_index]))));

View File

@@ -441,7 +441,7 @@ namespace ams::kern::board::nintendo::nx {
KThread::Register(new_thread);
/* Run the thread. */
new_thread->Run();
MESOSPHERE_R_ABORT_UNLESS(new_thread->Run());
}
}
@@ -524,6 +524,14 @@ namespace ams::kern::board::nintendo::nx {
/* Ensure that all cores get to this point before continuing. */
cpu::SynchronizeAllCores();
/* Wait 100us before continuing. */
{
const s64 timeout = KHardwareTimer::GetTick() + ams::svc::Tick(TimeSpan::FromMicroSeconds(100));
while (KHardwareTimer::GetTick() < timeout) {
__asm__ __volatile__("" ::: "memory");
}
}
/* Save the interrupt manager's state. */
Kernel::GetInterruptManager().Save(core_id);

View File

@@ -361,8 +361,18 @@ namespace ams::kern::board::nintendo::nx {
}();
/* Return (possibly) adjusted size. */
constexpr size_t ExtraSystemMemoryForAtmosphere = 40_MB;
return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
/* NOTE: On 20.0.0+ (and even more-so 21.0.0+) the browser requires much more memory in the applet pool in order to function. */
/* Thus, we have to reduce our extra system memory size by 26 MB to compensate. */
if (kern::GetTargetFirmware() >= ams::TargetFirmware_21_0_0) {
constexpr size_t ExtraSystemMemoryForAtmosphere_21_0_0 = 7_MB;
return base_pool_size - ExtraSystemMemoryForAtmosphere_21_0_0 - KTraceBufferSize;
} else if (kern::GetTargetFirmware() >= ams::TargetFirmware_20_0_0) {
constexpr size_t ExtraSystemMemoryForAtmosphere_20_0_0 = 14_MB;
return base_pool_size - ExtraSystemMemoryForAtmosphere_20_0_0 - KTraceBufferSize;
} else {
constexpr size_t ExtraSystemMemoryForAtmosphere = 40_MB;
return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
}
}
size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
@@ -405,22 +415,22 @@ namespace ams::kern::board::nintendo::nx {
/* Configure KTargetSystem. */
volatile auto *ts = const_cast<volatile KTargetSystem::KTargetSystemData *>(std::addressof(KTargetSystem::s_data));
{
/* Set IsDebugMode. */
/* Set whether we're in debug mode. */
{
ts->is_debug_mode = GetConfigBool(smc::ConfigItem::IsDebugMode);
ts->is_not_debug_mode = !GetConfigBool(smc::ConfigItem::IsDebugMode);
/* If debug mode, we want to initialize uart logging. */
ts->enable_debug_logging = ts->is_debug_mode;
/* If we're not in debug mode, we don't want to initialize uart logging. */
ts->disable_debug_logging = ts->is_not_debug_mode;
}
/* Set Kernel Configuration. */
{
const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)};
ts->enable_debug_memory_fill = kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>();
ts->enable_user_exception_handlers = kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>();
ts->enable_dynamic_resource_limits = !kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>();
ts->enable_user_pmu_access = kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>();
ts->disable_debug_memory_fill = !kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>();
ts->disable_user_exception_handlers = !kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>();
ts->disable_dynamic_resource_limits = kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>();
ts->disable_user_pmu_access = !kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>();
/* Configure call smc on panic. */
*const_cast<volatile bool *>(std::addressof(g_call_smc_on_panic)) = kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>();
@@ -430,7 +440,7 @@ namespace ams::kern::board::nintendo::nx {
{
/* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */
/* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */
ts->enable_kernel_debugging = GetConfigBool(smc::ConfigItem::DisableProgramVerification);
ts->disable_kernel_debugging = !GetConfigBool(smc::ConfigItem::DisableProgramVerification);
}
}
}
@@ -524,7 +534,7 @@ namespace ams::kern::board::nintendo::nx {
KScopedSpinLock lk(s_random_lock);
if (AMS_LIKELY(s_initialized_random_generator)) {
if (AMS_LIKELY(!s_uninitialized_random_generator)) {
return KSystemControlBase::GenerateUniformRange(min, max, []() ALWAYS_INLINE_LAMBDA -> u64 { return s_random_generator.GenerateRandomU64(); });
} else {
return KSystemControlBase::GenerateUniformRange(min, max, GenerateRandomU64FromSmc);
@@ -535,7 +545,7 @@ namespace ams::kern::board::nintendo::nx {
KScopedInterruptDisable intr_disable;
KScopedSpinLock lk(s_random_lock);
if (AMS_LIKELY(s_initialized_random_generator)) {
if (AMS_LIKELY(!s_uninitialized_random_generator)) {
return s_random_generator.GenerateRandomU64();
} else {
return GenerateRandomU64FromSmc();

View File

@@ -140,14 +140,12 @@ namespace ams::kern {
/* Add the previously reserved pages. */
if (src_pool == dst_pool && binary_pages != 0) {
/* NOTE: Nintendo does not check the result of this operation. */
pg.AddBlock(KMemoryLayout::GetLinearPhysicalAddress(data), binary_pages);
MESOSPHERE_R_ABORT_UNLESS(pg.AddBlock(KMemoryLayout::GetLinearPhysicalAddress(data), binary_pages));
}
/* Add the previously unreserved pages. */
for (const auto &block : unreserve_pg) {
/* NOTE: Nintendo does not check the result of this operation. */
pg.AddBlock(block.GetAddress(), block.GetNumPages());
MESOSPHERE_R_ABORT_UNLESS(pg.AddBlock(block.GetAddress(), block.GetNumPages()));
}
}
MESOSPHERE_ABORT_UNLESS(pg.GetNumPages() == static_cast<size_t>(params.code_num_pages));

View File

@@ -66,12 +66,39 @@ namespace ams::kern {
}
uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(ams::svc::CreateProcessFlag flags, KAddressSpaceInfo::Type type) {
uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(ams::svc::CreateProcessFlag flags, KAddressSpaceInfo::Type type, size_t code_size) {
MESOSPHERE_UNUSED(code_size);
return GetAddressSpaceInfo(GetAddressSpaceWidth(flags), type).GetAddress();
}
size_t KAddressSpaceInfo::GetAddressSpaceSize(ams::svc::CreateProcessFlag flags, KAddressSpaceInfo::Type type) {
return GetAddressSpaceInfo(GetAddressSpaceWidth(flags), type).GetSize();
/* Extract the address space from the create process flags. */
const auto as_flags = (flags & ams::svc::CreateProcessFlag_AddressSpaceMask);
/* Get the address space width. */
const auto as_width = GetAddressSpaceWidth(flags);
/* Get the size. */
size_t as_size = GetAddressSpaceInfo(as_width, type).GetSize();
/* If we're getting size for 32-bit without alias, adjust the sizes accordingly. */
if (as_flags == ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias) {
switch (type) {
/* The heap space receives space that would otherwise go to the alias space. */
case KAddressSpaceInfo::Type_Heap:
as_size += GetAddressSpaceInfo(as_width, KAddressSpaceInfo::Type_Alias).GetSize();
break;
/* The alias space doesn't exist. */
case KAddressSpaceInfo::Type_Alias:
as_size = 0;
break;
/* Nothing to do by default. */
default:
break;
}
}
return as_size;
}
void KAddressSpaceInfo::SetAddressSpaceSize(size_t width, Type type, size_t size) {

View File

@@ -37,7 +37,7 @@ namespace ams::kern {
/* Clear and store cache. */
void * const block_address = GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block.GetAddress()));
std::memset(block_address, 0xFF, block.GetSize());
cpu::StoreDataCache(block_address, block.GetSize());
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(block_address, block.GetSize()));
}
/* Set remaining tracking members. */

View File

@@ -23,8 +23,8 @@ namespace ams::kern {
return UserspaceAccess::CopyMemoryFromUserSize32Bit(out, GetVoidPointer(address));
}
ALWAYS_INLINE bool WriteToUser(KProcessAddress address, const u32 *p) {
return UserspaceAccess::CopyMemoryToUserSize32Bit(GetVoidPointer(address), p);
ALWAYS_INLINE bool WriteToUser(KProcessAddress address, u32 val) {
return UserspaceAccess::CopyMemoryToUserSize32Bit(GetVoidPointer(address), val);
}
ALWAYS_INLINE bool UpdateLockAtomic(u32 *out, KProcessAddress address, u32 if_zero, u32 new_orr_mask) {
@@ -94,7 +94,7 @@ namespace ams::kern {
/* Write the value to userspace. */
Result result;
if (AMS_LIKELY(WriteToUser(addr, std::addressof(next_value)))) {
if (AMS_LIKELY(WriteToUser(addr, next_value))) {
result = ResultSuccess();
} else {
result = svc::ResultInvalidCurrentMemory();
@@ -210,8 +210,8 @@ namespace ams::kern {
/* If we have no waiters, clear the has waiter flag. */
if (it == m_tree.end() || it->GetConditionVariableKey() != cv_key) {
const u32 has_waiter_flag = 0;
WriteToUser(cv_key, std::addressof(has_waiter_flag));
constexpr u32 HasNoWaiterFlag = 0;
WriteToUser(cv_key, HasNoWaiterFlag);
}
}
}
@@ -252,13 +252,13 @@ namespace ams::kern {
/* Write to the cv key. */
{
const u32 has_waiter_flag = 1;
WriteToUser(key, std::addressof(has_waiter_flag));
constexpr u32 HasWaiterFlag = 1;
WriteToUser(key, HasWaiterFlag);
cpu::DataMemoryBarrierInnerShareable();
}
/* Write the value to userspace. */
if (!WriteToUser(addr, std::addressof(next_value))) {
if (!WriteToUser(addr, next_value)) {
slp.CancelSleep();
R_THROW(svc::ResultInvalidCurrentMemory());
}

View File

@@ -416,7 +416,8 @@ namespace ams::kern {
KProcess * const target = this->GetProcessUnsafe();
/* Terminate the process. */
target->Terminate();
/* NOTE: This result is seemingly-intentionally not checked by Nintendo. */
static_cast<void>(target->Terminate());
R_SUCCEED();
}
@@ -1133,7 +1134,7 @@ namespace ams::kern {
R_SUCCEED();
}
Result KDebugBase::OnExitProcess(KProcess *process) {
void KDebugBase::OnExitProcess(KProcess *process) {
MESOSPHERE_ASSERT(process != nullptr);
/* Check if we're attached to a debugger. */
@@ -1148,11 +1149,9 @@ namespace ams::kern {
debug->NotifyAvailable();
}
}
R_SUCCEED();
}
Result KDebugBase::OnTerminateProcess(KProcess *process) {
void KDebugBase::OnTerminateProcess(KProcess *process) {
MESOSPHERE_ASSERT(process != nullptr);
/* Check if we're attached to a debugger. */
@@ -1167,21 +1166,17 @@ namespace ams::kern {
debug->NotifyAvailable();
}
}
R_SUCCEED();
}
Result KDebugBase::OnExitThread(KThread *thread) {
void KDebugBase::OnExitThread(KThread *thread) {
MESOSPHERE_ASSERT(thread != nullptr);
/* Check if we're attached to a debugger. */
if (KProcess *process = thread->GetOwnerProcess(); process != nullptr && process->IsAttachedToDebugger()) {
/* If we are, submit the event. */
const uintptr_t params[2] = { thread->GetId(), static_cast<uintptr_t>(thread->IsTerminationRequested() ? ams::svc::ThreadExitReason_TerminateThread : ams::svc::ThreadExitReason_ExitThread) };
R_TRY(OnDebugEvent(ams::svc::DebugEvent_ExitThread, params, util::size(params)));
static_cast<void>(OnDebugEvent(ams::svc::DebugEvent_ExitThread, params, util::size(params)));
}
R_SUCCEED();
}
}

View File

@@ -167,7 +167,7 @@ namespace ams::kern {
KThread::Register(new_thread);
/* Run the thread. */
new_thread->Run();
MESOSPHERE_R_ABORT_UNLESS(new_thread->Run());
}
void KDpcManager::HandleDpc() {

View File

@@ -38,20 +38,20 @@ namespace ams::kern {
MESOSPHERE_ASSERT_THIS();
}
Result KEvent::Signal() {
void KEvent::Signal() {
KScopedSchedulerLock sl;
R_SUCCEED_IF(m_readable_event_destroyed);
R_RETURN(m_readable_event.Signal());
if (!m_readable_event_destroyed) {
m_readable_event.Signal();
}
}
Result KEvent::Clear() {
void KEvent::Clear() {
KScopedSchedulerLock sl;
R_SUCCEED_IF(m_readable_event_destroyed);
R_RETURN(m_readable_event.Clear());
if (!m_readable_event_destroyed) {
m_readable_event.Clear();
}
}
void KEvent::PostDestroy(uintptr_t arg) {

View File

@@ -17,7 +17,7 @@
namespace ams::kern {
Result KHandleTable::Finalize() {
void KHandleTable::Finalize() {
MESOSPHERE_ASSERT_THIS();
/* Get the table and clear our record of it. */
@@ -35,8 +35,6 @@ namespace ams::kern {
obj->Close();
}
}
R_SUCCEED();
}
bool KHandleTable::Remove(ams::svc::Handle handle) {

View File

@@ -229,9 +229,12 @@ namespace ams::kern {
out->flags |= ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge;
/* Set and check code address. */
/* NOTE: Even though Nintendo passes a size to GetAddressSpaceStart at other call sites, they pass */
/* a number of pages here. Even though this is presumably only used for debug assertions, this is */
/* almost certainly a bug. */
using ASType = KAddressSpaceInfo::Type;
const ASType as_type = this->Is64BitAddressSpace() ? ((GetTargetFirmware() >= TargetFirmware_2_0_0) ? KAddressSpaceInfo::Type_Map39Bit : KAddressSpaceInfo::Type_MapSmall) : KAddressSpaceInfo::Type_MapSmall;
const uintptr_t map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(out->flags), as_type);
const uintptr_t map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(out->flags), as_type, out->code_num_pages);
const size_t map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(out->flags), as_type);
const uintptr_t map_end = map_start + map_size;
out->code_address = map_start + start_address;

View File

@@ -118,29 +118,78 @@ namespace ams::kern {
MESOSPHERE_ASSERT(m_memory_block_tree.empty());
}
bool KMemoryBlockManager::GetRegionForFindFreeArea(KProcessAddress *out_start, KProcessAddress *out_end, KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) {
/* Check that there's room for the pages in the specified region. */
if (num_pages + 2 * guard_pages > region_num_pages) {
return false;
}
/* Determine the aligned start of the guarded region. */
const KProcessAddress guarded_start = region_start + guard_pages * PageSize;
const KProcessAddress aligned_guarded_start = util::AlignDown(GetInteger(guarded_start), alignment);
KProcessAddress aligned_guarded_start_with_offset = aligned_guarded_start + offset;
if (guarded_start > aligned_guarded_start_with_offset) {
if (!util::CanAddWithoutOverflow<uintptr_t>(GetInteger(aligned_guarded_start), alignment)) {
return false;
}
aligned_guarded_start_with_offset += alignment;
}
/* Determine the aligned end of the guarded region. */
const KProcessAddress guarded_end = region_start + ((region_num_pages - (num_pages + guard_pages)) * PageSize);
const KProcessAddress aligned_guarded_end = util::AlignDown(GetInteger(guarded_end), alignment);
KProcessAddress aligned_guarded_end_with_offset = aligned_guarded_end + offset;
if (aligned_guarded_end_with_offset > guarded_end) {
if (aligned_guarded_end < alignment) {
return false;
}
aligned_guarded_end_with_offset -= alignment;
}
/* Check that the extents are valid. */
if (aligned_guarded_end_with_offset < aligned_guarded_start_with_offset) {
return false;
}
/* Set the output extents. */
*out_start = aligned_guarded_start_with_offset;
*out_end = aligned_guarded_end_with_offset;
return true;
}
KProcessAddress KMemoryBlockManager::FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const {
if (num_pages > 0) {
const KProcessAddress region_end = region_start + region_num_pages * PageSize;
const KProcessAddress region_last = region_end - 1;
for (const_iterator it = this->FindIterator(region_start); it != m_memory_block_tree.cend(); it++) {
if (region_last < it->GetAddress()) {
/* Determine the range to search in. */
KProcessAddress search_start = Null<KProcessAddress>;
KProcessAddress search_end = Null<KProcessAddress>;
if (this->GetRegionForFindFreeArea(std::addressof(search_start), std::addressof(search_end), region_start, region_num_pages, num_pages, alignment, offset, guard_pages)) {
/* Iterate over blocks in the search space, looking for a suitable one. */
for (const_iterator it = this->FindIterator(search_start); it != m_memory_block_tree.cend(); it++) {
/* If our block is past the end of our search space, we're done. */
if (search_end < it->GetAddress()) {
break;
}
/* We only want to consider free blocks. */
if (it->GetState() != KMemoryState_Free) {
continue;
}
KProcessAddress area = (it->GetAddress() <= GetInteger(region_start)) ? region_start : it->GetAddress();
area += guard_pages * PageSize;
/* Determine the candidate range. */
KProcessAddress candidate_start = Null<KProcessAddress>;
KProcessAddress candidate_end = Null<KProcessAddress>;
if (!this->GetRegionForFindFreeArea(std::addressof(candidate_start), std::addressof(candidate_end), it->GetAddress(), it->GetNumPages(), num_pages, alignment, offset, guard_pages)) {
continue;
}
const KProcessAddress offset_area = util::AlignDown(GetInteger(area), alignment) + offset;
area = (area <= offset_area) ? offset_area : offset_area + alignment;
/* Try the suggested candidate (coercing into the search region if needed). */
KProcessAddress candidate = candidate_start;
if (candidate < search_start) {
candidate = search_start;
}
const KProcessAddress area_end = area + num_pages * PageSize + guard_pages * PageSize;
const KProcessAddress area_last = area_end - 1;
if (GetInteger(it->GetAddress()) <= GetInteger(area) && area < area_last && area_last <= region_last && GetInteger(area_last) <= GetInteger(it->GetLastAddress())) {
return area;
/* Check if the candidate is valid. */
if (candidate <= search_end && candidate <= candidate_end) {
return candidate;
}
}
}

View File

@@ -88,7 +88,7 @@ namespace ams::kern {
}
}
Result KPageTableBase::InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end) {
void KPageTableBase::InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end) {
/* Initialize our members. */
m_address_space_width = (is_64_bit) ? BITSIZEOF(u64) : BITSIZEOF(u32);
m_address_space_start = KProcessAddress(GetInteger(start));
@@ -130,7 +130,7 @@ namespace ams::kern {
m_impl.InitializeForKernel(table, start, end);
/* Initialize our memory block manager. */
R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager));
MESOSPHERE_R_ABORT_UNLESS(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager));
}
Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
@@ -141,7 +141,7 @@ namespace ams::kern {
/* Define helpers. */
auto GetSpaceStart = [&](KAddressSpaceInfo::Type type) ALWAYS_INLINE_LAMBDA {
return KAddressSpaceInfo::GetAddressSpaceStart(flags, type);
return KAddressSpaceInfo::GetAddressSpaceStart(flags, type, code_size);
};
auto GetSpaceSize = [&](KAddressSpaceInfo::Type type) ALWAYS_INLINE_LAMBDA {
return KAddressSpaceInfo::GetAddressSpaceSize(flags, type);
@@ -155,12 +155,6 @@ namespace ams::kern {
size_t alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Alias);
size_t heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Heap);
/* Adjust heap/alias size if we don't have an alias region. */
if ((flags & ams::svc::CreateProcessFlag_AddressSpaceMask) == ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias) {
heap_region_size += alias_region_size;
alias_region_size = 0;
}
/* Set code regions and determine remaining sizes. */
KProcessAddress process_code_start;
KProcessAddress process_code_end;
@@ -1339,34 +1333,37 @@ namespace ams::kern {
KProcessAddress KPageTableBase::FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const {
KProcessAddress address = Null<KProcessAddress>;
if (num_pages <= region_num_pages) {
KProcessAddress search_start = Null<KProcessAddress>;
KProcessAddress search_end = Null<KProcessAddress>;
if (m_memory_block_manager.GetRegionForFindFreeArea(std::addressof(search_start), std::addressof(search_end), region_start, region_num_pages, num_pages, alignment, offset, guard_pages)) {
if (this->IsAslrEnabled()) {
/* Try to directly find a free area up to 8 times. */
for (size_t i = 0; i < 8; i++) {
const size_t random_offset = KSystemControl::GenerateRandomRange(0, (region_num_pages - num_pages - guard_pages) * PageSize / alignment) * alignment;
const KProcessAddress candidate = util::AlignDown(GetInteger(region_start + random_offset), alignment) + offset;
const size_t random_offset = KSystemControl::GenerateRandomRange(0, (search_end - search_start) / alignment) * alignment;
const KProcessAddress candidate = search_start + random_offset;
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(candidate);
MESOSPHERE_ABORT_UNLESS(it != m_memory_block_manager.end());
if (it->GetState() != KMemoryState_Free) { continue; }
if (!(region_start <= candidate)) { continue; }
if (!(it->GetAddress() + guard_pages * PageSize <= GetInteger(candidate))) { continue; }
if (!(candidate + (num_pages + guard_pages) * PageSize - 1 <= it->GetLastAddress())) { continue; }
if (!(candidate + (num_pages + guard_pages) * PageSize - 1 <= region_start + region_num_pages * PageSize - 1)) { continue; }
address = candidate;
break;
}
/* Fall back to finding the first free area with a random offset. */
if (address == Null<KProcessAddress>) {
/* NOTE: Nintendo does not account for guard pages here. */
/* This may theoretically cause an offset to be chosen that cannot be mapped. */
/* We will account for guard pages. */
const size_t offset_pages = KSystemControl::GenerateRandomRange(0, region_num_pages - num_pages - guard_pages);
address = m_memory_block_manager.FindFreeArea(region_start + offset_pages * PageSize, region_num_pages - offset_pages, num_pages, alignment, offset, guard_pages);
const size_t offset_blocks = KSystemControl::GenerateRandomRange(0, (search_end - search_start) / alignment);
const auto region_end = region_start + region_num_pages * PageSize;
address = m_memory_block_manager.FindFreeArea(search_start + offset_blocks * alignment, (region_end - (search_start + offset_blocks * alignment)) / PageSize, num_pages, alignment, offset, guard_pages);
}
}
/* Find the first free area. */
if (address == Null<KProcessAddress>) {
address = m_memory_block_manager.FindFreeArea(region_start, region_num_pages, num_pages, alignment, offset, guard_pages);
@@ -1792,19 +1789,24 @@ namespace ams::kern {
KScopedSchedulerLock sl;
}
/* Ensure cache coherency, if we're setting pages as executable. */
if (is_x) {
for (const auto &block : pg) {
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(GetVoidPointer(GetHeapVirtualAddress(block.GetAddress())), block.GetSize()));
}
cpu::InvalidateEntireInstructionCache();
}
/* Perform mapping operation. */
const KPageProperties properties = { new_perm, false, false, DisableMergeAttribute_None };
const auto operation = was_x ? OperationType_ChangePermissionsAndRefreshAndFlush : OperationType_ChangePermissions;
const auto operation = was_x ? OperationType_ChangePermissionsAndRefresh : OperationType_ChangePermissions;
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, operation, false));
/* Update the blocks. */
m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, new_state, new_perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None);
/* Ensure cache coherency, if we're setting pages as executable. */
if (is_x) {
for (const auto &block : pg) {
cpu::StoreDataCache(GetVoidPointer(GetHeapVirtualAddress(block.GetAddress())), block.GetSize());
}
if (was_x) {
cpu::InvalidateEntireInstructionCache();
}
@@ -2546,6 +2548,11 @@ namespace ams::kern {
/* We're going to perform an update, so create a helper. */
KScopedPageTableUpdater updater(this);
/* Ensure cache coherency, if we're mapping executable pages. */
if ((perm & KMemoryPermission_UserExecute) == KMemoryPermission_UserExecute) {
cpu::InvalidateEntireInstructionCache();
}
/* Perform mapping operation. */
const KPageProperties properties = { perm, false, false, DisableMergeAttribute_DisableHead };
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
@@ -2569,8 +2576,9 @@ namespace ams::kern {
KScopedLightLock lk(m_general_lock);
/* Check if state allows us to unmap. */
KMemoryPermission old_perm;
size_t num_allocator_blocks;
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, state, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
R_TRY(this->CheckMemoryState(nullptr, std::addressof(old_perm), nullptr, std::addressof(num_allocator_blocks), address, size, KMemoryState_All, state, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
/* Check that the page group is valid. */
R_UNLESS(this->IsValidPageGroup(pg, address, num_pages), svc::ResultInvalidCurrentMemory());
@@ -2587,6 +2595,11 @@ namespace ams::kern {
const KPageProperties properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
R_TRY(this->Operate(updater.GetPageList(), address, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_Unmap, false));
/* Ensure cache coherency, if we're mapping executable pages. */
if ((old_perm & KMemoryPermission_UserExecute) == KMemoryPermission_UserExecute) {
cpu::InvalidateEntireInstructionCache();
}
/* Update the blocks. */
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal);
@@ -2652,8 +2665,7 @@ namespace ams::kern {
/* Invalidate the block. */
if (cur_size > 0) {
/* NOTE: Nintendo does not check the result of invalidation. */
cpu::InvalidateDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size);
MESOSPHERE_R_ABORT_UNLESS(cpu::InvalidateDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size));
}
/* Advance. */
@@ -2676,8 +2688,7 @@ namespace ams::kern {
/* Invalidate the last block. */
if (cur_size > 0) {
/* NOTE: Nintendo does not check the result of invalidation. */
cpu::InvalidateDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size);
MESOSPHERE_R_ABORT_UNLESS(cpu::InvalidateDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size));
}
R_SUCCEED();
@@ -2755,7 +2766,7 @@ namespace ams::kern {
if (cur_size >= sizeof(u32)) {
const size_t copy_size = util::AlignDown(cur_size, sizeof(u32));
const void * copy_src = GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr));
cpu::FlushDataCache(copy_src, copy_size);
MESOSPHERE_R_ABORT_UNLESS(cpu::FlushDataCache(copy_src, copy_size));
R_UNLESS(UserspaceAccess::CopyMemoryToUserAligned32Bit(buffer, copy_src, copy_size), svc::ResultInvalidPointer());
buffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + copy_size);
cur_addr += copy_size;
@@ -2765,7 +2776,7 @@ namespace ams::kern {
/* Copy remaining data. */
if (cur_size > 0) {
const void * copy_src = GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr));
cpu::FlushDataCache(copy_src, cur_size);
MESOSPHERE_R_ABORT_UNLESS(cpu::FlushDataCache(copy_src, cur_size));
R_UNLESS(UserspaceAccess::CopyMemoryToUser(buffer, copy_src, cur_size), svc::ResultInvalidPointer());
}
@@ -2840,7 +2851,7 @@ namespace ams::kern {
if (cur_size >= sizeof(u32)) {
const size_t copy_size = util::AlignDown(cur_size, sizeof(u32));
R_UNLESS(UserspaceAccess::CopyMemoryFromUserAligned32Bit(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), buffer, copy_size), svc::ResultInvalidCurrentMemory());
cpu::StoreDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), copy_size);
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), copy_size));
buffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + copy_size);
cur_addr += copy_size;
@@ -2850,7 +2861,7 @@ namespace ams::kern {
/* Copy remaining data. */
if (cur_size > 0) {
R_UNLESS(UserspaceAccess::CopyMemoryFromUser(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), buffer, cur_size), svc::ResultInvalidCurrentMemory());
cpu::StoreDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size);
MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size));
}
R_SUCCEED();

View File

@@ -221,7 +221,7 @@ namespace ams::kern {
}
/* Set max memory. */
m_max_process_memory = m_page_table.GetHeapRegionSize();
m_max_process_memory = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(m_flags), KAddressSpaceInfo::Type_Heap);
/* Generate random entropy. */
KSystemControl::GenerateRandom(m_entropy, util::size(m_entropy));
@@ -404,7 +404,7 @@ namespace ams::kern {
void KProcess::DoWorkerTaskImpl() {
/* Terminate child threads. */
TerminateChildren(this, nullptr);
MESOSPHERE_R_ABORT_UNLESS(TerminateChildren(this, nullptr));
/* Finalize the handle table, if we're not immortal. */
if (!m_is_immortal && m_is_handle_table_initialized) {
@@ -420,7 +420,7 @@ namespace ams::kern {
Result KProcess::StartTermination() {
/* Finalize the handle table when we're done, if the process isn't immortal. */
ON_SCOPE_EXIT {
ON_RESULT_SUCCESS {
if (!m_is_immortal) {
this->FinalizeHandleTable();
}
@@ -471,7 +471,7 @@ namespace ams::kern {
/* If we need to start termination, do so. */
if (needs_terminate) {
this->StartTermination();
static_cast<void>(this->StartTermination());
/* Note for debug that we're exiting the process. */
MESOSPHERE_LOG("KProcess::Exit() pid=%ld name=%-12s\n", m_process_id, m_name);
@@ -507,23 +507,26 @@ namespace ams::kern {
/* If we need to terminate, do so. */
if (needs_terminate) {
/* Start termination. */
if (R_SUCCEEDED(this->StartTermination())) {
/* Note for debug that we're terminating the process. */
MESOSPHERE_LOG("KProcess::Terminate() OK pid=%ld name=%-12s\n", m_process_id, m_name);
/* Call the debug callback. */
KDebug::OnTerminateProcess(this);
/* Finish termination. */
this->FinishTermination();
} else {
/* If we fail to terminate, register as a worker task. */
ON_RESULT_FAILURE {
/* Note for debug that we're terminating the process. */
MESOSPHERE_LOG("KProcess::Terminate() FAIL pid=%ld name=%-12s\n", m_process_id, m_name);
/* Register the process as a work task. */
KWorkerTaskManager::AddTask(KWorkerTaskManager::WorkerType_ExitProcess, this);
}
};
/* Start termination. */
R_TRY(this->StartTermination());
/* Note for debug that we're terminating the process. */
MESOSPHERE_LOG("KProcess::Terminate() OK pid=%ld name=%-12s\n", m_process_id, m_name);
/* Call the debug callback. */
KDebug::OnTerminateProcess(this);
/* Finish termination. */
this->FinishTermination();
}
R_SUCCEED();
@@ -666,7 +669,7 @@ namespace ams::kern {
R_SUCCEED();
}
Result KProcess::DeleteThreadLocalRegion(KProcessAddress addr) {
void KProcess::DeleteThreadLocalRegion(KProcessAddress addr) {
KThreadLocalPage *page_to_free = nullptr;
/* Release the region. */
@@ -678,7 +681,7 @@ namespace ams::kern {
if (it == m_partially_used_tlp_tree.end()) {
/* If we don't find it, it has to be in the fully used list. */
it = m_fully_used_tlp_tree.find_key(util::AlignDown(GetInteger(addr), PageSize));
R_UNLESS(it != m_fully_used_tlp_tree.end(), svc::ResultInvalidAddress());
MESOSPHERE_ABORT_UNLESS(it != m_fully_used_tlp_tree.end());
/* Release the region. */
it->Release(addr);
@@ -710,8 +713,6 @@ namespace ams::kern {
KThreadLocalPage::Free(page_to_free);
}
R_SUCCEED();
}
void *KProcess::GetThreadLocalRegionPointer(KProcessAddress addr) {
@@ -767,7 +768,7 @@ namespace ams::kern {
MESOSPHERE_ASSERT(m_num_running_threads.Load() > 0);
if (const auto prev = m_num_running_threads--; prev == 1) {
this->Terminate();
static_cast<void>(this->Terminate());
}
}

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