Compare commits

...

114 Commits

Author SHA1 Message Date
Michael Scire
4fe9a89ab8 docs: commit saddest changelog of all time, this is your brain on going to vacation 2023-08-21 17:30:06 -07:00
Michael Scire
de73f6c5bb git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "c3dc418a2"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "c3dc418a2"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-08-21 17:27:16 -07:00
Michael Scire
e488b6ee47 ams: add enum recognition for 16.1.0 2023-08-21 17:26:27 -07:00
Michael Scire
99810dc091 fssystem: fix typo error in BucketTree::Visitor::MoveNext 2023-08-15 14:47:09 -07:00
Liam
e54957285f libstrat: comment fixes for fssystem 2023-08-12 11:33:29 -07:00
Michael Scire
fca213460b libstrat: fix more minor style issues pointed out by Pharynx 2023-08-10 11:48:28 -07:00
Michael Scire
4e6bd19fcd fssystem: fix stupid issue in NodeBuffer move-ctor
Code compiles with this constructor deleted, so it wasn't used, but even so...
2023-08-03 16:58:55 -07:00
Michael Scire
8b88351cb4 mitm: fix errant include on non-hos 2023-06-06 19:32:06 -07:00
Michael Scire
63ea152349 fatal: take good idea from shrek 2023-05-19 11:47:38 -07:00
Michael Scire
3cb54e2b4b git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "f4a966eb4"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "f4a966eb4"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-05-14 03:17:20 -07:00
Michael Scire
e9de11a746 ams: bump version to 1.5.4 2023-05-14 03:16:27 -07:00
Michael Scire
b979b5aa36 docs: 1.5.4 changelog, zelda why the fuck 2023-05-14 03:16:15 -07:00
SciresM
f2ee44da74 romfs/ams.mitm/pm: refactor to dynamically steal heap for certain games. (#2122)
* fs.mitm: skeleton the use of special allocation in romfs build

* pm: add api for ams.mitm to steal application memory

* pm/mitm: okay, that api won't work, try a different one

* romfs: revert memory usage increases; we'll handle torture games case-by-case.

* pm/romfs: first (broken?) pass at dynamic heap.

I cannot wait to figure out all the ways this is wrong.

* Release the dynamic heap a little more eagerly

* romfs: animal crossing is also not a nice game

* romfs: fix issues in close-during-build

* romfs: zelda is a blight upon this earth
2023-05-14 03:06:52 -07:00
Michael Scire
85c23b5781 fusee: actually identify new FS 2023-05-08 18:38:13 -07:00
Michael Scire
8e042f2262 git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "30205111e"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "30205111e"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-05-08 18:25:25 -07:00
Michael Scire
81e9154a52 emummc: add enums for 16.0.3 2023-05-08 18:24:49 -07:00
Michael Scire
e9b9dbc2aa docs: add changelog for 1.5.3 2023-05-08 18:19:31 -07:00
Michael Scire
7e6c849ca4 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "cd0fc2c1d"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "cd0fc2c1d"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-05-08 18:06:50 -07:00
Michael Scire
8ec7c096d0 git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "d2fcc73eb"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "d2fcc73eb"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-05-08 18:05:36 -07:00
Michael Scire
6e5b901a9b emummc: support 16.0.3 2023-05-08 18:03:35 -07:00
Michael Scire
b800953d66 ams: recognize 16.0.3('s FS) 2023-05-08 17:51:13 -07:00
Michael Scire
f0240db75a fs.mitm: mitm glue for font replacement, before I forget 2023-05-08 17:40:10 -07:00
Michael Scire
1f5ec68a5c ams: fix compilation with gcc 13 2023-05-07 03:36:46 -07:00
Michael Scire
ed9e60acb9 kern: track heap in KPageTableBase::MemoryRange 2023-04-30 16:50:53 -07:00
Liam
a7300b0fa4 haze: fix file size transmission issue 2023-04-18 22:15:48 -07:00
Liam
8e2eca2004 haze: abstract firmware version and serial number fetch 2023-04-18 22:15:48 -07:00
Michael Scire
9f83b3c838 ams: I really need to automate keeping this in sync 2023-04-17 20:57:57 -07:00
Michael Scire
434c8cefc4 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "ecc8b1811"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "ecc8b1811"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-04-17 20:40:41 -07:00
Michael Scire
d8aed7de6d ams: add 16.0.2 enum 2023-04-17 20:40:02 -07:00
Liam
a346014dc7 haze: get serial number and firmware version from set:sys 2023-04-17 22:22:28 -04:00
Michael Scire
4b3c801e9f dist: add haze to output zip 2023-04-17 14:35:25 -07:00
Michael Scire
90db1223f6 docs: avoid unintended insinuations 2023-04-17 14:24:27 -07:00
Michael Scire
fa64a6ff4d docs: pretend to be literate 2023-04-17 14:20:16 -07:00
Michael Scire
0c6a06a0cf git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "7340e2eab"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "7340e2eab"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-04-17 14:19:59 -07:00
Michael Scire
5efb4a2a98 docs: bump version, 16.0.1 exists too 2023-04-17 14:19:18 -07:00
liamwhite
3b662122f9 troposphere: add haze MTP server (#2095)
* troposphere: add haze MTP server

* haze: adjust banner, new lines between class sections, single-statement if

* haze: remove additional newlines between sections

* haze: avoid use of reference out parameter

* haze: console_main_loop: style

* haze: event_reactor, file_system_proxy, ptp: style

* haze: ptp_data_builder, ptp_object_database, ptp_object_heap, results, usb_session: style

* haze: event_reactor, ptp_data_parser, async_usb_server, ptp_object_database, ptp_object_heap: style

* haze: ptp_responder: style

* haze: usb_session: style

* haze: use svc defs from vapours

* haze: misc comments

* haze: fix pointer overflow check

* haze: fix copy paste error

* haze: use alignment, invalidate cached use values in console

* haze: fix stray hex constant

* haze: misc style

* haze: fixes for windows

* haze: add GetObjectPropsSupported, GetObjectPropDesc, GetObjectPropValue

* haze: add SetObjectPropValue

* haze: improve object database API

* haze: improve WriteVariableLengthData readability

* haze: fix directory renames on windows

* haze: ptp_object_database: fix collation

* haze: event_reactor: fix size validation

* haze: ptp_responder: improve documentation

* haze: ptp_responder: avoid unnecessary fs interaction in GetObjectPropValue

* haze: ptp_responder: fix object deletion on windows

* haze: tear down sessions on suspension

* haze: prefer more specific data types

* haze: misc

* haze: fix usb 3.0 support

* haze: improve host-to-device file transfer performance

* haze: report device serial

* haze: move static_assert to requires, fix alignment
2023-04-17 14:08:05 -07:00
Michael Scire
e9b28ab4b1 kern: adjust wording to be more technically correct 2023-03-27 10:54:58 -07:00
Michael Scire
1afb184c14 docs: pretend I know how to type common words 2023-03-14 01:52:06 -07:00
Michael Scire
5e070600a9 docs: add faq.md
"Alexa, what does June 15th mean?"
2023-03-14 01:48:19 -07:00
Michael Scire
8274081e39 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "b1607dc8a"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "b1607dc8a"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-03-13 17:17:50 -07:00
Michael Scire
f1ad26ce84 ams: bump version 2023-03-13 17:16:51 -07:00
Michael Scire
e4c314146e docs: update changelog 2023-03-13 17:16:33 -07:00
Michael Scire
52f00731d9 settings: add os guard 2023-03-12 22:34:23 -07:00
Michael Scire
476d658a79 ams: allow convertible-to-result in abort print macros 2023-03-11 15:14:33 -07:00
Michael Scire
7263022bac docs: mention bluetooth db feature 2023-03-10 10:24:19 -07:00
Michael Scire
e0e7aa1e2f set.mitm: misc style fixes for bluetooth db 2023-03-10 10:19:58 -07:00
ndeadly
bd9d8fff46 Add system setting to mirror bluetooth pairing database to sd card (#1787)
* ams_mitm: add ability to mirror bluetooth device pairing database to sd card via a system setting

* ams_mitm: address requested stylistic changes

* ams_mitm: make use of R_SUCCEED macro

* ams_mitm: use settings::BluetoothDevicesSettings instead of libnx type

* ams_mitm: fix logic error when truncating pairing database on read

* Update .ini comment

* ams_mitm: missing R_TRY around call to fs::FlushFile

* stratosphere: remove union from BluetoothDevicesSettings type

---------

Co-authored-by: ndeadly <24677491+ndeadly@users.noreply.github.com>
2023-03-10 10:06:38 -07:00
Michael Scire
61e3f0b391 windows: disable -fdata-sections
This causes all data to be emitted as .data$*. This breaks fzero-initialized-in-bss,
because linker puts stuff in .data even when it's all-zero and should end up in .bss.
2023-03-09 23:46:54 -07:00
Michael Scire
cd9b173318 windows: re-enable lto for os/fs libraries 2023-03-09 23:46:31 -07:00
Michael Scire
a8df400825 kern: fix stray addressof operator 2023-03-08 09:46:38 -07:00
Michael Scire
68040e2922 windows: add brave new mingw compat hook for gcc 12.2.0+ 2023-03-07 22:07:03 -07:00
Michael Scire
8da4d14e15 kern: minor cleanup (thanks @liamwhite) 2023-03-06 21:18:00 -07:00
Michael Scire
e2ebf9c0ff fatal: correct comment about pools 2023-03-01 03:21:51 -07:00
Michael Scire
5fb6f52b9e fatal: dynamically allocate memory as required (preferring system > nonsecure > unsafe) 2023-03-01 03:20:49 -07:00
Michael Scire
982389dceb os: add UnsafeMemory apis 2023-03-01 03:20:49 -07:00
Adubbz
f636596ee2 daybreak: scale title font size
(cherry picked from commit 035b37c615183bd387210a54d269346e3a9b379a)
2023-02-25 10:53:16 +11:00
Michael Scire
0a2440522f fatal: use a hack to be kinder wrt pl:u session limit 2023-02-23 22:06:49 -07:00
Michael Scire
3292ea5970 kern: fix stray comment copy/paste error 2023-02-23 22:00:00 -07:00
Michael Scire
33d42f4831 erpt: update server code for 16.0.0 logic changes 2023-02-23 21:51:51 -07:00
Michael Scire
46094cfb3e kern: increase non-dynamic heap sizes to 8 GB to match 2023-02-23 19:05:52 -07:00
Michael Scire
618691a500 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "af0d00890"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "af0d00890"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-02-23 09:01:41 -07:00
Michael Scire
356d89244f docs: add 1.5.0 pre-release changelog 2023-02-22 18:36:01 -07:00
Michael Scire
1ce3611695 git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "bba1f1fb6"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "bba1f1fb6"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-02-22 18:26:15 -07:00
Michael Scire
1ab8b23444 emummc: try fixing commit id 2023-02-22 18:25:41 -07:00
Michael Scire
06b4738d54 emummc: re-update for 16.0.0 2023-02-22 18:24:51 -07:00
Michael Scire
b92c614347 git subrepo clone --force --branch=develop https://github.com/m4xw/emummc
subrepo:
  subdir:   "emummc"
  merged:   "4714b2df9"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "4714b2df9"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-02-22 18:23:27 -07:00
Michael Scire
99175c1149 loader: update usb3 patches for 16.0.0 2023-02-22 17:19:51 -08:00
Michael Scire
8876eedfb0 ncm: alignment was changed for PlaceHolderId/ContentId in 16.0.0 2023-02-22 17:19:51 -08:00
Michael Scire
bbcee8c77c ncm: fix inversion in activation skipping 2023-02-22 17:19:51 -08:00
Michael Scire
f7915c2c05 ncm: Add IntegratedContent*Impl 2023-02-22 17:19:51 -08:00
Michael Scire
668cabd4a2 ncm: first pass at ContentManagerImpl refactor (missing the IntegratedImpls, won't link) 2023-02-22 17:19:51 -08:00
Michael Scire
d64ab354ad kern: 16.x web applet crashes on exit with 48 MB stolen (rip) 2023-02-22 17:19:51 -08:00
Michael Scire
59b518783d ncm: fix copy/paste error in switch case 2023-02-22 17:19:51 -08:00
Michael Scire
6462101b6f strat: fix sysmodule building, bump version so I don't forget later 2023-02-22 17:19:51 -08:00
Michael Scire
0ea5dbcfbb libstrat: make build with new ncm/fs api changes (sysmodules probably fail to build) 2023-02-22 17:19:51 -08:00
Michael Scire
bb6446aada erpt: update for new ids 2023-02-22 17:19:51 -08:00
Michael Scire
e46e7e0eb1 boot2: update for 16.0.0 2023-02-22 17:19:51 -08:00
Michael Scire
cb89c66bd8 emummc: update for 16.0.0 2023-02-22 17:19:51 -08:00
Michael Scire
e85a512cf4 fusee/exo: implement the usual changes for new firmware support 2023-02-22 17:19:51 -08:00
Michael Scire
7d9fea01c3 kern: bump supported version to 16.x 2023-02-22 17:19:51 -08:00
Michael Scire
406320f6ec kern: better divide non-secure size, don't waste fatal memory unless necessary 2023-02-22 17:19:51 -08:00
Michael Scire
aad2be0a01 kern: delete creation time field from KProcess 2023-02-22 17:19:51 -08:00
Michael Scire
25383db524 kern: add InfoType_IoRegionHint 2023-02-22 17:19:51 -08:00
Michael Scire
48f4c526f3 kern: refactor priority inheritance to represent locks as C++ objects 2023-02-22 17:19:51 -08:00
Michael Scire
1279d236f3 kern: remove unnecessary interrupt disables from arbiter/condvar 2023-02-22 17:19:51 -08:00
Michael Scire
008eb974d4 kern: KConditionVariable::SignalToAddress now emits dmb before userspace write 2023-02-22 17:19:51 -08:00
Michael Scire
035cebef9d kern: refactor init (kill identity map, merge cpu on logic) 2023-02-22 17:19:51 -08:00
Michael Scire
8db22967bf kern: use variable-count parameter arrays for DebugEvents 2023-02-22 17:19:51 -08:00
Michael Scire
db510f96c3 kern: update KSystemControl::InitializePhase1, dynamically scale 39-bit address space regions 2023-02-22 17:19:51 -08:00
Michael Scire
6e2dd791b2 kern: update for new ChangePermissions page table operation 2023-02-22 17:19:51 -08:00
Michael Scire
bff61c68ab kern: adjust pool allocations 2023-02-22 17:19:51 -08:00
Michael Scire
ca7734ffaf kern: simplify KSchedulerLock::Lock 2023-02-22 17:19:51 -08:00
Michael Scire
ed22f802ee kern: allow QueryIoMapping to find Static mappings 2023-02-22 17:19:51 -08:00
Michael Scire
8ffc177b44 kern: update UnmapIoRegion for new Mapping_Memory handling 2023-02-22 17:19:51 -08:00
Michael Scire
c058376b3b kern: use tree for IoPool regions instead of list 2023-02-22 17:19:51 -08:00
Michael Scire
d5ebf13094 kern: optimize userspace access asm to use cheaper instruction in io memory loops 2023-02-22 17:19:51 -08:00
Michael Scire
695c125721 kern: use different psr masks for 64 and 32-bit El0 threads 2023-02-22 17:19:51 -08:00
Michael Scire
e7e3e7b374 kern: increase stack parameter size by 0x10 2023-02-22 17:19:51 -08:00
Michael Scire
3a5f406c5f kern: update scheduler for new switch count tracking logic 2023-02-21 03:12:17 -07:00
Michael Scire
8176f085f1 gpio: really not sure how this works before, lol 2023-01-30 23:13:45 -07:00
Michael Scire
7a69f2f062 kern/pm: only steal 8 MB from applet.
WebApplet crashes on exit with 16 more MB stolen, apparently.
2023-01-24 19:54:28 -07:00
Michael Scire
32b590e7ab git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "b7711b8fb"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "b7711b8fb"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-01-24 14:39:54 -07:00
Michael Scire
590f22933d docs/ams: bump version to 1.4.1 2023-01-24 14:39:06 -07:00
Michael Scire
0dd071b279 romfs: thank you fire emblem, very cool (closes #2021) 2023-01-24 14:07:50 -07:00
Michael Scire
f1132fbf5a romfs: push clobber fix missed by git add 2023-01-24 14:03:54 -07:00
Michael Scire
9cd57b6c61 romfs: reduce peak allocation sizes by enabling intermediate context frees 2023-01-24 14:02:05 -07:00
0x8ff
bf66e40a7b Update ReSwitched Team URL
reswitched.team is a dead domain no longer owned by the ReSwitched Team
2023-01-20 19:01:33 -08:00
Michael Scire
77cc53227a sdmmc: fix wrong mode select for GcAsic(Fpga)Speed 2023-01-19 21:47:19 -07:00
Michael Scire
59a295db79 sdmmc: fix missing call to GetSdStatus at non-uhsi mode 2023-01-19 21:44:44 -07:00
Michael Scire
e4b9930bf3 kern: fix unnecessarily strong load in aligned spinlock
Copy-paste error I didn't notice for two years, whoops
2022-12-25 01:56:31 -07:00
Michael Scire
04c9004e05 erpt: fix multiple issues with automatic report cleanup (thanks @yellows8)
* Setting retrieval was performed before the call that used the setting.
* Call to detect number of files passed incomplete path and was guaranteed to fail.
* Call to delete reports passed incomplete path and was guaranteed to do nothing.
2022-12-13 01:08:13 -07:00
Michael Scire
1f8798ace7 kern: fix GetProcessId wrong result on invalid parameter 2022-12-04 13:40:44 -07:00
Michael Scire
ff7a80e592 dmnt: allow string termination to end a toggle (closes #1980) 2022-10-28 14:14:38 -07:00
Michael Scire
e3ace4be15 exo: fix MemoryArrange enum typo 2022-10-19 15:18:08 -07:00
271 changed files with 9436 additions and 1727 deletions

View File

@@ -38,7 +38,7 @@ In no particular order, we credit the following for their invaluable contributio
* __switchbrew__ for the [libnx](https://github.com/switchbrew/libnx) project and the extensive [documentation, research and tool development](http://switchbrew.org) pertaining to the Nintendo Switch.
* __devkitPro__ for the [devkitA64](https://devkitpro.org/) toolchain and libnx support.
* __ReSwitched Team__ for additional [documentation, research and tool development](https://reswitched.team/) pertaining to the Nintendo Switch.
* __ReSwitched Team__ for additional [documentation, research and tool development](https://reswitched.github.io/) pertaining to the Nintendo Switch.
* __ChaN__ for the [FatFs](http://elm-chan.org/fsw/ff/00index_e.html) module.
* __Marcus Geelnard__ for the [bcl-1.2.0](https://sourceforge.net/projects/bcl/files/bcl/bcl-1.2.0) library.
* __naehrwert__ and __st4rk__ for the original [hekate](https://github.com/nwert/hekate) project and its hwinit code base.

View File

@@ -51,6 +51,8 @@ dist: dist-no-debug
cp $(CURRENT_DIRECTORY)/stratosphere/spl/$(ATMOSPHERE_OUT_DIR)/spl.elf $(DIST_DIR)/spl.elf
cp $(CURRENT_DIRECTORY)/stratosphere/TioServer/$(ATMOSPHERE_OUT_DIR)/TioServer.elf $(DIST_DIR)/TioServer.elf
cp $(CURRENT_DIRECTORY)/troposphere/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf
cp $(CURRENT_DIRECTORY)/troposphere/haze/haze.elf $(DIST_DIR)/haze.elf
cp $(CURRENT_DIRECTORY)/troposphere/reboot_to_payload/reboot_to_payload.elf $(DIST_DIR)/reboot_to_payload.elf
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../;
rm -rf $(DIST_DIR)
@@ -106,6 +108,7 @@ dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
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
cp troposphere/haze/haze.nro $(DIST_DIR)/switch/haze.nro
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION).zip ./*; cd ../;
rm -rf $(DIST_DIR)
cp fusee/$(ATMOSPHERE_BOOT_OUT_DIR)/fusee.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin

View File

@@ -67,6 +67,10 @@
; Note that this setting is ignored (and treated as 1) when htc is enabled.
; 0 = Disabled, 1 = Enabled
; enable_log_manager = u8!0x0
; Controls whether the bluetooth pairing database is redirected to the SD card (shared across sysmmc/all emummcs)
; NOTE: On <13.0.0, the database size was 10 instead of 20; booting pre-13.0.0 will truncate the database.
; 0 = Disabled, 1 = Enabled
; enable_external_bluetooth_db = u8!0x0
[hbloader]
; Controls the size of the homebrew heap when running as applet.
; If set to zero, all available applet memory is used as heap.

View File

@@ -1,8 +1,77 @@
# Changelog
## 1.5.5
+ Support was added for 16.1.0.
+ General system stability improvements to enhance the user's experience.
## 1.5.4
+ Experimental new functionality was implemented to prevent crashing when building romfs for certain games with obscene file counts.
+ This includes both Fire Emblem: Engage (~190000 files), and The Legend of Zelda: Tears of the Kingdom (~300000) files.
+ The solution involved adding functionality to ams.mitm/pm to dynamically steal memory from the application (and system) pool as needed when the games have romfs mods.
+ No memory is taken, and there is no cost to this functionality when playing without mods (or with overrides disabled).
+ The Legend of Zelda: Tears of the Kingdom is currently the absolute worst case game, requiring ~48 MB of memory to build a romfs image to play with mods.
+ Right now, the memory is sourced as follows: 32 MB (base ams.mitm heap), 10 MB (stolen from application pool), 8 MB (dynamically stolen from system pool).
+ This is 50 MB, which allows a little overhead in the worst case (prevents crashing due to exhausting the heap for other allocations in ams.mitm).
+ Zelda is remarkably sensitive to memory being stolen from the application pool, tolerating no more than 16 MB on 1.0.0 and 12 MB on 1.1.0. I have chosen to steal 10 MB, to be safe, for now.
+ This may break on a future game update, but I will fix it if and when that happens. There is no perfect solution; the game simply requires too much memory to support mods flawlessly, and I am forced to compromise.
+ As usual, if you encounter a game that exhausts ams.mitm's memory (crashing it) when loading layeredfs mods, please contact `SciresM#0524`.
"I am jinxing myself by saying this, but it's really hard to imagine any game being worse than The Legend of Zelda: Tears of the Kingdom, but if it happens again I will drop everything to fix it as usual".
+ General system stability improvements to enhance the user's experience.
## 1.5.3
+ Support was added for 16.0.3.
+ Atmosphère was updated to use GCC 13/newlib (latest devkitA64/devkitARM releases).
+ **Please note**: This introduces a known issue, which is currently being worked on.
+ As you may recall from the 1.4.1 changelog, Fire Emblem: Engage requires enormous amounts of memory to support using layeredfs mods with the game.
+ Latest GCC/newlib slightly increases malloc overhead size, which makes the previous memory increase insufficient.
+ A general-case solution to this is in the works, which should hopefully fix the problem in a way that doesn't jinx me for the future.
+ A number of minor issues were fixed and improvements were made, including:
+ An issue was fixed that caused system font replacement to not work on 16.0.0+.
+ An minor accuracy issue was addressed in mesosphere's management of certain memory ranges; this issue would have had zero visible impact to the end-user.
+ General system stability improvements to enhance the user's experience.
## 1.5.2
+ A homebrew application (`haze`) was added for performing USB file transfer (with thanks to @liamwhite for both design and implementation).
+ `haze` is included with atmosphère, and provides access to the SD card via the PTP/MTP protocol.
+ **Please note**: haze will show inside the homebrew menu under the name "USB File Transfer".
+ **Please note**: Atmosphère cannot be updated at runtime, and trying to install an atmosphère update via haze will fail as usual.
+ General system stability improvements to enhance the user's experience.
## 1.5.1
+ `fatal` was updated to reduce memory footprint.
+ Starting in 16.0.0, official `fatal` has no framebuffer or rendering logic, and instead calls other system service commands to draw the screen.
+ However, these commands aren't usable by atmosphère (too small rendering window, bad color support).
+ To reduce the relative memory footprint differential between atmosphère and official code, the framebuffer (2 MB) is now dynamically allocated when needed.
+ This will try to allocate from multiple pools (preferring System > System_NonSecure > Application).
+ This technically requires that 2 MB be available in at least one of these pools for the fatal screen to render (otherwise, a reboot-to-black-and-white-fatal will occur), but this should be a non-issue in almost all cases.
+ A feature was added to optionally mirror the bluetooth pairing database to the SD card (thanks @ndeadly).
+ This allows device pairings to be automatically kept in-sync across sysmmc/all emummcs.
+ This is opt-in, and can be controlled by setting `atmosphere!enable_external_bluetooth_db = u8!0x1`.
+ When enabled, the pairing database will be synchronized to `/atmosphere/bluetooth_devices.db`.
+ General system stability improvements to enhance the user's experience.
## 1.5.0
+ Support was added for 16.0.0
+ `mesosphère` was updated to reflect the latest official kernel behavior.
+ `ncm` was updated to reflect the latest official behavior.
+ Many FS apis were updated under the hood to reflect the latest official behavior.
+ **Please Note**: 16.0.0 made breaking changes to a number of system APIs, including in FS/NCM/Shared Font commands that some homebrew programs may use.
+ These programs may encounter strange errors, and may need to be recompiled with a libnx updated to support 16.0.0's changes to function properly.
+ A number of minor issues were fixed and improvements were made, including:
+ An issue was fixed that could cause GPIO outputs to be misconfigured under certain circumstances.
+ General system stability improvements to enhance the user's experience.
## 1.4.1
+ A number of minor issues were fixed and improvements were made, including:
+ `dmnt` cheat toggle files are no longer ignored when they are missing a trailing newline.
+ The mechanism for automatically cleaning up `erpt_reports` added in 1.3.0 was fixed.
+ This was actually just very fundamentally broken and has never worked, but it is verified working now.
+ Minor fixes were made in `mesosphère` to match official kernel behavior (spin lock assembly was corrected, wrong result on failure in in GetProcessId was corrected).
+ A missing call to GetSdStatus when initializing SD cards at non uhs-i mode was added in the sdmmc driver.
+ `ams.mitm`'s memory usage was increased by 16 MB, to prevent crashing when building romfs for games with obscene file counts.
+ To quote the changelog for 1.2.3: "Animal Crossing's 2.0.0 update contains >99000 files [...] It's really hard to imagine any game being worse than Animal Crossing".
+ As it turns out, Fire Emblem: Engage has ~186000 files, and is approximately twice as bad as animal crossing.
+ The additional memory here is taken from the applet pool; no issues are expected to arise from this, but please report anything you may run into.
+ As usual, if you encounter a game that exhausts ams.mitm's memory (crashing it) when loading layeredfs mods, please contact `SciresM#0524`.
+ I am jinxing myself by saying this, but it's really hard to imagine any game being worse than Fire Emblem: Engage, but if it happens again I will drop everything to fix it as usual.
+ General system stability improvements to enhance the user's experience.
## 1.4.0
+ Support was added for 15.0.0.
+ `mesosphère` was updated to reflect the latest official kernel behavior.
+ `ncm` was updated to reflect the latest official kernel behavior.
+ `ncm` was updated to reflect the latest official behavior.
+ A number of minor issues were fixed and improvements were made, including:
+ The capacity limit on registered add-on contents was fixed in NCM to reflect the increase that occurred in 12.0.0.
+ An off-by-one was fixed in mesosphere when computing the new value for an address arbiter signaled with ModifyByWaitingCountIfEqual.

18
docs/faq.md Normal file
View File

@@ -0,0 +1,18 @@
# Frequently Asked Questions
This document serves as a place to store answers for common questions received about Atmosphère.
## What does "June 15th" mean?
When Atmosphère began development in February 2018, "June 15" was given as the estimate/target date for a first release, to coincide with the planned disclosure of a vulnerability.
This deadline was missed, hard.
People made rather a lot of fun of me (SciresM) for this.
Several months later, when the first Atmosphère release occurred, I captioned it "Happy June 15th!" and pretended like I hadn't missed the first deadline.
This amused me a lot, and so the practice has been kept up for every single release since.
Depending on who you ask, you may be told that this is a dumb joke and it is not funny.
This is incorrect. It is definitely a dumb joke, but it is also hilarious.

View File

@@ -27,3 +27,6 @@ A list of planned features for Atmosphère can be found [here](roadmap.md).
## Release History
A changelog of previous versions of Atmosphère can be found [here](changelog.md).
## Frequently Asked Questions
Answers to one or more frequently asked questions may be found [here](faq.md).

4
emummc/.gitrepo vendored
View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/m4xw/emummc
branch = develop
commit = 4714b2df9eaf68fb85516b35f7f4265ab0413825
parent = 99f6a96845b6097d50f5059eea9245d27876f26a
commit = 30205111ee375bef96f0f76cb6a3130a2f0fc85c
parent = 81e9154a52a976f85317bddd0131426599d26a62
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 - 15.0.0**
**1.0.0 - 16.0.3**
## Features
* Arbitrary SDMMC backend selection

View File

@@ -63,6 +63,10 @@
#include "offsets/1400_exfat.h"
#include "offsets/1500.h"
#include "offsets/1500_exfat.h"
#include "offsets/1600.h"
#include "offsets/1600_exfat.h"
#include "offsets/1603.h"
#include "offsets/1603_exfat.h"
#include "../utils/fatal.h"
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
@@ -137,6 +141,10 @@ DEFINE_OFFSET_STRUCT(_1400);
DEFINE_OFFSET_STRUCT(_1400_EXFAT);
DEFINE_OFFSET_STRUCT(_1500);
DEFINE_OFFSET_STRUCT(_1500_EXFAT);
DEFINE_OFFSET_STRUCT(_1600);
DEFINE_OFFSET_STRUCT(_1600_EXFAT);
DEFINE_OFFSET_STRUCT(_1603);
DEFINE_OFFSET_STRUCT(_1603_EXFAT);
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
switch (version) {
@@ -234,6 +242,14 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
return &(GET_OFFSET_STRUCT_NAME(_1500));
case FS_VER_15_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_1500_EXFAT));
case FS_VER_16_0_0:
return &(GET_OFFSET_STRUCT_NAME(_1600));
case FS_VER_16_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_1600_EXFAT));
case FS_VER_16_0_3:
return &(GET_OFFSET_STRUCT_NAME(_1603));
case FS_VER_16_0_3_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_1603_EXFAT));
default:
fatal_abort(Fatal_UnknownVersion);
}

View File

@@ -92,6 +92,12 @@ enum FS_VER
FS_VER_15_0_0,
FS_VER_15_0_0_EXFAT,
FS_VER_16_0_0,
FS_VER_16_0_0_EXFAT,
FS_VER_16_0_3,
FS_VER_16_0_3_EXFAT,
FS_VER_MAX,
};

59
emummc/source/FS/offsets/1600.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_1600_H__
#define __FS_1600_H__
// Accessor vtable getters
#define FS_OFFSET_1600_SDMMC_ACCESSOR_GC 0x1862A0
#define FS_OFFSET_1600_SDMMC_ACCESSOR_SD 0x187F20
#define FS_OFFSET_1600_SDMMC_ACCESSOR_NAND 0x186760
// Hooks
#define FS_OFFSET_1600_SDMMC_WRAPPER_READ 0x1821F0
#define FS_OFFSET_1600_SDMMC_WRAPPER_WRITE 0x182250
#define FS_OFFSET_1600_RTLD 0x269B0
#define FS_OFFSET_1600_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
#define FS_OFFSET_1600_CLKRST_SET_MIN_V_CLK_RATE 0x1A2D30
// Misc funcs
#define FS_OFFSET_1600_LOCK_MUTEX 0x17B730
#define FS_OFFSET_1600_UNLOCK_MUTEX 0x17B780
#define FS_OFFSET_1600_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1821B0
#define FS_OFFSET_1600_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1821D0
// Misc Data
#define FS_OFFSET_1600_SD_MUTEX 0xFFB3F0
#define FS_OFFSET_1600_NAND_MUTEX 0xFF6B58
#define FS_OFFSET_1600_ACTIVE_PARTITION 0xFF6B98
#define FS_OFFSET_1600_SDMMC_DAS_HANDLE 0xFDC8B0
// NOPs
#define FS_OFFSET_1600_SD_DAS_INIT 0x258D4
// Nintendo Paths
#define FS_OFFSET_1600_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x00063B48, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00070D6C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0007790C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008A754, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_1600_H__

59
emummc/source/FS/offsets/1600_exfat.h vendored Normal file
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_1600_EXFAT_H__
#define __FS_1600_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_1600_EXFAT_SDMMC_ACCESSOR_GC 0x190F80
#define FS_OFFSET_1600_EXFAT_SDMMC_ACCESSOR_SD 0x192C00
#define FS_OFFSET_1600_EXFAT_SDMMC_ACCESSOR_NAND 0x191440
// Hooks
#define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_READ 0x18CED0
#define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_WRITE 0x18CF30
#define FS_OFFSET_1600_EXFAT_RTLD 0x269B0
#define FS_OFFSET_1600_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
#define FS_OFFSET_1600_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1ADA10
// Misc funcs
#define FS_OFFSET_1600_EXFAT_LOCK_MUTEX 0x186410
#define FS_OFFSET_1600_EXFAT_UNLOCK_MUTEX 0x186460
#define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x18CE90
#define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x18CEB0
// Misc Data
#define FS_OFFSET_1600_EXFAT_SD_MUTEX 0x100D3F0
#define FS_OFFSET_1600_EXFAT_NAND_MUTEX 0x1008B58
#define FS_OFFSET_1600_EXFAT_ACTIVE_PARTITION 0x1008B98
#define FS_OFFSET_1600_EXFAT_SDMMC_DAS_HANDLE 0xFE98B0
// NOPs
#define FS_OFFSET_1600_EXFAT_SD_DAS_INIT 0x258D4
// Nintendo Paths
#define FS_OFFSET_1600_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x00063B48, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00070D6C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0007790C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008A754, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_1600_EXFAT_H__

59
emummc/source/FS/offsets/1603.h vendored Normal file
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_1603_H__
#define __FS_1603_H__
// Accessor vtable getters
#define FS_OFFSET_1603_SDMMC_ACCESSOR_GC 0x1862F0
#define FS_OFFSET_1603_SDMMC_ACCESSOR_SD 0x187F70
#define FS_OFFSET_1603_SDMMC_ACCESSOR_NAND 0x1867B0
// Hooks
#define FS_OFFSET_1603_SDMMC_WRAPPER_READ 0x182240
#define FS_OFFSET_1603_SDMMC_WRAPPER_WRITE 0x1822A0
#define FS_OFFSET_1603_RTLD 0x269B0
#define FS_OFFSET_1603_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
#define FS_OFFSET_1603_CLKRST_SET_MIN_V_CLK_RATE 0x1A2D80
// Misc funcs
#define FS_OFFSET_1603_LOCK_MUTEX 0x17B780
#define FS_OFFSET_1603_UNLOCK_MUTEX 0x17B7D0
#define FS_OFFSET_1603_SDMMC_WRAPPER_CONTROLLER_OPEN 0x182200
#define FS_OFFSET_1603_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x182220
// Misc Data
#define FS_OFFSET_1603_SD_MUTEX 0xFFB3F0
#define FS_OFFSET_1603_NAND_MUTEX 0xFF6B58
#define FS_OFFSET_1603_ACTIVE_PARTITION 0xFF6B98
#define FS_OFFSET_1603_SDMMC_DAS_HANDLE 0xFDC8B0
// NOPs
#define FS_OFFSET_1603_SD_DAS_INIT 0x258D4
// Nintendo Paths
#define FS_OFFSET_1603_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x00063B98, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00070DBC, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0007795C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008A7A4, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_1603_H__

59
emummc/source/FS/offsets/1603_exfat.h vendored Normal file
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_1603_EXFAT_H__
#define __FS_1603_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_1603_EXFAT_SDMMC_ACCESSOR_GC 0x190FD0
#define FS_OFFSET_1603_EXFAT_SDMMC_ACCESSOR_SD 0x192C50
#define FS_OFFSET_1603_EXFAT_SDMMC_ACCESSOR_NAND 0x191490
// Hooks
#define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_READ 0x18CF20
#define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_WRITE 0x18CF80
#define FS_OFFSET_1603_EXFAT_RTLD 0x269B0
#define FS_OFFSET_1603_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
#define FS_OFFSET_1603_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1ADA60
// Misc funcs
#define FS_OFFSET_1603_EXFAT_LOCK_MUTEX 0x186460
#define FS_OFFSET_1603_EXFAT_UNLOCK_MUTEX 0x1864B0
#define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x18CEE0
#define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x18CF00
// Misc Data
#define FS_OFFSET_1603_EXFAT_SD_MUTEX 0x100D3F0
#define FS_OFFSET_1603_EXFAT_NAND_MUTEX 0x1008B58
#define FS_OFFSET_1603_EXFAT_ACTIVE_PARTITION 0x1008B98
#define FS_OFFSET_1603_EXFAT_SDMMC_DAS_HANDLE 0xFE98B0
// NOPs
#define FS_OFFSET_1603_EXFAT_SD_DAS_INIT 0x258D4
// Nintendo Paths
#define FS_OFFSET_1603_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x00063B98, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00070DBC, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0007795C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008A7A4, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_1603_EXFAT_H__

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 0x18, 0xA5, 0x6F, 0xEF, 0x72, 0x11, 0x62, 0xC5, 0x1A, 0x14, 0xF1, 0x8C, 0x21, 0x83, 0x27, 0xB7
.byte 0x3A, 0x9C, 0xF0, 0x39, 0x70, 0x23, 0xF6, 0xAF, 0x71, 0x44, 0x60, 0xF4, 0x6D, 0xED, 0xA1, 0xD6
/* Mariko Production Master Kek Source. */
.byte 0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D
.byte 0xA5, 0xEC, 0x16, 0x39, 0x1A, 0x30, 0x16, 0x08, 0x2E, 0xCF, 0x09, 0x6F, 0x5E, 0x7C, 0xEE, 0xA9
/* 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. */
@@ -106,6 +106,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15 /* Master key 0B encrypted with Master key 0C. */
.byte 0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12 /* Master key 0C encrypted with Master key 0D. */
.byte 0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D /* Master key 0D encrypted with Master key 0E. */
.byte 0x78, 0x66, 0x19, 0xBD, 0x86, 0xE7, 0xC1, 0x09, 0x9B, 0x6F, 0x92, 0xB2, 0x58, 0x7D, 0xCF, 0x26 /* Master key 0E encrypted with Master key 0F. */
/* 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. */
@@ -123,6 +124,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 /* Master key 0B encrypted with Master key 0C. */
.byte 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 /* Master key 0C encrypted with Master key 0D. */
.byte 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 /* Master key 0D encrypted with Master key 0E. */
.byte 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 /* Master key 0E encrypted with Master key 0F. */
/* 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. */
@@ -137,6 +139,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F /* 13.0.0 Device Master Key Source Source. */
.byte 0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D /* 14.0.0 Device Master Key Source Source. */
.byte 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 /* 15.0.0 Device Master Key Source Source. */
.byte 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C /* 16.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. */
@@ -151,6 +154,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F /* 13.0.0 Device Master Kek Source. */
.byte 0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA /* 14.0.0 Device Master Kek Source. */
.byte 0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E /* 15.0.0 Device Master Kek Source. */
.byte 0xFF, 0xF6, 0x4B, 0x0F, 0xFF, 0x0D, 0xC0, 0x4F, 0x56, 0x8A, 0x40, 0x74, 0x67, 0xC5, 0xFE, 0x9F /* 16.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. */
@@ -165,3 +169,4 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 /* 13.0.0 Device Master Kek Source. */
.byte 0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2 /* 14.0.0 Device Master Kek Source. */
.byte 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 /* 15.0.0 Device Master Kek Source. */
.byte 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F /* 16.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 == 15);
static_assert(pkg1::KeyGeneration_Count == 16);
if (key_generation >= pkg1::KeyGeneration_Count) {
return false;
}

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. */
0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D
0xA5, 0xEC, 0x16, 0x39, 0x1A, 0x30, 0x16, 0x08, 0x2E, 0xCF, 0x09, 0x6F, 0x5E, 0x7C, 0xEE, 0xA9
};
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = {
/* TODO: Update on next change of keys. */
0x18, 0xA5, 0x6F, 0xEF, 0x72, 0x11, 0x62, 0xC5, 0x1A, 0x14, 0xF1, 0x8C, 0x21, 0x83, 0x27, 0xB7
0x3A, 0x9C, 0xF0, 0x39, 0x70, 0x23, 0xF6, 0xAF, 0x71, 0x44, 0x60, 0xF4, 0x6D, 0xED, 0xA1, 0xD6
};
alignas(se::AesBlockSize) constexpr inline const u8 EristaMasterKekSource[se::AesBlockSize] = {
/* TODO: Update on next change of keys. */
0x6E, 0x77, 0x86, 0xAC, 0x83, 0x0A, 0x8D, 0x3E, 0x7D, 0xB7, 0x66, 0xA0, 0x22, 0xB7, 0x6E, 0x67
0x99, 0x22, 0x09, 0x57, 0xA7, 0xF9, 0x5E, 0x94, 0xFE, 0x78, 0x7F, 0x41, 0xD6, 0xE7, 0x56, 0xE6
};
alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = {
@@ -69,6 +69,7 @@ namespace ams::nxboot {
{ 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F }, /* 13.0.0 Device Master Key Source Source. */
{ 0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D }, /* 14.0.0 Device Master Key Source Source. */
{ 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 }, /* 15.0.0 Device Master Key Source Source. */
{ 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C }, /* 16.0.0 Device Master Key Source Source. */
};
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
@@ -84,6 +85,7 @@ namespace ams::nxboot {
{ 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 }, /* 13.0.0 Device Master Kek Source. */
{ 0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2 }, /* 14.0.0 Device Master Kek Source. */
{ 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 }, /* 15.0.0 Device Master Kek Source. */
{ 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F }, /* 16.0.0 Device Master Kek Source. */
};
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
@@ -99,6 +101,7 @@ namespace ams::nxboot {
{ 0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F }, /* 13.0.0 Device Master Kek Source. */
{ 0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA }, /* 14.0.0 Device Master Kek Source. */
{ 0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E }, /* 15.0.0 Device Master Kek Source. */
{ 0xFF, 0xF6, 0x4B, 0x0F, 0xFF, 0x0D, 0xC0, 0x4F, 0x56, 0x8A, 0x40, 0x74, 0x67, 0xC5, 0xFE, 0x9F }, /* 16.0.0 Device Master Kek Source. */
};
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySources[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
@@ -117,6 +120,7 @@ namespace ams::nxboot {
{ 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 }, /* Master key 0B encrypted with Master key 0C. */
{ 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 }, /* Master key 0C encrypted with Master key 0D. */
{ 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 }, /* Master key 0D encrypted with Master key 0E. */
{ 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 }, /* Master key 0E encrypted with Master key 0F. */
};
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySourcesDev[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
@@ -135,6 +139,7 @@ namespace ams::nxboot {
{ 0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15 }, /* Master key 0B encrypted with Master key 0C. */
{ 0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12 }, /* Master key 0C encrypted with Master key 0D. */
{ 0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D }, /* Master key 0D encrypted with Master key 0E. */
{ 0x78, 0x66, 0x19, 0xBD, 0x86, 0xE7, 0xC1, 0x09, 0x9B, 0x6F, 0x92, 0xB2, 0x58, 0x7D, 0xCF, 0x26 }, /* Master key 0E encrypted with Master key 0F. */
};
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 == 15);
static_assert(pkg1::KeyGeneration_Count == 16);
if (key_generation >= pkg1::KeyGeneration_Count) {
return false;
}

View File

@@ -255,6 +255,8 @@ namespace ams::nxboot {
return ams::TargetFirmware_14_0_0;
} else if (std::memcmp(package1 + 0x10, "20220801", 8) == 0) {
return ams::TargetFirmware_15_0_0;
} else if (std::memcmp(package1 + 0x10, "20230111", 8) == 0) {
return ams::TargetFirmware_16_0_0;
}
break;
default:

View File

@@ -159,6 +159,12 @@ namespace ams::nxboot {
FsVersion_15_0_0,
FsVersion_15_0_0_Exfat,
FsVersion_16_0_0,
FsVersion_16_0_0_Exfat,
FsVersion_16_0_3,
FsVersion_16_0_3_Exfat,
FsVersion_Count,
};
@@ -231,9 +237,14 @@ namespace ams::nxboot {
{ 0x88, 0x7A, 0xC1, 0x50, 0x80, 0x6C, 0x75, 0xCC }, /* FsVersion_14_0_0 */
{ 0xD4, 0x88, 0xD1, 0xF2, 0x92, 0x17, 0x35, 0x5C }, /* FsVersion_14_0_0_Exfat */
{ 0xD0, 0xD4, 0x49, 0x18, 0x14, 0xB5, 0x62, 0xAF }, /* FsVersion_15_0_0 */
{ 0x34, 0xC0, 0xD9, 0xED, 0x6A, 0xD1, 0x87, 0x3D }, /* FsVersion_15_0_0_Exfat */
{ 0x56, 0xE8, 0x56, 0x56, 0x6C, 0x38, 0xD8, 0xBE }, /* FsVersion_16_0_0 */
{ 0xCF, 0xAB, 0x45, 0x0C, 0x2C, 0x53, 0x9D, 0xA9 }, /* FsVersion_16_0_0_Exfat */
{ 0x39, 0xEE, 0x1F, 0x1E, 0x0E, 0xA7, 0x32, 0x5D }, /* FsVersion_16_0_3 */
{ 0x62, 0xC6, 0x5E, 0xFD, 0x9A, 0xBF, 0x7C, 0x43 }, /* FsVersion_16_0_3_Exfat */
};
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
@@ -643,6 +654,22 @@ namespace ams::nxboot {
AddPatch(fs_meta, 0x18F1E9, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x169D74, NogcPatch1, sizeof(NogcPatch1));
break;
case FsVersion_16_0_0:
AddPatch(fs_meta, 0x1866D9, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x160C70, NogcPatch1, sizeof(NogcPatch1));
break;
case FsVersion_16_0_0_Exfat:
AddPatch(fs_meta, 0x1913B9, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x16B950, NogcPatch1, sizeof(NogcPatch1));
break;
case FsVersion_16_0_3:
AddPatch(fs_meta, 0x186729, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x160CC0, NogcPatch1, sizeof(NogcPatch1));
break;
case FsVersion_16_0_3_Exfat:
AddPatch(fs_meta, 0x191409, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x16B9A0, NogcPatch1, sizeof(NogcPatch1));
break;
default:
break;
}

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = b2232894f31953511d33bc665f68216badc3bb07
parent = 8ce4f1961580a09381e486cc51c160a00fa86b88
commit = c3dc418a28e390bc57426016aa2c9e7e87d7a584
parent = e488b6ee478f5b3a0380e75e4b468e1e4b1d816f
method = merge
cmdver = 0.4.1

View File

@@ -1,5 +1,5 @@
export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_WINDOWS
export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer
export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer -fno-data-sections
export ATMOSPHERE_CFLAGS +=
export ATMOSPHERE_CXXFLAGS +=
export ATMOSPHERE_ASFLAGS +=

View File

@@ -58,7 +58,7 @@ export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
-Wl,--wrap,exit
else ifeq ($(ATMOSPHERE_BOARD),generic_windows)
export CXXREQUIRED :=
export CXXWRAPS := -Wl,--wrap,__p__acmdln
export CXXWRAPS := -Wl,--wrap,__p__acmdln -Wl,--wrap,_set_invalid_parameter_handler
else
export CXXREQUIRED :=
export CXXWRAPS :=

View File

@@ -27,7 +27,7 @@ namespace ams::pkg1 {
enum MemoryArrange {
MemoryArrange_Normal = 1,
MemoryArrange_AppletDev = 2,
MemoryArrange_SystemDev = 2,
MemoryArrange_SystemDev = 3,
};
enum MemoryMode {

View File

@@ -35,6 +35,7 @@ namespace ams::pkg1 {
KeyGeneration_13_0_0 = 0x0C,
KeyGeneration_14_0_0 = 0x0D,
KeyGeneration_15_0_0 = 0x0E,
KeyGeneration_16_0_0 = 0x0F,
KeyGeneration_Count,

View File

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

View File

@@ -177,6 +177,7 @@ namespace ams::fuse {
}
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
TargetFirmware_16_0_0,
TargetFirmware_15_0_0,
TargetFirmware_13_2_1,
TargetFirmware_12_0_2,

View File

@@ -29,8 +29,6 @@ namespace ams::kern::init {
u64 sp;
u64 entrypoint;
u64 argument;
u64 setup_function;
u64 exception_stack;
};
static_assert(alignof(KInitArguments) == util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE));
static_assert(sizeof(KInitArguments) == std::max(INIT_ARGUMENTS_SIZE, util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)));
@@ -45,7 +43,5 @@ namespace ams::kern::init {
static_assert(AMS_OFFSETOF(KInitArguments, sp) == INIT_ARGUMENTS_SP);
static_assert(AMS_OFFSETOF(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT);
static_assert(AMS_OFFSETOF(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT);
static_assert(AMS_OFFSETOF(KInitArguments, setup_function) == INIT_ARGUMENTS_SETUP_FUNCTION);
static_assert(AMS_OFFSETOF(KInitArguments, exception_stack) == INIT_ARGUMENTS_EXCEPTION_STACK);
}

View File

@@ -23,17 +23,6 @@
namespace ams::kern::arch::arm64::init {
inline void ClearPhysicalMemory(KPhysicalAddress address, size_t size) {
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(size, sizeof(u64)));
/* This Physical Address -> void * conversion is valid, because this is init page table code. */
/* The MMU is necessarily not yet turned on, if we are creating an initial page table. */
volatile u64 *ptr = reinterpret_cast<volatile u64 *>(GetInteger(address));
for (size_t i = 0; i < size / sizeof(u64); ++i) {
ptr[i] = 0;
}
}
/* NOTE: Nintendo uses virtual functions, rather than a concept + template. */
template<typename T>
concept IsInitialPageAllocator = requires (T &t, KPhysicalAddress phys_addr, size_t size) {
@@ -41,25 +30,23 @@ namespace ams::kern::arch::arm64::init {
{ t.Free(phys_addr, size) } -> std::same_as<void>;
};
template<IsInitialPageAllocator _PageAllocator>
class KInitialPageTableTemplate {
public:
using PageAllocator = _PageAllocator;
class KInitialPageTable {
private:
KPhysicalAddress m_l1_tables[2];
u32 m_num_entries[2];
public:
KInitialPageTableTemplate(KVirtualAddress start_address, KVirtualAddress end_address, PageAllocator &allocator) {
template<IsInitialPageAllocator PageAllocator>
KInitialPageTable(KVirtualAddress start_address, KVirtualAddress end_address, PageAllocator &allocator) {
/* Set tables. */
m_l1_tables[0] = AllocateNewPageTable(allocator);
m_l1_tables[1] = AllocateNewPageTable(allocator);
m_l1_tables[0] = AllocateNewPageTable(allocator, 0);
m_l1_tables[1] = AllocateNewPageTable(allocator, 0);
/* Set counts. */
m_num_entries[0] = MaxPageTableEntries;
m_num_entries[1] = ((end_address / L1BlockSize) & (MaxPageTableEntries - 1)) - ((start_address / L1BlockSize) & (MaxPageTableEntries - 1)) + 1;
}
KInitialPageTableTemplate() {
KInitialPageTable() {
/* Set tables. */
m_l1_tables[0] = util::AlignDown(cpu::GetTtbr0El1(), PageSize);
m_l1_tables[1] = util::AlignDown(cpu::GetTtbr1El1(), PageSize);
@@ -82,30 +69,35 @@ namespace ams::kern::arch::arm64::init {
return GetInteger(m_l1_tables[1]);
}
private:
constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KVirtualAddress address) const {
constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KVirtualAddress address, u64 phys_to_virt_offset = 0) const {
const size_t index = (GetInteger(address) >> (BITSIZEOF(address) - 1)) & 1;
L1PageTableEntry *l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[index]));
L1PageTableEntry *l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[index]) + phys_to_virt_offset);
return l1_table + ((GetInteger(address) / L1BlockSize) & (m_num_entries[index] - 1));
}
static constexpr ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KVirtualAddress address) {
L2PageTableEntry *l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(entry->GetTable()));
static constexpr ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KVirtualAddress address, u64 phys_to_virt_offset = 0) {
L2PageTableEntry *l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(entry->GetTable()) + phys_to_virt_offset);
return l2_table + ((GetInteger(address) / L2BlockSize) & (MaxPageTableEntries - 1));
}
static constexpr ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KVirtualAddress address) {
L3PageTableEntry *l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(entry->GetTable()));
static constexpr ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KVirtualAddress address, u64 phys_to_virt_offset = 0) {
L3PageTableEntry *l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(entry->GetTable()) + phys_to_virt_offset);
return l3_table + ((GetInteger(address) / L3BlockSize) & (MaxPageTableEntries - 1));
}
static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(PageAllocator &allocator) {
template<IsInitialPageAllocator PageAllocator>
static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(PageAllocator &allocator, u64 phys_to_virt_offset) {
auto address = allocator.Allocate(PageSize);
ClearNewPageTable(address);
ClearNewPageTable(address, phys_to_virt_offset);
return address;
}
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address) {
ClearPhysicalMemory(address, PageSize);
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address, u64 phys_to_virt_offset) {
/* Convert to a deferenceable address, and clear. */
volatile u64 *ptr = reinterpret_cast<volatile u64 *>(GetInteger(address) + phys_to_virt_offset);
for (size_t i = 0; i < PageSize / sizeof(u64); ++i) {
ptr[i] = 0;
}
}
public:
static consteval size_t GetMaximumOverheadSize(size_t size) {
@@ -327,7 +319,8 @@ namespace ams::kern::arch::arm64::init {
}
}
public:
void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, PageAllocator &allocator) {
template<IsInitialPageAllocator PageAllocator>
void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, PageAllocator &allocator, u64 phys_to_virt_offset) {
/* Ensure that addresses and sizes are page aligned. */
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize));
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(phys_addr), PageSize));
@@ -335,7 +328,7 @@ namespace ams::kern::arch::arm64::init {
/* Iteratively map pages until the requested region is mapped. */
while (size > 0) {
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr, phys_to_virt_offset);
/* Can we make an L1 block? */
if (util::IsAligned(GetInteger(virt_addr), L1BlockSize) && util::IsAligned(GetInteger(phys_addr), L1BlockSize) && size >= L1BlockSize) {
@@ -349,12 +342,12 @@ namespace ams::kern::arch::arm64::init {
/* If we don't already have an L2 table, we need to make a new one. */
if (!l1_entry->IsTable()) {
KPhysicalAddress new_table = AllocateNewPageTable(allocator);
KPhysicalAddress new_table = AllocateNewPageTable(allocator, phys_to_virt_offset);
cpu::DataSynchronizationBarrierInnerShareable();
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
}
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr, phys_to_virt_offset);
/* Can we make a contiguous L2 block? */
if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && size >= L2ContiguousBlockSize) {
@@ -380,12 +373,12 @@ namespace ams::kern::arch::arm64::init {
/* If we don't already have an L3 table, we need to make a new one. */
if (!l2_entry->IsTable()) {
KPhysicalAddress new_table = AllocateNewPageTable(allocator);
KPhysicalAddress new_table = AllocateNewPageTable(allocator, phys_to_virt_offset);
cpu::DataSynchronizationBarrierInnerShareable();
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
}
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr, phys_to_virt_offset);
/* Can we make a contiguous L3 block? */
if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && size >= L3ContiguousBlockSize) {
@@ -410,6 +403,98 @@ namespace ams::kern::arch::arm64::init {
cpu::DataSynchronizationBarrierInnerShareable();
}
void UnmapTtbr0Entries(u64 phys_to_virt_offset) {
/* Ensure data consistency before we unmap. */
cpu::DataSynchronizationBarrierInnerShareable();
/* Define helper, as we only want to clear non-nGnRE pages. */
constexpr auto ShouldUnmap = [](const PageTableEntry *entry) ALWAYS_INLINE_LAMBDA -> bool {
return entry->GetPageAttribute() != PageTableEntry::PageAttribute_Device_nGnRE;
};
/* Iterate all L1 entries. */
L1PageTableEntry * const l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[0]) + phys_to_virt_offset);
for (size_t l1_index = 0; l1_index < m_num_entries[0]; l1_index++) {
/* Get L1 entry. */
L1PageTableEntry * const l1_entry = l1_table + l1_index;
if (l1_entry->IsBlock()) {
/* Unmap the L1 entry, if we should. */
if (ShouldUnmap(l1_entry)) {
*static_cast<PageTableEntry *>(l1_entry) = InvalidPageTableEntry;
}
} else if (l1_entry->IsTable()) {
/* Get the L2 table. */
L2PageTableEntry * const l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(l1_entry->GetTable()) + phys_to_virt_offset);
/* Unmap all L2 entries, as relevant. */
size_t remaining_l2_entries = 0;
for (size_t l2_index = 0; l2_index < MaxPageTableEntries; ++l2_index) {
/* Get L2 entry. */
L2PageTableEntry * const l2_entry = l2_table + l2_index;
if (l2_entry->IsBlock()) {
const size_t num_to_clear = (l2_entry->IsContiguous() ? L2ContiguousBlockSize : L2BlockSize) / L2BlockSize;
if (ShouldUnmap(l2_entry)) {
for (size_t i = 0; i < num_to_clear; ++i) {
static_cast<PageTableEntry *>(l2_entry)[i] = InvalidPageTableEntry;
}
} else {
remaining_l2_entries += num_to_clear;
}
l2_index = l2_index + num_to_clear - 1;
} else if (l2_entry->IsTable()) {
/* Get the L3 table. */
L3PageTableEntry * const l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(l2_entry->GetTable()) + phys_to_virt_offset);
/* Unmap all L3 entries, as relevant. */
size_t remaining_l3_entries = 0;
for (size_t l3_index = 0; l3_index < MaxPageTableEntries; ++l3_index) {
/* Get L3 entry. */
if (L3PageTableEntry * const l3_entry = l3_table + l3_index; l3_entry->IsBlock()) {
const size_t num_to_clear = (l3_entry->IsContiguous() ? L3ContiguousBlockSize : L3BlockSize) / L3BlockSize;
if (ShouldUnmap(l3_entry)) {
for (size_t i = 0; i < num_to_clear; ++i) {
static_cast<PageTableEntry *>(l3_entry)[i] = InvalidPageTableEntry;
}
} else {
remaining_l3_entries += num_to_clear;
}
l3_index = l3_index + num_to_clear - 1;
}
}
/* If we unmapped all L3 entries, clear the L2 entry. */
if (remaining_l3_entries == 0) {
*static_cast<PageTableEntry *>(l2_entry) = InvalidPageTableEntry;
/* Invalidate the entire tlb. */
cpu::DataSynchronizationBarrierInnerShareable();
cpu::InvalidateEntireTlb();
} else {
remaining_l2_entries++;
}
}
}
/* If we unmapped all L2 entries, clear the L1 entry. */
if (remaining_l2_entries == 0) {
*static_cast<PageTableEntry *>(l1_entry) = InvalidPageTableEntry;
/* Invalidate the entire tlb. */
cpu::DataSynchronizationBarrierInnerShareable();
cpu::InvalidateEntireTlb();
}
}
}
/* Invalidate the entire tlb. */
cpu::DataSynchronizationBarrierInnerShareable();
cpu::InvalidateEntireTlb();
}
KPhysicalAddress GetPhysicalAddress(KVirtualAddress virt_addr) const {
/* Get the L1 entry. */
const L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
@@ -861,6 +946,4 @@ namespace ams::kern::arch::arm64::init {
};
static_assert(IsInitialPageAllocator<KInitialPageAllocator>);
using KInitialPageTable = KInitialPageTableTemplate<KInitialPageAllocator>;
}

View File

@@ -23,7 +23,7 @@
#define THREAD_KERNEL_STACK_TOP 0x280
/* ams::kern::KThread::StackParameters, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp */
#define THREAD_STACK_PARAMETERS_SIZE 0x130
#define THREAD_STACK_PARAMETERS_SIZE 0x140
#define THREAD_STACK_PARAMETERS_SVC_PERMISSION 0x00
#define THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS 0x18
#define THREAD_STACK_PARAMETERS_CUR_THREAD 0x20
@@ -34,7 +34,8 @@
#define THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS 0x2D
#define THREAD_STACK_PARAMETERS_IS_PINNED 0x2E
#define THREAD_STACK_PARAMETERS_RESERVED_2F 0x2F
#define THREAD_STACK_PARAMETERS_THREAD_CONTEXT 0x30
#define THREAD_STACK_PARAMETERS_RESERVED_30 0x30
#define THREAD_STACK_PARAMETERS_THREAD_CONTEXT 0x40
#define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_CALLING_SVC (0)
#define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_EXCEPTION_HANDLER (1)
@@ -245,7 +246,7 @@
#define THREAD_LOCAL_REGION_SIZE 0x200
/* ams::kern::init::KInitArguments, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_arguments.hpp */
#define INIT_ARGUMENTS_SIZE 0x60
#define INIT_ARGUMENTS_SIZE 0x50
#define INIT_ARGUMENTS_TTBR0 0x00
#define INIT_ARGUMENTS_TTBR1 0x08
#define INIT_ARGUMENTS_TCR 0x10
@@ -256,14 +257,12 @@
#define INIT_ARGUMENTS_SP 0x38
#define INIT_ARGUMENTS_ENTRYPOINT 0x40
#define INIT_ARGUMENTS_ARGUMENT 0x48
#define INIT_ARGUMENTS_SETUP_FUNCTION 0x50
#define INIT_ARGUMENTS_EXCEPTION_STACK 0x58
/* ams::kern::KScheduler (::SchedulingState), https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp */
/* NOTE: Due to constraints on ldarb relative offsets, KSCHEDULER_NEEDS_SCHEDULING cannot trivially be changed, and will require assembly edits. */
#define KSCHEDULER_NEEDS_SCHEDULING 0x00
#define KSCHEDULER_INTERRUPT_TASK_RUNNABLE 0x01
#define KSCHEDULER_HIGHEST_PRIORITY_THREAD 0x10
#define KSCHEDULER_IDLE_THREAD_STACK 0x18
#define KSCHEDULER_PREVIOUS_THREAD 0x20
#define KSCHEDULER_INTERRUPT_TASK_MANAGER 0x28
#define KSCHEDULER_HIGHEST_PRIORITY_THREAD 0x18
#define KSCHEDULER_IDLE_THREAD_STACK 0x20
#define KSCHEDULER_PREVIOUS_THREAD 0x28
#define KSCHEDULER_INTERRUPT_TASK_MANAGER 0x30

View File

@@ -36,6 +36,9 @@ namespace ams::kern::arch::arm64::cpu {
#error "Unknown Board for cpu::NumCores"
#endif
constexpr inline u32 El0Aarch64PsrMask = 0xF0000000;
constexpr inline u32 El0Aarch32PsrMask = 0xFE0FFE20;
/* Initialization. */
NOINLINE void InitializeInterruptThreads(s32 core_id);
@@ -186,6 +189,14 @@ namespace ams::kern::arch::arm64::cpu {
return (par >> (BITSIZEOF(par) - BITSIZEOF(u8))) == 0xFF;
}
ALWAYS_INLINE void StoreDataCacheForInitArguments(const void *addr, size_t size) {
const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), DataCacheLineSize);
for (size_t stored = 0; stored < size; stored += cpu::DataCacheLineSize) {
__asm__ __volatile__("dc cvac, %[cur]" :: [cur]"r"(start + stored) : "memory");
}
DataSynchronizationBarrier();
}
/* Synchronization helpers. */
NOINLINE void SynchronizeAllCores();
void SynchronizeCores(u64 core_mask);

View File

@@ -216,7 +216,7 @@ namespace ams::kern::arch::arm64 {
ALWAYS_INLINE Result SeparatePagesImpl(KProcessAddress virt_addr, size_t block_size, PageLinkedList *page_list, bool reuse_ll);
Result SeparatePages(KProcessAddress virt_addr, size_t block_size, PageLinkedList *page_list, bool reuse_ll);
Result ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, PageLinkedList *page_list, bool reuse_ll);
Result ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, bool flush_mapping, PageLinkedList *page_list, bool reuse_ll);
static ALWAYS_INLINE void PteDataMemoryBarrier() {
cpu::DataMemoryBarrierInnerShareableStore();

View File

@@ -161,9 +161,12 @@ namespace ams::kern::arch::arm64 {
constexpr ALWAYS_INLINE bool IsPrivilegedExecuteNever() const { return this->GetBits(53, 1) != 0; }
constexpr ALWAYS_INLINE bool IsContiguous() const { return this->GetBits(52, 1) != 0; }
constexpr ALWAYS_INLINE bool IsGlobal() const { return this->GetBits(11, 1) == 0; }
constexpr ALWAYS_INLINE AccessFlag GetAccessFlag() const { return static_cast<AccessFlag>(this->GetBits(10, 1)); }
constexpr ALWAYS_INLINE Shareable GetShareable() const { return static_cast<Shareable>(this->GetBits(8, 2)); }
constexpr ALWAYS_INLINE PageAttribute GetPageAttribute() const { return static_cast<PageAttribute>(this->GetBits(2, 3)); }
constexpr ALWAYS_INLINE AccessFlag GetAccessFlag() const { return static_cast<AccessFlag>(this->SelectBits(10, 1)); }
constexpr ALWAYS_INLINE Shareable GetShareable() const { return static_cast<Shareable>(this->SelectBits(8, 2)); }
constexpr ALWAYS_INLINE PageAttribute GetPageAttribute() const { return static_cast<PageAttribute>(this->SelectBits(2, 3)); }
constexpr ALWAYS_INLINE int GetAccessFlagInteger() const { return static_cast<int>(this->GetBits(10, 1)); }
constexpr ALWAYS_INLINE int GetShareableInteger() const { return static_cast<int>(this->GetBits(8, 2)); }
constexpr ALWAYS_INLINE int GetPageAttributeInteger() const { return static_cast<int>(this->GetBits(2, 3)); }
constexpr ALWAYS_INLINE bool IsReadOnly() const { return this->GetBits(7, 1) != 0; }
constexpr ALWAYS_INLINE bool IsUserAccessible() const { return this->GetBits(6, 1) != 0; }
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBits(5, 1) != 0; }

View File

@@ -98,8 +98,8 @@ namespace ams::kern::arch::arm64 {
R_RETURN(m_page_table.MapIoRegion(dst_address, phys_addr, size, mapping, perm));
}
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size) {
R_RETURN(m_page_table.UnmapIoRegion(dst_address, phys_addr, size));
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping) {
R_RETURN(m_page_table.UnmapIoRegion(dst_address, phys_addr, size, mapping));
}
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) {

View File

@@ -77,7 +77,7 @@ namespace ams::kern::arch::arm64 {
__asm__ __volatile__(
" prfm pstl1keep, %[m_next_ticket]\n"
"1:\n"
" ldaxrh %w[tmp0], %[m_next_ticket]\n"
" ldxrh %w[tmp0], %[m_next_ticket]\n"
" add %w[tmp1], %w[tmp0], #0x1\n"
" stxrh %w[got_lock], %w[tmp1], %[m_next_ticket]\n"
" cbnz %w[got_lock], 1b\n"

View File

@@ -25,12 +25,15 @@ namespace ams::kern::board::nintendo::nx {
static constexpr size_t SecureAppletMemorySize = 4_MB;
public:
class Init : public KSystemControlBase::Init {
private:
friend class KSystemControlBase::Init;
private:
static void CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
public:
/* Initialization. */
static size_t GetRealMemorySize();
static size_t GetIntendedMemorySize();
static bool ShouldIncreaseThreadResourceLimit();
static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
static size_t GetApplicationPoolSize();
static size_t GetAppletPoolSize();
static size_t GetMinimumNonSecureSystemPoolSize();

View File

@@ -26,6 +26,6 @@ namespace ams::kern::init {
static_assert(util::IsPowerOfTwo(alignof(KInitArguments)) && util::IsPowerOfTwo(sizeof(KInitArguments)));
KPhysicalAddress GetInitArgumentsAddress(s32 core_id);
KInitArguments *GetInitArguments(s32 core_id);
}

View File

@@ -42,6 +42,11 @@
#define MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP
#define MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP
/* NOTE: In 16.0.0, Nintendo deleted the creation time field for KProcess, */
/* but this may be useful for some debugging applications, and so can be. */
/* re-enabled by toggling this define. */
//#define MESOSPHERE_ENABLE_PROCESS_CREATION_TIME
/* NOTE: This enables fast class token storage using a class member. */
/* This saves a virtual call when doing KAutoObject->DynCast<>(), */
/* at the cost of storing class tokens inside the class object. */

View File

@@ -40,12 +40,16 @@ namespace ams::kern {
static uintptr_t GetAddressSpaceStart(size_t width, Type type);
static size_t GetAddressSpaceSize(size_t width, Type type);
static void SetAddressSpaceSize(size_t width, Type type, size_t size);
constexpr KAddressSpaceInfo(size_t bw, size_t a, size_t s, Type t) : m_bit_width(bw), m_address(a), m_size(s), m_type(t) { /* ... */ }
constexpr size_t GetWidth() const { return m_bit_width; }
constexpr size_t GetAddress() const { return m_address; }
constexpr size_t GetSize() const { return m_size; }
constexpr Type GetType() const { return m_type; }
constexpr void SetSize(size_t size) { m_size = size; }
};
}

View File

@@ -79,7 +79,7 @@ namespace ams::kern {
}
ALWAYS_INLINE bool Close() {
/* Atomically decrement the reference count, not allowing it to become negative. */
/* Atomically decrement the reference count, not allowing it to decrement past zero. */
u32 cur = m_value.Load<std::memory_order_relaxed>();
do {
MESOSPHERE_ABORT_UNLESS(cur > 0);
@@ -257,7 +257,7 @@ namespace ams::kern {
class KScopedAutoObject {
NON_COPYABLE(KScopedAutoObject);
private:
template<typename U>
template<typename U> requires std::derived_from<U, KAutoObject>
friend class KScopedAutoObject;
private:
T *m_obj;

View File

@@ -74,7 +74,7 @@ namespace ams::kern {
return m_process_holder.Get();
}
private:
void PushDebugEvent(ams::svc::DebugEvent event, uintptr_t param0 = 0, uintptr_t param1 = 0, uintptr_t param2 = 0, uintptr_t param3 = 0, uintptr_t param4 = 0);
void PushDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
void EnqueueDebugEventInfo(KEventInfo *info);
template<typename T> requires (std::same_as<T, ams::svc::lp64::DebugEventInfo> || std::same_as<T, ams::svc::ilp32::DebugEventInfo>)
@@ -85,13 +85,13 @@ namespace ams::kern {
/* NOTE: This is public/virtual override in Nintendo's kernel. */
void OnFinalizeSynchronizationObject();
private:
static Result ProcessDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4);
static Result ProcessDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
public:
static Result OnDebugEvent(ams::svc::DebugEvent event, uintptr_t param0 = 0, uintptr_t param1 = 0, uintptr_t param2 = 0, uintptr_t param3 = 0, uintptr_t param4 = 0);
static Result OnDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
static Result OnExitProcess(KProcess *process);
static Result OnTerminateProcess(KProcess *process);
static Result OnExitThread(KThread *thread);
static KEventInfo *CreateDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4, u64 thread_id);
static KEventInfo *CreateDebugEvent(ams::svc::DebugEvent event, u64 thread_id, const uintptr_t *params, size_t num_params);
};
}

View File

@@ -38,7 +38,7 @@ namespace ams::kern {
ams::svc::DebugException exception_type;
s32 exception_data_count;
uintptr_t exception_address;
uintptr_t exception_data[4];
uintptr_t exception_data[std::max<size_t>(4, cpu::NumCores)];
};
struct InfoSystemCall {

View File

@@ -24,10 +24,10 @@ namespace ams::kern {
class KIoPool final : public KAutoObjectWithSlabHeapAndContainer<KIoPool, KAutoObjectWithList> {
MESOSPHERE_AUTOOBJECT_TRAITS(KIoPool, KAutoObject);
private:
using IoRegionList = util::IntrusiveListMemberTraits<&KIoRegion::m_pool_list_node>::ListType;
using IoRegionTree = util::IntrusiveRedBlackTreeBaseTraits<KIoRegion>::TreeType<KIoRegion>;
private:
KLightLock m_lock;
IoRegionList m_io_region_list;
IoRegionTree m_io_region_tree;
ams::svc::IoPoolType m_pool_type;
bool m_is_initialized;
public:

View File

@@ -23,11 +23,30 @@ namespace ams::kern {
class KProcess;
class KIoPool;
class KIoRegion final : public KAutoObjectWithSlabHeapAndContainer<KIoRegion, KAutoObjectWithList> {
class KIoRegion final : public KAutoObjectWithSlabHeapAndContainer<KIoRegion, KAutoObjectWithList>, public util::IntrusiveRedBlackTreeBaseNode<KIoRegion> {
MESOSPHERE_AUTOOBJECT_TRAITS(KIoRegion, KAutoObject);
private:
friend class KProcess;
friend class KIoPool;
public:
using RedBlackKeyType = KPhysicalAddress;
static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const RedBlackKeyType &v) { return v; }
static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const KIoRegion &v) { return v.GetAddress(); }
template<typename T> requires (std::same_as<T, KIoRegion> || std::same_as<T, RedBlackKeyType>)
static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KIoRegion &rhs) {
const RedBlackKeyType lval = GetRedBlackKey(lhs);
const RedBlackKeyType rval = GetRedBlackKey(rhs);
if (lval < rval) {
return -1;
} else if (lval == rval) {
return 0;
} else {
return 1;
}
}
private:
KLightLock m_lock;
KIoPool *m_pool;
@@ -38,7 +57,6 @@ namespace ams::kern {
bool m_is_initialized;
bool m_is_mapped;
util::IntrusiveListNode m_process_list_node;
util::IntrusiveListNode m_pool_list_node;
public:
explicit KIoRegion() : m_pool(nullptr), m_is_initialized(false) { /* ... */ }
@@ -51,12 +69,25 @@ namespace ams::kern {
Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm);
Result Unmap(KProcessAddress address, size_t size);
bool Overlaps(KPhysicalAddress address, size_t size) const {
constexpr bool Overlaps(KPhysicalAddress address, size_t size) const {
return m_physical_address <= (address + size - 1) && address <= (m_physical_address + m_size - 1);
}
ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; }
ALWAYS_INLINE size_t GetSize() const { return m_size; }
constexpr ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; }
constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; }
constexpr uintptr_t GetHint() const {
/* TODO: Is this architecture specific? */
if (m_size >= 2_MB) {
return GetInteger(m_physical_address) & (2_MB - 1);
} else if (m_size >= 64_KB) {
return GetInteger(m_physical_address) & (64_KB - 1);
} else if (m_size >= 4_KB) {
return GetInteger(m_physical_address) & (4_KB - 1);
} else {
return 0;
}
}
};
}

View File

@@ -183,10 +183,10 @@ namespace ams::kern {
return std::make_tuple(total_size, kernel_size);
}
static void InitializeLinearMemoryAddresses(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start) {
static void InitializeLinearMemoryAddresses(u64 phys_to_virt_diff) {
/* Set static differences. */
s_linear_phys_to_virt_diff = GetInteger(linear_virtual_start) - GetInteger(aligned_linear_phys_start);
s_linear_virt_to_phys_diff = GetInteger(aligned_linear_phys_start) - GetInteger(linear_virtual_start);
s_linear_phys_to_virt_diff = phys_to_virt_diff;
s_linear_virt_to_phys_diff = -phys_to_virt_diff;
}
static void InitializeLinearMemoryRegionTrees();

View File

@@ -48,7 +48,7 @@ namespace ams::kern {
/* Check that the object is closed. */
R_UNLESS(derived->IsServerClosed(), svc::ResultInvalidState());
return Delete(obj.GetPointerUnsafe(), name);
R_RETURN(Delete(obj.GetPointerUnsafe(), name));
}
template<typename Derived> requires std::derived_from<Derived, KAutoObject>

View File

@@ -57,11 +57,26 @@ namespace ams::kern {
using TraversalEntry = KPageTableImpl::TraversalEntry;
using TraversalContext = KPageTableImpl::TraversalContext;
struct MemoryRange {
KPhysicalAddress address;
size_t size;
class MemoryRange {
private:
KPhysicalAddress m_address;
size_t m_size;
bool m_heap;
public:
constexpr MemoryRange() : m_address(Null<KPhysicalAddress>), m_size(0), m_heap(false) { /* ... */ }
void Close();
void Set(KPhysicalAddress address, size_t size, bool heap) {
m_address = address;
m_size = size;
m_heap = heap;
}
constexpr KPhysicalAddress GetAddress() const { return m_address; }
constexpr size_t GetSize() const { return m_size; }
constexpr bool IsHeap() const { return m_heap; }
void Open();
void Close();
};
protected:
enum MemoryFillValue {
@@ -72,13 +87,14 @@ namespace ams::kern {
};
enum OperationType {
OperationType_Map = 0,
OperationType_MapFirst = 1,
OperationType_MapGroup = 2,
OperationType_Unmap = 3,
OperationType_ChangePermissions = 4,
OperationType_ChangePermissionsAndRefresh = 5,
OperationType_Separate = 6,
OperationType_Map = 0,
OperationType_MapFirst = 1,
OperationType_MapGroup = 2,
OperationType_Unmap = 3,
OperationType_ChangePermissions = 4,
OperationType_ChangePermissionsAndRefresh = 5,
OperationType_ChangePermissionsAndRefreshAndFlush = 6,
OperationType_Separate = 7,
};
static constexpr size_t MaxPhysicalMapAlignment = 1_GB;
@@ -363,7 +379,7 @@ namespace ams::kern {
Result UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
Result MapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm);
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size);
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping);
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm);
Result MapInsecureMemory(KProcessAddress address, size_t size);

View File

@@ -234,11 +234,11 @@ namespace ams::kern {
KPriorityQueueImpl m_scheduled_queue;
KPriorityQueueImpl m_suggested_queue;
private:
constexpr ALWAYS_INLINE void ClearAffinityBit(u64 &affinity, s32 core) {
static constexpr ALWAYS_INLINE void ClearAffinityBit(u64 &affinity, s32 core) {
affinity &= ~(UINT64_C(1) << core);
}
constexpr ALWAYS_INLINE s32 GetNextCore(u64 &affinity) {
static constexpr ALWAYS_INLINE s32 GetNextCore(u64 &affinity) {
const s32 core = __builtin_ctzll(static_cast<unsigned long long>(affinity));
ClearAffinityBit(affinity, core);
return core;

View File

@@ -84,7 +84,9 @@ namespace ams::kern {
KCapabilities m_capabilities;
ams::svc::ProgramId m_program_id;
u64 m_process_id;
#if defined(MESOSPHERE_ENABLE_PROCESS_CREATION_TIME)
s64 m_creation_time;
#endif
KProcessAddress m_code_address;
size_t m_code_size;
size_t m_main_thread_stack_size;
@@ -108,6 +110,7 @@ namespace ams::kern {
KWaitObject m_wait_object;
KThread *m_running_threads[cpu::NumCores];
u64 m_running_thread_idle_counts[cpu::NumCores];
u64 m_running_thread_switch_counts[cpu::NumCores];
KThread *m_pinned_threads[cpu::NumCores];
util::Atomic<s64> m_cpu_time;
util::Atomic<s64> m_num_process_switches;
@@ -285,9 +288,10 @@ namespace ams::kern {
return m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->GetUsedSize() : 0;
}
void SetRunningThread(s32 core, KThread *thread, u64 idle_count) {
m_running_threads[core] = thread;
m_running_thread_idle_counts[core] = idle_count;
void SetRunningThread(s32 core, KThread *thread, u64 idle_count, u64 switch_count) {
m_running_threads[core] = thread;
m_running_thread_idle_counts[core] = idle_count;
m_running_thread_switch_counts[core] = switch_count;
}
void ClearRunningThread(KThread *thread) {
@@ -306,6 +310,7 @@ namespace ams::kern {
constexpr KThread *GetRunningThread(s32 core) const { return m_running_threads[core]; }
constexpr u64 GetRunningThreadIdleCount(s32 core) const { return m_running_thread_idle_counts[core]; }
constexpr u64 GetRunningThreadSwitchCount(s32 core) const { return m_running_thread_switch_counts[core]; }
void RegisterThread(KThread *thread);
void UnregisterThread(KThread *thread);

View File

@@ -43,6 +43,7 @@ namespace ams::kern {
bool interrupt_task_runnable{false};
bool should_count_idle{false};
u64 idle_count{0};
u64 switch_count{0};
KThread *highest_priority_thread{nullptr};
void *idle_thread_stack{nullptr};
KThread *prev_thread{nullptr};
@@ -67,6 +68,7 @@ namespace ams::kern {
m_state.interrupt_task_runnable = false;
m_state.should_count_idle = false;
m_state.idle_count = 0;
m_state.switch_count = 0;
m_state.idle_thread_stack = nullptr;
m_state.highest_priority_thread = nullptr;
m_state.prev_thread = nullptr;
@@ -93,6 +95,10 @@ namespace ams::kern {
return m_state.idle_count;
}
ALWAYS_INLINE u64 GetSwitchCount() const {
return m_state.switch_count;
}
ALWAYS_INLINE KThread *GetIdleThread() const {
return m_idle_thread;
}

View File

@@ -49,9 +49,9 @@ namespace ams::kern {
MESOSPHERE_ASSERT_THIS();
if (this->IsLockedByCurrentThread()) {
/* If we already own the lock, we can just increment the count. */
/* If we already own the lock, the lock count should be > 0. */
/* For debug, ensure this is true. */
MESOSPHERE_ASSERT(m_lock_count > 0);
m_lock_count++;
} else {
/* Otherwise, we want to disable scheduling and acquire the spinlock. */
SchedulerType::DisableScheduling();
@@ -61,10 +61,12 @@ namespace ams::kern {
MESOSPHERE_ASSERT(m_lock_count == 0);
MESOSPHERE_ASSERT(m_owner_thread == nullptr);
/* Increment count, take ownership. */
m_lock_count = 1;
/* Take ownership of the lock. */
m_owner_thread = GetCurrentThreadPointer();
}
/* Increment the lock count. */
m_lock_count++;
}
MESOSPHERE_ALWAYS_INLINE_IF_RELEASE void Unlock() {

View File

@@ -21,6 +21,12 @@ namespace ams::kern {
struct InitialProcessBinaryLayout;
namespace init {
struct KInitArguments;
}
}
namespace ams::kern {
@@ -40,6 +46,8 @@ namespace ams::kern {
static constinit inline KSpinLock s_random_lock;
public:
class Init {
private:
static void CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
public:
/* Initialization. */
static size_t GetRealMemorySize();
@@ -47,7 +55,7 @@ namespace ams::kern {
static KPhysicalAddress GetKernelPhysicalBaseAddress(KPhysicalAddress base_address);
static void GetInitialProcessBinaryLayout(InitialProcessBinaryLayout *out);
static bool ShouldIncreaseThreadResourceLimit();
static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
static void TurnOnCpu(u64 core_id, const ams::kern::init::KInitArguments *args);
static size_t GetApplicationPoolSize();
static size_t GetAppletPoolSize();
static size_t GetMinimumNonSecureSystemPoolSize();
@@ -57,9 +65,11 @@ namespace ams::kern {
static void GenerateRandom(u64 *dst, size_t count);
static u64 GenerateRandomRange(u64 min, u64 max);
};
protected:
static NOINLINE void InitializePhase1Base(u64 seed);
public:
/* Initialization. */
static NOINLINE void InitializePhase1(bool skip_target_system = false);
static NOINLINE void InitializePhase1();
static NOINLINE void InitializePhase2();
static NOINLINE u32 GetCreateProcessMemoryPool();

View File

@@ -108,10 +108,12 @@ namespace ams::kern {
u8 exception_flags;
bool is_pinned;
u8 reserved_2f;
u8 reserved_30[0x10];
KThreadContext context;
};
static_assert(util::IsAligned(AMS_OFFSETOF(StackParameters, context), 0x10));
static_assert(sizeof(StackParameters) == THREAD_STACK_PARAMETERS_SIZE);
static_assert(AMS_OFFSETOF(StackParameters, svc_access_flags) == THREAD_STACK_PARAMETERS_SVC_PERMISSION);
static_assert(AMS_OFFSETOF(StackParameters, caller_save_fpu_registers) == THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS);
@@ -123,8 +125,10 @@ namespace ams::kern {
static_assert(AMS_OFFSETOF(StackParameters, exception_flags) == THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS);
static_assert(AMS_OFFSETOF(StackParameters, is_pinned) == THREAD_STACK_PARAMETERS_IS_PINNED);
static_assert(AMS_OFFSETOF(StackParameters, reserved_2f) == THREAD_STACK_PARAMETERS_RESERVED_2F);
static_assert(AMS_OFFSETOF(StackParameters, reserved_30) == THREAD_STACK_PARAMETERS_RESERVED_30);
static_assert(AMS_OFFSETOF(StackParameters, context) == THREAD_STACK_PARAMETERS_THREAD_CONTEXT);
static_assert(ExceptionFlag_IsCallingSvc == THREAD_EXCEPTION_FLAG_IS_CALLING_SVC);
static_assert(ExceptionFlag_IsInExceptionHandler == THREAD_EXCEPTION_FLAG_IS_IN_EXCEPTION_HANDLER);
static_assert(ExceptionFlag_IsFpuContextRestoreNeeded == THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED);
@@ -197,6 +201,28 @@ namespace ams::kern {
};
static_assert(ams::util::HasRedBlackKeyType<ConditionVariableComparator>);
static_assert(std::same_as<ams::util::RedBlackKeyType<ConditionVariableComparator, void>, ConditionVariableComparator::RedBlackKeyType>);
struct LockWithPriorityInheritanceComparator {
struct RedBlackKeyType {
s32 m_priority;
constexpr ALWAYS_INLINE s32 GetPriority() const {
return m_priority;
}
};
template<typename T> requires (std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>)
static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KThread &rhs) {
if (lhs.GetPriority() < rhs.GetPriority()) {
/* Sort by priority. */
return -1;
} else {
return 1;
}
}
};
static_assert(ams::util::HasRedBlackKeyType<LockWithPriorityInheritanceComparator>);
static_assert(std::same_as<ams::util::RedBlackKeyType<LockWithPriorityInheritanceComparator, void>, LockWithPriorityInheritanceComparator::RedBlackKeyType>);
private:
util::IntrusiveListNode m_process_list_node;
util::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node;
@@ -205,6 +231,67 @@ namespace ams::kern {
using ConditionVariableThreadTreeTraits = util::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&KThread::m_condvar_arbiter_tree_node>;
using ConditionVariableThreadTree = ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
using LockWithPriorityInheritanceThreadTreeTraits = util::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&KThread::m_condvar_arbiter_tree_node>;
using LockWithPriorityInheritanceThreadTree = ConditionVariableThreadTreeTraits::TreeType<LockWithPriorityInheritanceComparator>;
public:
class LockWithPriorityInheritanceInfo : public KSlabAllocated<LockWithPriorityInheritanceInfo>, public util::IntrusiveListBaseNode<LockWithPriorityInheritanceInfo> {
private:
LockWithPriorityInheritanceThreadTree m_tree;
KProcessAddress m_address_key;
KThread *m_owner;
u32 m_waiter_count;
public:
constexpr LockWithPriorityInheritanceInfo() : m_tree(), m_address_key(Null<KProcessAddress>), m_owner(nullptr), m_waiter_count() {
/* ... */
}
static LockWithPriorityInheritanceInfo *Create(KProcessAddress address_key) {
/* Create a new lock info. */
auto *new_lock = LockWithPriorityInheritanceInfo::Allocate();
MESOSPHERE_ABORT_UNLESS(new_lock != nullptr);
/* Set the new lock's address key. */
new_lock->m_address_key = address_key;
return new_lock;
}
void SetOwner(KThread *new_owner) {
/* Set new owner. */
m_owner = new_owner;
}
void AddWaiter(KThread *waiter) {
/* Insert the waiter. */
m_tree.insert(*waiter);
m_waiter_count++;
waiter->SetWaitingLockInfo(this);
}
[[nodiscard]] bool RemoveWaiter(KThread *waiter) {
m_tree.erase(m_tree.iterator_to(*waiter));
waiter->SetWaitingLockInfo(nullptr);
return (--m_waiter_count) == 0;
}
KThread *GetHighestPriorityWaiter() { return std::addressof(m_tree.front()); }
const KThread *GetHighestPriorityWaiter() const { return std::addressof(m_tree.front()); }
LockWithPriorityInheritanceThreadTree &GetThreadTree() { return m_tree; }
const LockWithPriorityInheritanceThreadTree &GetThreadTree() const { return m_tree; }
constexpr KProcessAddress GetAddressKey() const { return m_address_key; }
constexpr KThread *GetOwner() const { return m_owner; }
constexpr u32 GetWaiterCount() const { return m_waiter_count; }
};
private:
using LockWithPriorityInheritanceInfoList = util::IntrusiveListBaseTraits<LockWithPriorityInheritanceInfo>::ListType;
ConditionVariableThreadTree *m_condvar_tree;
uintptr_t m_condvar_key;
alignas(16) KThreadContext::CallerSaveFpuRegisters m_caller_save_fpu_registers;
@@ -224,9 +311,9 @@ namespace ams::kern {
s64 m_last_scheduled_tick;
QueueEntry m_per_core_priority_queue_entry[cpu::NumCores];
KThreadQueue *m_wait_queue;
WaiterList m_waiter_list;
LockWithPriorityInheritanceInfoList m_held_lock_info_list;
LockWithPriorityInheritanceInfo *m_waiting_lock_info;
WaiterList m_pinned_waiter_list;
KThread *m_lock_owner;
uintptr_t m_debug_params[3];
KAutoObject *m_closed_object;
u32 m_address_key_value;
@@ -260,8 +347,8 @@ namespace ams::kern {
m_process_list_node{}, m_condvar_arbiter_tree_node{util::ConstantInitialize}, m_priority{-1}, m_condvar_tree{}, m_condvar_key{},
m_caller_save_fpu_registers{}, m_virtual_affinity_mask{}, m_physical_affinity_mask{}, m_thread_id{}, m_cpu_time{0}, m_address_key{Null<KProcessAddress>}, m_parent{},
m_kernel_stack_top{}, m_light_ipc_data{}, m_tls_address{Null<KProcessAddress>}, m_tls_heap_address{}, m_activity_pause_lock{}, m_sync_object_buffer{util::ConstantInitialize},
m_schedule_count{}, m_last_scheduled_tick{}, m_per_core_priority_queue_entry{}, m_wait_queue{}, m_waiter_list{}, m_pinned_waiter_list{},
m_lock_owner{}, m_debug_params{}, m_closed_object{}, m_address_key_value{}, m_suspend_request_flags{}, m_suspend_allowed_flags{}, m_synced_index{},
m_schedule_count{}, m_last_scheduled_tick{}, m_per_core_priority_queue_entry{}, m_wait_queue{}, m_held_lock_info_list{}, m_waiting_lock_info{},
m_pinned_waiter_list{}, m_debug_params{}, m_closed_object{}, m_address_key_value{}, m_suspend_request_flags{}, m_suspend_allowed_flags{}, m_synced_index{},
m_wait_result{svc::ResultNoSynchronizationObject()}, m_debug_exception_result{ResultSuccess()}, m_base_priority{}, m_base_priority_on_unpin{},
m_physical_ideal_core_id{}, m_virtual_ideal_core_id{}, m_num_kernel_waiters{}, m_current_core_id{}, m_core_id{}, m_original_physical_affinity_mask{},
m_original_physical_ideal_core_id{}, m_num_core_migration_disables{}, m_thread_state{}, m_termination_requested{false}, m_wait_cancelled{},
@@ -407,6 +494,10 @@ namespace ams::kern {
void ClearUsermodeExceptionSvcPermissions();
private:
void UpdateState();
ALWAYS_INLINE void AddHeldLock(LockWithPriorityInheritanceInfo *lock_info);
ALWAYS_INLINE LockWithPriorityInheritanceInfo *FindHeldLock(KProcessAddress address_key);
ALWAYS_INLINE void AddWaiterImpl(KThread *thread);
ALWAYS_INLINE void RemoveWaiterImpl(KThread *thread);
ALWAYS_INLINE static void RestorePriority(KThread *thread);
@@ -441,6 +532,8 @@ namespace ams::kern {
constexpr uintptr_t GetAddressArbiterKey() const { return m_condvar_key; }
constexpr void SetConditionVariable(ConditionVariableThreadTree *tree, KProcessAddress address, uintptr_t cv_key, u32 value) {
MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr);
m_condvar_tree = tree;
m_condvar_key = cv_key;
m_address_key = address;
@@ -456,6 +549,8 @@ namespace ams::kern {
}
constexpr void SetAddressArbiter(ConditionVariableThreadTree *tree, uintptr_t address) {
MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr);
m_condvar_tree = tree;
m_condvar_key = address;
}
@@ -491,15 +586,17 @@ namespace ams::kern {
void AddWaiter(KThread *thread);
void RemoveWaiter(KThread *thread);
KThread *RemoveWaiterByKey(s32 *out_num_waiters, KProcessAddress key);
KThread *RemoveWaiterByKey(bool *out_has_waiters, KProcessAddress key);
constexpr KProcessAddress GetAddressKey() const { return m_address_key; }
constexpr u32 GetAddressKeyValue() const { return m_address_key_value; }
constexpr void SetAddressKey(KProcessAddress key) { m_address_key = key; }
constexpr void SetAddressKey(KProcessAddress key, u32 val) { m_address_key = key; m_address_key_value = val; }
constexpr void SetAddressKey(KProcessAddress key) { MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr); m_address_key = key; }
constexpr void SetAddressKey(KProcessAddress key, u32 val) { MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr); m_address_key = key; m_address_key_value = val; }
constexpr void SetLockOwner(KThread *owner) { m_lock_owner = owner; }
constexpr KThread *GetLockOwner() const { return m_lock_owner; }
constexpr void SetWaitingLockInfo(LockWithPriorityInheritanceInfo *lock) { m_waiting_lock_info = lock; }
constexpr LockWithPriorityInheritanceInfo *GetWaitingLockInfo() { return m_waiting_lock_info; }
constexpr KThread *GetLockOwner() const { return m_waiting_lock_info != nullptr ? m_waiting_lock_info->GetOwner() : nullptr; }
constexpr void ClearWaitQueue() { m_wait_queue = nullptr; }
@@ -529,8 +626,6 @@ namespace ams::kern {
constexpr u32 *GetLightSessionData() const { return m_light_ipc_data; }
constexpr void SetLightSessionData(u32 *data) { m_light_ipc_data = data; }
bool HasWaiters() const { return !m_waiter_list.empty(); }
constexpr s64 GetLastScheduledTick() const { return m_last_scheduled_tick; }
constexpr void SetLastScheduledTick(s64 tick) { m_last_scheduled_tick = tick; }

View File

@@ -120,10 +120,6 @@ namespace ams::kern {
return m_address == rhs;
}
constexpr ALWAYS_INLINE bool operator!=(uintptr_t rhs) const {
return m_address != rhs;
}
/* Allow getting the address explicitly, for use in accessors. */
constexpr ALWAYS_INLINE uintptr_t GetValue() const {
return m_address;

View File

@@ -164,8 +164,9 @@ namespace ams::kern {
};
template<typename Derived, typename Base, bool SupportDynamicExpansion = false> requires std::derived_from<Base, KAutoObjectWithList>
template<typename Derived, typename Base, bool SupportDynamicExpansion = false>
class KAutoObjectWithSlabHeapAndContainer : public KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion> {
static_assert(std::derived_from<Base, KAutoObjectWithList>);
private:
static constinit inline KAutoObjectWithListContainer<Derived> s_container;
public:

View File

@@ -25,8 +25,6 @@ namespace ams::kern::arch::arm64 {
namespace {
constexpr inline u32 El0PsrMask = 0xFF0FFE20;
enum EsrEc : u32 {
EsrEc_Unknown = 0b000000,
EsrEc_WaitForInterruptOrEvent = 0b000001,
@@ -134,7 +132,7 @@ namespace ams::kern::arch::arm64 {
info->sp = context->sp;
info->lr = context->x[30];
info->pc = context->pc;
info->pstate = (context->psr & El0PsrMask);
info->pstate = (context->psr & cpu::El0Aarch64PsrMask);
info->afsr0 = afsr0;
info->afsr1 = afsr1;
info->esr = esr;
@@ -151,7 +149,7 @@ namespace ams::kern::arch::arm64 {
info->pc = context->pc;
info->flags = 1;
info->status_64.pstate = (context->psr & El0PsrMask);
info->status_64.pstate = (context->psr & cpu::El0Aarch32PsrMask);
info->status_64.afsr0 = afsr0;
info->status_64.afsr1 = afsr1;
info->status_64.esr = esr;
@@ -231,73 +229,71 @@ namespace ams::kern::arch::arm64 {
{
/* Collect additional information based on the ec. */
ams::svc::DebugException exception;
uintptr_t param2 = 0;
uintptr_t param3 = 0;
uintptr_t params[3] = {};
switch (ec) {
case EsrEc_Unknown:
case EsrEc_IllegalExecution:
case EsrEc_BkptInstruction:
case EsrEc_BrkInstruction:
{
exception = ams::svc::DebugException_UndefinedInstruction;
param2 = far;
param3 = data;
params[0] = ams::svc::DebugException_UndefinedInstruction;
params[1] = far;
params[2] = data;
}
break;
case EsrEc_PcAlignmentFault:
case EsrEc_SpAlignmentFault:
{
exception = ams::svc::DebugException_AlignmentFault;
param2 = far;
params[0] = ams::svc::DebugException_AlignmentFault;
params[1] = far;
}
break;
case EsrEc_Svc32:
case EsrEc_Svc64:
{
exception = ams::svc::DebugException_UndefinedSystemCall;
param2 = far;
param3 = (esr & 0xFF);
params[0] = ams::svc::DebugException_UndefinedSystemCall;
params[1] = far;
params[2] = (esr & 0xFF);
}
break;
case EsrEc_BreakPointEl0:
case EsrEc_SoftwareStepEl0:
{
exception = ams::svc::DebugException_BreakPoint;
param2 = far;
param3 = ams::svc::BreakPointType_HardwareInstruction;
params[0] = ams::svc::DebugException_BreakPoint;
params[1] = far;
params[2] = ams::svc::BreakPointType_HardwareInstruction;
}
break;
case EsrEc_WatchPointEl0:
{
exception = ams::svc::DebugException_BreakPoint;
param2 = far;
param3 = ams::svc::BreakPointType_HardwareData;
params[0] = ams::svc::DebugException_BreakPoint;
params[1] = far;
params[2] = ams::svc::BreakPointType_HardwareData;
}
break;
case EsrEc_SErrorInterrupt:
{
exception = ams::svc::DebugException_MemorySystemError;
param2 = far;
params[0] = ams::svc::DebugException_MemorySystemError;
params[1] = far;
}
break;
case EsrEc_InstructionAbortEl0:
{
exception = ams::svc::DebugException_InstructionAbort;
param2 = far;
params[0] = ams::svc::DebugException_InstructionAbort;
params[1] = far;
}
break;
case EsrEc_DataAbortEl0:
default:
{
exception = ams::svc::DebugException_DataAbort;
param2 = far;
params[0] = ams::svc::DebugException_DataAbort;
params[1] = far;
}
break;
}
/* Process the debug event. */
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, exception, param2, param3);
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params));
/* If we should stop processing the exception, do so. */
if (svc::ResultStopProcessingException::Includes(result)) {
@@ -342,7 +338,7 @@ namespace ams::kern::arch::arm64 {
/* If the SVC is handled, handle it. */
if (!svc::ResultNotHandled::Includes(result)) {
/* If we successfully enter jit debug, stop processing the exception. */
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, exception, param2, param3)) {
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, static_cast<ams::svc::DebugException>(params[0]), params[1], params[2])) {
return;
}
}
@@ -399,7 +395,7 @@ namespace ams::kern::arch::arm64 {
e_ctx->x[30] = info.info64.lr;
e_ctx->sp = info.info64.sp;
e_ctx->pc = info.info64.pc;
e_ctx->psr = (info.info64.pstate & El0PsrMask) | (e_ctx->psr & ~El0PsrMask);
e_ctx->psr = (info.info64.pstate & cpu::El0Aarch64PsrMask) | (e_ctx->psr & ~cpu::El0Aarch64PsrMask);
} else {
for (size_t i = 0; i < util::size(info.info32.r); ++i) {
e_ctx->x[i] = info.info32.r[i];
@@ -407,7 +403,7 @@ namespace ams::kern::arch::arm64 {
e_ctx->x[14] = info.info32.lr;
e_ctx->x[13] = info.info32.sp;
e_ctx->pc = info.info32.pc;
e_ctx->psr = (info.info32.status_64.pstate & El0PsrMask) | (e_ctx->psr & ~El0PsrMask);
e_ctx->psr = (info.info32.status_64.pstate & cpu::El0Aarch32PsrMask) | (e_ctx->psr & ~cpu::El0Aarch32PsrMask);
}
/* Note that PC was adjusted. */
@@ -422,58 +418,56 @@ namespace ams::kern::arch::arm64 {
GetCurrentThread().RestoreDebugParams(std::addressof(far), std::addressof(esr), std::addressof(data));
/* Collect additional information based on the ec. */
ams::svc::DebugException exception;
uintptr_t param2 = 0;
uintptr_t param3 = 0;
uintptr_t params[3] = {};
switch ((esr >> 26) & 0x3F) {
case EsrEc_Unknown:
case EsrEc_IllegalExecution:
case EsrEc_BkptInstruction:
case EsrEc_BrkInstruction:
{
exception = ams::svc::DebugException_UndefinedInstruction;
param2 = far;
param3 = data;
params[0] = ams::svc::DebugException_UndefinedInstruction;
params[1] = far;
params[2] = data;
}
break;
case EsrEc_PcAlignmentFault:
case EsrEc_SpAlignmentFault:
{
exception = ams::svc::DebugException_AlignmentFault;
param2 = far;
params[0] = ams::svc::DebugException_AlignmentFault;
params[1] = far;
}
break;
case EsrEc_Svc32:
case EsrEc_Svc64:
{
exception = ams::svc::DebugException_UndefinedSystemCall;
param2 = far;
param3 = (esr & 0xFF);
params[0] = ams::svc::DebugException_UndefinedSystemCall;
params[1] = far;
params[2] = (esr & 0xFF);
}
break;
case EsrEc_SErrorInterrupt:
{
exception = ams::svc::DebugException_MemorySystemError;
param2 = far;
params[0] = ams::svc::DebugException_MemorySystemError;
params[1] = far;
}
break;
case EsrEc_InstructionAbortEl0:
{
exception = ams::svc::DebugException_InstructionAbort;
param2 = far;
params[0] = ams::svc::DebugException_InstructionAbort;
params[1] = far;
}
break;
case EsrEc_DataAbortEl0:
default:
{
exception = ams::svc::DebugException_DataAbort;
param2 = far;
params[0] = ams::svc::DebugException_DataAbort;
params[1] = far;
}
break;
}
/* Process the debug event. */
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, exception, param2, param3);
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params));
/* If the SVC is handled, handle it. */
if (!svc::ResultNotHandled::Includes(result)) {
@@ -483,7 +477,7 @@ namespace ams::kern::arch::arm64 {
}
/* If we successfully enter jit debug, restore. */
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, exception, param2, param3)) {
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, static_cast<ams::svc::DebugException>(params[0]), params[1], params[2])) {
svc::RestoreContext(reinterpret_cast<uintptr_t>(e_ctx));
}
}

View File

@@ -37,8 +37,6 @@ namespace ams::kern::arch::arm64 {
static_assert(ForbiddenWatchPointFlagsMask == 0xFFFFFFFF00F0E006ul);
constexpr inline u32 El0PsrMask = 0xFF0FFE20;
}
uintptr_t KDebug::GetProgramCounter(const KThread &thread) {
@@ -104,7 +102,7 @@ namespace ams::kern::arch::arm64 {
out->lr = e_ctx->x[30];
out->sp = e_ctx->sp;
out->pc = e_ctx->pc;
out->pstate = (e_ctx->psr & El0PsrMask);
out->pstate = (e_ctx->psr & cpu::El0Aarch64PsrMask);
/* Adjust PC if we should. */
if (e_ctx->write == 0 && thread->IsCallingSvc()) {
@@ -119,7 +117,7 @@ namespace ams::kern::arch::arm64 {
out->lr = 0;
out->sp = 0;
out->pc = e_ctx->pc;
out->pstate = (e_ctx->psr & El0PsrMask);
out->pstate = (e_ctx->psr & cpu::El0Aarch32PsrMask);
/* Adjust PC if we should. */
if (e_ctx->write == 0 && thread->IsCallingSvc()) {
@@ -166,7 +164,7 @@ namespace ams::kern::arch::arm64 {
e_ctx->x[30] = ctx.lr;
e_ctx->sp = ctx.sp;
e_ctx->pc = ctx.pc;
e_ctx->psr = ((ctx.pstate & El0PsrMask) | (e_ctx->psr & ~El0PsrMask));
e_ctx->psr = ((ctx.pstate & cpu::El0Aarch64PsrMask) | (e_ctx->psr & ~cpu::El0Aarch64PsrMask));
e_ctx->tpidr = ctx.tpidr;
} else {
e_ctx->x[13] = static_cast<u32>(ctx.r[13]);
@@ -174,7 +172,7 @@ namespace ams::kern::arch::arm64 {
e_ctx->x[30] = 0;
e_ctx->sp = 0;
e_ctx->pc = static_cast<u32>(ctx.pc);
e_ctx->psr = ((ctx.pstate & El0PsrMask) | (e_ctx->psr & ~El0PsrMask));
e_ctx->psr = ((ctx.pstate & cpu::El0Aarch32PsrMask) | (e_ctx->psr & ~cpu::El0Aarch32PsrMask));
e_ctx->tpidr = ctx.tpidr;
}
}
@@ -251,7 +249,8 @@ namespace ams::kern::arch::arm64 {
}
Result KDebug::BreakIfAttached(ams::svc::BreakReason break_reason, uintptr_t address, size_t size) {
R_RETURN(KDebugBase::OnDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_UserBreak, GetProgramCounter(GetCurrentThread()), break_reason, address, size));
const uintptr_t params[5] = { ams::svc::DebugException_UserBreak, GetProgramCounter(GetCurrentThread()), break_reason, address, size };
R_RETURN(KDebugBase::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params)));
}
#define MESOSPHERE_SET_HW_BREAK_POINT(ID, FLAGS, VALUE) \

View File

@@ -378,9 +378,11 @@ namespace ams::kern::arch::arm64 {
case OperationType_MapFirst:
R_RETURN(this->MapContiguous(virt_addr, phys_addr, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, operation != OperationType_MapFirst, page_list, reuse_ll));
case OperationType_ChangePermissions:
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, false, page_list, reuse_ll));
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, false, false, page_list, reuse_ll));
case OperationType_ChangePermissionsAndRefresh:
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, true, page_list, reuse_ll));
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, true, false, page_list, reuse_ll));
case OperationType_ChangePermissionsAndRefreshAndFlush:
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, true, true, page_list, reuse_ll));
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
}
}
@@ -1233,7 +1235,7 @@ namespace ams::kern::arch::arm64 {
R_RETURN(this->SeparatePagesImpl(virt_addr, block_size, page_list, reuse_ll));
}
Result KPageTable::ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, PageLinkedList *page_list, bool reuse_ll) {
Result KPageTable::ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, bool flush_mapping, PageLinkedList *page_list, bool reuse_ll) {
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
/* Separate pages before we change permissions. */
@@ -1451,8 +1453,8 @@ namespace ams::kern::arch::arm64 {
KScopedSchedulerLock sl;
}
/* Finally, apply the changes as directed, flushing the mappings before they're applied. */
ApplyEntryTemplate(entry_template, ApplyOption_FlushDataCache);
/* 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);
}
/* We've succeeded, now perform what coalescing we can. */

View File

@@ -353,12 +353,12 @@ namespace ams::kern::arch::arm64 {
l1_entry->IsPrivilegedExecuteNever(),
l1_entry->IsContiguous(),
!l1_entry->IsGlobal(),
static_cast<int>(l1_entry->GetAccessFlag()),
static_cast<unsigned int>(l1_entry->GetShareable()),
static_cast<int>(l1_entry->GetAccessFlagInteger()),
static_cast<unsigned int>(l1_entry->GetShareableInteger()),
l1_entry->IsReadOnly(),
l1_entry->IsUserAccessible(),
l1_entry->IsNonSecure(),
static_cast<int>(l1_entry->GetPageAttribute()),
static_cast<int>(l1_entry->GetPageAttributeInteger()),
l1_entry->IsHeadMergeDisabled(),
l1_entry->IsHeadAndBodyMergeDisabled(),
l1_entry->IsTailMergeDisabled());
@@ -398,12 +398,12 @@ namespace ams::kern::arch::arm64 {
l2_entry->IsPrivilegedExecuteNever(),
l2_entry->IsContiguous(),
!l2_entry->IsGlobal(),
static_cast<int>(l2_entry->GetAccessFlag()),
static_cast<unsigned int>(l2_entry->GetShareable()),
static_cast<int>(l2_entry->GetAccessFlagInteger()),
static_cast<unsigned int>(l2_entry->GetShareableInteger()),
l2_entry->IsReadOnly(),
l2_entry->IsUserAccessible(),
l2_entry->IsNonSecure(),
static_cast<int>(l2_entry->GetPageAttribute()),
static_cast<int>(l2_entry->GetPageAttributeInteger()),
l2_entry->IsHeadMergeDisabled(),
l2_entry->IsHeadAndBodyMergeDisabled(),
l2_entry->IsTailMergeDisabled());
@@ -443,12 +443,12 @@ namespace ams::kern::arch::arm64 {
l3_entry->IsPrivilegedExecuteNever(),
l3_entry->IsContiguous(),
!l3_entry->IsGlobal(),
static_cast<int>(l3_entry->GetAccessFlag()),
static_cast<unsigned int>(l3_entry->GetShareable()),
static_cast<int>(l3_entry->GetAccessFlagInteger()),
static_cast<unsigned int>(l3_entry->GetShareableInteger()),
l3_entry->IsReadOnly(),
l3_entry->IsUserAccessible(),
l3_entry->IsNonSecure(),
static_cast<int>(l3_entry->GetPageAttribute()),
static_cast<int>(l3_entry->GetPageAttributeInteger()),
l3_entry->IsHeadMergeDisabled(),
l3_entry->IsHeadAndBodyMergeDisabled(),
l3_entry->IsTailMergeDisabled());

View File

@@ -26,7 +26,9 @@ namespace ams::kern::arch::arm64 {
/* Send KDebug event for this thread's creation. */
{
KScopedInterruptEnable ei;
KDebug::OnDebugEvent(ams::svc::DebugEvent_CreateThread, GetCurrentThread().GetId(), GetInteger(GetCurrentThread().GetThreadLocalRegionAddress()));
const uintptr_t params[2] = { GetCurrentThread().GetId(), GetInteger(GetCurrentThread().GetThreadLocalRegionAddress()) };
KDebug::OnDebugEvent(ams::svc::DebugEvent_CreateThread, params, util::size(params));
}
/* Handle any pending dpc. */
@@ -40,8 +42,6 @@ namespace ams::kern::arch::arm64 {
namespace {
constexpr inline u32 El0PsrMask = 0xFF0FFE20;
ALWAYS_INLINE bool IsFpuEnabled() {
return cpu::ArchitecturalFeatureAccessControlRegisterAccessor().IsFpEnabled();
}
@@ -96,8 +96,8 @@ namespace ams::kern::arch::arm64 {
/* SP */
/* | */
/* v */
/* | u64 argument | u64 entrypoint | KThread::StackParameters (size 0x130) | */
static_assert(sizeof(KThread::StackParameters) == 0x130);
/* | u64 argument | u64 entrypoint | KThread::StackParameters (size 0x140) | */
static_assert(sizeof(KThread::StackParameters) == 0x140);
u64 *stack = GetPointer<u64>(sp);
*(--stack) = GetInteger(pc);
@@ -191,7 +191,7 @@ namespace ams::kern::arch::arm64 {
out->lr = e_ctx->x[30];
out->sp = e_ctx->sp;
out->pc = e_ctx->pc;
out->pstate = e_ctx->psr & El0PsrMask;
out->pstate = e_ctx->psr & cpu::El0Aarch64PsrMask;
/* Get the thread's general purpose registers. */
if (thread->IsCallingSvc()) {
@@ -227,7 +227,7 @@ namespace ams::kern::arch::arm64 {
} else {
/* Set special registers. */
out->pc = static_cast<u32>(e_ctx->pc);
out->pstate = e_ctx->psr & El0PsrMask;
out->pstate = e_ctx->psr & cpu::El0Aarch32PsrMask;
/* Get the thread's general purpose registers. */
for (size_t i = 0; i < 15; ++i) {

View File

@@ -596,8 +596,11 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory32BitEPvPKvm:
/* Save our return address. */
mov x8, x30
/* Prepare return address for read failure. */
adr x10, 4f
1: /* Set our return address so that on read failure we continue as though we read -1. */
adr x30, 4f
mov x30, x10
/* Read the word from io. */
ldtr w9, [x5]
@@ -643,8 +646,11 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory16BitEPvPKvm:
/* Save our return address. */
mov x8, x30
/* Prepare return address for read failure. */
adr x10, 4f
1: /* Set our return address so that on read failure we continue as though we read -1. */
adr x30, 4f
mov x30, x10
/* Read the word from io. */
ldtrh w9, [x5]
@@ -690,8 +696,11 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess16ReadIoMemory8BitEPvPKvm:
/* Save our return address. */
mov x8, x30
/* Prepare return address for read failure. */
adr x10, 4f
1: /* Set our return address so that on read failure we continue as though we read -1. */
adr x30, 4f
mov x30, x10
/* Read the word from io. */
ldtrb w9, [x5]
@@ -737,11 +746,14 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory32BitEPvPKvm:
/* Save our return address. */
mov x8, x30
/* Prepare return address for failure. */
adr x10, 2f
1: /* Read the word from normal memory. */
ldtr w9, [x5]
/* Set our return address so that on read failure we continue. */
adr x30, 2f
/* Set our return address so that on failure we continue. */
mov x30, x10
/* Write the word to io. */
sttr w9, [x5]
@@ -779,11 +791,14 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory16BitEPvPKvm:
/* Save our return address. */
mov x8, x30
/* Prepare return address for failure. */
adr x10, 2f
1: /* Read the word from normal memory. */
ldtrh w9, [x5]
/* Set our return address so that on read failure we continue. */
adr x30, 2f
/* Set our return address so that on failure we continue. */
mov x30, x10
/* Write the word to io. */
sttrh w9, [x5]
@@ -821,11 +836,14 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17WriteIoMemory8BitEPvPKvm:
/* Save our return address. */
mov x8, x30
/* Prepare return address for failure. */
adr x10, 2f
1: /* Read the word from normal memory. */
ldtrb w9, [x5]
/* Set our return address so that on read failure we continue. */
adr x30, 2f
/* Set our return address so that on failure we continue. */
mov x30, x10
/* Write the word to io. */
sttrb w9, [x5]

View File

@@ -1133,17 +1133,17 @@ namespace ams::kern::board::nintendo::nx {
size_t cur_size;
{
/* Get the current contiguous range. */
KPageTableBase::MemoryRange contig_range = { .address = Null<KPhysicalAddress>, .size = 0 };
KPageTableBase::MemoryRange contig_range;
R_TRY(page_table->OpenMemoryRangeForMapDeviceAddressSpace(std::addressof(contig_range), process_address + mapped_size, size - mapped_size, ConvertToKMemoryPermission(device_perm), is_aligned));
/* Ensure we close the range when we're done. */
ON_SCOPE_EXIT { contig_range.Close(); };
/* Get the current size. */
cur_size = contig_range.size;
cur_size = contig_range.GetSize();
/* Map the device page. */
R_TRY(this->MapDevicePage(contig_range.address, contig_range.size, cur_addr, device_perm));
R_TRY(this->MapDevicePage(contig_range.GetAddress(), cur_size, cur_addr, device_perm));
}
/* Advance. */
@@ -1288,7 +1288,7 @@ namespace ams::kern::board::nintendo::nx {
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
/* We need to traverse the ranges that make up our mapping, to make sure they're all good. Start by getting a contiguous range. */
KPageTableBase::MemoryRange contig_range = { .address = Null<KPhysicalAddress>, .size = 0 };
KPageTableBase::MemoryRange contig_range;
if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), process_address, size))) {
return false;
}
@@ -1300,8 +1300,8 @@ namespace ams::kern::board::nintendo::nx {
/* Walk the directory. */
KProcessAddress cur_process_address = process_address;
size_t remaining_size = size;
KPhysicalAddress cur_phys_address = contig_range.address;
size_t remaining_in_range = contig_range.size;
KPhysicalAddress cur_phys_address = contig_range.GetAddress();
size_t remaining_in_range = contig_range.GetSize();
bool first = true;
u32 first_attr = 0;
while (remaining_size > 0) {
@@ -1347,8 +1347,8 @@ namespace ams::kern::board::nintendo::nx {
}
range_open = true;
cur_phys_address = contig_range.address;
remaining_in_range = contig_range.size;
cur_phys_address = contig_range.GetAddress();
remaining_in_range = contig_range.GetSize();
}
/* Check that the physical address is expected. */
@@ -1390,8 +1390,8 @@ namespace ams::kern::board::nintendo::nx {
}
range_open = true;
cur_phys_address = contig_range.address;
remaining_in_range = contig_range.size;
cur_phys_address = contig_range.GetAddress();
remaining_in_range = contig_range.GetSize();
}
/* Check that the physical address is expected, and there's enough in the range. */

View File

@@ -18,6 +18,12 @@
#include "kern_secure_monitor.hpp"
#include "kern_lps_driver.hpp"
namespace ams::kern::init {
void StartOtherCore(const ams::kern::init::KInitArguments *init_args);
}
namespace ams::kern::board::nintendo::nx {
namespace {
@@ -67,15 +73,10 @@ namespace ams::kern::board::nintendo::nx {
constinit KLightLock g_request_lock;
constinit KLightLock g_cv_lock;
constinit KLightConditionVariable g_cv{util::ConstantInitialize};
constinit KPhysicalAddress g_sleep_buffer_phys_addrs[cpu::NumCores];
alignas(1_KB) constinit u64 g_sleep_buffers[cpu::NumCores][1_KB / sizeof(u64)];
constinit ams::kern::init::KInitArguments g_sleep_init_arguments[cpu::NumCores];
constinit SavedSystemRegisters g_sleep_system_registers[cpu::NumCores] = {};
void PowerOnCpu(int core_id, KPhysicalAddress entry_phys_addr, u64 context_id) {
/* Request the secure monitor power on the core. */
::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor, true>(cpu::MultiprocessorAffinityRegisterAccessor().GetCpuOnArgument() | core_id, GetInteger(entry_phys_addr), context_id);
}
void WaitOtherCpuPowerOff() {
constexpr u64 PmcPhysicalAddress = 0x7000E400;
constexpr u32 PWRGATE_STATUS_CE123_MASK = ((1u << 3) - 1) << 9;
@@ -473,18 +474,20 @@ namespace ams::kern::board::nintendo::nx {
}
}
void KSleepManager::ProcessRequests(uintptr_t buffer) {
void KSleepManager::ProcessRequests(uintptr_t sleep_buffer) {
const auto target_fw = GetTargetFirmware();
const s32 core_id = GetCurrentCoreId();
KPhysicalAddress resume_entry_phys_addr = Null<KPhysicalAddress>;
ams::kern::init::KInitArguments * const init_args = g_sleep_init_arguments + core_id;
KPhysicalAddress start_core_phys_addr = Null<KPhysicalAddress>;
KPhysicalAddress init_args_phys_addr = Null<KPhysicalAddress>;
/* Get the physical addresses we'll need. */
{
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(g_sleep_buffer_phys_addrs[core_id]), KProcessAddress(buffer)));
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(resume_entry_phys_addr), KProcessAddress(&::ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry)));
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(start_core_phys_addr), KProcessAddress(&::ams::kern::init::StartOtherCore)));
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(init_args_phys_addr), KProcessAddress(init_args)));
}
const KPhysicalAddress sleep_buffer_phys_addr = g_sleep_buffer_phys_addrs[core_id];
const u64 target_core_mask = (1ul << core_id);
const bool use_legacy_lps_driver = target_fw < TargetFirmware_2_0_0;
@@ -547,15 +550,29 @@ namespace ams::kern::board::nintendo::nx {
/* Save the interrupt manager's state. */
Kernel::GetInterruptManager().Save(core_id);
/* Setup the initial arguments. */
{
init_args->ttbr0 = cpu::GetTtbr0El1();
init_args->ttbr1 = cpu::GetTtbr1El1();
init_args->tcr = cpu::GetTcrEl1();
init_args->mair = cpu::GetMairEl1();
init_args->cpuactlr = cpu::GetCpuActlrEl1();
init_args->cpuectlr = cpu::GetCpuEctlrEl1();
init_args->sctlr = cpu::GetSctlrEl1();
init_args->sp = 0;
init_args->entrypoint = reinterpret_cast<uintptr_t>(::ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry);
init_args->argument = sleep_buffer;
}
/* Ensure that all cores get to this point before continuing. */
cpu::SynchronizeAllCores();
/* Log that the core is going to sleep. */
MESOSPHERE_LOG("Core[%d]: Going to sleep, buffer = %010lx\n", core_id, GetInteger(sleep_buffer_phys_addr));
MESOSPHERE_LOG("Core[%d]: Going to sleep, buffer = %010lx\n", core_id, sleep_buffer);
/* If we're on a core other than zero, we can just invoke the sleep handler. */
if (core_id != 0) {
CpuSleepHandler(GetInteger(sleep_buffer_phys_addr), GetInteger(resume_entry_phys_addr));
CpuSleepHandler(sleep_buffer, GetInteger(start_core_phys_addr), GetInteger(init_args_phys_addr));
} else {
/* Wait for all other cores to be powered off. */
WaitOtherCpuPowerOff();
@@ -574,9 +591,9 @@ namespace ams::kern::board::nintendo::nx {
/* Invoke the sleep handler. */
if (!use_legacy_lps_driver) {
/* When not using the legacy driver, invoke directly. */
CpuSleepHandler(GetInteger(sleep_buffer_phys_addr), GetInteger(resume_entry_phys_addr));
CpuSleepHandler(sleep_buffer, GetInteger(start_core_phys_addr), GetInteger(init_args_phys_addr));
} else {
lps::InvokeCpuSleepHandler(GetInteger(sleep_buffer_phys_addr), GetInteger(resume_entry_phys_addr));
lps::InvokeCpuSleepHandler(sleep_buffer, GetInteger(start_core_phys_addr), GetInteger(init_args_phys_addr));
}
/* Restore the debug log state. */
@@ -586,8 +603,10 @@ namespace ams::kern::board::nintendo::nx {
MESOSPHERE_LOG("Exiting SC7\n");
/* Wake up the other cores. */
cpu::MultiprocessorAffinityRegisterAccessor mpidr;
const auto arg = mpidr.GetCpuOnArgument();
for (s32 i = 1; i < static_cast<s32>(cpu::NumCores); ++i) {
PowerOnCpu(i, resume_entry_phys_addr, GetInteger(g_sleep_buffer_phys_addrs[i]));
KSystemControl::Init::TurnOnCpu(arg | i, g_sleep_init_arguments + i);
}
}

View File

@@ -22,14 +22,12 @@ namespace ams::kern::board::nintendo::nx {
private:
static void ResumeEntry(uintptr_t arg);
static void InvalidateDataCacheForResumeEntry(uintptr_t level);
static void ProcessRequests(uintptr_t buffer);
public:
static void Initialize();
static void SleepSystem();
public:
static void CpuSleepHandler(uintptr_t arg, uintptr_t entry);
static void CpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_args);
};

View File

@@ -22,14 +22,14 @@
mov reg, #(((val) >> 0x00) & 0xFFFF); \
movk reg, #(((val) >> 0x10) & 0xFFFF), lsl#16
/* ams::kern::board::nintendo::nx::KSleepManager::CpuSleepHandler(uintptr_t arg, uintptr_t entry) */
.section .sleep._ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm, "ax", %progbits
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm, %function
_ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
/* ams::kern::board::nintendo::nx::KSleepManager::CpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_arg) */
.section .sleep._ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm, "ax", %progbits
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm, %function
_ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm:
/* Save arguments. */
mov x16, x0
mov x17, x1
mov x16, x1
mov x17, x2
/* Enable access to FPU registers. */
mrs x1, cpacr_el1
@@ -74,28 +74,8 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
stp q28, q29, [x0], #0x20
stp q30, q31, [x0], #0x20
/* Save cpuactlr/cpuectlr. */
mrs x1, cpuectlr_el1
mrs x2, cpuactlr_el1
stp x1, x2, [x0], #0x10
/* Save ttbr0/ttbr1. */
mrs x1, ttbr0_el1
mrs x2, ttbr1_el1
stp x1, x2, [x0], #0x10
/* Save tcr/mair. */
mrs x1, tcr_el1
mrs x2, mair_el1
stp x1, x2, [x0], #0x10
/* Save sctlr/tpidr. */
mrs x1, sctlr_el1
mrs x2, tpidr_el1
stp x1, x2, [x0], #0x10
/* Save the virtual resumption entrypoint and cntv_cval_el0. */
adr x1, 77f
/* Save tpidr/cntv_cval_el0. */
mrs x1, tpidr_el1
mrs x2, cntv_cval_el0
stp x1, x2, [x0], #0x10
@@ -114,8 +94,8 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
1: /* Suspend. */
LOAD_IMMEDIATE_32(x0, 0xC4000001)
LOAD_IMMEDIATE_32(x1, 0x0201001B)
mov x2, x17
mov x3, x16
mov x2, x16
mov x3, x17
smc #1
0: b 0b
@@ -124,65 +104,6 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, %function
_ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm:
/* Mask interrupts. */
msr daifset, #0xF
/* Save the argument. */
mov x21, x0
/* Check that we're at the correct exception level. */
mrs x0, currentel
/* Check if we're EL1. */
cmp x0, #0x4
b.eq 3f
/* Check if we're EL2. */
cmp x0, #0x8
b.eq 2f
1: /* We're running at EL3. */
b 1b
2: /* We're running at EL2. */
b 2b
3: /* We're running at EL1. */
/* Invalidate the L1 cache. */
mov x0, #0
bl _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm
/* Get the current core id. */
mrs x0, mpidr_el1
and x0, x0, #0xFF
/* If we're on core0, we want to invalidate the L2 cache. */
cbnz x0, 4f
mov x0, #1
bl _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm
4: /* Invalidate the L1 cache. */
mov x0, #0
bl _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm
/* Invalidate the instruction cache. */
ic ialluis
dsb sy
isb
/* Invalidate the entire tlb. */
tlbi vmalle1is
dsb sy
isb
/* Switch to sp 1. */
msr spsel, #1
/* Prepare to restore the saved context. */
mov x0, x21
/* Enable access to FPU registers. */
mrs x1, cpacr_el1
orr x1, x1, #0x100000
@@ -226,121 +147,12 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm:
ldp q28, q29, [x0], #0x20
ldp q30, q31, [x0], #0x20
/* Restore cpuactlr/cpuectlr. */
/* Restore tpidr/cntv_cval_el0. */
ldp x1, x2, [x0], #0x10
mrs x3, cpuectlr_el1
cmp x1, x3
5: b.ne 5b
mrs x3, cpuactlr_el1
cmp x2, x3
6: b.ne 6b
/* Restore ttbr0/ttbr1. */
ldp x1, x2, [x0], #0x10
msr ttbr0_el1, x1
msr ttbr1_el1, x2
/* Restore tcr/mair. */
ldp x1, x2, [x0], #0x10
msr tcr_el1, x1
msr mair_el1, x2
/* Get sctlr, tpidr, the entrypoint, and cntv_cval_el0. */
ldp x1, x2, [x0], #0x10
ldp x3, x4, [x0], #0x10
/* Set the global context back into x18/tpidr. */
msr tpidr_el1, x2
msr cntv_cval_el0, x4
dsb sy
isb
/* Restore sctlr with the wxn bit cleared. */
bic x2, x1, #0x80000
msr sctlr_el1, x2
dsb sy
isb
/* Jump to the entrypoint. */
br x3
77: /* Virtual resumption entrypoint. */
/* Restore sctlr. */
msr sctlr_el1, x1
msr tpidr_el1, x1
msr cntv_cval_el0, x2
dsb sy
isb
ret
/* ams::kern::board::nintendo::nx::KSleepManager::InvalidateDataCacheForResumeEntry(uintptr_t level) */
.section .sleep._ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm, "ax", %progbits
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm, %function
_ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm:
/* cpu::DataSynchronizationBarrier(); */
dsb sy
/* const u64 level_sel_value = level << 1; */
lsl x8, x0, #1
/* cpu::SetCsselrEl1(level_sel_value); */
msr csselr_el1, x8
/* cpu::InstructionMemoryBarrier(); */
isb
/* CacheSizeIdAccessor ccsidr_el1; */
mrs x13, ccsidr_el1
/* const int num_ways = ccsidr_el1.GetAssociativity(); */
ubfx w10, w13, #3, #0xA
/* const int line_size = ccsidr_el1.GetLineSize(); */
and w11, w13, #7
/* const int num_sets = ccsidr_el1.GetNumberOfSets(); */
ubfx w13, w13, #0xD, #0xF
/* int way = 0; */
mov w9, wzr
/* const u64 set_shift = static_cast<u64>(line_size + 4); */
add w11, w11, #4
/* const u64 way_shift = static_cast<u64>(__builtin_clz(num_ways)); */
clz w12, w10
0: /* do { */
/* int set = 0; */
mov w14, wzr
/* const u64 way_value = (static_cast<u64>(way) << way_shift); */
lsl w15, w9, w12
1: /* do { */
/* const u64 isw_value = (static_cast<u64>(set) << set_shift) | way_value | level_sel_value; */
lsl w16, w14, w11
orr w16, w16, w15
sxtw x16, w16
orr x16, x16, x8
/* __asm__ __volatile__("dc isw, %0" :: "r"(isw_value) : "memory"); */
dc isw, x16
/* while (set <= num_sets); */
cmp w13, w14
add w14, w14, #1
b.ne 1b
/* while (way <= num_ways); */
cmp w9, w10
add w9, w9, #1
b.ne 0b
/* cpu::EnsureInstructionConsistency(); */
dsb sy
isb
/* Return. */
ret

View File

@@ -367,10 +367,14 @@ namespace ams::kern::board::nintendo::nx {
size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
/* Verify that our minimum is at least as large as Nintendo's. */
constexpr size_t MinimumSize = ::ams::svc::RequiredNonSecureSystemMemorySize;
static_assert(MinimumSize >= 0x29C8000);
constexpr size_t MinimumSizeWithFatal = ::ams::svc::RequiredNonSecureSystemMemorySizeWithFatal;
static_assert(MinimumSizeWithFatal >= 0x2C04000);
return MinimumSize;
constexpr size_t MinimumSizeWithoutFatal = ::ams::svc::RequiredNonSecureSystemMemorySize;
static_assert(MinimumSizeWithoutFatal >= 0x2A00000);
/* Include fatal in non-seure size on 16.0.0+. */
return kern::GetTargetFirmware() >= ams::TargetFirmware_16_0_0 ? MinimumSizeWithFatal : MinimumSizeWithoutFatal;
}
u8 KSystemControl::Init::GetDebugLogUartPort() {
@@ -382,7 +386,7 @@ namespace ams::kern::board::nintendo::nx {
return static_cast<u8>((value >> 32) & 0xFF);
}
void KSystemControl::Init::CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
void KSystemControl::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor, false>(core_id, entrypoint, arg)) == 0);
}
@@ -398,40 +402,41 @@ namespace ams::kern::board::nintendo::nx {
/* System Initialization. */
void KSystemControl::InitializePhase1() {
/* Initialize our random generator. */
/* Configure KTargetSystem. */
{
/* Set IsDebugMode. */
{
KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
/* If debug mode, we want to initialize uart logging. */
KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode());
}
/* Set Kernel Configuration. */
{
const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)};
KTargetSystem::EnableDebugMemoryFill(kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>());
KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>());
KTargetSystem::EnableDynamicResourceLimits(!kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>());
KTargetSystem::EnableUserPmuAccess(kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>());
g_call_smc_on_panic = kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>();
}
/* Set Kernel Debugging. */
{
/* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */
/* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */
KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification));
}
}
/* Initialize random and resource limit. */
{
u64 seed;
smc::GenerateRandomBytes(std::addressof(seed), sizeof(seed));
s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
s_initialized_random_generator = true;
}
/* Set IsDebugMode. */
{
KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
/* If debug mode, we want to initialize uart logging. */
KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode());
KDebugLog::Initialize();
}
/* Set Kernel Configuration. */
{
const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)};
KTargetSystem::EnableDebugMemoryFill(kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>());
KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>());
KTargetSystem::EnableDynamicResourceLimits(!kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>());
KTargetSystem::EnableUserPmuAccess(kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>());
g_call_smc_on_panic = kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>();
}
/* Set Kernel Debugging. */
{
/* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */
/* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */
KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification));
KSystemControlBase::InitializePhase1Base(seed);
}
/* Configure the Kernel Carveout region. */
@@ -441,9 +446,6 @@ namespace ams::kern::board::nintendo::nx {
smc::ConfigureCarveout(0, carveout.GetAddress(), carveout.GetSize());
}
/* Initialize the system resource limit (and potentially other things). */
KSystemControlBase::InitializePhase1(true);
}
void KSystemControl::InitializePhase2() {

View File

@@ -395,7 +395,7 @@ namespace ams::kern::board::nintendo::nx::lps {
R_SUCCEED();
}
void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry) {
void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_arg) {
/* Verify that we're allowed to perform suspension. */
MESOSPHERE_ABORT_UNLESS(g_lps_init_done);
MESOSPHERE_ABORT_UNLESS(GetCurrentCoreId() == 0);
@@ -416,7 +416,7 @@ namespace ams::kern::board::nintendo::nx::lps {
Read(g_pmc_address + APBDEV_PMC_SCRATCH0);
/* Invoke the sleep hander. */
KSleepManager::CpuSleepHandler(arg, entry);
KSleepManager::CpuSleepHandler(arg, entry, entry_arg);
/* Disable deep power down. */
Write(g_pmc_address + APBDEV_PMC_DPD_ENABLE, 0);

View File

@@ -22,7 +22,7 @@ namespace ams::kern::board::nintendo::nx {
void Initialize();
Result EnableSuspend(bool enable);
void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry);
void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_arg);
void ResumeBpmpFirmware();
}

View File

@@ -19,6 +19,7 @@ namespace ams::kern::init {
/* For macro convenience. */
using KSessionRequestMappings = KSessionRequest::SessionMappings::DynamicMappings;
using KThreadLockInfo = KThread::LockWithPriorityInheritanceInfo;
#define SLAB_COUNT(CLASS) g_slab_resource_counts.num_##CLASS
@@ -43,8 +44,9 @@ namespace ams::kern::init {
HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
HANDLER(KIoPool, (SLAB_COUNT(KIoPool)), ## __VA_ARGS__) \
HANDLER(KIoRegion, (SLAB_COUNT(KIoRegion)), ## __VA_ARGS__) \
HANDLER(KSessionRequestMappings, (SLAB_COUNT(KSessionRequestMappings)), ## __VA_ARGS__) \
HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \
HANDLER(KSessionRequestMappings, (SLAB_COUNT(KSessionRequestMappings)), ## __VA_ARGS__)
HANDLER(KThreadLockInfo, (SLAB_COUNT(KThread)), ## __VA_ARGS__)
namespace {
@@ -140,7 +142,7 @@ namespace ams::kern::init {
}
size_t CalculateSlabHeapGapSize() {
constexpr size_t KernelSlabHeapGapSize = 2_MB - 320_KB;
constexpr size_t KernelSlabHeapGapSize = 2_MB - 356_KB;
static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax);
return KernelSlabHeapGapSize;
}

View File

@@ -24,7 +24,9 @@ namespace ams::kern {
}
ALWAYS_INLINE bool DecrementIfLessThan(s32 *out, KProcessAddress address, s32 value) {
KScopedInterruptDisable di;
/* NOTE: If scheduler lock is not held here, interrupt disable is required. */
/* KScopedInterruptDisable di; */
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
if (!cpu::CanAccessAtomic(address)) {
return false;
@@ -34,7 +36,9 @@ namespace ams::kern {
}
ALWAYS_INLINE bool UpdateIfEqual(s32 *out, KProcessAddress address, s32 value, s32 new_value) {
KScopedInterruptDisable di;
/* NOTE: If scheduler lock is not held here, interrupt disable is required. */
/* KScopedInterruptDisable di; */
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
if (!cpu::CanAccessAtomic(address)) {
return false;

View File

@@ -21,7 +21,7 @@ namespace ams::kern {
constexpr uintptr_t Invalid = std::numeric_limits<uintptr_t>::max();
constexpr KAddressSpaceInfo AddressSpaceInfos[] = {
constinit KAddressSpaceInfo AddressSpaceInfos[] = {
{ 32, ams::svc::AddressSmallMap32Start, ams::svc::AddressSmallMap32Size, KAddressSpaceInfo::Type_MapSmall, },
{ 32, ams::svc::AddressLargeMap32Start, ams::svc::AddressLargeMap32Size, KAddressSpaceInfo::Type_MapLarge, },
{ 32, Invalid, ams::svc::AddressMemoryRegionHeap32Size, KAddressSpaceInfo::Type_Heap, },
@@ -37,67 +37,27 @@ namespace ams::kern {
{ 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, },
};
constexpr bool IsAllowedIndexForAddress(size_t index) {
return index < util::size(AddressSpaceInfos) && AddressSpaceInfos[index].GetAddress() != Invalid;
}
constexpr size_t AddressSpaceIndices32Bit[KAddressSpaceInfo::Type_Count] = {
0, 1, 0, 2, 0, 3,
};
constexpr size_t AddressSpaceIndices36Bit[KAddressSpaceInfo::Type_Count] = {
4, 5, 4, 6, 4, 7,
};
constexpr size_t AddressSpaceIndices39Bit[KAddressSpaceInfo::Type_Count] = {
9, 8, 8, 10, 12, 11,
};
constexpr bool IsAllowed32BitType(KAddressSpaceInfo::Type type) {
return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Map39Bit && type != KAddressSpaceInfo::Type_Stack;
}
constexpr bool IsAllowed36BitType(KAddressSpaceInfo::Type type) {
return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Map39Bit && type != KAddressSpaceInfo::Type_Stack;
}
constexpr bool IsAllowed39BitType(KAddressSpaceInfo::Type type) {
return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_MapLarge;
KAddressSpaceInfo &GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) {
for (auto &info : AddressSpaceInfos) {
if (info.GetWidth() == width && info.GetType() == type) {
return info;
}
}
MESOSPHERE_PANIC("Could not find AddressSpaceInfo");
}
}
uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) {
switch (width) {
case 32:
MESOSPHERE_ABORT_UNLESS(IsAllowed32BitType(type));
MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[type]));
return AddressSpaceInfos[AddressSpaceIndices32Bit[type]].GetAddress();
case 36:
MESOSPHERE_ABORT_UNLESS(IsAllowed36BitType(type));
MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[type]));
return AddressSpaceInfos[AddressSpaceIndices36Bit[type]].GetAddress();
case 39:
MESOSPHERE_ABORT_UNLESS(IsAllowed39BitType(type));
MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[type]));
return AddressSpaceInfos[AddressSpaceIndices39Bit[type]].GetAddress();
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
}
return GetAddressSpaceInfo(width, type).GetAddress();
}
size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) {
switch (width) {
case 32:
MESOSPHERE_ABORT_UNLESS(IsAllowed32BitType(type));
return AddressSpaceInfos[AddressSpaceIndices32Bit[type]].GetSize();
case 36:
MESOSPHERE_ABORT_UNLESS(IsAllowed36BitType(type));
return AddressSpaceInfos[AddressSpaceIndices36Bit[type]].GetSize();
case 39:
MESOSPHERE_ABORT_UNLESS(IsAllowed39BitType(type));
return AddressSpaceInfos[AddressSpaceIndices39Bit[type]].GetSize();
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
}
return GetAddressSpaceInfo(width, type).GetSize();
}
void KAddressSpaceInfo::SetAddressSpaceSize(size_t width, Type type, size_t size) {
GetAddressSpaceInfo(width, type).SetSize(size);
}
}

View File

@@ -77,34 +77,35 @@ namespace ams::kern {
KScopedSchedulerLock sl;
/* Remove waiter thread. */
s32 num_waiters;
KThread *next_owner_thread = owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
bool has_waiters;
KThread * const next_owner_thread = owner_thread->RemoveWaiterByKey(std::addressof(has_waiters), addr);
/* Determine the next tag. */
u32 next_value = 0;
if (next_owner_thread != nullptr) {
next_value = next_owner_thread->GetAddressKeyValue();
if (num_waiters > 1) {
if (has_waiters) {
next_value |= ams::svc::HandleWaitMask;
}
/* Write the value to userspace. */
Result result;
if (AMS_LIKELY(WriteToUser(addr, std::addressof(next_value)))) {
result = ResultSuccess();
} else {
result = svc::ResultInvalidCurrentMemory();
}
/* Signal the next owner thread. */
next_owner_thread->EndWait(result);
R_RETURN(result);
} else {
/* Just write the value to userspace. */
R_UNLESS(WriteToUser(addr, std::addressof(next_value)), svc::ResultInvalidCurrentMemory());
R_SUCCEED();
}
/* Synchronize memory before proceeding. */
cpu::DataMemoryBarrierInnerShareable();
/* Write the value to userspace. */
Result result;
if (AMS_LIKELY(WriteToUser(addr, std::addressof(next_value)))) {
result = ResultSuccess();
} else {
result = svc::ResultInvalidCurrentMemory();
}
/* If necessary, signal the next owner thread. */
if (next_owner_thread != nullptr) {
next_owner_thread->EndWait(result);
}
R_RETURN(result);
}
}
@@ -157,7 +158,8 @@ namespace ams::kern {
u32 prev_tag;
bool can_access;
{
KScopedInterruptDisable di;
/* NOTE: If scheduler lock is not held here, interrupt disable is required. */
/* KScopedInterruptDisable di; */
can_access = cpu::CanAccessAtomic(address);
if (AMS_LIKELY(can_access)) {
@@ -198,9 +200,11 @@ namespace ams::kern {
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetConditionVariableKey() == cv_key)) {
KThread *target_thread = std::addressof(*it);
this->SignalImpl(target_thread);
it = m_tree.erase(it);
target_thread->ClearConditionVariable();
this->SignalImpl(target_thread);
++num_waiters;
}
@@ -230,15 +234,15 @@ namespace ams::kern {
/* Update the value and process for the next owner. */
{
/* Remove waiter thread. */
s32 num_waiters;
KThread *next_owner_thread = cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), GetInteger(addr));
bool has_waiters;
KThread *next_owner_thread = cur_thread->RemoveWaiterByKey(std::addressof(has_waiters), GetInteger(addr));
/* Update for the next owner thread. */
u32 next_value = 0;
if (next_owner_thread != nullptr) {
/* Get the next tag value. */
next_value = next_owner_thread->GetAddressKeyValue();
if (num_waiters > 1) {
if (has_waiters) {
next_value |= ams::svc::HandleWaitMask;
}

View File

@@ -219,12 +219,21 @@ namespace ams::kern {
const s32 core_id = GetCurrentCoreId();
KThread *thread = process->GetRunningThread(core_id);
/* Check that the thread's idle count is correct. */
R_UNLESS(process->GetRunningThreadIdleCount(core_id) == Kernel::GetScheduler(core_id).GetIdleCount(), svc::ResultNoThread());
/* Check that the thread is running on the current core. */
R_UNLESS(thread != nullptr, svc::ResultUnknownThread());
R_UNLESS(thread->GetActiveCore() == core_id, svc::ResultUnknownThread());
/* We want to check that the thread is actually running. */
/* If it is, then the scheduler will have just switched from the thread to the current thread. */
/* This implies exactly one switch will have taken place, and the current thread will be on the current core. */
const auto &scheduler = Kernel::GetScheduler(core_id);
if (!(thread != nullptr && thread->GetActiveCore() == core_id && process->GetRunningThreadSwitchCount(core_id) + 1 == scheduler.GetSwitchCount())) {
/* The most recent thread switch was from a thread other than the expected one to the current one. */
/* We want to use the appropriate result to inform userland about what thread we switched from. */
if (scheduler.GetIdleCount() + 1 == scheduler.GetSwitchCount()) {
/* We switched from the idle thread. */
R_THROW(svc::ResultNoThread());
} else {
/* We switched from some other unknown thread. */
R_THROW(svc::ResultUnknownThread());
}
}
/* Get the thread's exception context. */
GetExceptionContext(thread)->GetSvcThreadContext(out_context);
@@ -280,7 +289,7 @@ namespace ams::kern {
m_old_process_state = target->SetDebugObject(this);
/* Send an event for our attaching to the process. */
this->PushDebugEvent(ams::svc::DebugEvent_CreateProcess);
this->PushDebugEvent(ams::svc::DebugEvent_CreateProcess, nullptr, 0);
/* Send events for attaching to each thread in the process. */
{
@@ -295,7 +304,8 @@ namespace ams::kern {
it->SetDebugAttached();
/* Send the event. */
this->PushDebugEvent(ams::svc::DebugEvent_CreateThread, it->GetId(), GetInteger(it->GetThreadLocalRegionAddress()));
const uintptr_t params[2] = { it->GetId(), GetInteger(it->GetThreadLocalRegionAddress()) };
this->PushDebugEvent(ams::svc::DebugEvent_CreateThread, params, util::size(params));
}
}
}
@@ -306,7 +316,8 @@ namespace ams::kern {
}
/* Send an exception event to represent our attaching. */
this->PushDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_DebuggerAttached);
const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::DebugException_DebuggerAttached) };
this->PushDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params));
/* Signal. */
this->NotifyAvailable();
@@ -344,22 +355,22 @@ namespace ams::kern {
/* Get the currently active threads. */
constexpr u64 ThreadIdNoThread = -1ll;
constexpr u64 ThreadIdUnknownThread = -2ll;
u64 thread_ids[cpu::NumCores];
for (size_t i = 0; i < util::size(thread_ids); ++i) {
uintptr_t debug_info_params[1 + cpu::NumCores] = { static_cast<uintptr_t>(ams::svc::DebugException_DebuggerBreak), };
for (size_t i = 0; i < cpu::NumCores; ++i) {
/* Get the currently running thread. */
KThread *thread = target->GetRunningThread(i);
/* Check that the thread's idle count is correct. */
if (target->GetRunningThreadIdleCount(i) == Kernel::GetScheduler(i).GetIdleCount()) {
if (thread != nullptr && static_cast<size_t>(thread->GetActiveCore()) == i) {
thread_ids[i] = thread->GetId();
debug_info_params[1 + i] = thread->GetId();
} else {
/* We found an unknown thread. */
thread_ids[i] = ThreadIdUnknownThread;
debug_info_params[1 + i] = ThreadIdUnknownThread;
}
} else {
/* We didn't find a thread. */
thread_ids[i] = ThreadIdNoThread;
debug_info_params[1 + i] = ThreadIdNoThread;
}
}
@@ -373,11 +384,7 @@ namespace ams::kern {
}
/* Send an exception event to represent our breaking the process. */
/* TODO: How should this be handled in the case of more than 4 physical cores? */
static_assert(util::size(thread_ids) <= 4);
[&]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA {
this->PushDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_DebuggerBreak, thread_ids[Ix]...);
}(std::make_index_sequence<util::size(thread_ids)>());
this->PushDebugEvent(ams::svc::DebugEvent_Exception, debug_info_params, util::size(debug_info_params));
/* Signal. */
this->NotifyAvailable();
@@ -725,7 +732,7 @@ namespace ams::kern {
R_SUCCEED();
}
KEventInfo *KDebugBase::CreateDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4, u64 cur_thread_id) {
KEventInfo *KDebugBase::CreateDebugEvent(ams::svc::DebugEvent event, u64 cur_thread_id, const uintptr_t *params, size_t num_params) {
/* Allocate a new event. */
KEventInfo *info = KEventInfo::Allocate();
@@ -740,23 +747,33 @@ namespace ams::kern {
switch (event) {
case ams::svc::DebugEvent_CreateProcess:
{
/* ... */
/* Check parameters. */
MESOSPHERE_ASSERT(params == nullptr);
MESOSPHERE_ASSERT(num_params == 0);
}
break;
case ams::svc::DebugEvent_CreateThread:
{
/* Check parameters. */
MESOSPHERE_ASSERT(params != nullptr);
MESOSPHERE_ASSERT(num_params == 2);
/* Set the thread id. */
info->thread_id = param0;
info->thread_id = params[0];
/* Set the thread creation info. */
info->info.create_thread.thread_id = param0;
info->info.create_thread.tls_address = param1;
info->info.create_thread.thread_id = params[0];
info->info.create_thread.tls_address = params[1];
}
break;
case ams::svc::DebugEvent_ExitProcess:
{
/* Check parameters. */
MESOSPHERE_ASSERT(params != nullptr);
MESOSPHERE_ASSERT(num_params == 1);
/* Set the exit reason. */
info->info.exit_process.reason = static_cast<ams::svc::ProcessExitReason>(param0);
info->info.exit_process.reason = static_cast<ams::svc::ProcessExitReason>(params[0]);
/* Clear the thread id and flags. */
info->thread_id = 0;
@@ -765,30 +782,40 @@ namespace ams::kern {
break;
case ams::svc::DebugEvent_ExitThread:
{
/* Check parameters. */
MESOSPHERE_ASSERT(params != nullptr);
MESOSPHERE_ASSERT(num_params == 2);
/* Set the thread id. */
info->thread_id = param0;
info->thread_id = params[0];
/* Set the exit reason. */
info->info.exit_thread.reason = static_cast<ams::svc::ThreadExitReason>(param1);
info->info.exit_thread.reason = static_cast<ams::svc::ThreadExitReason>(params[1]);
}
break;
case ams::svc::DebugEvent_Exception:
{
/* Check parameters. */
MESOSPHERE_ASSERT(params != nullptr);
MESOSPHERE_ASSERT(num_params >= 1);
/* Set the thread id. */
info->thread_id = cur_thread_id;
/* Set the exception type, and clear the count. */
info->info.exception.exception_type = static_cast<ams::svc::DebugException>(param0);
info->info.exception.exception_type = static_cast<ams::svc::DebugException>(params[0]);
info->info.exception.exception_data_count = 0;
switch (static_cast<ams::svc::DebugException>(param0)) {
switch (static_cast<ams::svc::DebugException>(params[0])) {
case ams::svc::DebugException_UndefinedInstruction:
case ams::svc::DebugException_BreakPoint:
case ams::svc::DebugException_UndefinedSystemCall:
{
info->info.exception.exception_address = param1;
MESOSPHERE_ASSERT(num_params >= 3);
info->info.exception.exception_address = params[1];
info->info.exception.exception_data_count = 1;
info->info.exception.exception_data[0] = param2;
info->info.exception.exception_data[0] = params[2];
}
break;
case ams::svc::DebugException_DebuggerAttached:
@@ -800,12 +827,14 @@ namespace ams::kern {
break;
case ams::svc::DebugException_UserBreak:
{
info->info.exception.exception_address = param1;
MESOSPHERE_ASSERT(num_params >= 2);
info->info.exception.exception_data_count = 3;
info->info.exception.exception_data[0] = param2;
info->info.exception.exception_data[1] = param3;
info->info.exception.exception_data[2] = param4;
info->info.exception.exception_address = params[1];
info->info.exception.exception_data_count = 0;
for (size_t i = 2; i < num_params; ++i) {
info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i];
}
}
break;
case ams::svc::DebugException_DebuggerBreak:
@@ -814,11 +843,10 @@ namespace ams::kern {
info->info.exception.exception_address = 0;
info->info.exception.exception_data_count = 4;
info->info.exception.exception_data[0] = param1;
info->info.exception.exception_data[1] = param2;
info->info.exception.exception_data[2] = param3;
info->info.exception.exception_data[3] = param4;
info->info.exception.exception_data_count = 0;
for (size_t i = 1; i < num_params; ++i) {
info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i];
}
}
break;
case ams::svc::DebugException_MemorySystemError:
@@ -831,7 +859,9 @@ namespace ams::kern {
case ams::svc::DebugException_AlignmentFault:
default:
{
info->info.exception.exception_address = param1;
MESOSPHERE_ASSERT(num_params >= 2);
info->info.exception.exception_address = params[1];
}
break;
}
@@ -843,9 +873,9 @@ namespace ams::kern {
return info;
}
void KDebugBase::PushDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) {
void KDebugBase::PushDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) {
/* Create and enqueue and event. */
if (KEventInfo *new_info = CreateDebugEvent(event, param0, param1, param2, param3, param4, GetCurrentThread().GetId()); new_info != nullptr) {
if (KEventInfo *new_info = CreateDebugEvent(event, GetCurrentThread().GetId(), params, num_params); new_info != nullptr) {
this->EnqueueDebugEventInfo(new_info);
}
}
@@ -952,7 +982,10 @@ namespace ams::kern {
break;
case ams::svc::DebugException_DebuggerBreak:
{
MESOSPHERE_ASSERT(info->info.exception.exception_data_count == 4);
/* TODO: How does this work with non-4 cpu count? */
static_assert(cpu::NumCores <= 4);
MESOSPHERE_ASSERT(info->info.exception.exception_data_count == cpu::NumCores);
out->info.exception.specific.debugger_break.active_thread_ids[0] = info->info.exception.exception_data[0];
out->info.exception.specific.debugger_break.active_thread_ids[1] = info->info.exception.exception_data[1];
out->info.exception.specific.debugger_break.active_thread_ids[2] = info->info.exception.exception_data[2];
@@ -1066,7 +1099,7 @@ namespace ams::kern {
return !empty || !m_is_attached || this->GetProcessUnsafe()->IsTerminated();
}
Result KDebugBase::ProcessDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) {
Result KDebugBase::ProcessDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) {
/* Get the current process. */
KProcess *process = GetCurrentProcessPointer();
@@ -1108,7 +1141,7 @@ namespace ams::kern {
}
/* Push the event. */
debug->PushDebugEvent(event, param0, param1, param2, param3, param4);
debug->PushDebugEvent(event, params, num_params);
debug->NotifyAvailable();
/* Set the process as breaked. */
@@ -1144,9 +1177,9 @@ namespace ams::kern {
R_SUCCEED();
}
Result KDebugBase::OnDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) {
Result KDebugBase::OnDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) {
if (KProcess *process = GetCurrentProcessPointer(); process != nullptr && process->IsAttachedToDebugger()) {
R_RETURN(ProcessDebugEvent(event, param0, param1, param2, param3, param4));
R_RETURN(ProcessDebugEvent(event, params, num_params));
}
R_SUCCEED();
}
@@ -1161,7 +1194,8 @@ namespace ams::kern {
/* Push the event. */
if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) {
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, ams::svc::ProcessExitReason_ExitProcess);
const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::ProcessExitReason_ExitProcess) };
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, params, util::size(params));
debug->NotifyAvailable();
}
}
@@ -1179,7 +1213,8 @@ namespace ams::kern {
/* Push the event. */
if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) {
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, ams::svc::ProcessExitReason_TerminateProcess);
const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::ProcessExitReason_TerminateProcess) };
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, params, util::size(params));
debug->NotifyAvailable();
}
}
@@ -1193,7 +1228,8 @@ namespace ams::kern {
/* Check if we're attached to a debugger. */
if (KProcess *process = thread->GetOwnerProcess(); process != nullptr && process->IsAttachedToDebugger()) {
/* If we are, submit the event. */
R_TRY(OnDebugEvent(ams::svc::DebugEvent_ExitThread, thread->GetId(), thread->IsTerminationRequested() ? ams::svc::ThreadExitReason_TerminateThread : ams::svc::ThreadExitReason_ExitThread));
const uintptr_t params[2] = { thread->GetId(), static_cast<uintptr_t>(thread->IsTerminationRequested() ? ams::svc::ThreadExitReason_TerminateThread : ams::svc::ThreadExitReason_ExitThread) };
R_TRY(OnDebugEvent(ams::svc::DebugEvent_ExitThread, params, util::size(params)));
}
R_SUCCEED();

View File

@@ -47,7 +47,7 @@ namespace ams::kern {
/* Check if the address/size falls within any allowable extents. */
for (const auto &extents : g_io_region_extents) {
if (extents.address <= address && address + size - 1 <= extents.address + extents.size - 1) {
if (extents.size != 0 && extents.address <= address && address + size - 1 <= extents.address + extents.size - 1) {
return true;
}
}
@@ -106,12 +106,23 @@ namespace ams::kern {
KScopedLightLock lk(m_lock);
/* Check that the desired range isn't already in our pool. */
for (const auto &region : m_io_region_list) {
R_UNLESS(!region.Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
{
/* Get the lowest region with address >= the new region that's already in our tree. */
auto lowest_after = m_io_region_tree.nfind_key(new_region->GetAddress());
if (lowest_after != m_io_region_tree.end()) {
R_UNLESS(!lowest_after->Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
}
/* There is no region with address >= the new region already in our tree, but we also need to check */
/* for a region with address < the new region already in our tree. */
if (lowest_after != m_io_region_tree.begin()) {
auto highest_before = --lowest_after;
R_UNLESS(!highest_before->Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
}
}
/* Add the region to our pool. */
m_io_region_list.push_back(*new_region);
m_io_region_tree.insert(*new_region);
R_SUCCEED();
}
@@ -122,8 +133,8 @@ namespace ams::kern {
/* Lock ourselves. */
KScopedLightLock lk(m_lock);
/* Remove the region from our list. */
m_io_region_list.erase(m_io_region_list.iterator_to(*region));
/* Remove the region from our tree. */
m_io_region_tree.erase(m_io_region_tree.iterator_to(*region));
}
}

View File

@@ -85,7 +85,7 @@ namespace ams::kern {
KScopedLightLock lk(m_lock);
/* Unmap ourselves. */
R_TRY(GetCurrentProcess().GetPageTable().UnmapIoRegion(address, m_physical_address, size));
R_TRY(GetCurrentProcess().GetPageTable().UnmapIoRegion(address, m_physical_address, size, m_mapping));
/* Remove ourselves from the current process. */
GetCurrentProcess().RemoveIoRegion(this);

View File

@@ -51,7 +51,7 @@ namespace ams::kern {
/* Sleep the thread. */
{
KScopedSchedulerLockAndSleep lk(&timer, owner, timeout);
KScopedSchedulerLockAndSleep lk(std::addressof(timer), owner, timeout);
if (!allow_terminating_thread && owner->IsTerminationRequested()) {
lk.CancelSleep();

View File

@@ -68,13 +68,13 @@ namespace ams::kern {
KScopedSchedulerLock sl;
/* Get the next owner. */
s32 num_waiters;
KThread *next_owner = owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_tag)));
bool has_waiters;
KThread *next_owner = owner_thread->RemoveWaiterByKey(std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_tag)));
/* Pass the lock to the next owner. */
uintptr_t next_tag = 0;
if (next_owner != nullptr) {
next_tag = reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(num_waiters > 1);
next_tag = reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(has_waiters);
next_owner->EndWait(ResultSuccess());

View File

@@ -74,8 +74,18 @@ namespace ams::kern {
}
void KPageTableBase::MemoryRange::Open() {
/* If the range contains heap pages, open them. */
if (this->IsHeap()) {
Kernel::GetMemoryManager().Open(this->GetAddress(), this->GetSize() / PageSize);
}
}
void KPageTableBase::MemoryRange::Close() {
Kernel::GetMemoryManager().Close(address, size / PageSize);
/* If the range contains heap pages, close them. */
if (this->IsHeap()) {
Kernel::GetMemoryManager().Close(this->GetAddress(), this->GetSize() / PageSize);
}
}
Result KPageTableBase::InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end) {
@@ -1504,16 +1514,13 @@ namespace ams::kern {
/* Check that the memory is contiguous (modulo the reference count bit). */
const u32 test_state_mask = state_mask | KMemoryState_FlagReferenceCounted;
if (R_FAILED(this->CheckMemoryStateContiguous(address, size, test_state_mask, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr))) {
const bool is_heap = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, test_state_mask, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr));
if (!is_heap) {
R_TRY(this->CheckMemoryStateContiguous(address, size, test_state_mask, state, perm_mask, perm, attr_mask, attr));
}
/* The memory is contiguous, so set the output range. */
*out = {
.address = phys_address,
.size = size,
};
out->Set(phys_address, size, is_heap);
R_SUCCEED();
}
@@ -1600,7 +1607,7 @@ namespace ams::kern {
/* Perform mapping operation. */
const KPageProperties properties = { new_perm, false, false, DisableMergeAttribute_None };
const auto operation = was_x ? OperationType_ChangePermissionsAndRefresh : OperationType_ChangePermissions;
const auto operation = was_x ? OperationType_ChangePermissionsAndRefreshAndFlush : OperationType_ChangePermissions;
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, operation, false));
/* Update the blocks. */
@@ -1649,7 +1656,7 @@ namespace ams::kern {
/* Perform operation. */
const KPageProperties properties = { old_perm, false, (new_attr & KMemoryAttribute_Uncached) != 0, DisableMergeAttribute_None };
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissionsAndRefresh, false));
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissionsAndRefreshAndFlush, false));
/* Update the blocks. */
m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, old_perm, new_attr, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None);
@@ -2019,15 +2026,22 @@ namespace ams::kern {
R_SUCCEED();
}
Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size) {
Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping) {
const size_t num_pages = size / PageSize;
/* Lock the table. */
KScopedLightLock lk(m_general_lock);
/* Validate the memory state. */
KMemoryState old_state;
KMemoryPermission old_perm;
KMemoryAttribute old_attr;
size_t num_allocator_blocks;
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Io, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_Locked));
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks),
dst_address, size,
KMemoryState_All, KMemoryState_Io,
KMemoryPermission_None, KMemoryPermission_None,
KMemoryAttribute_All, KMemoryAttribute_Locked));
/* Validate that the region being unmapped corresponds to the physical range described. */
{
@@ -2060,9 +2074,23 @@ namespace ams::kern {
/* We're going to perform an update, so create a helper. */
KScopedPageTableUpdater updater(this);
/* If the region being unmapped is Memory, synchronize. */
if (mapping == ams::svc::MemoryMapping_Memory) {
/* Change the region to be uncached. */
const KPageProperties properties = { old_perm, false, true, DisableMergeAttribute_None };
MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), dst_address, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissionsAndRefresh, false));
/* Temporarily unlock ourselves, so that other operations can occur while we flush the region. */
m_general_lock.Unlock();
ON_SCOPE_EXIT { m_general_lock.Lock(); };
/* Flush the region. */
MESOSPHERE_R_ABORT_UNLESS(cpu::FlushDataCache(GetVoidPointer(dst_address), size));
}
/* Perform the unmap. */
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), dst_address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
/* Update the blocks. */
m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal);
@@ -2911,7 +2939,7 @@ namespace ams::kern {
KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None));
/* We got the range, so open it. */
Kernel::GetMemoryManager().Open(out->address, out->size / PageSize);
out->Open();
R_SUCCEED();
}
@@ -2928,7 +2956,7 @@ namespace ams::kern {
KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared));
/* We got the range, so open it. */
Kernel::GetMemoryManager().Open(out->address, out->size / PageSize);
out->Open();
R_SUCCEED();
}
@@ -2999,7 +3027,7 @@ namespace ams::kern {
KMemoryAttribute_Uncached, KMemoryAttribute_None));
/* We got the range, so open it. */
Kernel::GetMemoryManager().Open(out->address, out->size / PageSize);
out->Open();
R_SUCCEED();
}

View File

@@ -198,7 +198,6 @@ namespace ams::kern {
/* Set misc fields. */
m_state = State_Created;
m_main_thread_stack_size = 0;
m_creation_time = KHardwareTimer::GetTick();
m_used_kernel_memory_size = 0;
m_ideal_core_id = 0;
m_flags = params.flags;
@@ -209,11 +208,16 @@ namespace ams::kern {
m_is_application = (params.flags & ams::svc::CreateProcessFlag_IsApplication);
m_is_jit_debug = false;
#if defined(MESOSPHERE_ENABLE_PROCESS_CREATION_TIME)
m_creation_time = KHardwareTimer::GetTick();
#endif
/* Set thread fields. */
for (size_t i = 0; i < cpu::NumCores; i++) {
m_running_threads[i] = nullptr;
m_pinned_threads[i] = nullptr;
m_running_thread_idle_counts[i] = 0;
m_running_threads[i] = nullptr;
m_pinned_threads[i] = nullptr;
m_running_thread_idle_counts[i] = 0;
m_running_thread_switch_counts[i] = 0;
}
/* Set max memory based on address space type. */
@@ -816,8 +820,8 @@ namespace ams::kern {
m_exception_thread = nullptr;
/* Remove waiter thread. */
s32 num_waiters;
if (KThread *next = thread->RemoveWaiterByKey(std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_exception_thread)) | 1); next != nullptr) {
bool has_waiters;
if (KThread *next = thread->RemoveWaiterByKey(std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_exception_thread)) | 1); next != nullptr) {
next->EndWait(ResultSuccess());
}
@@ -1241,7 +1245,8 @@ namespace ams::kern {
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
if (m_is_jit_debug) {
return KDebugBase::CreateDebugEvent(m_jit_debug_event_type, m_jit_debug_exception_type, m_jit_debug_params[0], m_jit_debug_params[1], m_jit_debug_params[2], m_jit_debug_params[3], m_jit_debug_thread_id);
const uintptr_t params[5] = { m_jit_debug_exception_type, m_jit_debug_params[0], m_jit_debug_params[1], m_jit_debug_params[2], m_jit_debug_params[3] };
return KDebugBase::CreateDebugEvent(m_jit_debug_event_type, m_jit_debug_thread_id, params, util::size(params));
} else {
return nullptr;
}

View File

@@ -88,10 +88,12 @@ namespace ams::kern {
if (m_state.should_count_idle) {
if (AMS_LIKELY(highest_thread != nullptr)) {
if (KProcess *process = highest_thread->GetOwnerProcess(); process != nullptr) {
process->SetRunningThread(m_core_id, highest_thread, m_state.idle_count);
/* Set running thread (and increment switch count). */
process->SetRunningThread(m_core_id, highest_thread, m_state.idle_count, ++m_state.switch_count);
}
} else {
m_state.idle_count++;
/* Set idle count and switch count to switch count + 1. */
m_state.idle_count = ++m_state.switch_count;
}
}
@@ -241,7 +243,7 @@ namespace ams::kern {
if (AMS_LIKELY(!cur_thread->IsTerminationRequested()) && AMS_LIKELY(cur_thread->GetActiveCore() == m_core_id)) {
m_state.prev_thread = cur_thread;
} else {
m_state.prev_thread =nullptr;
m_state.prev_thread = nullptr;
}
}

View File

@@ -20,6 +20,13 @@
namespace ams::kern {
namespace init {
/* TODO: Is this function name architecture specific? */
void StartOtherCore(const ams::kern::init::KInitArguments *init_args);
}
/* Initialization. */
size_t KSystemControlBase::Init::GetRealMemorySize() {
return ams::kern::MainMemorySize;
@@ -68,7 +75,7 @@ namespace ams::kern {
return 0;
}
void KSystemControlBase::Init::CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
void KSystemControlBase::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
#if defined(ATMOSPHERE_ARCH_ARM64)
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<0, false>(core_id, entrypoint, arg)) == 0);
#else
@@ -76,6 +83,22 @@ namespace ams::kern {
#endif
}
void KSystemControlBase::Init::TurnOnCpu(u64 core_id, const ams::kern::init::KInitArguments *args) {
/* Get entrypoint. */
KPhysicalAddress entrypoint = Null<KPhysicalAddress>;
while (!cpu::GetPhysicalAddressReadable(std::addressof(entrypoint), reinterpret_cast<uintptr_t>(::ams::kern::init::StartOtherCore), true)) { /* ... */ }
/* Get arguments. */
KPhysicalAddress args_addr = Null<KPhysicalAddress>;
while (!cpu::GetPhysicalAddressReadable(std::addressof(args_addr), reinterpret_cast<uintptr_t>(args), true)) { /* ... */ }
/* Ensure cache is correct for the initial arguments. */
cpu::StoreDataCacheForInitArguments(args, sizeof(*args));
/* Turn on the cpu. */
KSystemControl::Init::CpuOnImpl(core_id, GetInteger(entrypoint), GetInteger(args_addr));
}
/* Randomness for Initialization. */
void KSystemControlBase::Init::GenerateRandom(u64 *dst, size_t count) {
if (AMS_UNLIKELY(!s_initialized_random_generator)) {
@@ -100,23 +123,15 @@ namespace ams::kern {
}
/* System Initialization. */
void KSystemControlBase::InitializePhase1(bool skip_target_system) {
/* Initialize the rng, if we somehow haven't already. */
if (AMS_UNLIKELY(!s_initialized_random_generator)) {
const u64 seed = KHardwareTimer::GetTick();
s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
s_initialized_random_generator = true;
}
/* Configure KTargetSystem, if we haven't already by an implementation SystemControl. */
if (!skip_target_system) {
void KSystemControlBase::InitializePhase1() {
/* Configure KTargetSystem. */
{
/* Set IsDebugMode. */
{
KTargetSystem::SetIsDebugMode(true);
/* If debug mode, we want to initialize uart logging. */
KTargetSystem::EnableDebugLogging(true);
KDebugLog::Initialize();
}
/* Set Kernel Configuration. */
@@ -135,6 +150,20 @@ namespace ams::kern {
}
}
/* Initialize random and resource limit. */
KSystemControlBase::InitializePhase1Base(KHardwareTimer::GetTick());
}
void KSystemControlBase::InitializePhase1Base(u64 seed) {
/* Initialize the rng, if we somehow haven't already. */
if (AMS_UNLIKELY(!s_initialized_random_generator)) {
s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
s_initialized_random_generator = true;
}
/* Initialize debug logging. */
KDebugLog::Initialize();
/* System ResourceLimit initialization. */
{
/* Construct the resource limit object. */
@@ -144,6 +173,19 @@ namespace ams::kern {
/* Set the initial limits. */
const auto [total_memory_size, kernel_memory_size] = KMemoryLayout::GetTotalAndKernelMemorySizes();
/* Update 39-bit address space infos. */
{
/* Heap should be equal to the total memory size, minimum 8 GB, maximum 32 GB. */
/* Alias should be equal to 8 * heap size, maximum 128 GB. */
const size_t heap_size = std::max(std::min(util::AlignUp(total_memory_size, 1_GB), 32_GB), 8_GB);
const size_t alias_size = std::min(heap_size * 8, 128_GB);
/* Set the address space sizes. */
KAddressSpaceInfo::SetAddressSpaceSize(39, KAddressSpaceInfo::Type_Heap, heap_size);
KAddressSpaceInfo::SetAddressSpaceSize(39, KAddressSpaceInfo::Type_Alias, alias_size);
}
const auto &slab_counts = init::GetSlabResourceCounts();
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax, total_memory_size));
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_ThreadCountMax, slab_counts.num_KThread));

View File

@@ -254,7 +254,7 @@ namespace ams::kern {
m_light_ipc_data = nullptr;
/* We're not waiting for a lock, and we haven't disabled migration. */
m_lock_owner = nullptr;
m_waiting_lock_info = nullptr;
m_num_core_migration_disables = 0;
/* We have no waiters, and no closed objects. */
@@ -397,25 +397,39 @@ namespace ams::kern {
/* Release any waiters. */
{
MESOSPHERE_ASSERT(m_lock_owner == nullptr);
MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr);
KScopedSchedulerLock sl;
auto it = m_waiter_list.begin();
while (it != m_waiter_list.end()) {
/* Get the thread. */
KThread * const waiter = std::addressof(*it);
/* Check that we have no kernel waiters. */
MESOSPHERE_ABORT_UNLESS(m_num_kernel_waiters == 0);
/* The thread shouldn't be a kernel waiter. */
MESOSPHERE_ASSERT(!IsKernelAddressKey(waiter->GetAddressKey()));
auto it = m_held_lock_info_list.begin();
while (it != m_held_lock_info_list.end()) {
/* Get the lock info. */
auto * const lock_info = std::addressof(*it);
/* Clear the lock owner. */
waiter->SetLockOwner(nullptr);
/* The lock shouldn't have a kernel waiter. */
MESOSPHERE_ASSERT(!IsKernelAddressKey(lock_info->GetAddressKey()));
/* Erase the waiter from our list. */
it = m_waiter_list.erase(it);
/* Remove all waiters. */
while (lock_info->GetWaiterCount() != 0) {
/* Get the front waiter. */
KThread * const waiter = lock_info->GetHighestPriorityWaiter();
/* Cancel the thread's wait. */
waiter->CancelWait(svc::ResultInvalidState(), true);
/* Remove it from the lock. */
if (lock_info->RemoveWaiter(waiter)) {
MESOSPHERE_ASSERT(lock_info->GetWaiterCount() == 0);
}
/* Cancel the thread's wait. */
waiter->CancelWait(svc::ResultInvalidState(), true);
}
/* Remove the held lock from our list. */
it = m_held_lock_info_list.erase(it);
/* Free the lock info. */
LockWithPriorityInheritanceInfo::Free(lock_info);
}
}
@@ -823,11 +837,8 @@ namespace ams::kern {
void KThread::IncreaseBasePriority(s32 priority) {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(ams::svc::HighestThreadPriority <= priority && priority <= ams::svc::LowestThreadPriority);
/* Set our unpin base priority, if we're pinned. */
if (this->GetStackParameters().is_pinned && m_base_priority_on_unpin > priority) {
m_base_priority_on_unpin = priority;
}
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
MESOSPHERE_ASSERT(!this->GetStackParameters().is_pinned);
/* Set our base priority. */
if (m_base_priority > priority) {
@@ -1044,28 +1055,58 @@ namespace ams::kern {
R_SUCCEED();
}
void KThread::AddWaiterImpl(KThread *thread) {
void KThread::AddHeldLock(LockWithPriorityInheritanceInfo *lock_info) {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
/* Find the right spot to insert the waiter. */
auto it = m_waiter_list.begin();
while (it != m_waiter_list.end()) {
if (it->GetPriority() > thread->GetPriority()) {
break;
/* Set ourselves as the lock's owner. */
lock_info->SetOwner(this);
/* Add the lock to our held list. */
m_held_lock_info_list.push_front(*lock_info);
}
KThread::LockWithPriorityInheritanceInfo *KThread::FindHeldLock(KProcessAddress address_key) {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
/* Try to find an existing held lock. */
for (auto &held_lock : m_held_lock_info_list) {
if (held_lock.GetAddressKey() == address_key) {
return std::addressof(held_lock);
}
it++;
}
return nullptr;
}
void KThread::AddWaiterImpl(KThread *thread) {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
MESOSPHERE_ASSERT(thread->GetConditionVariableTree() == nullptr);
/* Get the thread's address key. */
const auto address_key = thread->GetAddressKey();
/* Keep track of how many kernel waiters we have. */
if (IsKernelAddressKey(thread->GetAddressKey())) {
if (IsKernelAddressKey(address_key)) {
MESOSPHERE_ABORT_UNLESS((m_num_kernel_waiters++) >= 0);
KScheduler::SetSchedulerUpdateNeeded();
}
/* Insert the waiter. */
m_waiter_list.insert(it, *thread);
thread->SetLockOwner(this);
/* Get the relevant lock info. */
auto *lock_info = this->FindHeldLock(address_key);
if (lock_info == nullptr) {
/* Create a new lock for the address key. */
lock_info = LockWithPriorityInheritanceInfo::Create(address_key);
/* Add the new lock to our list. */
this->AddHeldLock(lock_info);
}
/* Add the thread as waiter to the lock info. */
lock_info->AddWaiter(thread);
}
void KThread::RemoveWaiterImpl(KThread *thread) {
@@ -1078,19 +1119,25 @@ namespace ams::kern {
KScheduler::SetSchedulerUpdateNeeded();
}
/* Get the info for the lock the thread is waiting on. */
auto *lock_info = thread->GetWaitingLockInfo();
MESOSPHERE_ASSERT(lock_info->GetOwner() == this);
/* Remove the waiter. */
m_waiter_list.erase(m_waiter_list.iterator_to(*thread));
thread->SetLockOwner(nullptr);
if (lock_info->RemoveWaiter(thread)) {
m_held_lock_info_list.erase(m_held_lock_info_list.iterator_to(*lock_info));
LockWithPriorityInheritanceInfo::Free(lock_info);
}
}
void KThread::RestorePriority(KThread *thread) {
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
while (true) {
while (thread != nullptr) {
/* We want to inherit priority where possible. */
s32 new_priority = thread->GetBasePriority();
if (thread->HasWaiters()) {
new_priority = std::min(new_priority, thread->m_waiter_list.front().GetPriority());
for (const auto &held_lock : thread->m_held_lock_info_list) {
new_priority = std::min(new_priority, held_lock.GetHighestPriorityWaiter()->GetPriority());
}
/* If the priority we would inherit is not different from ours, don't do anything. */
@@ -1098,6 +1145,14 @@ namespace ams::kern {
return;
}
/* Get the owner of whatever lock this thread is waiting on. */
KThread * const lock_owner = thread->GetLockOwner();
/* If the thread is waiting on some lock, remove it as a waiter to prevent violating red black tree invariants. */
if (lock_owner != nullptr) {
lock_owner->RemoveWaiterImpl(thread);
}
/* Ensure we don't violate condition variable red black tree invariants. */
if (auto *cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) {
BeforeUpdatePriority(cv_tree, thread);
@@ -1112,73 +1167,94 @@ namespace ams::kern {
AfterUpdatePriority(cv_tree, thread);
}
/* If we removed the thread from some lock's waiting list, add it back. */
if (lock_owner != nullptr) {
lock_owner->AddWaiterImpl(thread);
}
/* Update the scheduler. */
KScheduler::OnThreadPriorityChanged(thread, old_priority);
/* Keep the lock owner up to date. */
KThread *lock_owner = thread->GetLockOwner();
if (lock_owner == nullptr) {
return;
}
/* Update the thread in the lock owner's sorted list, and continue inheriting. */
lock_owner->RemoveWaiterImpl(thread);
lock_owner->AddWaiterImpl(thread);
/* Continue inheriting priority. */
thread = lock_owner;
}
}
void KThread::AddWaiter(KThread *thread) {
MESOSPHERE_ASSERT_THIS();
this->AddWaiterImpl(thread);
RestorePriority(this);
/* If the thread has a higher priority than us, we should inherit. */
if (thread->GetPriority() < this->GetPriority()) {
RestorePriority(this);
}
}
void KThread::RemoveWaiter(KThread *thread) {
MESOSPHERE_ASSERT_THIS();
this->RemoveWaiterImpl(thread);
RestorePriority(this);
/* If our priority is the same as the thread's (and we've inherited), we may need to restore to lower priority. */
if (this->GetPriority() == thread->GetPriority() && this->GetPriority() < this->GetBasePriority()) {
RestorePriority(this);
}
}
KThread *KThread::RemoveWaiterByKey(s32 *out_num_waiters, KProcessAddress key) {
KThread *KThread::RemoveWaiterByKey(bool *out_has_waiters, KProcessAddress key) {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
s32 num_waiters = 0;
KThread *next_lock_owner = nullptr;
auto it = m_waiter_list.begin();
while (it != m_waiter_list.end()) {
if (it->GetAddressKey() == key) {
KThread *thread = std::addressof(*it);
/* Get the relevant lock info. */
auto *lock_info = this->FindHeldLock(key);
if (lock_info == nullptr) {
*out_has_waiters = false;
return nullptr;
}
/* Keep track of how many kernel waiters we have. */
if (IsKernelAddressKey(thread->GetAddressKey())) {
MESOSPHERE_ABORT_UNLESS((m_num_kernel_waiters--) > 0);
KScheduler::SetSchedulerUpdateNeeded();
}
it = m_waiter_list.erase(it);
/* Remove the lock info from our held list. */
m_held_lock_info_list.erase(m_held_lock_info_list.iterator_to(*lock_info));
/* Update the next lock owner. */
if (next_lock_owner == nullptr) {
next_lock_owner = thread;
next_lock_owner->SetLockOwner(nullptr);
} else {
next_lock_owner->AddWaiterImpl(thread);
}
num_waiters++;
} else {
it++;
/* Keep track of how many kernel waiters we have. */
if (IsKernelAddressKey(lock_info->GetAddressKey())) {
m_num_kernel_waiters -= lock_info->GetWaiterCount();
MESOSPHERE_ABORT_UNLESS(m_num_kernel_waiters >= 0);
KScheduler::SetSchedulerUpdateNeeded();
}
MESOSPHERE_ASSERT(lock_info->GetWaiterCount() > 0);
/* Remove the highest priority waiter from the lock to be the next owner. */
KThread *next_lock_owner = lock_info->GetHighestPriorityWaiter();
if (lock_info->RemoveWaiter(next_lock_owner)) {
/* The new owner was the only waiter. */
*out_has_waiters = false;
/* Free the lock info, since it has no waiters. */
LockWithPriorityInheritanceInfo::Free(lock_info);
} else {
/* There are additional waiters on the lock. */
*out_has_waiters = true;
/* Add the lock to the new owner's held list. */
next_lock_owner->AddHeldLock(lock_info);
/* Keep track of any kernel waiters for the new owner. */
if (IsKernelAddressKey(lock_info->GetAddressKey())) {
next_lock_owner->m_num_kernel_waiters += lock_info->GetWaiterCount();
MESOSPHERE_ABORT_UNLESS(next_lock_owner->m_num_kernel_waiters > 0);
/* NOTE: No need to set scheduler update needed, because we will have already done so when removing earlier. */
}
}
/* Do priority updates, if we have a next owner. */
if (next_lock_owner) {
/* If our priority is the same as the next owner's (and we've inherited), we may need to restore to lower priority. */
if (this->GetPriority() == next_lock_owner->GetPriority() && this->GetPriority() < this->GetBasePriority()) {
RestorePriority(this);
RestorePriority(next_lock_owner);
/* NOTE: No need to restore priority on the next lock owner, because it was already the highest priority waiter on the lock. */
}
/* Return output. */
*out_num_waiters = num_waiters;
/* Return the next lock owner. */
return next_lock_owner;
}
@@ -1309,9 +1385,7 @@ namespace ams::kern {
}
/* Change the thread's priority to be higher than any system thread's. */
if (this->GetBasePriority() >= ams::svc::SystemThreadPriorityHighest) {
this->SetBasePriority(TerminatingThreadPriority);
}
this->IncreaseBasePriority(TerminatingThreadPriority);
/* If the thread is runnable, send a termination interrupt to other cores. */
if (this->GetState() == ThreadState_Runnable) {

View File

@@ -48,7 +48,7 @@ namespace ams::kern::svc {
/* Check whether the address is aligned. */
const bool aligned = util::IsAligned(phys_addr, PageSize);
auto QueryIoMappingFromPageTable = [&](uint64_t phys_addr, size_t size) ALWAYS_INLINE_LAMBDA -> Result {
auto QueryMappingFromPageTable = [&](uint64_t phys_addr, size_t size) ALWAYS_INLINE_LAMBDA -> Result {
/* The size must be non-zero. */
R_UNLESS(size > 0, svc::ResultInvalidSize());
@@ -56,7 +56,12 @@ namespace ams::kern::svc {
R_UNLESS((phys_addr < phys_addr + size), svc::ResultNotFound());
/* Query the mapping. */
R_TRY(pt.QueryIoMapping(std::addressof(found_address), phys_addr, size));
R_TRY_CATCH(pt.QueryIoMapping(std::addressof(found_address), phys_addr, size)) {
R_CATCH(svc::ResultNotFound) {
/* If we failed to find an io mapping, check if the address is a static mapping. */
R_TRY(pt.QueryStaticMapping(std::addressof(found_address), phys_addr, size));
}
} R_END_TRY_CATCH;
/* Use the size as the found size. */
found_size = size;
@@ -66,12 +71,12 @@ namespace ams::kern::svc {
if (aligned) {
/* Query the input. */
R_TRY(QueryIoMappingFromPageTable(phys_addr, size));
R_TRY(QueryMappingFromPageTable(phys_addr, size));
} else {
if (kern::GetTargetFirmware() < TargetFirmware_8_0_0 && phys_addr >= PageSize) {
/* Query the aligned-down page. */
const size_t offset = phys_addr & (PageSize - 1);
R_TRY(QueryIoMappingFromPageTable(phys_addr - offset, size + offset));
R_TRY(QueryMappingFromPageTable(phys_addr - offset, size + offset));
/* Adjust the output address. */
found_address += offset;

View File

@@ -36,15 +36,15 @@ namespace ams::kern::svc {
size_t remaining = size;
while (remaining > 0) {
/* Get a contiguous range to operate on. */
KPageTableBase::MemoryRange contig_range = { .address = Null<KPhysicalAddress>, .size = 0 };
KPageTableBase::MemoryRange contig_range;
R_TRY(page_table.OpenMemoryRangeForProcessCacheOperation(std::addressof(contig_range), cur_address, aligned_end - cur_address));
/* Close the range when we're done operating on it. */
ON_SCOPE_EXIT { contig_range.Close(); };
/* Adjust to remain within range. */
KVirtualAddress operate_address = KMemoryLayout::GetLinearVirtualAddress(contig_range.address);
size_t operate_size = contig_range.size;
KVirtualAddress operate_address = KMemoryLayout::GetLinearVirtualAddress(contig_range.GetAddress());
size_t operate_size = contig_range.GetSize();
if (cur_address < address) {
operate_address += (address - cur_address);
operate_size -= (address - cur_address);
@@ -57,7 +57,7 @@ namespace ams::kern::svc {
operation.Operate(GetVoidPointer(operate_address), operate_size);
/* Advance. */
cur_address += contig_range.size;
cur_address += contig_range.GetSize();
remaining -= operate_size;
}
MESOSPHERE_ASSERT(remaining == 0);

View File

@@ -297,6 +297,19 @@ namespace ams::kern::svc {
*out = GetCurrentProcess().IsPermittedSvc(static_cast<svc::SvcId>(info_subtype));
}
break;
case ams::svc::InfoType_IoRegionHint:
{
/* Verify the sub-type is valid. */
R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination());
/* Get the io region from its handle. */
KScopedAutoObject io_region = GetCurrentProcess().GetHandleTable().GetObject<KIoRegion>(handle);
R_UNLESS(io_region.IsNotNull(), svc::ResultInvalidHandle());
/* Get the io region's address hint. */
*out = io_region->GetHint();
}
break;
case ams::svc::InfoType_MesosphereMeta:
{
/* Verify the handle is invalid. */

View File

@@ -27,7 +27,7 @@ namespace ams::kern::svc {
R_UNLESS(size < ams::kern::MainMemorySizeMax, svc::ResultInvalidSize());
/* Set the heap size. */
KProcessAddress address;
KProcessAddress address = Null<KProcessAddress>;
R_TRY(GetCurrentProcess().GetPageTable().SetHeapSize(std::addressof(address), size));
/* Set the output. */

View File

@@ -63,6 +63,8 @@ namespace ams::kern::svc {
/* Get the process id. */
*out_process_id = d->GetProcessUnsafe()->GetProcessId();
} else {
R_THROW(svc::ResultInvalidHandle());
}
R_SUCCEED();

View File

@@ -73,6 +73,7 @@
#include <stratosphere/ldr.hpp>
#include <stratosphere/lr.hpp>
#include <stratosphere/lm.hpp>
#include <stratosphere/mitm.hpp>
#include <stratosphere/ncm.hpp>
#include <stratosphere/nim.hpp>
#include <stratosphere/ns.hpp>

View File

@@ -174,6 +174,10 @@
HANDLER(ServiceProfileInfo, 133) \
HANDLER(BluetoothAudioInfo, 134) \
HANDLER(BluetoothPairingCountInfo, 135) \
HANDLER(FsProxyErrorInfo2, 136) \
HANDLER(BuiltInWirelessOUIInfo, 137) \
HANDLER(WirelessAPOUIInfo, 138) \
HANDLER(EthernetAdapterOUIInfo, 139) \
#define AMS_ERPT_FOREACH_FIELD(HANDLER) \
HANDLER(TestU64, 0, Test, FieldType_NumericU64, FieldFlag_None ) \
@@ -840,4 +844,10 @@
HANDLER(FatFsBisUserUniqueDirectoryEntryPeakOpenCount, 661, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(FatFsSdCardUniqueFileEntryPeakOpenCount, 662, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(FatFsSdCardUniqueDirectoryEntryPeakOpenCount, 663, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(ServerErrorIsRetryable, 664, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(FsDeepRetryStartCount, 665, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(FsUnrecoverableByGameCardAccessFailedCount, 666, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(BuiltInWirelessOUI, 667, BuiltInWirelessOUIInfo, FieldType_String, FieldFlag_None ) \
HANDLER(WirelessAPOUI, 668, WirelessAPOUIInfo, FieldType_String, FieldFlag_None ) \
HANDLER(EthernetAdapterOUI, 669, EthernetAdapterOUIInfo, FieldType_String, FieldFlag_None ) \

View File

@@ -21,6 +21,7 @@
namespace ams::erpt::srv {
constexpr inline const char ReportOnSdStoragePath[] = "ersd";
constexpr inline const char ReportOnSdStorageRootDirectoryPath[] = "ersd:/";
constexpr inline const char ReportStoragePath[] = "save";
constexpr inline const char JournalFileName[] = "save:/journal";

View File

@@ -44,6 +44,8 @@ namespace ams::fs {
SystemProperEncryption = 32,
SystemProperPartition = 33,
SignedSystemPartitionOnSafeMode = 34,
DeviceTreeBlob = 35,
System0 = 36,
};
const char *GetBisMountName(BisPartitionId id);

View File

@@ -20,10 +20,10 @@
namespace ams::fs {
/* ACCURATE_TO_VERSION: 13.4.0.0 */
Result MountCode(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id);
/* ACCURATE_TO_VERSION: 16.2.0.0 */
Result MountCode(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id);
Result MountCodeForAtmosphereWithRedirection(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific);
Result MountCodeForAtmosphere(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id);
Result MountCodeForAtmosphereWithRedirection(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, bool is_hbl, bool is_specific);
Result MountCodeForAtmosphere(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id);
}

View File

@@ -28,8 +28,8 @@ namespace ams::fs {
ContentType_Data = 4,
};
Result MountContent(const char *name, const char *path, ContentType content_type);
Result MountContent(const char *name, const char *path, ncm::ProgramId id, ContentType content_type);
Result MountContent(const char *name, const char *path, ncm::DataId id, ContentType content_type);
Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ContentType content_type);
Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId id, ContentType content_type);
Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ncm::DataId id, ContentType content_type);
}

View File

@@ -21,7 +21,8 @@ namespace ams::fs {
/* ACCURATE_TO_VERSION: Unknown */
enum ContentAttributes : u8 {
ContentAttributes_None = 0,
ContentAttributes_None = 0x0,
ContentAttributes_All = 0xF,
};
}

View File

@@ -15,16 +15,10 @@
*/
#pragma once
#include <stratosphere/fs/fs_common.hpp>
#include <stratosphere/fs/fs_content_storage_id.hpp>
namespace ams::fs {
/* ACCURATE_TO_VERSION: Unknown */
enum class ContentStorageId : u32 {
System = 0,
User = 1,
SdCard = 2,
};
constexpr inline const char * const ContentStorageDirectoryName = "Contents";
const char *GetContentStorageMountName(ContentStorageId id);

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::fs {
/* ACCURATE_TO_VERSION: 16.2.0.0 */
enum class ContentStorageId : u32 {
System = 0,
User = 1,
SdCard = 2,
System0 = 3,
};
}

View File

@@ -15,6 +15,7 @@
*/
#pragma once
#include <vapours.hpp>
#include <stratosphere/fs/fs_content_attributes.hpp>
namespace ams::fs {
@@ -41,7 +42,7 @@ namespace ams::fs {
constexpr inline RightsId InvalidRightsId = {};
/* Rights ID API */
Result GetRightsId(RightsId *out, const char *path);
Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path);
Result GetRightsId(RightsId *out, const char *path, fs::ContentAttributes attr);
Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path, fs::ContentAttributes attr);
}

View File

@@ -50,8 +50,9 @@ namespace ams::fssrv {
Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid);
Result OpenDataFileSystemByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out);
Result OpenFileSystemWithPatch(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 type);
Result OpenFileSystemWithId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type);
Result OpenFileSystemWithIdObsolete(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type);
Result OpenDataFileSystemByProgramId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id);
Result OpenFileSystemWithId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u64 program_id, u32 type);
Result OpenBisFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 id);
Result OpenBisStorage(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 id);
Result InvalidateBisCache();
@@ -90,7 +91,8 @@ namespace ams::fssrv {
Result OpenPatchDataStorageByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out);
Result OpenDataFileSystemWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 index);
Result OpenDataStorageWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u8 index);
Result OpenDataStorageByPath(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type);
Result OpenDataStorageByPathObsolete(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type);
Result OpenDataStorageByPath(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u32 type);
Result OpenDeviceOperator(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDeviceOperator>> out);
Result OpenSdCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out);
Result OpenGameCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out);
@@ -103,7 +105,8 @@ namespace ams::fssrv {
Result RegisterExternalKey(const fs::RightsId &rights_id, const spl::AccessKey &access_key);
Result UnregisterAllExternalKey();
Result GetRightsIdByPath(ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path);
Result GetRightsIdAndKeyGenerationByPath(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path);
Result GetRightsIdAndKeyGenerationByPathObsolete(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path);
Result GetRightsIdAndKeyGenerationByPath(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path, fs::ContentAttributes attr);
Result SetCurrentPosixTimeWithTimeDifference(s64 posix_time, s32 time_difference);
Result GetFreeSpaceSizeForSaveData(ams::sf::Out<s64> out, u8 space_id);
Result VerifySaveDataFileSystemBySaveDataSpaceId();
@@ -142,7 +145,8 @@ namespace ams::fssrv {
public:
/* fsp-ldr */
Result OpenCodeFileSystemDeprecated(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id);
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id);
Result OpenCodeFileSystemDeprecated2(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id);
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id);
Result IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id);
};
static_assert(sf::IsIFileSystemProxy<FileSystemProxyImpl>);
@@ -156,11 +160,16 @@ namespace ams::fssrv {
R_THROW(fs::ResultPortAcceptableCountLimited());
}
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id) {
Result OpenCodeFileSystemDeprecated2(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id) {
AMS_UNUSED(out_fs, out_verif, path, program_id);
R_THROW(fs::ResultPortAcceptableCountLimited());
}
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
AMS_UNUSED(out_fs, out_verif, path, attr, program_id);
R_THROW(fs::ResultPortAcceptableCountLimited());
}
Result IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id) {
AMS_UNUSED(out, process_id);
R_THROW(fs::ResultPortAcceptableCountLimited());

View File

@@ -27,8 +27,9 @@
AMS_SF_METHOD_INFO(C, H, 1, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid)) \
AMS_SF_METHOD_INFO(C, H, 2, Result, OpenDataFileSystemByCurrentProcess, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 7, Result, OpenFileSystemWithPatch, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 type), (out, program_id, type), hos::Version_2_0_0) \
AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithId, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type), (out, path, program_id, type), hos::Version_2_0_0) \
AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithIdObsolete, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type), (out, path, program_id, type), hos::Version_2_0_0) \
AMS_SF_METHOD_INFO(C, H, 9, Result, OpenDataFileSystemByProgramId, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id), (out, program_id), hos::Version_3_0_0) \
AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithId, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u64 program_id, u32 type), (out, path, attr, program_id, type), hos::Version_16_0_0) \
AMS_SF_METHOD_INFO(C, H, 11, Result, OpenBisFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 id), (out, path, id)) \
AMS_SF_METHOD_INFO(C, H, 12, Result, OpenBisStorage, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 id), (out, id)) \
AMS_SF_METHOD_INFO(C, H, 13, Result, InvalidateBisCache, (), ()) \
@@ -87,7 +88,8 @@
AMS_SF_METHOD_INFO(C, H, 203, Result, OpenPatchDataStorageByCurrentProcess, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 204, Result, OpenDataFileSystemWithProgramIndex, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 index), (out, index), hos::Version_7_0_0) \
AMS_SF_METHOD_INFO(C, H, 205, Result, OpenDataStorageWithProgramIndex, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u8 index), (out, index), hos::Version_7_0_0) \
AMS_SF_METHOD_INFO(C, H, 206, Result, OpenDataStorageByPath, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type), (out, path, type), hos::Version_13_0_0) \
AMS_SF_METHOD_INFO(C, H, 206, Result, OpenDataStorageByPathObsolete, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type), (out, path, type), hos::Version_13_0_0, hos::Version_15_0_1) \
AMS_SF_METHOD_INFO(C, H, 206, Result, OpenDataStorageByPath, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u32 type), (out, path, attr, type), hos::Version_16_0_0) \
AMS_SF_METHOD_INFO(C, H, 400, Result, OpenDeviceOperator, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDeviceOperator>> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 500, Result, OpenSdCardDetectionEventNotifier, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 501, Result, OpenGameCardDetectionEventNotifier, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out), (out)) \
@@ -103,8 +105,9 @@
AMS_SF_METHOD_INFO(C, H, 606, Result, GetRightsId, (ams::sf::Out<fs::RightsId> out, ncm::ProgramId program_id, ncm::StorageId storage_id), (out, program_id, storage_id), hos::Version_2_0_0) \
AMS_SF_METHOD_INFO(C, H, 607, Result, RegisterExternalKey, (const fs::RightsId &rights_id, const spl::AccessKey &access_key), (rights_id, access_key), hos::Version_2_0_0) \
AMS_SF_METHOD_INFO(C, H, 608, Result, UnregisterAllExternalKey, (), (), hos::Version_2_0_0) \
AMS_SF_METHOD_INFO(C, H, 609, Result, GetRightsIdByPath, (ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path), (out, path), hos::Version_2_0_0) \
AMS_SF_METHOD_INFO(C, H, 610, Result, GetRightsIdAndKeyGenerationByPath, (ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path), (out, out_key_generation, path), hos::Version_3_0_0) \
AMS_SF_METHOD_INFO(C, H, 609, Result, GetRightsIdByPath, (ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path), (out, path), hos::Version_2_0_0, hos::Version_15_0_1) \
AMS_SF_METHOD_INFO(C, H, 610, Result, GetRightsIdAndKeyGenerationByPathObsolete, (ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path), (out, out_key_generation, path), hos::Version_3_0_0) \
AMS_SF_METHOD_INFO(C, H, 610, Result, GetRightsIdAndKeyGenerationByPath, (ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path, fs::ContentAttributes attr), (out, out_key_generation, path, attr), hos::Version_16_0_0) \
AMS_SF_METHOD_INFO(C, H, 611, Result, SetCurrentPosixTimeWithTimeDifference, (s64 posix_time, s32 time_difference), (posix_time, time_difference), hos::Version_4_0_0) \
AMS_SF_METHOD_INFO(C, H, 612, Result, GetFreeSpaceSizeForSaveData, (ams::sf::Out<s64> out, u8 space_id), (out, space_id), hos::Version_4_0_0) \
AMS_SF_METHOD_INFO(C, H, 613, Result, VerifySaveDataFileSystemBySaveDataSpaceId, (), (), hos::Version_4_0_0) \

View File

@@ -18,12 +18,14 @@
#include <stratosphere/sf.hpp>
#include <stratosphere/fssrv/sf/fssrv_sf_ifilesystem.hpp>
#include <stratosphere/fs/fs_code_verification_data.hpp>
#include <stratosphere/fs/fs_content_attributes.hpp>
/* ACCURATE_TO_VERSION: 13.4.0.0 */
#define AMS_FSSRV_I_FILE_SYSTEM_PROXY_FOR_LOADER_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, path, program_id), hos::Version_Min, hos::Version_9_2_0) \
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, out_verif, path, program_id), hos::Version_10_0_0) \
AMS_SF_METHOD_INFO(C, H, 1, Result, IsArchivedProgram, (ams::sf::Out<bool> out, u64 process_id), (out, process_id)) \
AMS_SF_METHOD_INFO(C, H, 2, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid), hos::Version_4_0_0)
#define AMS_FSSRV_I_FILE_SYSTEM_PROXY_FOR_LOADER_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, path, program_id), hos::Version_Min, hos::Version_9_2_0) \
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated2, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, out_verif, path, program_id), hos::Version_10_0_0, hos::Version_15_0_1) \
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id), (out_fs, out_verif, path, attr, program_id), hos::Version_16_0_0) \
AMS_SF_METHOD_INFO(C, H, 1, Result, IsArchivedProgram, (ams::sf::Out<bool> out, u64 process_id), (out, process_id)) \
AMS_SF_METHOD_INFO(C, H, 2, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid), hos::Version_4_0_0)
AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IFileSystemProxyForLoader, AMS_FSSRV_I_FILE_SYSTEM_PROXY_FOR_LOADER_INTERFACE_INFO, 0xDC92EE15)

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