Compare commits

..

227 Commits

Author SHA1 Message Date
Michael Scire
691a453d77 docs: amend changelog 2021-05-12 09:11:19 -07:00
Michael Scire
88246f475c git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "9ac6f527"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "9ac6f527"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2021-05-12 09:10:13 -07:00
Michael Scire
269d4496b2 docs: update changelog for 0.19.3 2021-05-12 09:08:55 -07:00
Michael Scire
bb4c7a390b ams: update for 12.0.2 2021-05-12 09:08:47 -07:00
Dark-Mind
b846628362 Update issue template to ask whether sysmmc or emummc. 2021-05-12 08:27:21 -07:00
Michael Scire
26fb201518 dns.mitm: handle nullptr hostname 2021-05-10 13:27:14 -07:00
Michael Scire
01ce7cef14 exo: revert section sorting 2021-05-10 07:59:38 -07:00
Michael Scire
3f3aaa01fa git subrepo clone --force https://github.com/m4xw/emummc
subrepo:
  subdir:   "emummc"
  merged:   "c6717b93"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "c6717b93"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2021-05-10 07:50:39 -07:00
Michael Scire
bf8de39e69 ams: move around abort handler to avoid linker errors 2021-05-07 17:49:10 -07:00
Michael Scire
6bb4253df5 emummc: style-change 2021-05-05 09:34:29 -07:00
Michael Scire
cfd7121574 emummc: advance buffer for multi-file case 2021-05-05 08:44:53 -07:00
Michael Scire
972681c57e emummc: fix file-based accesses that cross file boundaries 2021-05-05 08:37:02 -07:00
Michael Scire
0a11cbc2d6 exo: sort sections by alignment 2021-05-02 10:50:18 -07:00
Michael Scire
32f487abfb sm: update to excise unnecessary library code 2021-05-02 10:33:15 -07:00
Michael Scire
7d61cab01c fs: add access log strings for DirectoryEntryType 2021-04-30 19:19:22 -07:00
Michael Scire
14ed4e4057 erpt: fix reading files that don't exist 2021-04-30 14:44:53 -07:00
Michael Scire
e8ba632606 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "acee57e8"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "acee57e8"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2021-04-30 10:04:30 -07:00
Michael Scire
dbcb1e1564 loader: avoid UB when doing count trailing zeros 2021-04-30 10:03:54 -07:00
Michael Scire
15381409dc fs: fix missed operation rename 2021-04-30 09:02:58 -07:00
Michael Scire
10ad6934ac git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "1c5df037"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "1c5df037"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2021-04-30 08:56:36 -07:00
Michael Scire
03e66efd85 docs: add changelog for 0.19.2 2021-04-30 08:56:03 -07:00
Michael Scire
7040e8976d i2c: add aula pmic device code 2021-04-30 08:42:25 -07:00
Michael Scire
296a6af058 boot: update all autogenerated parameters other than charge 2021-04-30 08:37:51 -07:00
Michael Scire
2c332d1cf8 ams: bump api version to 0.19.2 2021-04-30 05:00:25 -07:00
Michael Scire
243d7dc777 ams: write-protect stratosphere.romfs 2021-04-30 04:57:46 -07:00
Michael Scire
355010ad84 erpt: implement forced shutdown detection 2021-04-30 04:21:03 -07:00
Michael Scire
ef0c15b764 erpt: Implement 12.0.0 AppletTotalActiveTime tracking 2021-04-29 21:48:47 -07:00
Michael Scire
0dc308d92a fs: properly implement OperateRangeWithBuffer, correct OperationId names. 2021-04-29 20:09:45 -07:00
Michael Scire
eb5542963f git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "4a48e0ee"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "4a48e0ee"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2021-04-29 03:05:29 -07:00
Michael Scire
18673d96cb daybreak: fix compat with newer deko3d 2021-04-29 01:21:09 -07:00
Michael Scire
36f6bdc3a0 fusee/sept: update to suppress spurious gcc warnings 2021-04-29 01:13:48 -07:00
Michael Scire
d6fff49845 exo: remove duplicate flags 2021-04-29 01:07:01 -07:00
Michael Scire
d05e8fb23a exo: fix for newer binutils 2021-04-29 01:04:26 -07:00
Michael Scire
0767d9f8da ams: assume gcc 11 2021-04-28 15:13:29 -07:00
Michael Scire
21f3d29df7 strat: compat with gcc 11 2021-04-26 20:06:28 -07:00
Michael Scire
4f16106702 exo/meso: update for gcc 11 compatibility 2021-04-26 20:06:18 -07:00
Michael Scire
19be54ff95 kern: fix initial process binary load on 2.0.0-4.1.0 (closes #1460) 2021-04-21 19:24:41 -07:00
Michael Scire
ed80d6ec8c util: add compile-time validation tests for intrusive red black trees 2021-04-21 05:06:11 -07:00
Michael Scire
57b6c71c1c util: implement red black trees as templates over macros 2021-04-20 16:56:33 -07:00
Michael Scire
0a11d341b7 kern: fix constant evaluation correctness, codegen tweak 2021-04-20 14:25:06 -07:00
Michael Scire
8010290472 kern: tweak KHandleTable codegen 2021-04-19 18:04:02 -07:00
Michael Scire
fbc526d163 kern: tweak KAutoObject::Open/Close codegen 2021-04-19 18:03:27 -07:00
Michael Scire
5bb790e4a7 erpt: implement AppletActiveTimeInfoList 2021-04-16 00:55:22 -07:00
Michael Scire
0a6219e6e0 kern: add names/links to kern_assembly_offsets.h 2021-04-15 15:43:29 -07:00
Michael Scire
037b04ac60 kern: mostly kill magic numbers in assembly, fix SVCs >= 0x80 2021-04-14 18:01:08 -07:00
Michael Scire
9e563d590b pm: account for 12.0.0 resource limit changes 2021-04-14 00:41:31 -07:00
Michael Scire
bdcf02a3ef tipc: ports use objects in the object manager 2021-04-14 00:34:46 -07:00
Michael Scire
88ac85c423 sm: save 0x1000 in data costs by not aligning server manager to 0x1000 2021-04-14 00:12:21 -07:00
Michael Scire
2e1a93f1d1 strat: no longer materially constrained by sm session limit 2021-04-13 23:58:10 -07:00
Michael Scire
997e4dd665 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "86c2eec8"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "86c2eec8"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2021-04-12 17:14:38 -07:00
Michael Scire
aa2d03d8e1 ams: bump to 0.19.1 2021-04-12 17:14:07 -07:00
Michael Scire
274c1deae4 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "68ddbc73"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "68ddbc73"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2021-04-12 17:13:43 -07:00
Michael Scire
d5bbf32a26 docs: add 0.19.1 changelog 2021-04-12 17:13:12 -07:00
Michael Scire
97a251b4b2 ncm: fix iteration of nested-subdirectory content files 2021-04-12 17:10:27 -07:00
Michael Scire
9d30917f4e boot2: migration also not launched in 12.0.0 2021-04-11 10:37:04 -07:00
Michael Scire
c67c29ebd5 ncm: fix random error when deleting content 2021-04-11 05:44:13 -07:00
Michael Scire
88dd414721 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "44279dbac"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "44279dbac"
git-subrepo:
  version:  "0.4.1"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "a04d8c2"
2021-04-11 04:02:17 -07:00
Michael Scire
0f6f13a1ac git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "b355ee6a8"
upstream:
  origin:   "https://github.com/m4xw/emuMMC"
  branch:   "develop"
  commit:   "b355ee6a8"
git-subrepo:
  version:  "0.4.1"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "a04d8c2"
2021-04-11 03:58:13 -07:00
Michael Scire
b24784f5c1 git subrepo pull emummc
subrepo:
  subdir:   "emummc"
  merged:   "38ed90b6e"
upstream:
  origin:   "https://github.com/m4xw/emuMMC"
  branch:   "develop"
  commit:   "5a29e1b2c"
git-subrepo:
  version:  "0.4.1"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "a04d8c2"
2021-04-11 03:51:53 -07:00
Michael Scire
3b3082cf58 changelog: add note about extensions needing recompile 2021-04-11 03:42:16 -07:00
Michael Scire
38a2fdcd76 docs: add changelog for 0.19.0 2021-04-11 03:42:16 -07:00
Michael Scire
0ca2f962de usb: add usb3.0 patches for 12.0.0 2021-04-11 03:42:16 -07:00
Michael Scire
03a98635d8 fs: add (stubbed) OperateRangeWithBuffer implementation 2021-04-11 03:42:16 -07:00
Michael Scire
461e2ced6f erpt: add (stubbed, TODO after 0.19.0) support for 12.0.0 2021-04-11 03:42:16 -07:00
Michael Scire
b2d2f65b87 boot2: grc is no longer launched by boot2 on 12.0.0+ 2021-04-11 03:42:16 -07:00
Michael Scire
b2b0c50802 pgl: update to use tipc (untested) 2021-04-11 03:42:16 -07:00
Michael Scire
1118421fa6 strat: changes for sm tipc (boots 11.0.1, now) 2021-04-11 03:42:16 -07:00
Michael Scire
b1b3914ccf tipc: Result is first raw data word, not last 2021-04-11 03:42:16 -07:00
Michael Scire
9be8b32311 tipc/sm: various fixes for issues 2021-04-11 03:42:16 -07:00
Michael Scire
57c8bc432d sm: reimplement using tipc instead of cmif (probably broken, untested) 2021-04-11 03:42:16 -07:00
Michael Scire
58776f5ba8 tipc: server processor fixes (compiles!) 2021-04-11 03:42:16 -07:00
Michael Scire
affeeb2724 tipc: implement ServerManager processing logic 2021-04-11 03:42:16 -07:00
Michael Scire
822875ecf5 tipc: implement framework/server support logic (except for actual processing) 2021-04-11 03:42:16 -07:00
Michael Scire
e3a65b1405 tipc: fix deserialization of buffers 2021-04-11 03:42:16 -07:00
Michael Scire
20a7fa1588 tipc: hard-enforce boolean constraints in command processing generation 2021-04-11 03:42:16 -07:00
Michael Scire
315b7bdf22 tipc: implement service object interface generation 2021-04-11 03:42:16 -07:00
Michael Scire
ec988c5a99 tipc: first draft object allocation logic 2021-04-11 03:42:16 -07:00
Michael Scire
21b883a75c tipc: fix compilation issues with core serialization routines 2021-04-11 03:42:16 -07:00
Michael Scire
e93d71d932 tipc: tentative core serialization logic (missing imports, won't compile) 2021-04-11 03:42:16 -07:00
Michael Scire
dc6a0d7562 ams: add target firmware 12.0.0, fusee recognition 2021-04-11 03:42:16 -07:00
Michael Scire
1d2be0a2eb kern: mesosphere now implements kernel/sdk 12.3 2021-04-11 03:42:16 -07:00
Michael Scire
96937a611d kern: fuck the KPolice^H^H^H^H^H^HPageGroups 2021-04-11 03:42:16 -07:00
Michael Scire
dc7862882f kern: who needs __purecall? 2021-04-11 03:42:16 -07:00
Michael Scire
6faa3534bf kern: update pinning semantics for terminating threads 2021-04-11 03:42:16 -07:00
Michael Scire
afb1d68d06 kern: ensure handle table is finalized when deferring termination 2021-04-11 03:42:16 -07:00
Michael Scire
911e431d65 kern: simplify handle table registration for port/session 2021-04-11 03:42:16 -07:00
Michael Scire
ee91063bbb kern: update kdebug process management semantics 2021-04-11 03:42:16 -07:00
Michael Scire
cbdf33260e kern: update port/session state semantics 2021-04-11 03:42:16 -07:00
Michael Scire
c62a7381f8 kern: update KLightConditionVariable 2021-04-11 03:42:16 -07:00
Michael Scire
b4498734e4 kern: optimize KHandleTable to use indices instead of pointers 2021-04-11 03:42:16 -07:00
Michael Scire
4407237f5b kern: KAutoObject destruction is now scheduled for next dpc-time 2021-04-11 03:42:16 -07:00
Michael Scire
15956fcf9a kern: update for new slab resource counts/extents 2021-04-11 03:42:16 -07:00
Michael Scire
6a368d3d1a kern: reallocate pool distributions for 8GB units 2021-04-11 03:42:16 -07:00
Michael Scire
8e4be9aef9 kern: simplify global rng initialization 2021-04-11 03:42:16 -07:00
Michael Scire
0f8b7be2d2 kern: load initial process binary from user pool, rather than from pt heap 2021-04-11 03:42:16 -07:00
Michael Scire
a1e137cc1c kern: update Initialize0 for new changes 2021-04-11 03:42:16 -07:00
Michael Scire
504472af4e kern: update KConditionVariable::WaitForAddress/Wait 2021-04-11 03:42:16 -07:00
Michael Scire
19b253fd17 kern: trivially optimize userspace io memory write 2021-04-11 03:42:16 -07:00
Michael Scire
01f5c89902 kern: add bounds checking to KHandleTable::Register/Unreserve 2021-04-11 03:42:16 -07:00
Michael Scire
44ccbc2a7b kern: update set/way cache operations for new semantics 2021-04-11 03:42:16 -07:00
Michael Scire
6e4664ee05 kern: if a page table region is zero-size, nothing overlaps it 2021-04-11 03:42:16 -07:00
Michael Scire
85f9355184 kern: use KScopedLightLockPair helper for page table pair-locks 2021-04-11 03:42:16 -07:00
Michael Scire
60b5bd73b7 kern: track mapped ipc server memory in page table 2021-04-11 03:42:16 -07:00
Michael Scire
53e7aa0a20 kern: add KPageTableBase::Read/WriteDebugIoMemory 2021-04-11 03:42:16 -07:00
Michael Scire
561a16a348 kern: flush memory before reading in KPageTableBase::ReadDebugMemory 2021-04-11 03:42:16 -07:00
Michael Scire
1fce7b08b1 kern: update KMemoryBlockManagerUpdaterAllocator for new ctor/init semantics 2021-04-11 03:42:16 -07:00
Michael Scire
c216f92a91 kern: swap tpidr_el1/cntv_cval_el0 as scratch vs exception stack 2021-04-11 03:42:16 -07:00
Michael Scire
2f930c2d5f kern: support immortal processes 2021-04-11 03:42:16 -07:00
Michael Scire
256eb92f4c kern: update process/thread for new running/termination semantics 2021-04-11 03:42:16 -07:00
Michael Scire
ec1d9c4c49 kern: unconditionally set thread state when appropriate 2021-04-11 03:42:16 -07:00
Michael Scire
3356eddcba kern: update kernel waiter management rules 2021-04-11 03:42:16 -07:00
Michael Scire
f67d1b7026 kern: update KInterruptEvent to store core id 2021-04-11 03:42:16 -07:00
Michael Scire
e64fef109c kern: update pinned thread priority rules 2021-04-11 03:42:16 -07:00
Michael Scire
1b2cf173b3 kern: add new checks to SetThreadPriority/CoreMask 2021-04-11 03:42:16 -07:00
Michael Scire
2fb258ca7e kern: update KInitialPageTable/KInitialPageAllocator 2021-04-11 03:42:16 -07:00
Michael Scire
962cf97150 kern: KLinkedList no longer exists 2021-04-11 03:42:16 -07:00
Michael Scire
b3bd443636 svc: sanitize booleans in autogenerated abi stubs 2021-04-11 03:42:16 -07:00
Michael Scire
4b9e7c7d27 kern: bump svc limit to 192 from 128 2021-04-11 03:42:16 -07:00
hexkyz
46612156f4 exo: add new dram ID 2021-04-11 03:42:16 -07:00
Michael Scire
279bb863df fusee: add support for 12.0.0 kernel 2021-04-11 03:42:16 -07:00
Michael Scire
252ea97ca5 nogc: add patches for 12.0.0 2021-04-11 03:42:16 -07:00
Michael Scire
f89cfe41da emummc: update for 12.0.0 2021-04-11 03:42:16 -07:00
Easy World
e3e3679cfe Update dmnt_cheat_vm.cpp
* fix case fallthrough in function "LogOpcode"
* use same attribute name in one opcode case
2021-04-07 18:46:23 -07:00
Michael Scire
75a2052144 ncm: fix GameCardStorageRoot mount point (closes #1404) 2021-03-24 07:17:03 -07:00
Adubbz
5666c59657 ncm: Updated ListContentId for 11.0.0 2021-03-22 14:58:28 -07:00
Michael Scire
c99ce36d7d ams: convert to util::ConstructAt where appropriate 2021-03-21 20:36:49 -07:00
Michael Scire
d84dcb653d ams: prefer construct_at/destroy_at over placement new/explicit destructor 2021-03-21 20:30:40 -07:00
Michael Scire
aff0da9427 ams: remove TYPED_STORAGE() macro in favor of template 2021-03-21 18:47:30 -07:00
Michael Scire
8d9174b227 ams: bump version to 0.19.0.
Release (probably) not actually imminent, I just don't want to forget.
2021-03-21 13:16:49 -07:00
Michael Scire
c8404e8452 boot2: clean up pre-0.19.0 ams contents on upgrade 2021-03-21 13:16:30 -07:00
Michael Scire
79e4c82d7e ams: distribute sysmodules in single file as stratosphere.romfs 2021-03-21 13:16:30 -07:00
Adubbz
3afd9a737c daybreak: Added a warning when resetting to factory settings 2021-03-18 21:08:22 -07:00
Michael Scire
a7564cf303 kern: add extension InfoType for retrieving current process handle. 2021-03-17 17:48:30 -07:00
SciresM
5362ee9450 [tma2] [Ongoing] Continue implementing modules for tma2. (#1388)
* cs: add stub sysmodule to host command shell server

* cs: implement logic for main (linker error paradise, for now)

* cs: implement more of the system module's skeleton

* htcs: update client type names for libnx pr merge
2021-03-16 17:13:30 -07:00
Michael Scire
021d4c88fa kern: use fix usage of incorrect page table for UserBuffer ipc 2021-03-13 15:14:36 -08:00
Michael Scire
deb4aece9a kern: fix inverted conditional in KDebugBase::SetThreadContext 2021-03-11 12:53:43 -08:00
SciresM
a6729171d3 set.mitm: fake compatibility for usb!usb30_force_enabled on 9.0.0+ (#1391)
* set.mitm: fake compatibility for usb!usb30_force_enabled on 9.0.0+

* set.mitm: add value meaning comment for usb!usb30_force_enabled

* loader: pretend to be polite about patch ordering
2021-03-01 14:18:27 -08:00
Michael Scire
c9015581ca boot2: fix tma launch when htc is disabled 2021-02-26 08:08:05 -08:00
Michael Scire
35c816d62f htclow: fix ordering of channels, uninitialized bug in service json parse 2021-02-26 04:49:20 -08:00
Michael Scire
18031ae107 tio: fix wrong body size on optimized ListDirectory 2021-02-26 04:49:20 -08:00
Michael Scire
c7e4f963e8 fs: fix GetFileTimeStampRawForDebug 2021-02-26 04:49:20 -08:00
Michael Scire
97875c7d2f tio: fix bug in body receive 2021-02-26 04:49:20 -08:00
Michael Scire
0da3b2b273 tio: implement SdCardObserver (finishes sysmodule) 2021-02-26 04:49:20 -08:00
Michael Scire
3cbd99a709 tio: implement all command processor logic 2021-02-26 04:49:20 -08:00
Michael Scire
6ce2076d92 tio: implement server/dispatch logic. 2021-02-26 04:49:20 -08:00
Michael Scire
cee1ecd06f tio: add stub sysmodule to host target io server 2021-02-26 04:49:20 -08:00
Michael Scire
a739e3fb20 docs: remove deprecated hid mitm from settings template 2021-02-24 04:08:15 -08:00
Michael Scire
953246a175 htc: disable socket driver, needs design thought before we can turn it on for real. 2021-02-24 04:06:54 -08:00
Michael Scire
d8faa37de0 socket: fix config size calculations 2021-02-24 04:06:54 -08:00
Michael Scire
64c7c6b2a5 ams: implement socket api for htclow socket driver 2021-02-24 04:06:54 -08:00
Michael Scire
1c974a387c htc: implement socket driver (socket api not really impl'd yet) 2021-02-24 04:06:54 -08:00
Michael Scire
b5ab491603 htc: implement htcmisc service object commands 2021-02-24 04:06:54 -08:00
Michael Scire
8b32b9eadf kern: Increase reserved system memory, require mesosphere for htc/tma 2021-02-24 04:06:54 -08:00
Michael Scire
ce149f996c htc: configure usage via system setting 2021-02-24 04:06:54 -08:00
Michael Scire
0ec54ed492 htcs: fixes, echo server is now fully functional 2021-02-24 04:06:54 -08:00
Michael Scire
72de4d85f3 htcs: implement remaining client bindings 2021-02-24 04:06:54 -08:00
Michael Scire
d0673aa2fb htcs: implement client socket bindings 2021-02-24 04:06:54 -08:00
Michael Scire
f7fcb54622 htcs: implement virtual socket collection 2021-02-24 04:06:54 -08:00
Michael Scire
ec643789ab htcs: implement data channel manager 2021-02-24 04:06:54 -08:00
Michael Scire
70caadafd5 htcs: implement rpc tasks 2021-02-24 04:06:54 -08:00
Michael Scire
7667104961 htcs: hook up HtcsService to rpc client 2021-02-24 04:06:54 -08:00
Michael Scire
0c791f2279 htcs: fix magic template argument deduction, do Close/Connect/Bind 2021-02-24 04:06:54 -08:00
Michael Scire
f71943c03a htcs: declare all rpc tasks 2021-02-24 04:06:54 -08:00
Michael Scire
536e3e99a8 htcs: hook up CreateSocket/RpcClient Begin<>/End<> 2021-02-24 04:06:54 -08:00
Michael Scire
abff428212 htcs: hook up manager impl to (unimplemented) service 2021-02-24 04:06:54 -08:00
Michael Scire
1541985222 htcs: hook manager up to (unimplemented) manager impl 2021-02-24 04:06:54 -08:00
Michael Scire
61929d6e21 htcs: hook service objects up to (unimplemented) manager apis 2021-02-24 04:06:54 -08:00
Michael Scire
f0ef9fb918 htc: fixes for WriteFileLarge/sending over data channel 2021-02-24 04:06:54 -08:00
Michael Scire
7621bd4e13 htcfs: fix CreateFile packet header 2021-02-24 04:06:54 -08:00
Michael Scire
d20bceff75 htc: implement the remaining commands for htcfs 2021-02-24 04:06:54 -08:00
Michael Scire
1961cb1034 htc: ReadDirectoryLarge/data channel support 2021-02-24 04:06:54 -08:00
Michael Scire
9daec3a66a htc: Implement (almost) all host-directory commands 2021-02-24 04:06:54 -08:00
Michael Scire
e79417c37c htcfs: implement OpenDirectory/CloseDirectory 2021-02-24 04:06:54 -08:00
Michael Scire
b371487525 sf: optimize argument parsing for const LargeData & 2021-02-24 04:06:54 -08:00
Michael Scire
5c97469348 htc: implement htcfs protocol bringup 2021-02-24 04:06:54 -08:00
Michael Scire
99a38dce32 htc: fix event wait loops for rpc clients 2021-02-24 04:06:54 -08:00
Michael Scire
f28a410ba0 htc: fixes, can now enter ReadyState with wip starlink code 2021-02-24 04:06:54 -08:00
Michael Scire
5fc1981061 htc: fix htcfs sf definition 2021-02-24 04:06:54 -08:00
Michael Scire
1bd0094bee htc: finish last code for Main() 2021-02-24 04:06:54 -08:00
Michael Scire
870b45f208 htc: add htcfs server/service object skeletons 2021-02-24 04:06:54 -08:00
Michael Scire
9fbbb9fadb htclow: add Channel wrapper class 2021-02-24 04:06:54 -08:00
Michael Scire
dec06ff649 htc: add htcfs service api definitions 2021-02-24 04:06:54 -08:00
Michael Scire
b898241112 htcs: add hipc server/service object skeletons 2021-02-24 04:06:54 -08:00
Michael Scire
10255f7f51 htc: skeleton HtcsManagerImpl, implement HtcsMonitor 2021-02-24 04:06:54 -08:00
Michael Scire
cb5a706659 htcs: add sf interface info/types 2021-02-24 04:06:54 -08:00
Michael Scire
4d86863f2c htc: ObserverThread (mostly), system now boots + works with htc in bg 2021-02-24 04:06:54 -08:00
Michael Scire
79a3f442d6 htc: implement psc/pm loop 2021-02-24 04:06:54 -08:00
Michael Scire
7485a1968a htc: implement HtcmiscImpl::ServerThread/HtcmiscRpcServer::ReceiveThread 2021-02-24 04:06:54 -08:00
Michael Scire
3be005b638 htc: Implement RpcClient::ReceiveThread + SendThread 2021-02-24 04:06:54 -08:00
Michael Scire
d60b1abed0 htc: Implement HtcmiscImpl::ClientThread 2021-02-24 04:06:54 -08:00
Michael Scire
1867c31f63 htc: add RpcTaskQueue/RpcTaskIdFreeList 2021-02-24 04:06:54 -08:00
Michael Scire
82757cd1b4 htc: nullptr != false 2021-02-24 04:06:54 -08:00
Michael Scire
f5e98de1a3 htc: add RpcTaskTable 2021-02-24 04:06:54 -08:00
Michael Scire
0880cebc4d htc: implement htcmisc rpc tasks 2021-02-24 04:06:54 -08:00
Michael Scire
1f03b11dbc htc: skeleton constructors for htcmisc 2021-02-24 04:06:54 -08:00
Michael Scire
b925344c3b htc: implement remainder of Mux/Tasks 2021-02-24 04:06:54 -08:00
Michael Scire
42cf3f50d7 htc: implement mux side of connecting (and more) 2021-02-24 04:06:54 -08:00
Michael Scire
70aae4e27a htc: fix driver manager c/p error 2021-02-24 04:06:54 -08:00
Michael Scire
87165e0f08 htc: implement remaining htclow::HtclowManagerImpl funcs (mux impls pending) 2021-02-24 04:06:54 -08:00
Michael Scire
e20c2450ce htc: declare and begin impl of HtclowManagerImpl interface 2021-02-24 04:06:54 -08:00
Michael Scire
968ce12492 htc: optimize Mux::QuerySendPacket 2021-02-24 04:06:54 -08:00
Michael Scire
00ab210e66 mux: optimize many accesses to O(log(n)) vs Nintendo's O(log(n)^2) 2021-02-24 04:06:54 -08:00
Michael Scire
4cb6c63516 htc: implement HtclowDriver 2021-02-24 04:06:54 -08:00
Michael Scire
1963ae7ec0 htc: begin skeletoning types for HtcmiscImpl 2021-02-24 04:06:54 -08:00
Michael Scire
889f144b27 htc: hook up creation of the htc manager service object 2021-02-24 04:06:54 -08:00
Michael Scire
4408ad6a47 htc: module id names, skeleton rest of main 2021-02-24 04:06:54 -08:00
Michael Scire
4ed665bcd3 htc: implement remaining worker thread send logic (for channel mux) 2021-02-24 04:06:54 -08:00
Michael Scire
df3d62df84 htc: send logic for HtcctrlService, bugfixes (thanks @misson20000) 2021-02-24 04:06:54 -08:00
Michael Scire
0977ee72ca rapidjson: add customization point for allocation/asserts 2021-02-24 04:06:54 -08:00
Michael Scire
2cdfde6637 htc: add remaining worker receive thread logic 2021-02-24 04:06:54 -08:00
Michael Scire
6fc24d8883 htc: implement service channel parsing (ReceiveReadyPacket) 2021-02-24 04:06:54 -08:00
Michael Scire
4e9bc617bb rapidjson: import -master as ams::rapidjson 2021-02-24 04:06:54 -08:00
Michael Scire
679fec2ddc htc: implement much of worker receive logic 2021-02-24 04:06:54 -08:00
Michael Scire
8f85cc17dc htc: fix copy/paste error in usb driver 2021-02-24 04:06:54 -08:00
Michael Scire
e40eece74e htc: free ourselves from the tyranny of numerical enums 2021-02-24 04:06:54 -08:00
Michael Scire
2341f18edd htc: implement htclow listener thread 2021-02-24 04:06:54 -08:00
Michael Scire
c9c41e0e8d htc: actually use the usb driver 2021-02-24 04:06:54 -08:00
Michael Scire
c59388caf1 htc: implement complete usb driver 2021-02-24 04:06:54 -08:00
Michael Scire
c878123274 htc: implement (fixing linker errors) through HtclowManagerImpl::OpenDriver 2021-02-24 04:06:54 -08:00
Michael Scire
1687bf2e07 htclow: fix copyright headers, skeleton more manager types 2021-02-24 04:06:54 -08:00
Michael Scire
cf99f54a34 htc: skeleton much of the type hierarchy for htclow manager 2021-02-24 04:06:54 -08:00
Michael Scire
83c1c175ba htc: skeleton some more of main 2021-02-24 04:06:54 -08:00
Michael Scire
fc060d3777 htc: skeleton main file/sysmodule dir 2021-02-24 04:06:54 -08:00
Michael Scire
eb50e99748 kern: alleviate a little KPort pressure. 2021-02-23 14:31:24 -08:00
Michael Scire
287f4e6fa1 sm: fix abort on RegisterService while at port limit
closes #1382
2021-02-23 14:21:46 -08:00
Michael Scire
cbf3ba9b75 General system stability improvements to enhance the user's experience. 2021-02-21 23:50:01 -08:00
Michael Scire
95a6b0828f dmnt: set the debug process handle slightly more carefully 2021-02-20 17:37:59 -08:00
730 changed files with 54885 additions and 5280 deletions

View File

@@ -49,6 +49,8 @@ X.X.X</br>
- [ Ex: Kosmos' distribution of Atmosphère ] - [ Ex: Kosmos' distribution of Atmosphère ]
- Do you have additional kips or sysmodules you're loading: - Do you have additional kips or sysmodules you're loading:
- Homebrew software installed: [ * ] - Homebrew software installed: [ * ]
- EmuMMC or SysNAND:
- [ If using an EmuMMC, include whether it's partition-based or file-based. ]
### Additional context? ### Additional context?

View File

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

View File

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

View File

@@ -1,4 +1,69 @@
# Changelog # Changelog
## 0.19.3
+ Support was added for 12.0.2.
+ A number of minor issues were fixed, including:
+ An issue was fixed in dns.mitm that caused a crash when games attempted to resolve the IP address of nullptr.
+ An issue was fixed in erpt that would cause an abort when booting without having ever booted stock previously.
+ An issue was fixed in (file-based) emummc that caused an error on system format/downloading certain games.
+ General system stability improvements to enhance the user's experience.
## 0.19.2
+ Atmosphère's components were further updated to reflect latest official behaviors as of 12.0.0.
+ Notably, `erpt` was updated to implement the new forced shutdown detection feature.
+ When a forced-shutdown occurs, an erpt_report will be generated and saved to the SD card on the next boot.
+ Atmosphere-libs was updated to use GCC 11 (latest devkitA64/devkitARM releases).
+ Initial inspections show mild-to-moderate optimizer improvements in several important places (kernel is 0x3000 smaller).
+ General system stability improvements to enhance the user's experience.
+ A number of minor issues were fixed, including:
+ A bug was fixed that caused a black screen when attempting to boot firmware versions 2.0.0-4.1.0.
+ A bug was fixed that caused sm to abort when at the session limit, rather than returning error codes.
+ A bug was fixed that allowed for resource exhaustion on 12.0.0, under certain circumstances.
+ Several issues were fixed, and usability and stability were improved.
## 0.19.1
+ An issue was fixed that caused a fatal error when using official `migration` services to transfer data between consoles.
+ An issue was fixed in `ncm` that caused an error when the OS tried to enumerate installed SD card content.
+ Several issues were fixed, and usability and stability were improved.
## 0.19.0
+ Support was added for 12.0.0.
+ `mesosphère` was updated to reflect the latest official kernel behavior.
+ `sm`, `boot2`, `pgl` were updated to reflect the latest official behaviors.
+ **Please Note**: 12.0.0 added a new protocol for IPC ("tipc"), which has been freshly reimplemented in its entirety.
+ It is possible there may be as of yet unfound issues; if there are, please send the appropriate crash reports to SciresM (SciresM#0524 on discord).
+ Homebrew which uses atmosphere extensions (including the mitm API) will need to be re-compiled in order to function on 0.19.0.
+ I apologize for this, but it's unavoidable for technical reasons. If you're affected by this and mad about it, please contact SciresM to complain.
+ `erpt` was partially updated to reflect the latest official behaviors.
+ New features were added to erpt to track the activity of running applets, and to detect when a forced shutdown occurs.
+ These behaviors have been temporarily stubbed, as they are not necessary for 12.0.0 to run (and their outputs won't be saved anywhere).
+ A future atmosphère update will implement these behaviors, in the interest of reflecting official logic as faithfully as we can.
+ Atmosphère no longer uses the /contents/ folder for its own programs.
+ Atmosphère's system modules are now bundled together in the single file "stratosphere.romfs".
+ For those working on developing for atmosphère, executables inside the /contents/ directory will be preferred to those in "stratosphere.romfs".
+ **Please Note**: In order to facilitate this change (and the desired behavior), the first time you boot after extracting a release zip, atmosphère system modules inside /contents/ will be deleted.
+ This will have no impact on user programs (it only removes programs with specific program ids).
+ Improvements were made to mesosphere, including:
+ An extension InfoType was added for getting the current process handle, without having to spawn a thread and do IPC with oneself.
+ An issue was fixed in SvcSetDebugThreadContext.
+ An issue was fixed when doing IPC with user buffers.
+ Support was fixed for toggling the custom setting `usb!usb30_force_enabled` on 9.0.0+.
+ This was broken by Nintendo's introducing a dependency that made USB a requirement to launch before custom settings are parsed.
+ Since the fix, you can now toggle the setting (as you could prior to atmosphère 0.9.4), and it will work as expected.
+ **Please Note**: Enabling USB 3.0 often severely impacts wireless communications.
+ Because of this, the setting will default to off. If you experience issues with it enabled, consider disabling it.
+ A warning was added to daybreak when resetting the console to factory settings.
+ Substantial work was completed towards atmosphere's upcoming implementation of the host target connection protocol.
+ Once completed, users will be able to interact with a Switch running atmosphère via a PC application ("Starlink") currently under development.
+ Planned eventual features for connected consoles include a gdbstub, interacting with memory (for cheat development), streaming gameplay audio and video, and accessing the Switch's SD card filesystem.
+ Switch homebrew will also have access to a (configurable and sandboxed) filesystem on the host PC, while connected.
+ Towards this end, the following was accomplished:
+ The "htc" system module was reimplemented completely.
+ The system module which provides remote access to the SD card was reimplemented completely.
+ This is currently the active focus of atmosphère's development.
+ **Please Note**: Support is not yet completed, and users are disadvised from interacting with the related settings for the time being, unless they particularly know what they're doing.
+ A number of minor issues were fixed, including:
+ A bug was fixed in `dmnt` that could cause a fatal when launching certain games with cheats active.
+ An issue was fixed that could cause an abort in `sm` when using a large number of custom system modules.
+ An issue was fixed that prevented launching gamecards on 1.0.0.
+ Minor issues were fixed in the cheat virtual machine's behavior.
+ Several issues were fixed, and usability and stability were improved.
## 0.18.1 ## 0.18.1
+ A number of minor issues were fixed, including: + A number of minor issues were fixed, including:
+ The new `dns.mitm` module added in 0.18.0 no longer fatal errors when receiving port=nullptr. + The new `dns.mitm` module added in 0.18.0 no longer fatal errors when receiving port=nullptr.
@@ -41,7 +106,7 @@
+ This also substantially improves power drain when the system is shut off; consoles powered off from Atmosphere should now drain battery at the same reduced rate as original firmware. + This also substantially improves power drain when the system is shut off; consoles powered off from Atmosphere should now drain battery at the same reduced rate as original firmware.
+ A number of minor changes were made, including: + A number of minor changes were made, including:
+ A number of inconsistencies in the build system were fixed. + A number of inconsistencies in the build system were fixed.
+ Fow those building atmosphère at home, the `boot` sysmodule will no longer rebuild every time make is invoked. + For those building atmosphère at home, the `boot` sysmodule will no longer rebuild every time make is invoked.
+ This substantially improves build times during development iteration. + This substantially improves build times during development iteration.
+ `sm` was updated to more accurately reflect how official code manages request deferral. + `sm` was updated to more accurately reflect how official code manages request deferral.
+ `mesosphère` was updated to more accurately reflect official kernel management of the trace buffer. + `mesosphère` was updated to more accurately reflect official kernel management of the trace buffer.

View File

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

View File

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

View File

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

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_1200_H__
#define __FS_1200_H__
// Accessor vtable getters
#define FS_OFFSET_1200_SDMMC_ACCESSOR_GC 0x154FD0
#define FS_OFFSET_1200_SDMMC_ACCESSOR_SD 0x156DE0
#define FS_OFFSET_1200_SDMMC_ACCESSOR_NAND 0x155500
// Hooks
#define FS_OFFSET_1200_SDMMC_WRAPPER_READ 0x150970
#define FS_OFFSET_1200_SDMMC_WRAPPER_WRITE 0x150A30
#define FS_OFFSET_1200_RTLD 0x688
#define FS_OFFSET_1200_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
#define FS_OFFSET_1200_CLKRST_SET_MIN_V_CLK_RATE 0x14FCC0
// Misc funcs
#define FS_OFFSET_1200_LOCK_MUTEX 0x29350
#define FS_OFFSET_1200_UNLOCK_MUTEX 0x293A0
#define FS_OFFSET_1200_SDMMC_WRAPPER_CONTROLLER_OPEN 0x150850
#define FS_OFFSET_1200_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1508E0
// Misc Data
#define FS_OFFSET_1200_SD_MUTEX 0xE3D3E8
#define FS_OFFSET_1200_NAND_MUTEX 0xE38768
#define FS_OFFSET_1200_ACTIVE_PARTITION 0xE387A8
#define FS_OFFSET_1200_SDMMC_DAS_HANDLE 0xE20DB0
// NOPs
#define FS_OFFSET_1200_SD_DAS_INIT 0x27244
// Nintendo Paths
#define FS_OFFSET_1200_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x0006E810, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x0007AEC0, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x00081254, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x00092850, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_1200_H__

View File

@@ -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_1200_EXFAT_H__
#define __FS_1200_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_1200_EXFAT_SDMMC_ACCESSOR_GC 0x154FD0
#define FS_OFFSET_1200_EXFAT_SDMMC_ACCESSOR_SD 0x156DE0
#define FS_OFFSET_1200_EXFAT_SDMMC_ACCESSOR_NAND 0x155500
// Hooks
#define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_READ 0x150970
#define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_WRITE 0x150A30
#define FS_OFFSET_1200_EXFAT_RTLD 0x688
#define FS_OFFSET_1200_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
#define FS_OFFSET_1200_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x14FCC0
// Misc funcs
#define FS_OFFSET_1200_EXFAT_LOCK_MUTEX 0x29350
#define FS_OFFSET_1200_EXFAT_UNLOCK_MUTEX 0x293A0
#define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x150850
#define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1508E0
// Misc Data
#define FS_OFFSET_1200_EXFAT_SD_MUTEX 0xE4B3E8
#define FS_OFFSET_1200_EXFAT_NAND_MUTEX 0xE46768
#define FS_OFFSET_1200_EXFAT_ACTIVE_PARTITION 0xE467A8
#define FS_OFFSET_1200_EXFAT_SDMMC_DAS_HANDLE 0xE2EDB0
// NOPs
#define FS_OFFSET_1200_EXFAT_SD_DAS_INIT 0x27244
// Nintendo Paths
#define FS_OFFSET_1200_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x0006E810, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x0007AEC0, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x00081254, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x00092850, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_1200_EXFAT_H__

View File

@@ -292,6 +292,36 @@ static uint64_t emummc_read_write_inner(void *buf, unsigned int sector, unsigned
{ {
fp = &f_emu.fp_gpp[sector / f_emu.part_size]; fp = &f_emu.fp_gpp[sector / f_emu.part_size];
sector = sector % f_emu.part_size; sector = sector % f_emu.part_size;
// Special handling for reads/writes which cross file-boundaries.
if (__builtin_expect(sector + num_sectors > f_emu.part_size, 0))
{
unsigned int remaining = num_sectors;
while (remaining > 0) {
const unsigned int cur_sectors = MIN(remaining, f_emu.part_size - sector);
if (f_lseek(fp, (u64)sector << 9) != FR_OK)
return 0; // Out of bounds.
if (is_write)
{
if (f_write_fast(fp, buf, (u64)cur_sectors << 9) != FR_OK)
return 0;
}
else
{
if (f_read_fast(fp, buf, (u64)cur_sectors << 9) != FR_OK)
return 0;
}
buf = (char *)buf + ((u64)cur_sectors << 9);
remaining -= cur_sectors;
sector = 0;
++fp;
}
return 1;
}
} }
else else
{ {
@@ -306,14 +336,14 @@ static uint64_t emummc_read_write_inner(void *buf, unsigned int sector, unsigned
break; break;
} }
if (f_lseek(fp, sector << 9) != FR_OK) if (f_lseek(fp, (u64)sector << 9) != FR_OK)
return 0; // Out of bounds. return 0; // Out of bounds.
uint64_t res = 0; uint64_t res = 0;
if (!is_write) if (!is_write)
res = !f_read_fast(fp, buf, num_sectors << 9); res = !f_read_fast(fp, buf, (u64)num_sectors << 9);
else else
res = !f_write_fast(fp, buf, num_sectors << 9); res = !f_write_fast(fp, buf, (u64)num_sectors << 9);
return res; return res;
} }
@@ -328,13 +358,13 @@ uint64_t sdmmc_wrapper_controller_open(int mmc_id)
if (_this != NULL) if (_this != NULL)
{ {
// Lock eMMC xfer while SD card is being initialized by FS. // Lock eMMC xfer while SD card is being initialized by FS.
if (_this == sdmmc_accessor_get(FS_SDMMC_SD)) if (mmc_id == FS_SDMMC_SD)
mutex_lock_handler(FS_SDMMC_EMMC); // Recursive Mutex, handler will lock SD as well if custom_driver mutex_lock_handler(FS_SDMMC_EMMC); // Recursive Mutex, handler will lock SD as well if custom_driver
result = _this->vtab->sdmmc_accessor_controller_open(_this); result = _this->vtab->sdmmc_accessor_controller_open(_this);
// Unlock eMMC. // Unlock eMMC.
if (_this == sdmmc_accessor_get(FS_SDMMC_SD)) if (mmc_id == FS_SDMMC_SD)
mutex_unlock_handler(FS_SDMMC_EMMC); mutex_unlock_handler(FS_SDMMC_EMMC);
return result; return result;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -348,6 +348,7 @@ uint32_t fuse_get_regulator(void) {
static const uint32_t fuse_version_increment_firmwares[] = { static const uint32_t fuse_version_increment_firmwares[] = {
ATMOSPHERE_TARGET_FIRMWARE_12_0_2,
ATMOSPHERE_TARGET_FIRMWARE_11_0_0, ATMOSPHERE_TARGET_FIRMWARE_11_0_0,
ATMOSPHERE_TARGET_FIRMWARE_10_0_0, ATMOSPHERE_TARGET_FIRMWARE_10_0_0,
ATMOSPHERE_TARGET_FIRMWARE_9_1_0, ATMOSPHERE_TARGET_FIRMWARE_9_1_0,

View File

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

View File

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

View File

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

View File

@@ -250,7 +250,7 @@ static bool package2_validate_metadata(package2_meta_t *metadata, uint8_t data[]
/* Perform version checks. */ /* Perform version checks. */
/* We will be compatible with all package2s released before current, but not newer ones. */ /* We will be compatible with all package2s released before current, but not newer ones. */
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_1100_CURRENT) { if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_1202_CURRENT) {
return true; return true;
} }

View File

@@ -41,7 +41,8 @@
#define PACKAGE2_MAXVER_900 0xC #define PACKAGE2_MAXVER_900 0xC
#define PACKAGE2_MAXVER_910_920 0xD #define PACKAGE2_MAXVER_910_920 0xD
#define PACKAGE2_MAXVER_1000 0xE #define PACKAGE2_MAXVER_1000 0xE
#define PACKAGE2_MAXVER_1100_CURRENT 0xF #define PACKAGE2_MAXVER_1100 0xF
#define PACKAGE2_MAXVER_1202_CURRENT 0x10
#define PACKAGE2_MINVER_100 0x3 #define PACKAGE2_MINVER_100 0x3
#define PACKAGE2_MINVER_200 0x4 #define PACKAGE2_MINVER_200 0x4
@@ -56,7 +57,8 @@
#define PACKAGE2_MINVER_900 0xD #define PACKAGE2_MINVER_900 0xD
#define PACKAGE2_MINVER_910_920 0xE #define PACKAGE2_MINVER_910_920 0xE
#define PACKAGE2_MINVER_1000 0xF #define PACKAGE2_MINVER_1000 0xF
#define PACKAGE2_MINVER_1100_CURRENT 0x10 #define PACKAGE2_MINVER_1100 0x10
#define PACKAGE2_MINVER_1202_CURRENT 0x11
#define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull)) #define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull))

View File

@@ -6,7 +6,7 @@
[subrepo] [subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master branch = master
commit = bc08912dd31bb172467add8e24b4f0adac431939 commit = 9ac6f527e2a48ba97636ba8f65538f960870cd8a
parent = 71add1add8521e0c2115ec612c514400ac7ba688 parent = 269d4496b2365785c87545b0337f89078cb76c3e
method = merge method = merge
cmdver = 0.4.1 cmdver = 0.4.1

View File

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

View File

@@ -34,7 +34,8 @@ export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
-Wl,--wrap,_Unwind_Resume \ -Wl,--wrap,_Unwind_Resume \
-Wl,--wrap,_ZSt19__throw_logic_errorPKc \ -Wl,--wrap,_ZSt19__throw_logic_errorPKc \
-Wl,--wrap,_ZSt20__throw_length_errorPKc \ -Wl,--wrap,_ZSt20__throw_length_errorPKc \
-Wl,--wrap,_ZNSt11logic_errorC2EPKc -Wl,--wrap,_ZNSt11logic_errorC2EPKc \
-Wl,--wrap,exit
export LDFLAGS = -specs=$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/stratosphere.specs -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) $(CXXWRAPS) -Wl,-Map,$(notdir $*.map) export LDFLAGS = -specs=$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/stratosphere.specs -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) $(CXXWRAPS) -Wl,-Map,$(notdir $*.map)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -165,6 +165,7 @@ namespace ams::fuse {
} }
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = { constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
TargetFirmware_12_0_2,
TargetFirmware_11_0_0, TargetFirmware_11_0_0,
TargetFirmware_10_0_0, TargetFirmware_10_0_0,
TargetFirmware_9_1_0, TargetFirmware_9_1_0,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -176,7 +176,7 @@ namespace ams::kern::arch::arm64 {
} }
NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end); NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager); NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit);
Result Finalize(); Result Finalize();
private: private:
Result MapL1Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll); Result MapL1Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -113,7 +113,7 @@ namespace ams::kern {
if (AMS_LIKELY(allocated != nullptr)) { if (AMS_LIKELY(allocated != nullptr)) {
/* Construct the object. */ /* Construct the object. */
new (allocated) T(); std::construct_at(allocated);
/* Update our tracking. */ /* Update our tracking. */
size_t used = m_used.fetch_add(1) + 1; size_t used = m_used.fetch_add(1) + 1;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -194,8 +194,20 @@ namespace ams::kern {
static bool s_scheduler_update_needed; static bool s_scheduler_update_needed;
static KSchedulerPriorityQueue s_priority_queue; static KSchedulerPriorityQueue s_priority_queue;
static LockType s_scheduler_lock; static LockType s_scheduler_lock;
public:
static consteval bool ValidateAssemblyOffsets();
}; };
consteval bool KScheduler::ValidateAssemblyOffsets() {
static_assert(__builtin_offsetof(KScheduler, m_state.needs_scheduling) == KSCHEDULER_NEEDS_SCHEDULING);
static_assert(__builtin_offsetof(KScheduler, m_state.interrupt_task_thread_runnable) == KSCHEDULER_INTERRUPT_TASK_THREAD_RUNNABLE);
static_assert(__builtin_offsetof(KScheduler, m_state.highest_priority_thread) == KSCHEDULER_HIGHEST_PRIORITY_THREAD);
static_assert(__builtin_offsetof(KScheduler, m_state.idle_thread_stack) == KSCHEDULER_IDLE_THREAD_STACK);
return true;
}
static_assert(KScheduler::ValidateAssemblyOffsets());
class KScopedSchedulerLock : KScopedLock<KScheduler::LockType> { class KScopedSchedulerLock : KScopedLock<KScheduler::LockType> {
public: public:
explicit ALWAYS_INLINE KScopedSchedulerLock() : KScopedLock(KScheduler::s_scheduler_lock) { /* ... */ } explicit ALWAYS_INLINE KScopedSchedulerLock() : KScopedLock(KScheduler::s_scheduler_lock) { /* ... */ }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -283,6 +283,16 @@ namespace ams::kern::arch::arm64::cpu {
} }
} }
void StoreDataCacheBySetWay(int level) {
PerformCacheOperationBySetWayImpl<false>(level, StoreDataCacheLineBySetWayImpl);
cpu::DataSynchronizationBarrier();
}
void FlushDataCacheBySetWay(int level) {
PerformCacheOperationBySetWayImpl<false>(level, FlushDataCacheLineBySetWayImpl);
cpu::DataSynchronizationBarrier();
}
void KCacheHelperInterruptHandler::ProcessOperation() { void KCacheHelperInterruptHandler::ProcessOperation() {
switch (m_operation) { switch (m_operation) {
case Operation::Idle: case Operation::Idle:
@@ -291,12 +301,10 @@ namespace ams::kern::arch::arm64::cpu {
InstructionMemoryBarrier(); InstructionMemoryBarrier();
break; break;
case Operation::StoreDataCache: case Operation::StoreDataCache:
PerformCacheOperationBySetWayLocal<false>(StoreDataCacheLineBySetWayImpl); StoreDataCacheBySetWay(0);
DataSynchronizationBarrier();
break; break;
case Operation::FlushDataCache: case Operation::FlushDataCache:
PerformCacheOperationBySetWayLocal<false>(FlushDataCacheLineBySetWayImpl); FlushDataCacheBySetWay(0);
DataSynchronizationBarrier();
break; break;
} }
@@ -374,7 +382,20 @@ namespace ams::kern::arch::arm64::cpu {
} }
void FlushEntireDataCache() { void FlushEntireDataCache() {
return PerformCacheOperationBySetWayShared<false>(FlushDataCacheLineBySetWayImpl); KScopedCoreMigrationDisable dm;
CacheLineIdRegisterAccessor clidr_el1;
const int levels_of_coherency = clidr_el1.GetLevelsOfCoherency();
/* Store cache from L2 up to the level of coherence (if there's an L3 cache or greater). */
for (int level = 2; level < levels_of_coherency; ++level) {
StoreDataCacheBySetWay(level - 1);
}
/* Flush cache from the level of coherence down to L2. */
for (int level = levels_of_coherency; level > 1; --level) {
FlushDataCacheBySetWay(level - 1);
}
} }
Result InvalidateDataCache(void *addr, size_t size) { Result InvalidateDataCache(void *addr, size_t size) {

View File

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

View File

@@ -239,14 +239,6 @@ namespace ams::kern::arch::arm64 {
} }
} }
Result KInterruptManager::ClearInterrupt(s32 irq) {
R_UNLESS(KInterruptController::IsGlobal(irq), svc::ResultOutOfRange());
KScopedInterruptDisable di;
KScopedSpinLock lk(this->GetGlobalInterruptLock());
return this->ClearGlobal(irq);
}
Result KInterruptManager::ClearInterrupt(s32 irq, s32 core_id) { Result KInterruptManager::ClearInterrupt(s32 irq, s32 core_id) {
MESOSPHERE_UNUSED(core_id); MESOSPHERE_UNUSED(core_id);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -492,7 +492,7 @@ namespace ams::kern::board::nintendo::nx {
/* Wait for a request. */ /* Wait for a request. */
{ {
KScopedLightLock lk(g_cv_lock); KScopedLightLock lk(g_cv_lock);
while (!(g_sleep_target_cores & target_core_mask)) { while ((g_sleep_target_cores & target_core_mask) == 0) {
g_cv.Wait(std::addressof(g_cv_lock)); g_cv.Wait(std::addressof(g_cv_lock));
} }
} }

View File

@@ -14,7 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */ /* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */
#define cpuactlr_el1 s3_1_c15_c2_0 #define cpuactlr_el1 s3_1_c15_c2_0
#define cpuectlr_el1 s3_1_c15_c2_1 #define cpuectlr_el1 s3_1_c15_c2_1
@@ -95,9 +94,10 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
mrs x2, tpidr_el1 mrs x2, tpidr_el1
stp x1, x2, [x0], #0x10 stp x1, x2, [x0], #0x10
/* Save the virtual resumption entrypoint. */ /* Save the virtual resumption entrypoint and cntv_cval_el0. */
adr x1, 77f adr x1, 77f
stp x1, xzr, [x0], #0x10 mrs x2, cntv_cval_el0
stp x1, x2, [x0], #0x10
/* Get the current core id. */ /* Get the current core id. */
mrs x0, mpidr_el1 mrs x0, mpidr_el1
@@ -245,12 +245,13 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm:
msr tcr_el1, x1 msr tcr_el1, x1
msr mair_el1, x2 msr mair_el1, x2
/* Get sctlr, tpidr, and the entrypoint. */ /* Get sctlr, tpidr, the entrypoint, and cntv_cval_el0. */
ldp x1, x2, [x0], #0x10 ldp x1, x2, [x0], #0x10
ldp x3, xzr, [x0], #0x10 ldp x3, x4, [x0], #0x10
/* Set the global context back into x18/tpidr. */ /* Set the global context back into x18/tpidr. */
msr tpidr_el1, x2 msr tpidr_el1, x2
msr cntv_cval_el0, x4
dsb sy dsb sy
isb isb

View File

@@ -21,7 +21,8 @@ namespace ams::kern::board::nintendo::nx {
namespace { namespace {
constexpr size_t SecureAlignment = 128_KB; constexpr uintptr_t DramPhysicalAddress = 0x80000000;
constexpr size_t SecureAlignment = 128_KB;
/* Global variables for panic. */ /* Global variables for panic. */
constinit bool g_call_smc_on_panic; constinit bool g_call_smc_on_panic;
@@ -41,8 +42,8 @@ namespace ams::kern::board::nintendo::nx {
/* Nintendo uses std::mt19937_t for randomness. */ /* Nintendo uses std::mt19937_t for randomness. */
/* To save space (and because mt19337_t isn't secure anyway), */ /* To save space (and because mt19337_t isn't secure anyway), */
/* We will use TinyMT. */ /* We will use TinyMT. */
bool g_initialized_random_generator; constinit bool g_initialized_random_generator;
util::TinyMT g_random_generator; constinit util::TinyMT g_random_generator;
constinit KSpinLock g_random_lock; constinit KSpinLock g_random_lock;
ALWAYS_INLINE size_t GetRealMemorySizeForInit() { ALWAYS_INLINE size_t GetRealMemorySizeForInit() {
@@ -89,13 +90,10 @@ namespace ams::kern::board::nintendo::nx {
return value; return value;
} }
void EnsureRandomGeneratorInitialized() { ALWAYS_INLINE u64 GenerateRandomU64FromSmc() {
if (AMS_UNLIKELY(!g_initialized_random_generator)) { u64 value;
u64 seed; smc::GenerateRandomBytes(std::addressof(value), sizeof(value));
smc::GenerateRandomBytes(&seed, sizeof(seed)); return value;
g_random_generator.Initialize(reinterpret_cast<u32*>(&seed), sizeof(seed) / sizeof(u32));
g_initialized_random_generator = true;
}
} }
ALWAYS_INLINE u64 GenerateRandomU64FromGenerator() { ALWAYS_INLINE u64 GenerateRandomU64FromGenerator() {
@@ -348,6 +346,10 @@ namespace ams::kern::board::nintendo::nx {
} }
} }
KPhysicalAddress KSystemControl::Init::GetInitialProcessBinaryPhysicalAddress() {
return GetKernelPhysicalBaseAddress(DramPhysicalAddress) + GetIntendedMemorySize() - KTraceBufferSize - InitialProcessBinarySizeMax;
}
bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() { bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() {
return GetKernelConfigurationForInit().Get<smc::KernelConfiguration::IncreaseThreadResourceLimit>(); return GetKernelConfigurationForInit().Get<smc::KernelConfiguration::IncreaseThreadResourceLimit>();
} }
@@ -368,7 +370,7 @@ namespace ams::kern::board::nintendo::nx {
case smc::MemoryArrangement_6GBForAppletDev: case smc::MemoryArrangement_6GBForAppletDev:
return 3285_MB; return 3285_MB;
case smc::MemoryArrangement_8GB: case smc::MemoryArrangement_8GB:
return 4916_MB; return 6964_MB;
} }
}(); }();
@@ -392,12 +394,12 @@ namespace ams::kern::board::nintendo::nx {
case smc::MemoryArrangement_6GBForAppletDev: case smc::MemoryArrangement_6GBForAppletDev:
return 2193_MB; return 2193_MB;
case smc::MemoryArrangement_8GB: case smc::MemoryArrangement_8GB:
return 2193_MB; return 562_MB;
} }
}(); }();
/* Return (possibly) adjusted size. */ /* Return (possibly) adjusted size. */
constexpr size_t ExtraSystemMemoryForAtmosphere = 33_MB; constexpr size_t ExtraSystemMemoryForAtmosphere = 40_MB;
return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize; return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
} }
@@ -434,6 +436,14 @@ namespace ams::kern::board::nintendo::nx {
/* System Initialization. */ /* System Initialization. */
void KSystemControl::InitializePhase1() { void KSystemControl::InitializePhase1() {
/* Initialize our random generator. */
{
u64 seed;
smc::GenerateRandomBytes(std::addressof(seed), sizeof(seed));
g_random_generator.Initialize(reinterpret_cast<u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
g_initialized_random_generator = true;
}
/* Set IsDebugMode. */ /* Set IsDebugMode. */
{ {
KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode)); KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
@@ -539,18 +549,23 @@ namespace ams::kern::board::nintendo::nx {
KScopedInterruptDisable intr_disable; KScopedInterruptDisable intr_disable;
KScopedSpinLock lk(g_random_lock); KScopedSpinLock lk(g_random_lock);
EnsureRandomGeneratorInitialized();
return GenerateUniformRange(min, max, GenerateRandomU64FromGenerator); if (AMS_LIKELY(g_initialized_random_generator)) {
return GenerateUniformRange(min, max, GenerateRandomU64FromGenerator);
} else {
return GenerateUniformRange(min, max, GenerateRandomU64FromSmc);
}
} }
u64 KSystemControl::GenerateRandomU64() { u64 KSystemControl::GenerateRandomU64() {
KScopedInterruptDisable intr_disable; KScopedInterruptDisable intr_disable;
KScopedSpinLock lk(g_random_lock); KScopedSpinLock lk(g_random_lock);
EnsureRandomGeneratorInitialized(); if (AMS_LIKELY(g_initialized_random_generator)) {
return GenerateRandomU64FromGenerator();
return GenerateRandomU64FromGenerator(); } else {
return GenerateRandomU64FromSmc();
}
} }
void KSystemControl::SleepSystem() { void KSystemControl::SleepSystem() {

View File

@@ -22,7 +22,6 @@ namespace ams::kern::init {
#define FOREACH_SLAB_TYPE(HANDLER, ...) \ #define FOREACH_SLAB_TYPE(HANDLER, ...) \
HANDLER(KProcess, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \ HANDLER(KProcess, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \
HANDLER(KThread, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \ HANDLER(KThread, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \
HANDLER(KLinkedListNode, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \
HANDLER(KEvent, (SLAB_COUNT(KEvent)), ## __VA_ARGS__) \ HANDLER(KEvent, (SLAB_COUNT(KEvent)), ## __VA_ARGS__) \
HANDLER(KInterruptEvent, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \ HANDLER(KInterruptEvent, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \
HANDLER(KInterruptEventTask, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \ HANDLER(KInterruptEventTask, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \
@@ -58,14 +57,14 @@ namespace ams::kern::init {
/* Constexpr counts. */ /* Constexpr counts. */
constexpr size_t SlabCountKProcess = 80; constexpr size_t SlabCountKProcess = 80;
constexpr size_t SlabCountKThread = 800; constexpr size_t SlabCountKThread = 800;
constexpr size_t SlabCountKEvent = 700; constexpr size_t SlabCountKEvent = 900;
constexpr size_t SlabCountKInterruptEvent = 100; constexpr size_t SlabCountKInterruptEvent = 100;
constexpr size_t SlabCountKPort = 256; constexpr size_t SlabCountKPort = 256 + 0x20 /* Extra 0x20 ports over Nintendo for homebrew. */;
constexpr size_t SlabCountKSharedMemory = 80; constexpr size_t SlabCountKSharedMemory = 80;
constexpr size_t SlabCountKTransferMemory = 200; constexpr size_t SlabCountKTransferMemory = 200;
constexpr size_t SlabCountKCodeMemory = 10; constexpr size_t SlabCountKCodeMemory = 10;
constexpr size_t SlabCountKDeviceAddressSpace = 300; constexpr size_t SlabCountKDeviceAddressSpace = 300;
constexpr size_t SlabCountKSession = 933; constexpr size_t SlabCountKSession = 1133;
constexpr size_t SlabCountKLightSession = 100; constexpr size_t SlabCountKLightSession = 100;
constexpr size_t SlabCountKObjectName = 7; constexpr size_t SlabCountKObjectName = 7;
constexpr size_t SlabCountKResourceLimit = 5; constexpr size_t SlabCountKResourceLimit = 5;
@@ -77,13 +76,13 @@ namespace ams::kern::init {
namespace test { namespace test {
constexpr size_t RequiredSizeForExtraThreadCount = SlabCountExtraKThread * (sizeof(KThread) + sizeof(KLinkedListNode) + (sizeof(KThreadLocalPage) / 8) + sizeof(KEventInfo)); constexpr size_t RequiredSizeForExtraThreadCount = SlabCountExtraKThread * (sizeof(KThread) + (sizeof(KThreadLocalPage) / 8) + sizeof(KEventInfo));
static_assert(RequiredSizeForExtraThreadCount <= KernelSlabHeapAdditionalSize); static_assert(RequiredSizeForExtraThreadCount <= KernelSlabHeapAdditionalSize);
} }
/* Global to hold our resource counts. */ /* Global to hold our resource counts. */
KSlabResourceCounts g_slab_resource_counts = { constinit KSlabResourceCounts g_slab_resource_counts = {
.num_KProcess = SlabCountKProcess, .num_KProcess = SlabCountKProcess,
.num_KThread = SlabCountKThread, .num_KThread = SlabCountKThread,
.num_KEvent = SlabCountKEvent, .num_KEvent = SlabCountKEvent,
@@ -132,7 +131,9 @@ namespace ams::kern::init {
} }
size_t CalculateSlabHeapGapSize() { size_t CalculateSlabHeapGapSize() {
return (kern::GetTargetFirmware() >= TargetFirmware_10_0_0) ? KernelSlabHeapGapsSize : KernelSlabHeapGapsSizeDeprecated; constexpr size_t KernelSlabHeapGapSize = 2_MB - 296_KB;
static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax);
return KernelSlabHeapGapSize;
} }
size_t CalculateTotalSlabHeapSize() { size_t CalculateTotalSlabHeapSize() {

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