Compare commits

..

206 Commits

Author SHA1 Message Date
TuxSH
2efdee5cb8 meso: KProcess: add ForEachThread 2019-06-03 17:41:09 -07:00
TuxSH
240f455bc0 Fix FindObject 2019-06-03 17:41:09 -07:00
TuxSH
6642373795 meso: add FindObject to KObjectAllocator * 2019-06-03 17:41:09 -07:00
TuxSH
1a924ad317 meso: invert process<>thread header deps 2019-06-03 17:41:09 -07:00
TuxSH
91662decf0 meso: add KProcess::SetDebugPauseState 2019-06-03 17:41:09 -07:00
TuxSH
529024448e meso: introduce ProcessState 2019-06-03 17:41:09 -07:00
TuxSH
757aa30e74 meso: Implement KObjectRegistry 2019-06-03 17:41:09 -07:00
TuxSH
fb4e0988b9 meso: KServerPort dtor 2019-06-03 17:41:09 -07:00
TuxSH
ad879ca327 meso: Implement ConnectLight 2019-06-03 17:41:08 -07:00
TuxSH
efe7325af3 meso: impl AddServerSession 2019-06-03 17:41:08 -07:00
TuxSH
173bde2eca meso: KPort mini skeleton 2019-06-03 17:41:08 -07:00
TuxSH
acf32f841c meso: Implement LightSession functions 2019-06-03 17:41:08 -07:00
TuxSH
be3550d382 meso: Implement KLightServerSession dtor 2019-06-03 17:41:08 -07:00
TuxSH
9c8f818c29 meso: add KLightSession skeleton, remove KBaseSession 2019-06-03 17:41:08 -07:00
TuxSH
eb7e4153d1 meso: use macro to refactor auto obj declaration 2019-06-03 17:41:08 -07:00
TuxSH
86c43331eb meso: KBaseSession 2019-06-03 17:41:08 -07:00
TuxSH
baa34ddab5 meso: same thing for KEvent 2019-06-03 17:41:07 -07:00
TuxSH
d9c97983a3 meso: Client/server ifaces: use friendship 2019-06-03 17:41:07 -07:00
TuxSH
b6bbc4f3e5 arm64.hpp => arch.hpp, add GetCurrentCoreContextInstance 2019-06-03 17:41:07 -07:00
TuxSH
195da2e599 Remove IServer client ref 2019-06-03 17:41:07 -07:00
TuxSH
1b3b26c3af Fix KEvent resource acquision timeout 2019-06-03 17:41:06 -07:00
TuxSH
0fb40d1ef5 Implement KCriticalSection (mostly) 2019-06-03 17:41:06 -07:00
TuxSH
4238d2e97f Add KInterruptSpinLock, which is what is really used in the official kernel 2019-06-03 17:41:06 -07:00
TuxSH
7b726c3184 Add KInterruptBottomHalfGuard 2019-06-03 17:41:05 -07:00
TuxSH
40b860c239 Removing useless func IsAlive, since it's handled by ISetAllocated 2019-06-03 17:41:05 -07:00
TuxSH
5222b429c5 Add KInterruptEvent skeleton; remove useless funcs 2019-06-03 17:41:05 -07:00
TuxSH
2949d08eb2 Add static assers to token generation 2019-06-03 17:41:05 -07:00
TuxSH
6d898acc98 Fix make_object 2019-06-03 17:41:04 -07:00
TuxSH
f72836d72c Fix GenerateClassToken 2019-06-03 17:41:04 -07:00
TuxSH
65b20d0685 Better solution for latest commit 2019-06-03 17:41:04 -07:00
TuxSH
d4241fd8ef Add operator new/delete in IClient/IServer 2019-06-03 17:41:04 -07:00
TuxSH
504c74bc57 Fix build issues in make_object; fix linkage issues 2019-06-03 17:41:04 -07:00
TuxSH
c47a9931d9 Handle table fixes & additions to makeobject 2019-06-03 17:41:04 -07:00
TuxSH
4a1021f220 Do the same for ILimitedResource; fix handle table def, for the moment 2019-06-03 17:41:04 -07:00
TuxSH
ac6762bb6c Add more reflexivity to client/server interfaces 2019-06-03 17:41:04 -07:00
TuxSH
e2d8316401 Fix KCondition variable; add timeout parameter to ILimitableResource 2019-06-03 17:41:03 -07:00
Michael Scire
0a0c05481e mesosphere: Result{} => Result() 2019-06-03 17:41:03 -07:00
TuxSH
cd1f74154d Use scoped_lock, etc 2019-06-03 17:41:03 -07:00
TuxSH
698fa9fcb0 Write KEvent::Initialize, fix build issues 2019-06-03 17:41:03 -07:00
Michael Scire
a4419dfc41 mesosphere: Skeleton K(Readable/Writable)Event 2019-06-03 17:41:03 -07:00
Michael Scire
600afa5f0f mesosphere: Add convenience KScopedCriticalSection 2019-06-03 17:41:03 -07:00
Michael Scire
9b1fb0c6df mesosphere: KSync->Signal() -> KSync->NotifyWaiters 2019-06-03 17:41:02 -07:00
Michael Scire
08970a82ea mesosphere: ResultNotPermitted -> ResultInvalidState 2019-06-03 17:41:02 -07:00
TuxSH
a035be66bd Rename initialize for client/server/parent 2019-06-03 17:41:02 -07:00
TuxSH
9318ab10b2 Add Client/Server interfaces 2019-06-03 17:41:02 -07:00
TuxSH
dffb233423 Add KThread::StackParameters 2019-06-03 17:41:02 -07:00
TuxSH
e57203a7d4 Implement WaitSynchronization 2019-06-03 17:41:02 -07:00
TuxSH
7fde5fbe40 Implement KSynchronizationObject 2019-06-03 17:41:02 -07:00
TuxSH
1684e1d35c Move KAutoObject.hpp to core/ 2019-06-03 17:41:01 -07:00
Michael Scire
edcd4cbc26 Result: Refactor to have compiletime defs 2019-06-03 17:41:01 -07:00
TuxSH
be17f1f494 Make Result produce the same code as Nintendo's 2019-06-03 17:41:01 -07:00
TuxSH
672204c993 Put handle in its own file & fix it 2019-06-03 17:41:01 -07:00
TuxSH
6166262b5c Fix build issues 2019-06-03 17:41:00 -07:00
TuxSH
b492096aed Add Result.hpp 2019-06-03 17:41:00 -07:00
TuxSH
cfeebbd1c9 Fix KLinkedList; make it work even with strict aliasing 2019-06-03 17:41:00 -07:00
TuxSH
4078c9a07d Implement KLinkedList; untested 2019-06-03 17:41:00 -07:00
TuxSH
ed982877bd Remove bugous MLQ reverse iterator 2019-06-03 17:41:00 -07:00
TuxSH
745fa84e5e Add mesosphere (VERY VERY WIP) 2019-06-03 17:41:00 -07:00
Michael Scire
50e307b4b7 Update for latest libnx 2019-06-03 12:19:05 -07:00
SciresM
4387da1ecc Add licensing exemption for yuzu. 2019-05-30 18:20:24 -07:00
Michael Scire
d6502c174a pm: actually implement GetBootFinishedEvent 2019-05-27 21:52:28 -07:00
Michael Scire
f38965d0bd dmnt: implement debug log opcode 2019-05-27 18:44:09 -07:00
SciresM
c2cb94062a Merge pull request #548 from Thog/feature/creport-32-stack-frames
creport: Add 32 bits stack frames parsing support
2019-05-27 18:11:10 -07:00
Michael Scire
cfa050cc8f dmnt: explicitly reserve double-extended width opcodes 2019-05-27 18:10:49 -07:00
Thomas Guillemard
bbcb3757bd Address comment 2019-05-28 00:26:56 +02:00
Thomas Guillemard
a33ace8996 creport: Add 32 bits stack frames parsing support
Also fix FP, SP and LR registers being set wrongly by svcGetDebugThreadParam for 32 bits processes.
2019-05-28 00:18:10 +02:00
Michael Scire
766097d0b7 creport: dump tls/name on crash (closes #310) 2019-05-25 13:33:33 -07:00
SciresM
5f5a8567ce docs: remove nonsense from thermo (closes #296) 2019-05-23 15:42:43 -07:00
Michael Scire
7dbe61c94c docs: mention we don't do smhax (closes #303) 2019-05-23 12:25:03 -07:00
Michael Scire
422dce6974 ams: bump version to 0.8.10 2019-05-22 12:30:37 -07:00
Michael Scire
1d429261e9 Add 0.8.10 changelog ahead of release. 2019-05-22 12:30:01 -07:00
Michael Scire
6f25e92892 set.mitm: language emulation (closes #489) 2019-05-22 12:13:10 -07:00
SciresM
6cc29185d2 Merge pull request #545 from Kronos2308/simple-sd-save-flag
simple sd_save flag
2019-05-17 07:34:07 -07:00
SciresM
13a1566b4e Merge pull request #542 from leo60228/master
Allow pressing buttons on all controllers in loader (closes #541)
2019-05-17 07:33:55 -07:00
Kronos2308
bbb658a7e5 orthography 2019-05-17 10:03:53 +01:00
Kronos2308
ad812c8125 use configuration of system_settings.ini
prioritize the configuration of system_settings.ini
2019-05-17 09:28:46 +01:00
Kronos2308
a64fdce505 flag is now "redirect_save" 2019-05-17 08:44:41 +01:00
Kronos2308
7e950c3bcc Revert "Add files via upload"
This reverts commit d0d7772f98.
2019-05-17 08:38:21 +01:00
Kronos2308
d0d7772f98 Add files via upload 2019-05-17 08:29:38 +01:00
Kronos2308
674175e1c6 simple sd_save flag
something that allows you to decide which title to redirect games saves and which does not
2019-05-17 03:28:24 +01:00
leo60228
eab2d05680 Do same in dmnt and reboot_to_payload 2019-05-12 10:43:49 -04:00
leo60228
56d7473451 Do same in ams_mitm 2019-05-12 09:04:58 -04:00
Michael Scire
bfd4d41834 boot: fix a few issues in gpio/pinmux config 2019-05-12 03:49:36 -07:00
leo60228
defee07625 Allow pressing buttons on all controllers in loader (closes #541) 2019-05-11 15:15:17 -04:00
hexkyz
2c3111f9c9 fusee: Add more verbose error messages
boot: Fix license text
2019-05-10 17:15:25 +01:00
Michael Scire
ca2c171482 fusee: how did this ever work 2019-05-10 08:40:21 -07:00
Michael Scire
cfcb1cd3a1 update libstratosphere 2019-05-10 05:36:55 -07:00
Michael Scire
bb6cc6532b fusee/exo: add ability to disable user exception handlers
please do not use this
yellows8 needs it to debug am, 99% of use cases want them on
2019-05-10 03:50:25 -07:00
Michael Scire
03a425a579 stratosphere: TODO: panic -> std::abort() 2019-05-10 03:28:18 -07:00
Michael Scire
41f5b39f6b stratosphere: stop using kernelAbove 2019-05-10 03:25:07 -07:00
Michael Scire
b5dd621250 pm: fix memory usage on 5.0 2019-05-10 03:24:50 -07:00
SciresM
27cde7da7a Merge pull request #536 from Atmosphere-NX/boot_dev
Boot: reimplement the boot sysmodule
2019-05-10 02:37:03 -07:00
Michael Scire
377b8dae9f boot: fix two logic inversions in wake pin init 2019-05-09 21:58:13 -07:00
Michael Scire
78828427a4 boot: fix writes to WAKE2_MASK 2019-05-09 20:47:18 -07:00
SciresM
fe28dac9d3 Merge pull request #537 from friedkeenan/boot_dev
boot: fix the width of the text splash
2019-05-09 12:23:34 -07:00
friedkeenan
a85102c97c boot: fix the width of the text splash 2019-05-09 14:18:57 -05:00
Michael Scire
9b11f1cb19 boot: improve display init consistency 2019-05-09 10:17:02 -07:00
Michael Scire
cf6b9de370 boot: correct typo in MipiCal03 config 2019-05-09 09:06:36 -07:00
Michael Scire
80c380e61e boot: fix missing write in LCD vendor 0xF20 init 2019-05-09 08:15:12 -07:00
Michael Scire
967fa456ba boot: fix trailing whitespace 2019-05-09 05:03:35 -07:00
Michael Scire
6ae6c80c25 fusee: enable boot sysmodule. 2019-05-09 03:23:26 -07:00
Michael Scire
142df74694 boot: remove boot_old legacy code 2019-05-09 03:22:40 -07:00
Michael Scire
00db1dc286 boot: fix abort on < 3.0.0 2019-05-09 03:20:06 -07:00
Michael Scire
1456246f60 boot: implement PmicDriver::ShutdownSystem 2019-05-09 02:45:31 -07:00
Michael Scire
7581306109 boot: implement CheckAndRepairBootImages 2019-05-09 01:17:56 -07:00
Michael Scire
a4ee4d20ad boot: use correct clock out setting on < 6.0 2019-05-08 06:20:36 -07:00
Michael Scire
625ac5b357 boot: implement wake event configuration 2019-05-07 10:02:53 -07:00
Michael Scire
3f75a92fd2 boot: implement pmc wake config init (todo: events) 2019-05-07 09:32:37 -07:00
Michael Scire
b5e91ff9a4 boot: fix some silly mistakes 2019-05-07 01:18:54 -07:00
Michael Scire
db47a0c041 boot: implement SetFanEnabled 2019-05-06 23:14:06 -07:00
Michael Scire
5e7b33cabd 20ms, not 2s 2019-05-06 23:09:13 -07:00
Michael Scire
3cc79f4e11 boot: finish implementing CheckBatteryCharge 2019-05-06 23:08:28 -07:00
Michael Scire
7c36a827da boot: implement bc24193 driver, part of CheckBatteryCharge 2019-05-06 15:53:29 -07:00
Michael Scire
ea90325535 boot: remove debug logic for showing battery icons 2019-05-06 13:34:44 -07:00
Michael Scire
72377c2345 boot: implement battery icon drawing functions 2019-05-06 13:33:54 -07:00
Michael Scire
cccef3b85c boot: Implement battery driver setup. 2019-05-06 08:00:22 -07:00
Michael Scire
e10c6a3217 boot: add battery calibration accessors. 2019-05-06 05:59:27 -07:00
Michael Scire
4ef7b83e34 boot: implement ConfigurePinmux 2019-05-03 06:20:50 -07:00
Michael Scire
4ca53e2ef1 boot: implement SetInitialClockConfiguration 2019-05-03 05:18:36 -07:00
Michael Scire
d9da531b41 boot: implement ShowSplashScreen/Display 2019-05-03 05:00:03 -07:00
Michael Scire
93fb060fac boot: Implement DetectBootReason 2019-05-02 19:33:12 -07:00
Michael Scire
fe0d41623c boot: i2c driver fixes 2019-05-02 19:32:03 -07:00
Michael Scire
4ea6ce3156 boot: implement CheckClock 2019-05-02 18:10:07 -07:00
Michael Scire
520b5f6c59 boot: fix gpio configuration access errors 2019-05-02 17:56:04 -07:00
Michael Scire
505324f625 boot: functional exception handling/rebooting to payload 2019-05-02 17:55:50 -07:00
Michael Scire
9319463a6e fatal: use new I2cDevice enum 2019-05-02 17:54:05 -07:00
Michael Scire
31c4c33042 boot: finish i2c driver 2019-05-02 08:30:13 -07:00
Michael Scire
55a8154691 boot: implement I2cResourceManager 2019-05-02 07:18:05 -07:00
Michael Scire
453c05cf7c boot: implement I2cDriverSession 2019-05-02 06:36:31 -07:00
Michael Scire
4c5c78858c boot: implement I2cBusAccessor 2019-05-02 05:57:10 -07:00
Michael Scire
967613a261 boot: add i2c device configs 2019-05-02 02:53:48 -07:00
Michael Scire
348345340d fs.mitm: Implement FileStorage 2019-04-29 12:55:02 -07:00
Michael Scire
38159bdf9a boot: Implement initial gpio configuration 2019-04-29 09:43:48 -07:00
Michael Scire
e58948a42b boot: implement voltage change 2019-04-29 07:22:49 -07:00
Michael Scire
9c53c0c0cc boot: make our tasks explicit. 2019-04-29 06:09:47 -07:00
Michael Scire
7c5dc61795 boot: prepare for rewrite of boot sysmodule 2019-04-29 03:25:24 -07:00
Michael Scire
6034beb084 boot_100.kip vs boot_200.kip is gross 2019-04-29 03:00:04 -07:00
Michael Scire
8c3dae846e Bump version to 0.8.9 2019-04-26 07:32:49 -07:00
Michael Scire
dcc93ce60e strat: disable exception handlers when creport would be better 2019-04-26 07:32:23 -07:00
Michael Scire
7fef83885f ams: improve fatal error context 2019-04-26 07:25:38 -07:00
Michael Scire
3207c38a44 spl: use deprecated ssl decrypt command on 4.x in child interfaces 2019-04-26 03:20:12 -07:00
Michael Scire
5952ebab54 spl: amend range for DecryptRsaPrivateKeyDeprecated 2019-04-26 03:13:15 -07:00
Michael Scire
ad41d010d3 Atmosphere: Add 0.8.9 changelog ahead of release, update system settings. 2019-04-26 03:10:56 -07:00
Michael Scire
21db90bae9 spl: make ssl key decryption work on >= 5.0.0 2019-04-26 02:32:23 -07:00
SciresM
cf4f74c8f9 Merge pull request #528 from Atmosphere-NX/spl_dev
Reimplement the SPL sysmodule (closes #92)
2019-04-26 01:17:55 -07:00
Michael Scire
bf5a649928 sept-secondary shouldn't be .PHONY 2019-04-25 12:12:36 -07:00
Michael Scire
c5fa4660c8 fatal: add clkrst service access. 2019-04-25 11:42:44 -07:00
Michael Scire
0d4a0348b5 spl: Loosen keyslot restrictions on 1.0.0 2019-04-25 11:36:23 -07:00
Michael Scire
51858e732a fusee: embed spl. 2019-04-25 11:24:25 -07:00
Michael Scire
edcfbf4254 spl: Implement DeprecatedService. 2019-04-25 11:12:30 -07:00
Michael Scire
d984621150 spl: Implement FsService lotus commands (gamecards work now) 2019-04-25 07:06:27 -07:00
Michael Scire
4b8ebfa7c3 spl: fix CryptAesCtr (eshop games work now) 2019-04-25 06:00:34 -07:00
Michael Scire
bc44e02aed spl: fix vtables/other issues, now boots (not all commands work) 2019-04-25 05:27:35 -07:00
Michael Scire
85e8506fa8 spl: Implement non-Lotus FsService commands. 2019-04-25 00:33:10 -07:00
Michael Scire
5633444d5e spl: implement ManuService 2019-04-25 00:01:47 -07:00
Michael Scire
99106076e6 spl: Finish implementing EsService. 2019-04-24 23:42:49 -07:00
Michael Scire
0a194cb6a6 spl: add spl:ssl/spl:es to main, fix cmd ids 2019-04-24 23:16:47 -07:00
Michael Scire
f4a8124dc3 spl: implement SslService, some of EsService 2019-04-24 23:10:13 -07:00
Michael Scire
9ea1a2a941 spl: Implement RsaService 2019-04-24 21:42:39 -07:00
Michael Scire
bfa84e27c1 spl: implement CryptoService. 2019-04-24 21:00:39 -07:00
Michael Scire
14683405be fatal: update to use clkrst api on 8.0.0+ 2019-04-24 16:39:06 -07:00
Michael Scire
ccbab35deb spl: finish GeneralService. 2019-04-24 06:10:30 -07:00
Michael Scire
2dfa1c96d1 spl: continue implementing. 2019-04-24 05:38:11 -07:00
Michael Scire
d44b91826d dmnt: only init roDmnt when we can 2019-04-24 05:19:37 -07:00
Michael Scire
3a8f9114fc fatal: fix sm session usage 2019-04-24 05:18:31 -07:00
Michael Scire
9858d6fc95 spl: Start skeletoning spl. 2019-04-24 01:19:38 -07:00
Michael Scire
f6645387b0 update libstrat 2019-04-24 00:55:14 -07:00
Michael Scire
df963967f5 8.0.1 seems to work fine. 2019-04-23 17:34:21 -07:00
Michael Scire
8313669716 Fix NRO patch offset application 2019-04-23 08:31:11 -07:00
Michael Scire
13c825a8bb ro: only hold sm session open when needed 2019-04-22 13:17:57 -07:00
Michael Scire
30485f1df9 pm: fix dangling -> 2019-04-22 13:10:29 -07:00
Michael Scire
7945a921ca Merge branch 'ro_dev' 2019-04-22 13:07:11 -07:00
Michael Scire
b09adb6a34 stratosphere: only hold sm sessions open when needed 2019-04-22 12:59:49 -07:00
Michael Scire
c3875796df dmnt: update for ldr/ro api change 2019-04-22 09:50:45 -07:00
Michael Scire
a1d4caa7b4 ro: add support for applying ips patches to NROs. 2019-04-22 04:32:15 -07:00
Michael Scire
9f972831cc fs.mitm: fix data abort 2019-04-22 03:42:37 -07:00
Michael Scire
f50bfaf7d7 dist: add boot2.flag for ro (to launch on <3.0.0) 2019-04-22 01:54:44 -07:00
Michael Scire
bfd04cfe92 loader: remove more unused ro functionality 2019-04-22 00:40:19 -07:00
Michael Scire
cb74bc6bb8 ro: fix UnloadNro logic error 2019-04-22 00:31:17 -07:00
Sun
be4ca7eee5 Implement Auto Reboot Timer (#518) (#519)
* Implement Auto Reboot Timer (#518)

* Use > to check for values below -1

* Use TimeoutHelper and accept MS

* Add fatal_auto_reboot_interval into config (commented)

* Check for 0
2019-04-22 00:18:01 -07:00
Michael Scire
7b24b43477 Merge branch 'master' into ro_dev 2019-04-21 09:08:19 -07:00
Michael Scire
253afc90a4 loader: remove ldr:ro (moved into ro sysmodule) 2019-04-21 09:08:08 -07:00
Michael Scire
a09c08994f sm: change location of apm:p check, fixes failure to launch older games 2019-04-21 08:57:21 -07:00
Michael Scire
13ded6bd1c ro: implement loadnro/unloadnro 2019-04-21 07:28:07 -07:00
Michael Scire
4ba6d8b24c ro: implement rest of LoadNrr/LoadNrrEx 2019-04-21 05:28:57 -07:00
Michael Scire
cb88fdfd62 ro: implement UnloadNrr, half of LoadNrr/LoadNrrEx 2019-04-21 03:39:29 -07:00
Michael Scire
d69fc060f4 ro: Implement ro:dmnt 2019-04-21 02:09:08 -07:00
Michael Scire
e04fcfff6b ro: fix typo 2019-04-20 18:37:50 -07:00
Michael Scire
79c52e2b91 ro: skeleton ldr:ro 2019-04-20 18:37:01 -07:00
Michael Scire
4ac8f2745b ro: skeleton ro:dmnt 2019-04-20 18:16:33 -07:00
Michael Scire
6004b7479e ro: add ro sysmodule skeleton 2019-04-20 18:16:33 -07:00
Michael Scire
ed86c44a49 loader: refactor to use LoaderModuleInfo 2019-04-20 18:15:39 -07:00
Michael Scire
5c9d0f05b1 loader: use libstratosphere randomness 2019-04-20 16:53:56 -07:00
Michael Scire
87f7a6ebdc fusee: support both exfat and non-exfat 2019-04-20 11:24:05 -07:00
Michael Scire
664e5e6b52 Small 0.8.8 changelog addition 2019-04-20 10:37:53 -07:00
Michael Scire
9691286d73 Bump version to 0.8.8 2019-04-20 10:36:38 -07:00
Michael Scire
81895c8019 fusee: update to support booting 8.0.0 2019-04-20 10:36:38 -07:00
Michael Scire
1a396235cd fusee: only partially hash 8.0.0 kernel, add ControlCodeMemory patch 2019-04-20 10:36:38 -07:00
hexkyz
732a6159f7 fusee: Properly finalize SDMMC1 (fixes 8.0.0 issues with PCV) 2019-04-20 10:36:38 -07:00
Michael Scire
a3389e25c9 nogc: implement 8.0.0 patches 2019-04-20 10:36:38 -07:00
Michael Scire
908de31a0e pm: on 7.0.0+, npns is launched in maintenance boot (closes #511) 2019-04-20 10:36:38 -07:00
Michael Scire
4e5f033e41 sm: for 8.0.0, add some first class homebrew support 2019-04-20 10:36:38 -07:00
Michael Scire
ae90a9d7a6 exo/fusee: implement 8.0.0 support (package2 changes still TODO) 2019-04-20 10:36:38 -07:00
Michael Scire
a67d4064f0 pm: update with new meme command for 8.0.0 2019-04-20 10:36:38 -07:00
Michael Scire
d0659377e8 creport: speed up code region detection (closes #491) 2019-04-12 23:04:12 -07:00
Michael Scire
ac07971211 stratosphere: custom exception handlers (reboot to fusee) 2019-04-12 15:28:46 -07:00
354 changed files with 26244 additions and 4695 deletions

View File

@@ -50,11 +50,13 @@ dist: all
mkdir atmosphere-$(AMSVER)/atmosphere
mkdir atmosphere-$(AMSVER)/sept
mkdir atmosphere-$(AMSVER)/switch
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032
cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/010000000000000D
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000037
mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors
cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/sept/payload.bin
cp sept/sept-primary/sept-primary.bin atmosphere-$(AMSVER)/sept/sept-primary.bin
@@ -65,13 +67,16 @@ dist: all
cp common/defaults/system_settings.ini atmosphere-$(AMSVER)/atmosphere/system_settings.ini
cp -r common/defaults/kip_patches atmosphere-$(AMSVER)/atmosphere/kip_patches
cp -r common/defaults/hbl_html atmosphere-$(AMSVER)/atmosphere/hbl_html
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036/exefs.nsp
cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034/exefs.nsp
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/atmosphere/titles/010000000000000D/exefs.nsp
cp stratosphere/eclct.stub/eclct.stub.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/exefs.nsp
cp troposphere/reboot_to_payload/reboot_to_payload.nro atmosphere-$(AMSVER)/switch/reboot_to_payload.nro
cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034/exefs.nsp
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036/exefs.nsp
cp stratosphere/ro/ro.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000037/exefs.nsp
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags
touch atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags/boot2.flag
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/atmosphere/titles/010000000000000D/exefs.nsp
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000037/flags
touch atmosphere-$(AMSVER)/atmosphere/titles/0100000000000037/flags/boot2.flag
cp troposphere/reboot_to_payload/reboot_to_payload.nro atmosphere-$(AMSVER)/switch/reboot_to_payload.nro
cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../;
rm -r atmosphere-$(AMSVER)
mkdir out

View File

@@ -19,6 +19,16 @@ Atmosphère consists of multiple components, each of which replaces/modifies a d
* Stratosphère: Custom Sysmodule(s), both Rosalina style to extend the kernel/provide new features, and of the loader reimplementation style to hook important system actions
* Troposphère: Application-level Horizon OS patches, used to implement desirable CFW features
Licensing
=====
This software is licensed under the terms of the GPLv2, with exemptions for specific projects noted below.
You can find a copy of the license in the [LICENSE file](LICENSE).
Exemptions:
* The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the Atmosphère project as GPLv2 or later.
Credits
=====

View File

@@ -8,6 +8,9 @@ stage2_entrypoint = 0xF0000000
; Note: Disabling debugmode will cause parts of ams.tma to not work, in the future.
debugmode = 1
debugmode_user = 0
; Note: Disabling usermode exception handlers will cause atmosphere to not fail gracefully under error conditions.
; Support will not be provided to users who disable these. If you do not know what you are doing, leave them on.
disable_user_exception_handlers = 0
[stratosphere]
; To force-enable nogc, add nogc = 1

View File

@@ -4,8 +4,15 @@ upload_enabled = u8!0x0
; Enable USB 3.0 superspeed for homebrew
[usb]
usb30_force_enabled = u8!0x0
; Control whether RO should ease its validation of NROs.
; (note: this is normally not necessary, and ips patches can be used.)
[ro]
ease_nro_restriction = u8!0x0
; Atmosphere custom settings
[atmosphere]
; Reboot from fatal automatically after some number of milliseconds.
; If field is not present or 0, fatal will wait indefinitely for user input.
fatal_auto_reboot_interval = u64!0x0
; Make the power menu's "reboot" button reboot to payload.
; Set to "normal" for normal reboot, "rcm" for rcm reboot.
power_menu_reboot_function = str!payload

View File

@@ -25,11 +25,12 @@
#define ATMOSPHERE_TARGET_FIRMWARE_600 6
#define ATMOSPHERE_TARGET_FIRMWARE_620 7
#define ATMOSPHERE_TARGET_FIRMWARE_700 8
#define ATMOSPHERE_TARGET_FIRMWARE_800 9
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_700
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_800
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_700
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_800
/* TODO: What should this be, for release? */
#define ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG ATMOSPHERE_TARGET_FIRMWARE_CURRENT

View File

@@ -19,9 +19,9 @@
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
#define ATMOSPHERE_RELEASE_VERSION_MINOR 8
#define ATMOSPHERE_RELEASE_VERSION_MICRO 7
#define ATMOSPHERE_RELEASE_VERSION_MICRO 10
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 7
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 8
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 1

View File

@@ -1,4 +1,52 @@
# Changelog
## 0.8.10
+ A bug was fixed that could cause incorrect system memory allocation on 5.0.0.
+ 5.0.0 should now correctly have an additional 12 MiB allocated for sysmodules.
+ Atmosphère features which check button presses now consider all controllers, isntead of just P1.
+ Support was added for configuring language/region on a per-game basis.
+ This is managed by editing `atmosphere/titles/<title id>/config.ini` for the game.
+ To edit title language, edit `override_config!override_language`.
+ The languages supported are `ja`, `en-US`, `fr`, `de`, `it`, `es`, `zh-CN`, `ko`, `nl`, `pt`, `ru`, `zh-TW`, `en-GB`, `fr-CA`, `es-419`, `zh-Hans`, `zh-Hant`.
+ To edit title region, edit `override_config!override_region`.
+ The regions supported are `jpn`, `usa`, `eur`, `aus`, `chn`, `kor`, `twn`.
+ Atmosphère now provides a reimplementation of the `boot` system module.
+ `boot` is responsible for performing hardware initialization, showing the Nintendo logo, and repairing NAND on system update failure.
+ Atmosphère's `boot` implementation preserves AutoRCM during NAND repair.
+ NAND repair occurs when an unexpected shutdown or error happens during a system update.
+ This fixes a final edge case where AutoRCM might be removed by HOS, which could cause a user to burn fuses.
+ General system stability improvements to enhance the user's experience.
## 0.8.9
+ A number of bugs were fixed, including:
+ A data abort was fixed when mounting certain partitions on NAND.
+ All Stratosphère system modules now only maintain a connection to `sm` when actively using it.
+ This helps mitigate the scenario where sm hits the limit of 64 active connections and crashes.
+ This sometimes caused crashes when custom non-Atmosphère sysmodules were active and the user played certain games (ex: Smash's Stage Builder).
+ fatal now uses the 8.0.0 clkrst API, instead of silently failing to adjust clock rates on that firmware version.
+ A wait loop is now performed when trying to get a session to `sm`, in the case where `sm:` is not yet registered.
+ This fixes a race condition that could cause a failure to boot under certain circumstances.
+ libstratosphere's handling of domain object closing has been improved.
+ Previously, this code could cause crashes/extremely odd behavior (misinterpreting what object a service is) under certain circumstances.
+ An optional automatic reboot timer was added to fatal.
+ By setting the system setting `atmosphere!fatal_auto_reboot_interval` to a non-zero u64 value, fatal can be made to automatically reboot after a certain number of milliseconds.
+ If the setting is zero or not present, fatal will wait for user input as usual.
+ Atmosphère now provides a reimplementation of the `ro` system module.
+ `ro` is responsible for loading dynamic libraries (NROs) on 3.0.0+.
+ On 1.0.0-2.3.0, this is handled by `loader`.
+ Atmosphere's `ro` provides this functionality (`ldr:ro`, `ro:dmnt`) on all firmware versions.
+ An extension was implemented to provide support for applying IPS patches to NROs.
+ All patches at paths like /atmosphere/nro_patches/<user-defined patch name>/<Hex Build-ID for NRO to patch>.ips will be applied, allowing for easy distribution of patches.
+ Both the IPS and IPS32 formats are supported.
+ Atmosphère now provides a reimplementation of the `spl` system module.
+ `spl` (Secure Platform Services) is responsible for cryptographic operations, including all communications with the secure monitor (exosphère).
+ In the future, this may be used to provide extensions to the API for interacting with exosphère from userland.
+ General system stability improvements to enhance the user's experience.
## 0.8.8
+ Support was added for firmware version 8.0.0.
+ Custom exception handlers were added to stratosphere modules.
+ If a crash happens in a core atmosphere module now, instead of silently failing a reboot will occur to log the information to the SD card.
+ A bug was fixed in creport that caused games to hang when crashing under certain circumstances.
+ A bug was fixed that prevented maintenance mode from booting on 7.0.0+.
+ General system stability improvements to enhance the user's experience.
## 0.8.7
+ A few bugs were fixed that could cause fatal to fail to show an error under certain circumstances.
+ A bug was fixed that caused an error when launching certain games (e.g. Hellblade: Senua's Sacrifice).

View File

@@ -1,6 +1,4 @@
# Thermosphère
Thermosphère is a hypervisor based implementation of emuNAND. An emuNAND is a copy of the firmware on the Switchs internal memory (sysNAND), and is typically installed on an external SD Card.
Thermosphère is a hypervisor based implementation of emuNAND.
An emuNAND operates completely independently of the sysNAND. This allows one to make or test various modifications and homebrew safely without needing to restore their NAND backup afterwards by testing things on the emuNAND, and switching back to the sysNAND when finished. In the case of past Nintendo systems such as the 3DS, an emuNAND could also be used to update your system to the latest firmware while keeping your sysNAND on a lower version, however this may be more difficult to do on the Switch due to Nintendo using efuse technology for major system updates.
Thermosphère is currently planned to be included in the 1.0 release of Atmosphère.
Thermosphère is currently planned to be included in a future release of Atmosphère.

View File

@@ -122,4 +122,4 @@ By default, the Stratosphere implementation of PM will raise any session limits
### Weak Service Verification
In system firmware versions before 3.0.1, if a process did not call the [Initialize](https://reswitched.github.io/SwIPC/ifaces.html#nn::sm::detail::IUserInterface(0)) command on its `sm:` session, normally used to inform sm of the process's identity, sm would assume that the process was a kernel internal process and skip any service registration or access checks. The Stratosphere implementation of sm reimplements this vulnerability, allowing homebrew processes to skip service registration and access checks.
In system firmware versions before 3.0.1, if a process did not call the [Initialize](https://reswitched.github.io/SwIPC/ifaces.html#nn::sm::detail::IUserInterface(0)) command on its `sm:` session, normally used to inform sm of the process's identity, sm would assume that the process was a kernel internal process and skip any service registration or access checks. The Stratosphere implementation of sm does not implement this vulnerability, and initialization is required on all firmware versions.

View File

@@ -100,6 +100,8 @@ uint64_t bootconfig_get_value_for_sysctr0(void) {
}
uint64_t bootconfig_get_memory_arrangement(void) {
/* TODO: This function has changed pretty significantly since we implemented it. */
/* Not relevant for retail, but we'll probably want this to be accurate sooner or later. */
if (bootconfig_is_debug_mode()) {
if (fuse_get_dram_id() == 4) {
if (LOADED_BOOTCONFIG->unsigned_config.data[0x23]) {

View File

@@ -35,13 +35,14 @@
#undef u8
#undef u32
static bool g_battery_profile = false;
static bool g_hiz_mode_enabled = false;
static bool g_debugmode_override_user = false, g_debugmode_override_priv = false;
static bool g_enable_usermode_exception_handlers = true;
uint32_t configitem_set(bool privileged, ConfigItem item, uint64_t value) {
switch (item) {
case CONFIGITEM_BATTERYPROFILE:
g_battery_profile = (value != 0);
case CONFIGITEM_HIZMODE:
g_hiz_mode_enabled = (value != 0);
break;
case CONFIGITEM_NEEDS_REBOOT:
/* Force a reboot, if requested. */
@@ -133,8 +134,12 @@ bool configitem_is_retail(void) {
return is_retail != 0;
}
bool configitem_should_profile_battery(void) {
return g_battery_profile;
bool configitem_is_hiz_mode_enabled(void) {
return g_hiz_mode_enabled;
}
void configitem_set_hiz_mode_enabled(bool enabled) {
g_hiz_mode_enabled = enabled;
}
bool configitem_is_debugmode_priv(void) {
@@ -159,6 +164,10 @@ void configitem_set_debugmode_override(bool user, bool priv) {
g_debugmode_override_priv = priv;
}
void configitem_disable_usermode_exception_handlers(void) {
g_enable_usermode_exception_handlers = false;
}
uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue) {
uint32_t result = 0;
switch (item) {
@@ -209,13 +218,15 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
case CONFIGITEM_KERNELCONFIGURATION:
{
uint64_t config = bootconfig_get_kernel_configuration();
/* Always enable usermode exception handlers. */
config |= KERNELCONFIGFLAG_ENABLE_USER_EXCEPTION_HANDLERS;
/* Enable usermode exception handlers by default. */
if (g_enable_usermode_exception_handlers) {
config |= KERNELCONFIGFLAG_ENABLE_USER_EXCEPTION_HANDLERS;
}
*p_outvalue = config;
}
break;
case CONFIGITEM_BATTERYPROFILE:
*p_outvalue = (int)g_battery_profile;
case CONFIGITEM_HIZMODE:
*p_outvalue = (int)g_hiz_mode_enabled;
break;
case CONFIGITEM_ISQUESTUNIT:
/* Added on 3.0, used to determine whether console is a kiosk unit. */

View File

@@ -33,7 +33,7 @@ typedef enum {
CONFIGITEM_MEMORYARRANGE = 10,
CONFIGITEM_ISDEBUGMODE = 11,
CONFIGITEM_KERNELCONFIGURATION = 12,
CONFIGITEM_BATTERYPROFILE = 13,
CONFIGITEM_HIZMODE = 13,
CONFIGITEM_ISQUESTUNIT = 14,
CONFIGITEM_NEWHARDWARETYPE_5X = 15,
CONFIGITEM_NEWKEYGENERATION_5X = 16,
@@ -56,10 +56,12 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue);
bool configitem_is_recovery_boot(void);
bool configitem_is_retail(void);
bool configitem_should_profile_battery(void);
bool configitem_is_hiz_mode_enabled(void);
bool configitem_is_debugmode_priv(void);
void configitem_set_debugmode_override(bool user, bool priv);
void configitem_disable_usermode_exception_handlers(void);
void configitem_set_hiz_mode_enabled(bool enabled);
uint64_t configitem_get_hardware_type(void);

View File

@@ -75,3 +75,11 @@ unsigned int exosphere_should_override_debugmode_user(void) {
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_USER);
}
unsigned int exosphere_should_disable_usermode_exception_handlers(void) {
if (!g_has_loaded_config) {
generic_panic();
}
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
}

View File

@@ -35,10 +35,11 @@
/* Exosphere config in DRAM shares physical/virtual mapping. */
#define MAILBOX_EXOSPHERE_CONFIG_PHYS MAILBOX_EXOSPHERE_CONFIG
#define EXOSPHERE_FLAGS_DEFAULT 0x00000000
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u)
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u)
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
#define EXOSPHERE_FLAGS_DEFAULT (EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV)
typedef struct {
unsigned int magic;
@@ -52,6 +53,7 @@ unsigned int exosphere_get_target_firmware(void);
unsigned int exosphere_should_perform_620_keygen(void);
unsigned int exosphere_should_override_debugmode_priv(void);
unsigned int exosphere_should_override_debugmode_user(void);
unsigned int exosphere_should_disable_usermode_exception_handlers(void);
static inline unsigned int exosphere_get_target_firmware_for_init(void) {
const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG_PHYS.magic;

View File

@@ -140,13 +140,19 @@ void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint6
carveout->size_big_pages = (uint32_t)(size >> 17);
carveout->client_access_0 = (BIT(CSR_PTCR) | BIT(CSR_DISPLAY0A) | BIT(CSR_DISPLAY0AB) | BIT(CSR_DISPLAY0B) | BIT(CSR_DISPLAY0BB) | BIT(CSR_DISPLAY0C) | BIT(CSR_DISPLAY0CB) | BIT(CSR_AFIR) | BIT(CSR_DISPLAYHC) | BIT(CSR_DISPLAYHCB) | BIT(CSR_HDAR) | BIT(CSR_HOST1XDMAR) | BIT(CSR_HOST1XR) | BIT(CSR_NVENCSRD) | BIT(CSR_PPCSAHBDMAR) | BIT(CSR_PPCSAHBSLVR));
carveout->client_access_1 = (BIT(CSR_MPCORER) | BIT(CSW_NVENCSWR) | BIT(CSW_AFIW) | BIT(CSW_HDAW) | BIT(CSW_HOST1XW) | BIT(CSW_MPCOREW) | BIT(CSW_PPCSAHBDMAW) | BIT(CSW_PPCSAHBSLVW));
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW) | BIT(CSR_TSECSRD) | BIT(CSW_TSECSWR));
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_NVDECSRD) | BIT(CSW_NVDECSWR) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR));
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) {
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_NVDECSRD) | BIT(CSW_NVDECSWR) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR) | BIT(CSR_TSECSRDB) | BIT(CSW_TSECSWRB));
} else {
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW) | BIT(CSR_TSECSRD) | BIT(CSW_TSECSWR));
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_NVDECSRD) | BIT(CSW_NVDECSWR) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR));
}
carveout->client_force_internal_access_0 = ((exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) && (carveout_id == 4)) ? BIT(CSR_AVPCARM7R) : 0;
carveout->client_force_internal_access_1 = ((exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) && (carveout_id == 4)) ? BIT(CSW_AVPCARM7W) : 0;
carveout->client_force_internal_access_2 = 0;
carveout->client_force_internal_access_3 = 0;
carveout->client_force_internal_access_4 = 0;
carveout->config = 0x8B;
carveout->config = (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) ? 0x4CB : 0x8B;
}

View File

@@ -144,6 +144,7 @@ static void setup_se(void) {
master_kek_source_ind = MASTERKEY_REVISION_620 - MASTERKEY_REVISION_620;
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
master_kek_source_ind = MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_620;
break;
default:
@@ -179,6 +180,7 @@ static void setup_se(void) {
case ATMOSPHERE_TARGET_FIRMWARE_600:
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
break;
}
@@ -334,10 +336,15 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
}
/* Ensure no overlap with later sections. */
for (unsigned int later_section = section + 1; later_section < PACKAGE2_SECTION_MAX; later_section++) {
uint32_t later_section_end = metadata->section_offsets[later_section] + metadata->section_sizes[later_section];
if (overlaps(metadata->section_offsets[section], section_end, metadata->section_offsets[later_section], later_section_end)) {
return false;
if (metadata->section_sizes[section] != 0) {
for (unsigned int later_section = section + 1; later_section < PACKAGE2_SECTION_MAX; later_section++) {
if (metadata->section_sizes[later_section] == 0) {
continue;
}
uint32_t later_section_end = metadata->section_offsets[later_section] + metadata->section_sizes[later_section];
if (overlaps(metadata->section_offsets[section], section_end, metadata->section_offsets[later_section], later_section_end)) {
return false;
}
}
}
@@ -390,7 +397,7 @@ static uint32_t decrypt_and_validate_header(package2_header_t *header) {
}
/* Ensure we successfully decrypted the header. */
if (mkey_rev > mkey_get_revision()) {
if (mkey_rev > mkey_get_revision()) {
panic(0xFAF00003);
}
} else if (!validate_package2_metadata(&header->metadata)) {
@@ -487,6 +494,7 @@ static void copy_warmboot_bin_to_dram() {
warmboot_src = (uint8_t *)0x4003D800;
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
warmboot_src = (uint8_t *)0x4003E000;
break;
}
@@ -530,6 +538,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Load Exosphere-specific config. */
exosphere_load_config();
configitem_set_debugmode_override(exosphere_should_override_debugmode_user() != 0, exosphere_should_override_debugmode_priv() != 0);
if (exosphere_should_disable_usermode_exception_handlers() != 0) {
configitem_disable_usermode_exception_handlers();
}
/* Setup the Security Engine. */
setup_se();
@@ -554,6 +565,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
MAKE_REG32(PMC_BASE + 0x360) = 0xA8;
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
MAKE_REG32(PMC_BASE + 0x360) = 0x129;
break;
}

View File

@@ -44,11 +44,11 @@
#undef u8
#undef u32
static void configure_battery_hi_z_mode(void) {
static void configure_battery_hiz_mode(void) {
clkrst_reboot(CARDEVICE_I2C1);
if (configitem_should_profile_battery() && !i2c_query_ti_charger_bit_7()) {
/* Profile the battery. */
if (configitem_is_hiz_mode_enabled() && !i2c_query_ti_charger_bit_7()) {
/* Configure HiZ mode. */
i2c_set_ti_charger_bit_7();
uint32_t start_time = get_time();
bool should_wait = true;
@@ -109,7 +109,7 @@ static void mitigate_jamais_vu(void) {
}
/* Jamais Vu mitigation #3: Ensure all relevant DMA controllers are held in reset. */
if ((CLK_RST_CONTROLLER_RST_DEVICES_H_0 & 0x4000004) != 0x4000004) {
if ((CLK_RST_CONTROLLER_RST_DEVICES_H_0 & 0x4000006) != 0x4000006) {
generic_panic();
}
}
@@ -262,7 +262,7 @@ uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argumen
}
/* Perform I2C comms with TI charger if required. */
configure_battery_hi_z_mode();
configure_battery_hiz_mode();
/* Enable LP0 Wake Event Detection. */
enable_lp0_wake_events();

View File

@@ -38,11 +38,6 @@
#include "sc7.h"
#include "exocfg.h"
#define SMC_USER_HANDLERS 0x13
#define SMC_PRIV_HANDLERS 0x9
#define SMC_AMS_HANDLERS 0x2
#define DEBUG_LOG_SMCS 0
#define DEBUG_PANIC_ON_FAILURE 0
@@ -83,8 +78,12 @@ uint32_t smc_read_write_register(smc_args_t *args);
/* Atmosphere SMC prototypes */
uint32_t smc_ams_iram_copy(smc_args_t *args);
/* TODO: Provide a way to set this. It's 0 on non-recovery boot anyway... */
static uint32_t g_smc_blacklist_mask = 0;
typedef struct {
uint32_t id;
uint32_t blacklist_mask;
uint32_t (*handler)(smc_args_t *args);
} smc_table_entry_t;
@@ -93,45 +92,49 @@ typedef struct {
uint32_t num_handlers;
} smc_table_t;
static smc_table_entry_t g_smc_user_table[SMC_USER_HANDLERS] = {
{0, NULL},
{0xC3000401, smc_set_config_user},
{0xC3000002, smc_get_config_user},
{0xC3000003, smc_check_status},
{0xC3000404, smc_get_result},
{0xC3000E05, smc_exp_mod},
{0xC3000006, smc_get_random_bytes_for_user},
{0xC3000007, smc_generate_aes_kek},
{0xC3000008, smc_load_aes_key},
{0xC3000009, smc_crypt_aes},
{0xC300000A, smc_generate_specific_aes_key},
{0xC300040B, smc_compute_cmac},
{0xC300100C, smc_load_rsa_oaep_key},
{0xC300100D, smc_decrypt_rsa_private_key},
{0xC300100E, smc_load_secure_exp_mod_key},
{0xC300060F, smc_secure_exp_mod},
{0xC3000610, smc_unwrap_rsa_oaep_wrapped_titlekey},
{0xC3000011, smc_load_titlekey},
{0xC3000012, smc_unwrap_aes_wrapped_titlekey}
static smc_table_entry_t g_smc_user_table[] = {
{0, 4, NULL},
{0xC3000401, 4, smc_set_config_user},
{0xC3000002, 1, smc_get_config_user},
{0xC3000003, 1, smc_check_status},
{0xC3000404, 1, smc_get_result},
{0xC3000E05, 4, smc_exp_mod},
{0xC3000006, 1, smc_get_random_bytes_for_user},
{0xC3000007, 1, smc_generate_aes_kek},
{0xC3000008, 1, smc_load_aes_key},
{0xC3000009, 1, smc_crypt_aes},
{0xC300000A, 1, smc_generate_specific_aes_key},
{0xC300040B, 1, smc_compute_cmac},
{0xC300100C, 1, smc_load_rsa_oaep_key},
{0xC300100D, 2, smc_decrypt_rsa_private_key},
{0xC300100E, 4, smc_load_secure_exp_mod_key},
{0xC300060F, 2, smc_secure_exp_mod},
{0xC3000610, 4, smc_unwrap_rsa_oaep_wrapped_titlekey},
{0xC3000011, 4, smc_load_titlekey},
{0xC3000012, 4, smc_unwrap_aes_wrapped_titlekey}
};
#define SMC_USER_HANDLERS (sizeof(g_smc_user_table) / sizeof(g_smc_user_table[0]))
static smc_table_entry_t g_smc_priv_table[SMC_PRIV_HANDLERS] = {
{0, NULL},
{0xC4000001, smc_cpu_suspend},
{0x84000002, smc_cpu_off},
{0xC4000003, smc_cpu_on},
{0xC3000004, smc_get_config_priv},
{0xC3000005, smc_get_random_bytes_for_priv},
{0xC3000006, smc_panic},
{0xC3000007, smc_configure_carveout},
{0xC3000008, smc_read_write_register}
static smc_table_entry_t g_smc_priv_table[] = {
{0, 4, NULL},
{0xC4000001, 4, smc_cpu_suspend},
{0x84000002, 4, smc_cpu_off},
{0xC4000003, 1, smc_cpu_on},
{0xC3000004, 1, smc_get_config_priv},
{0xC3000005, 1, smc_get_random_bytes_for_priv},
{0xC3000006, 1, smc_panic},
{0xC3000007, 1, smc_configure_carveout},
{0xC3000008, 1, smc_read_write_register}
};
#define SMC_PRIV_HANDLERS (sizeof(g_smc_priv_table) / sizeof(g_smc_priv_table[0]))
/* This is a table used for atmosphere-specific SMCs. */
static smc_table_entry_t g_smc_ams_table[SMC_AMS_HANDLERS] = {
{0, NULL},
{0xF0000201, smc_ams_iram_copy},
static smc_table_entry_t g_smc_ams_table[] = {
{0, 4, NULL},
{0xF0000201, 0, smc_ams_iram_copy},
{0xF0000002, 0, smc_read_write_register},
};
#define SMC_AMS_HANDLERS (sizeof(g_smc_ams_table) / sizeof(g_smc_ams_table[0]))
static smc_table_t g_smc_tables[SMC_HANDLER_COUNT + 1] = {
{ /* SMC_HANDLER_USER */
@@ -177,6 +180,7 @@ void set_version_specific_smcs(void) {
case ATMOSPHERE_TARGET_FIRMWARE_600:
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
/* No more LoadSecureExpModKey. */
g_smc_user_table[0xE].handler = NULL;
g_smc_user_table[0xC].id = 0xC300D60C;
@@ -292,13 +296,17 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
#endif
/* Call function. */
args->X[0] = smc_handler(args);
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_800 ||
(g_smc_tables[handler_id].handlers[smc_id].blacklist_mask & g_smc_blacklist_mask) == 0) {
args->X[0] = smc_handler(args);
} else {
/* Call not allowed due to current boot conditions. */
args->X[0] = 6;
}
#if DEBUG_LOG_SMCS
if (handler_id == SMC_HANDLER_USER) {
*(volatile smc_args_t *)(get_iram_address_for_debug() + 0x100 + ((0x80 * num + 0x40) & 0x3FFF)) = *args;
/*if (num >= 0x69) {
panic(PANIC_REBOOT);
}*/
}
#endif

View File

@@ -51,6 +51,7 @@ static bool is_user_keyslot_valid(unsigned int keyslot) {
case ATMOSPHERE_TARGET_FIRMWARE_600:
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
default:
return keyslot <= 5;
}

View File

@@ -37,8 +37,8 @@ __attribute__ ((noreturn)) void panic(uint32_t code) {
SAVE_SYSREG64(ELR_EL3, 0x18);
SAVE_SYSREG64(FAR_EL3, 0x20);
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x450ull) = 0x2;
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x400ull) = 0x10;
*/
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x400ull) = 0x10; */
/* TODO: Custom Panic Driver, which displays to screen without rebooting. */
/* For now, just use NX BOOTLOADER's panic. */
@@ -68,9 +68,9 @@ __attribute__ ((noreturn)) void panic_predefined(uint32_t which) {
__attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be)
{
if(as <= bs && bs <= ae)
if(as <= bs && bs < ae)
return true;
if(bs <= as && as <= be)
if(bs <= as && as < be)
return true;
return false;
}

View File

@@ -67,8 +67,8 @@ void init_dma_controllers(unsigned int target_firmware) {
/* MSELECT_CONFIG_0 |= WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */
MAKE_REG32(0x50060000) |= 0x38000000;
/* AHB_ARBITRATION_DISABLE_0 - Disables USB and USB2 from arbitration */
MAKE_REG32(0x6000C004) = 0x40040;
/* AHB_ARBITRATION_DISABLE_0 - Disables USB, USB2, and AHB-DMA from arbitration */
MAKE_REG32(0x6000C004) = 0x40060;
/* AHB_ARBITRATION_PRIORITY_CTRL_0 - Select high prio group with prio 7 */
MAKE_REG32(0x6000C008) = 0xE0000001;

View File

@@ -39,6 +39,17 @@ uintptr_t get_warmboot_main_stack_address(void) {
return TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x780;
}
static void warmboot_configure_hiz_mode(void) {
/* Enable input to I2C1 */
PINMUX_AUX_GEN1_I2C_SCL_0 = 0x40;
PINMUX_AUX_GEN1_I2C_SDA_0 = 0x40;
clkrst_reboot(CARDEVICE_I2C1);
i2c_init(0);
i2c_clear_ti_charger_bit_7();
clkrst_disable(CARDEVICE_I2C1);
}
void __attribute__((noreturn)) warmboot_main(void) {
/*
This function and its callers are reached in either of the following events, under normal conditions:
@@ -79,15 +90,10 @@ void __attribute__((noreturn)) warmboot_main(void) {
/* Make PMC (2.x+), MC (4.x+) registers secure-only */
secure_additional_devices();
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_400 || configitem_get_hardware_type() == 0) {
/* Enable input to I2C1 */
PINMUX_AUX_GEN1_I2C_SCL_0 = 0x40;
PINMUX_AUX_GEN1_I2C_SDA_0 = 0x40;
clkrst_reboot(CARDEVICE_I2C1);
i2c_init(0);
i2c_clear_ti_charger_bit_7();
clkrst_disable(CARDEVICE_I2C1);
if ((exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_400) ||
((exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_800) && configitem_get_hardware_type() == 0) ||
(configitem_is_hiz_mode_enabled())) {
warmboot_configure_hiz_mode();
}
clear_user_smc_in_progress();

View File

@@ -90,9 +90,6 @@ static void setup_env(void) {
/* Initialize hardware. */
nx_hwinit();
/* Check for panics. */
check_and_display_panic();
/* Zero-fill the framebuffer and register it as printk provider. */
video_init(g_framebuffer);
@@ -138,6 +135,9 @@ int main(void) {
/* Initialize the display, console, etc. */
setup_env();
/* Check for panics. */
check_and_display_panic();
/* Load the BCT0 configuration ini off of the SD. */
bct0 = load_config();

View File

@@ -14,15 +14,78 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "panic.h"
#include "di.h"
#include "pmc.h"
#include "fuse.h"
#include "utils.h"
#include "fs_utils.h"
#include "lib/log.h"
static uint32_t g_panic_code = 0;
static const char *get_error_desc_str(uint32_t error_desc) {
switch (error_desc) {
case 0x100:
return "Instruction Abort";
case 0x101:
return "Data Abort";
case 0x102:
return "PC Misalignment";
case 0x103:
return "SP Misalignment";
case 0x104:
return "Trap";
case 0x106:
return "SError";
case 0x301:
return "Bad SVC";
case 0xFFE:
return "std::abort() called";
default:
return "Unknown";
}
}
static void _check_and_display_atmosphere_fatal_error(void) {
/* Check for valid magic. */
if (ATMOSPHERE_FATAL_ERROR_CONTEXT->magic != ATMOSPHERE_REBOOT_TO_FATAL_MAGIC &&
ATMOSPHERE_FATAL_ERROR_CONTEXT->magic != ATMOSPHERE_REBOOT_TO_FATAL_MAGIC_0) {
return;
}
{
/* Copy fatal error context to the stack. */
atmosphere_fatal_error_ctx ctx = *(ATMOSPHERE_FATAL_ERROR_CONTEXT);
/* Change magic to invalid, to prevent double-display of error/bootlooping. */
ATMOSPHERE_FATAL_ERROR_CONTEXT->magic = 0xCCCCCCCC;
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "A fatal error occurred when running Atmosph\xe8re.\n");
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Title ID: %016llx\n", ctx.title_id);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Error Desc: %s (0x%x)\n", get_error_desc_str(ctx.error_desc), ctx.error_desc);
/* Save context to the SD card. */
{
char filepath[0x40];
snprintf(filepath, sizeof(filepath) - 1, "/atmosphere/fatal_errors/report_%016llx.bin", ctx.report_identifier);
filepath[sizeof(filepath)-1] = 0;
write_to_file(&ctx, sizeof(ctx), filepath);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"Report saved to %s\n", filepath);
}
/* Display error. */
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"\nPress POWER to reboot\n");
}
wait_for_button_and_reboot();
}
void check_and_display_panic(void) {
/* Handle a panic sent via a stratosphere module. */
_check_and_display_atmosphere_fatal_error();
/* We also handle our own panics. */
/* In the case of our own panics, we assume that the display has already been initialized. */
bool has_panic = APBDEV_PMC_RST_STATUS_0 != 0 || g_panic_code != 0;

View File

@@ -28,6 +28,45 @@
#define PANIC_CODE_SAFEMODE 0x00000020
#define AMS_FATAL_ERROR_MAX_STACKTRACE 0x20
#define AMS_FATAL_ERROR_MAX_STACKDUMP 0x100
/* Atmosphere reboot-to-fatal-error. */
typedef struct {
uint32_t magic;
uint32_t error_desc;
uint64_t title_id;
union {
uint64_t gprs[32];
struct {
uint64_t _gprs[29];
uint64_t fp;
uint64_t lr;
uint64_t sp;
};
};
uint64_t pc;
uint64_t module_base;
uint32_t pstate;
uint32_t afsr0;
uint32_t afsr1;
uint32_t esr;
uint64_t far;
uint64_t report_identifier; /* Normally just system tick. */
uint64_t stack_trace_size;
uint64_t stack_dump_size;
uint64_t stack_trace[AMS_FATAL_ERROR_MAX_STACKTRACE];
uint8_t stack_dump[AMS_FATAL_ERROR_MAX_STACKDUMP];
} atmosphere_fatal_error_ctx;
/* "AFE1" */
#define ATMOSPHERE_REBOOT_TO_FATAL_MAGIC 0x31454641
/* "AFE0" */
#define ATMOSPHERE_REBOOT_TO_FATAL_MAGIC_0 0x30454641
#define ATMOSPHERE_FATAL_ERROR_CONTEXT ((volatile atmosphere_fatal_error_ctx *)(0x4003E000))
void check_and_display_panic(void);
__attribute__ ((noreturn)) void panic(uint32_t code);

View File

@@ -668,7 +668,7 @@ static int sdmmc_int_clk_enable(sdmmc_t *sdmmc)
/* Clock failed to stabilize. */
if (is_timeout) {
sdmmc_error(sdmmc, "clock never stabilized!");
sdmmc_error(sdmmc, "Clock never stabilized!");
return 0;
}
@@ -1202,6 +1202,9 @@ void sdmmc_finish(sdmmc_t *sdmmc)
/* Power cycle for 100ms without power. */
mdelay(100);
/* Disable the regulator. */
max77620_regulator_enable(REGULATOR_LDO2, 0);
}
/* Force a register read to refresh the clock control value. */
@@ -1350,8 +1353,11 @@ static int sdmmc_dma_init(sdmmc_t *sdmmc, sdmmc_request_t *req)
{
/* Invalid block count or size. */
if (!req->blksz || !req->num_blocks)
{
sdmmc_error(sdmmc, "Empty DMA request!");
return 0;
}
uint32_t blkcnt = req->num_blocks;
/* Truncate block count. Length can't be over 65536 bytes. */
@@ -1363,8 +1369,11 @@ static int sdmmc_dma_init(sdmmc_t *sdmmc, sdmmc_request_t *req)
/* DMA buffer address must be aligned to 4 bytes. */
if ((4 - (dma_base_addr & 0x03)) & 0x03)
{
sdmmc_error(sdmmc, "Invalid DMA request data buffer: 0x%08X", dma_base_addr);
return 0;
}
/* Write our address to the registers. */
if (sdmmc->use_adma)
{

View File

@@ -84,7 +84,7 @@ ifneq ($(BUILD),$(notdir $(CURDIR)))
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export KIPDIRS := $(AMS)/stratosphere/loader $(AMS)/stratosphere/pm $(AMS)/stratosphere/sm $(AMS)/stratosphere/boot $(AMS)/stratosphere/ams_mitm
export KIPDIRS := $(AMS)/stratosphere/loader $(AMS)/stratosphere/pm $(AMS)/stratosphere/sm $(AMS)/stratosphere/boot $(AMS)/stratosphere/spl $(AMS)/stratosphere/ams_mitm
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
$(AMS)/exosphere $(AMS)/exosphere/lp0fw $(AMS)/exosphere/rebootstub \
@@ -96,7 +96,7 @@ export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
KIPFILES := loader.kip pm.kip sm.kip ams_mitm.kip boot_100.kip boot_200.kip
KIPFILES := loader.kip pm.kip sm.kip ams_mitm.kip spl.kip boot.kip
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary.bin \
exosphere.bin lp0fw.bin rebootstub.bin thermosphere.bin splash_screen.bmp \
sept-primary.bin sept-secondary.enc \

View File

@@ -220,10 +220,8 @@ SECTIONS
======================= */
PROVIDE(__ams_mitm_kip_start__ = ams_mitm_kip - __start__);
PROVIDE(__ams_mitm_kip_size__ = ams_mitm_kip_end - ams_mitm_kip);
PROVIDE(__boot_100_kip_start__ = boot_100_kip - __start__);
PROVIDE(__boot_100_kip_size__ = boot_100_kip_end - boot_100_kip);
PROVIDE(__boot_200_kip_start__ = boot_200_kip - __start__);
PROVIDE(__boot_200_kip_size__ = boot_200_kip_end - boot_200_kip);
PROVIDE(__boot_kip_start__ = boot_kip - __start__);
PROVIDE(__boot_kip_size__ = boot_kip_end - boot_kip);
PROVIDE(__exosphere_bin_start__ = exosphere_bin - __start__);
PROVIDE(__exosphere_bin_size__ = exosphere_bin_end - exosphere_bin);
PROVIDE(__fusee_primary_bin_start__ = fusee_primary_bin - __start__);
@@ -242,6 +240,8 @@ SECTIONS
PROVIDE(__sept_secondary_enc_size__ = sept_secondary_enc_end - sept_secondary_enc);
PROVIDE(__sm_kip_start__ = sm_kip - __start__);
PROVIDE(__sm_kip_size__ = sm_kip_end - sm_kip);
PROVIDE(__spl_kip_start__ = spl_kip - __start__);
PROVIDE(__spl_kip_size__ = spl_kip_end - spl_kip);
PROVIDE(__splash_screen_bmp_start__ = splash_screen_bmp - __start__);
PROVIDE(__splash_screen_bmp_size__ = splash_screen_bmp_end - splash_screen_bmp);
PROVIDE(__thermosphere_bin_start__ = thermosphere_bin - __start__);

View File

@@ -24,10 +24,11 @@
/* "EXO0" */
#define MAGIC_EXOSPHERE_CONFIG (0x304F5845)
#define EXOSPHERE_FLAGS_DEFAULT 0x00000000
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u)
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u)
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
#define EXOSPHERE_FLAGS_DEFAULT (EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV)
typedef struct {
unsigned int magic;
@@ -41,5 +42,6 @@ typedef struct {
#define EXOSPHERE_TARGETFW_KEY "target_firmware"
#define EXOSPHERE_DEBUGMODE_PRIV_KEY "debugmode"
#define EXOSPHERE_DEBUGMODE_USER_KEY "debugmode_user"
#define EXOSPHERE_DISABLE_USERMODE_EXCEPTION_HANDLERS_KEY "disable_user_exception_handlers"
#endif

View File

@@ -41,6 +41,10 @@ typedef struct {
typedef struct {
uint8_t hash[0x20]; /* TODO: Come up with a better way to identify kernels, that doesn't rely on hashing them. */
size_t hash_offset; /* Start hashing at offset N, if this is set. */
size_t hash_size; /* Only hash the first N bytes of the kernel, if this is set. */
size_t embedded_ini_offset; /* 8.0.0+ embeds the INI in kernel section. */
size_t embedded_ini_ptr; /* 8.0.0+ embeds the INI in kernel section. */
size_t free_code_space_offset;
unsigned int num_patches;
const kernel_patch_t *patches;
@@ -366,11 +370,67 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(700, proc_id_send)[] = {0xA9BF
static const uint8_t MAKE_KERNEL_PATTERN_NAME(700, proc_id_recv)[] = {0x68, 0x03, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0xE0, 0x03, 0x1B, 0xAA, 0x00, 0x01, 0x3F, 0xD6, 0xA9, 0x83, 0x50, 0xF8, 0xE8, 0x03, 0x16, 0x2A, 0xD6, 0x0A, 0x00, 0x11};
static const instruction_t MAKE_KERNEL_PATCH_NAME(700, proc_id_recv)[] = {0xA9BF2FEA, 0xF9404FEB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
/*
stp x10, x11, [sp, #-0x10]!
ldr x11, [sp, #0x70]
mov w10, w25
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, [x21]
ldr x8, [x8, #0x38]
mov x0, x21
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(800, proc_id_send)[] = {0xA8, 0x02, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0xE0, 0x03, 0x15, 0xAA, 0x00, 0x01, 0x3F, 0xD6, 0xE8, 0x03, 0x19, 0x2A, 0x39, 0x0B, 0x00, 0x11, 0x08, 0xF5, 0x7E, 0xD3};
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, proc_id_send)[] = {0xA9BF2FEA, 0xF9403BEB, 0x2A1903EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
/*
stp x10, x11, [sp, #-0x10]!
ldr x11, [sp, #0x98]
mov w10, w22
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, [x27]
ldr x8, [x8, #0x38]
mov x0, x27
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(800, proc_id_recv)[] = {0x68, 0x03, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0xE0, 0x03, 0x1B, 0xAA, 0x00, 0x01, 0x3F, 0xD6, 0xA9, 0x83, 0x50, 0xF8, 0xE8, 0x03, 0x16, 0x2A, 0xD6, 0x0A, 0x00, 0x11};
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, proc_id_recv)[] = {0xA9BF2FEA, 0xF9404FEB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
/* svcControlCodeMemory Patches */
/* 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(600, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(700, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, svc_control_codememory)[] = {MAKE_NOP};
/* Hook Definitions. */
static const kernel_patch_t g_kernel_patches_100[] = {
@@ -532,6 +592,29 @@ static const kernel_patch_t g_kernel_patches_700[] = {
.patch_offset = 0x3C6E0,
}
};
static const kernel_patch_t g_kernel_patches_800[] = {
{ /* Send Message Process ID Patch. */
.pattern_size = 0x1C,
.pattern = MAKE_KERNEL_PATTERN_NAME(800, proc_id_send),
.pattern_hook_offset = 0x0,
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(800, proc_id_send))/sizeof(instruction_t),
.branch_back_offset = 0x10,
.payload = MAKE_KERNEL_PATCH_NAME(800, proc_id_send)
},
{ /* Receive Message Process ID Patch. */
.pattern_size = 0x1C,
.pattern = MAKE_KERNEL_PATTERN_NAME(800, proc_id_recv),
.pattern_hook_offset = 0x0,
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(800, proc_id_recv))/sizeof(instruction_t),
.branch_back_offset = 0x10,
.payload = MAKE_KERNEL_PATCH_NAME(800, proc_id_recv)
},
{ /* svcControlCodeMemory Patch. */
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(800, svc_control_codememory))/sizeof(instruction_t),
.payload = MAKE_KERNEL_PATCH_NAME(800, svc_control_codememory),
.patch_offset = 0x3FAD0,
}
};
#define KERNEL_PATCHES(vers) .num_patches = sizeof(g_kernel_patches_##vers)/sizeof(kernel_patch_t), .patches = g_kernel_patches_##vers,
@@ -581,6 +664,15 @@ static const kernel_info_t g_kernel_infos[] = {
.hash = {0xA2, 0x5E, 0x47, 0x0C, 0x8E, 0x6D, 0x2F, 0xD7, 0x5D, 0xAD, 0x24, 0xD7, 0xD8, 0x24, 0x34, 0xFB, 0xCD, 0x77, 0xBB, 0xE6, 0x66, 0x03, 0xCB, 0xAF, 0xAB, 0x85, 0x45, 0xA0, 0x91, 0xAF, 0x34, 0x25},
.free_code_space_offset = 0x5FEC0,
KERNEL_PATCHES(700)
},
{ /* 8.0.0. */
.hash = {0xA6, 0xAD, 0x5D, 0x7F, 0xCF, 0x25, 0x80, 0xAE, 0xE6, 0x57, 0x9F, 0x6F, 0xC5, 0xC5, 0xF6, 0x13, 0x77, 0x23, 0xAC, 0x88, 0x79, 0x76, 0xF7, 0x25, 0x06, 0x16, 0x35, 0x3B, 0x3F, 0xA7, 0x59, 0x49},
.hash_offset = 0x1A8,
.hash_size = 0x95000 - 0x1A8,
.embedded_ini_offset = 0x95000,
.embedded_ini_ptr = 0x168,
.free_code_space_offset = 0x607F0,
KERNEL_PATCHES(800)
}
};
@@ -607,17 +699,27 @@ uint8_t *search_pattern(void *_mem, size_t mem_size, const void *_pattern, size_
const kernel_info_t *get_kernel_info(void *kernel, size_t size) {
uint8_t calculated_hash[0x20];
uint8_t calculated_partial_hash[0x20];
se_calculate_sha256(calculated_hash, kernel, size);
for (unsigned int i = 0; i < sizeof(g_kernel_infos)/sizeof(kernel_info_t); i++) {
if (memcmp(calculated_hash, g_kernel_infos[i].hash, sizeof(calculated_hash)) == 0) {
return &g_kernel_infos[i];
if (g_kernel_infos[i].hash_size == 0 || size <= g_kernel_infos[i].hash_size) {
if (memcmp(calculated_hash, g_kernel_infos[i].hash, sizeof(calculated_hash)) == 0) {
return &g_kernel_infos[i];
}
} else {
se_calculate_sha256(calculated_partial_hash, (void *)((uintptr_t)kernel + g_kernel_infos[i].hash_offset), g_kernel_infos[i].hash_size);
if (memcmp(calculated_partial_hash, g_kernel_infos[i].hash, sizeof(calculated_partial_hash)) == 0) {
return &g_kernel_infos[i];
}
}
}
return NULL;
}
void package2_patch_kernel(void *_kernel, size_t size, bool is_sd_kernel) {
void package2_patch_kernel(void *_kernel, size_t size, bool is_sd_kernel, void **out_ini1) {
const kernel_info_t *kernel_info = get_kernel_info(_kernel, size);
*out_ini1 = NULL;
/* Apply IPS patches. */
apply_kernel_ips_patches(_kernel, size);
@@ -631,6 +733,11 @@ void package2_patch_kernel(void *_kernel, size_t size, bool is_sd_kernel) {
return;
}
if (kernel_info->embedded_ini_offset != 0) {
*out_ini1 = (void *)((uintptr_t)_kernel + kernel_info->embedded_ini_offset);
*((volatile uint64_t *)((uintptr_t)_kernel + kernel_info->embedded_ini_ptr)) = (uint64_t)size;
}
/* Apply hooks and patches. */
uint8_t *kernel = (uint8_t *)_kernel;
size_t free_space_offset = kernel_info->free_code_space_offset;

View File

@@ -19,6 +19,6 @@
#include "utils.h"
void package2_patch_kernel(void *kernel, size_t kernel_size, bool is_sd_kernel);
void package2_patch_kernel(void *kernel, size_t kernel_size, bool is_sd_kernel, void **out_ini1);
#endif

View File

@@ -149,6 +149,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
desired_keyblob = MASTERKEY_REVISION_620;
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
desired_keyblob = MASTERKEY_REVISION_700_CURRENT;
break;
default:
@@ -223,6 +224,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
case ATMOSPHERE_TARGET_FIRMWARE_600:
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);

View File

@@ -39,6 +39,7 @@
extern void (*__program_exit_callback)(int rc);
static __attribute__((__aligned__(0x200))) stage2_args_t g_stage2_args_store;
static stage2_args_t *g_stage2_args;
static bool g_do_nxboot;
@@ -59,10 +60,10 @@ static void setup_env(void) {
train_dram();
}
static void cleanup_env(void) {
/* Unmount everything (this causes all open files to be flushed and closed) */
nxfs_unmount_all();
//console_end();
}
static void exit_callback(int rc) {
@@ -84,7 +85,8 @@ int main(int argc, void **argv) {
generic_panic();
}
g_stage2_args = (stage2_args_t *)argv[STAGE2_ARGV_ARGUMENT_STRUCT];
g_stage2_args = &g_stage2_args_store;
memcpy(g_stage2_args, (stage2_args_t *)argv[STAGE2_ARGV_ARGUMENT_STRUCT], sizeof(*g_stage2_args));
if (g_stage2_args->version != 0) {
generic_panic();
@@ -101,10 +103,11 @@ int main(int argc, void **argv) {
/* Load BCT0 from SD if needed. */
if (strcmp(g_stage2_args->bct0, "") == 0) {
read_from_file(g_stage2_args->bct0, sizeof(g_stage2_args->bct0) - 1, "atmosphere/BCT.ini");
if (!read_from_file(g_stage2_args->bct0, sizeof(g_stage2_args->bct0) - 1, "atmosphere/BCT.ini")) {
uint32_t bct_tmp_buf[sizeof(g_stage2_args->bct0) / sizeof(uint32_t)] = {0};
if (!read_from_file(bct_tmp_buf, sizeof(bct_tmp_buf) - 1, "atmosphere/BCT.ini")) {
fatal_error("Failed to read BCT0 from SD!\n");
}
memcpy(g_stage2_args->bct0, bct_tmp_buf, sizeof(bct_tmp_buf));
}
/* This will load all remaining binaries off of the SD. */
@@ -118,6 +121,8 @@ int main(int argc, void **argv) {
uint32_t boot_memaddr = nxboot_main();
/* Wait for the splash screen to have been displayed as long as it should be. */
splash_screen_wait_delay();
/* Cleanup environment. */
cleanup_env();
/* Finish boot. */
nxboot_finish(boot_memaddr);
} else {

View File

@@ -106,22 +106,27 @@ static int exosphere_ini_handler(void *user, const char *section, const char *na
if (strcmp(section, "exosphere") == 0) {
if (strcmp(name, EXOSPHERE_TARGETFW_KEY) == 0) {
sscanf(value, "%d", &exo_cfg->target_firmware);
}
if (strcmp(name, EXOSPHERE_DEBUGMODE_PRIV_KEY) == 0) {
} else if (strcmp(name, EXOSPHERE_DEBUGMODE_PRIV_KEY) == 0) {
sscanf(value, "%d", &tmp);
if (tmp) {
exo_cfg->flags |= EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV;
} else {
exo_cfg->flags &= ~(EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV);
}
}
if (strcmp(name, EXOSPHERE_DEBUGMODE_USER_KEY) == 0) {
} else if (strcmp(name, EXOSPHERE_DEBUGMODE_USER_KEY) == 0) {
sscanf(value, "%d", &tmp);
if (tmp) {
exo_cfg->flags |= EXOSPHERE_FLAG_IS_DEBUGMODE_USER;
} else {
exo_cfg->flags &= ~(EXOSPHERE_FLAG_IS_DEBUGMODE_USER);
}
} else if (strcmp(name, EXOSPHERE_DISABLE_USERMODE_EXCEPTION_HANDLERS_KEY) == 0) {
sscanf(value, "%d", &tmp);
if (tmp) {
exo_cfg->flags |= EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS;
} else {
exo_cfg->flags &= ~(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
}
} else {
return 0;
}
@@ -170,8 +175,10 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
fatal_error("[NXBOOT]: Unable to identify package1!\n");
}
}
case 0x0F:
case 0x0F: /* 7.0.0 - 7.0.1 */
return ATMOSPHERE_TARGET_FIRMWARE_700;
case 0x10: /* 8.0.0 */
return ATMOSPHERE_TARGET_FIRMWARE_800;
default:
fatal_error("[NXBOOT]: Unable to identify package1!\n");
}
@@ -412,7 +419,7 @@ uint32_t nxboot_main(void) {
if (!package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size)) {
fatal_error("[NXBOOT]: Failed to read the TSEC firmware from Package1loader!\n");
}
if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_700) {
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) {
tsec_fw_size = 0x3000;
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
tsec_fw_size = 0x2900;

View File

@@ -52,7 +52,8 @@ SdmmcPartitionNum g_current_emmc_partition = SDMMC_PARTITION_INVALID;
static int mmc_partition_initialize(device_partition_t *devpart) {
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
if (devpart->read_cipher != NULL || devpart->write_cipher != NULL) {
/* Allocate the crypto work buffer. */
if ((devpart->read_cipher != NULL) || (devpart->write_cipher != NULL)) {
devpart->crypto_work_buffer = memalign(16, devpart->sector_size * 16);
if (devpart->crypto_work_buffer == NULL) {
return ENOMEM;
@@ -70,6 +71,7 @@ static int mmc_partition_initialize(device_partition_t *devpart) {
g_ahb_redirect_enabled = true;
}
/* Initialize hardware. */
if (mmcpart->device == &g_sd_device) {
if (!g_sd_device_initialized) {
int rc = sdmmc_device_sd_init(mmcpart->device, &g_sd_sdmmc, SDMMC_BUS_WIDTH_4BIT, SDMMC_SPEED_SDR104) ? 0 : EIO;
@@ -94,13 +96,33 @@ static int mmc_partition_initialize(device_partition_t *devpart) {
}
static void mmc_partition_finalize(device_partition_t *devpart) {
free(devpart->crypto_work_buffer);
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
/* Finalize hardware. */
if (mmcpart->device == &g_sd_device) {
if (g_sd_device_initialized) {
sdmmc_device_finish(&g_sd_device);
g_sd_device_initialized = false;
}
devpart->initialized = false;
} else if (mmcpart->device == &g_emmc_device) {
if (g_emmc_device_initialized) {
sdmmc_device_finish(&g_emmc_device);
g_emmc_device_initialized = false;
}
devpart->initialized = false;
}
/* Disable AHB redirection if necessary. */
if (g_ahb_redirect_enabled) {
mc_disable_ahb_redirect();
g_ahb_redirect_enabled = false;
}
/* Free the crypto work buffer. */
if (devpart->crypto_work_buffer != NULL) {
free(devpart->crypto_work_buffer);
}
}
static int mmc_partition_read(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors) {

View File

@@ -16,6 +16,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <atmosphere.h>
#include "utils.h"
#include "masterkey.h"
#include "stratosphere.h"
@@ -86,10 +87,22 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
}
/* Perform any patches we want to the NX kernel. */
package2_patch_kernel(kernel, kernel_size, is_sd_kernel);
package2_patch_kernel(kernel, kernel_size, is_sd_kernel, (void *)&orig_ini1);
/* Ensure we know where embedded INI is if present, and we don't if not. */
if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) ||
(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 == NULL)) {
fatal_error("Error: inappropriate kernel embedded ini context");
}
print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilding the INI1 section...\n");
package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1);
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800) {
package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1);
} else {
/* On 8.0.0, place INI1 right after kernelldr for our sanity. */
package2->metadata.section_offsets[PACKAGE2_SECTION_INI1] = package2->metadata.section_offsets[PACKAGE2_SECTION_KERNEL] + package2->metadata.section_sizes[PACKAGE2_SECTION_KERNEL];
}
/* Perform any patches to the INI1, rebuilding it (This is where our built-in sysmodules will be added.) */
rebuilt_ini1 = package2_rebuild_ini1(orig_ini1, target_firmware);
print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilt INI1...\n");
@@ -187,10 +200,15 @@ static bool package2_validate_metadata(package2_meta_t *metadata, uint8_t data[]
}
/* Ensure no overlap with later sections. */
for (unsigned int later_section = section + 1; later_section < PACKAGE2_SECTION_MAX; later_section++) {
uint32_t later_section_end = metadata->section_offsets[later_section] + metadata->section_sizes[later_section];
if (overlaps(metadata->section_offsets[section], section_end, metadata->section_offsets[later_section], later_section_end)) {
return false;
if (metadata->section_sizes[section] != 0) {
for (unsigned int later_section = section + 1; later_section < PACKAGE2_SECTION_MAX; later_section++) {
if (metadata->section_sizes[later_section] == 0) {
continue;
}
uint32_t later_section_end = metadata->section_offsets[later_section] + metadata->section_sizes[later_section];
if (overlaps(metadata->section_offsets[section], section_end, metadata->section_offsets[later_section], later_section_end)) {
return false;
}
}
}

View File

@@ -668,7 +668,7 @@ static int sdmmc_int_clk_enable(sdmmc_t *sdmmc)
/* Clock failed to stabilize. */
if (is_timeout) {
sdmmc_error(sdmmc, "clock never stabilized!");
sdmmc_error(sdmmc, "Clock never stabilized!");
return 0;
}
@@ -1202,6 +1202,9 @@ void sdmmc_finish(sdmmc_t *sdmmc)
/* Power cycle for 100ms without power. */
mdelay(100);
/* Disable the regulator. */
max77620_regulator_enable(REGULATOR_LDO2, 0);
}
/* Force a register read to refresh the clock control value. */
@@ -1350,8 +1353,11 @@ static int sdmmc_dma_init(sdmmc_t *sdmmc, sdmmc_request_t *req)
{
/* Invalid block count or size. */
if (!req->blksz || !req->num_blocks)
{
sdmmc_error(sdmmc, "Empty DMA request!");
return 0;
}
uint32_t blkcnt = req->num_blocks;
/* Truncate block count. Length can't be over 65536 bytes. */
@@ -1363,8 +1369,11 @@ static int sdmmc_dma_init(sdmmc_t *sdmmc, sdmmc_request_t *req)
/* DMA buffer address must be aligned to 4 bytes. */
if ((4 - (dma_base_addr & 0x03)) & 0x03)
{
sdmmc_error(sdmmc, "Invalid DMA request data buffer: 0x%08X", dma_base_addr);
return 0;
}
/* Write our address to the registers. */
if (sdmmc->use_adma)
{

View File

@@ -103,20 +103,12 @@ _content_headers:
.asciz "ams_mitm"
.align 5
/* boot_100 content header */
.word __boot_100_kip_start__
.word __boot_100_kip_size__
/* boot content header */
.word __boot_kip_start__
.word __boot_kip_size__
.word CONTENT_TYPE_KIP
.word 0xCCCCCCCC
.asciz "boot_100"
.align 5
/* boot_200 content header */
.word __boot_200_kip_start__
.word __boot_200_kip_size__
.word CONTENT_TYPE_KIP
.word 0xCCCCCCCC
.asciz "boot_200"
.asciz "boot"
.align 5
/* exosphere content header */
@@ -191,6 +183,14 @@ _content_headers:
.asciz "sm"
.align 5
/* spl content header */
.word __spl_kip_start__
.word __spl_kip_size__
.word CONTENT_TYPE_KIP
.word 0xCCCCCCCC
.asciz "spl"
.align 5
/* splash_screen content header */
.word __splash_screen_bmp_start__
.word __splash_screen_bmp_size__

View File

@@ -33,8 +33,8 @@
#include "pm_kip.h"
#include "sm_kip.h"
#include "ams_mitm_kip.h"
#include "boot_100_kip.h"
#include "boot_200_kip.h"
#include "boot_kip.h"
#include "spl_kip.h"
#undef u8
#undef u32
@@ -45,18 +45,15 @@ static bool g_stratosphere_loader_enabled = true;
static bool g_stratosphere_sm_enabled = true;
static bool g_stratosphere_pm_enabled = true;
static bool g_stratosphere_ams_mitm_enabled = true;
static bool g_stratosphere_boot_enabled = false;
static bool g_stratosphere_spl_enabled = true;
static bool g_stratosphere_boot_enabled = true;
extern const uint8_t boot_100_kip[], boot_200_kip[];
extern const uint8_t loader_kip[], pm_kip[], sm_kip[], ams_mitm_kip[];
extern const uint32_t boot_100_kip_size, boot_200_kip_size;
extern const uint32_t loader_kip_size, pm_kip_size, sm_kip_size, ams_mitm_kip_size;
extern const uint8_t loader_kip[], pm_kip[], sm_kip[], spl_kip[], boot_kip[], ams_mitm_kip[];
extern const uint32_t loader_kip_size, pm_kip_size, sm_kip_size, spl_kip_size, boot_kip_size, ams_mitm_kip_size;
/* GCC doesn't consider the size as const... we have to write it ourselves. */
ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) {
const uint8_t *boot_kip = NULL;
uint32_t boot_kip_size = 0;
uint32_t num_processes = 0;
uint8_t *data;
@@ -64,14 +61,6 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) {
return g_stratosphere_ini1;
}
if (target_firmware <= ATMOSPHERE_TARGET_FIRMWARE_100) {
boot_kip = boot_100_kip;
boot_kip_size = boot_100_kip_size;
} else {
boot_kip = boot_200_kip;
boot_kip_size = boot_200_kip_size;
}
size_t size = sizeof(ini1_header_t);
/* Calculate our processes' sizes. */
@@ -90,6 +79,11 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) {
num_processes++;
}
if (g_stratosphere_spl_enabled) {
size += spl_kip_size;
num_processes++;
}
if (g_stratosphere_ams_mitm_enabled) {
size += ams_mitm_kip_size;
num_processes++;
@@ -129,6 +123,11 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) {
data += sm_kip_size;
}
if (g_stratosphere_spl_enabled) {
memcpy(data, spl_kip, spl_kip_size);
data += spl_kip_size;
}
if (g_stratosphere_ams_mitm_enabled) {
memcpy(data, ams_mitm_kip, ams_mitm_kip_size);
data += ams_mitm_kip_size;

View File

@@ -168,9 +168,9 @@ __attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
__attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be)
{
if(as <= bs && bs <= ae)
if(as <= bs && bs < ae)
return true;
if(bs <= as && as <= be)
if(bs <= as && as < be)
return true;
return false;
}

152
mesosphere/Makefile Normal file
View File

@@ -0,0 +1,152 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(MESOSPHERE_BOARD),)
export MESOSPHERE_BOARD := nintendo-switch
endif
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
ifneq ($(BUILD),$(notdir $(CURDIR)))
export CONFIG_DIR := $(CURDIR)/config
ifeq ($(MESOSPHERE_BOARD),nintendo-switch)
export BOARD_MAKE_DIR := $(CURDIR)/config/board/nintendo/switch
export ARCH_MAKE_DIR := $(CURDIR)/config/arch/arm64
endif
endif
include $(CONFIG_DIR)/rules.mk
include $(CONFIG_DIR)/common.mk
include $(ARCH_MAKE_DIR)/arch.mk
include $(BOARD_MAKE_DIR)/board.mk
SOURCES := $(COMMON_SOURCES_DIRS) $(ARCH_SOURCE_DIRS) $(BOARD_SOURCE_DIRS)
DATA := data
INCLUDES := include ../common/include
DEFINES := $(COMMON_DEFINES) $(ARCH_DEFINES) $(BOARD_DEFINES)
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
SETTING := $(COMMON_SETTING) $(ARCH_SETTING) $(BOARD_SETTING)
CFLAGS := $(SETTING) $(DEFINES) $(COMMON_CFLAGS) $(ARCH_CFLAGS) $(BOARD_CFLAGS)
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) $(COMMON_CXXFLAGS) $(ARCH_CXXFLAGS) $(BOARD_CXXFLAGS)
ASFLAGS := -g $(SETTING)
LDFLAGS = -specs=$(ARCH_MAKE_DIR)/linker.specs $(SETTING) $(COMMON_LDFLAGS)
LIBS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all : $(OUTPUT).bin
$(OUTPUT).bin : $(OUTPUT).elf
$(OBJCOPY) -S -O binary $< $@
@echo built ... $(notdir $@)
$(OUTPUT).elf : $(OFILES)
%.elf:
@echo linking $(notdir $@)
$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
@$(NM) -CSn $@ > $(notdir $*.lst)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

9
mesosphere/README.md Normal file
View File

@@ -0,0 +1,9 @@
# Mesosphère
**WORK IN PROGRESS**
Special thanks to:
* @gdkchan ([Ryujinx](https://github.com/Ryujinx/Ryujinx)'s author), without whom I would have been unable to understand many complex mechanisms of the Horizon kernel, such as the scheduler, etc. Ryujinx's kernel HLE is pretty accurate, and of course part of this work has strong similarites to Ryujinx's kernel code.
* @fincs, who helped me in the kernel reverse-engineering process a lot as well, and with countless other things too.

View File

@@ -0,0 +1,25 @@
ifeq ($(strip $(DEVKITPRO)),)
PREFIX := aarch64-none-elf-
export CC := $(PREFIX)gcc
export CXX := $(PREFIX)g++
export AS := $(PREFIX)as
export AR := $(PREFIX)gcc-ar
export OBJCOPY := $(PREFIX)objcopy
ISVC=$(or $(VCBUILDHELPER_COMMAND),$(MSBUILDEXTENSIONSPATH32),$(MSBUILDEXTENSIONSPATH))
ifneq (,$(ISVC))
ERROR_FILTER := 2>&1 | sed -e 's/\(.[a-zA-Z]\+\):\([0-9]\+\):/\1(\2):/g'
endif
else
include $(DEVKITPRO)/devkitA64/base_tools
endif
ARCH_SETTING := -march=armv8-a -mgeneral-regs-only
ARCH_DEFINES := -DMESOSPHERE_ARCH_ARM64
ARCH_CFLAGS :=
ARCH_CXXFLAGS :=
ARCH_SOURCE_DIRS := source/arch/arm64

View File

@@ -0,0 +1,214 @@
OUTPUT_ARCH(aarch64)
ENTRY(_start)
/* TODO overhaul */
PHDRS
{
code PT_LOAD FLAGS(5) /* Read | Execute */;
rodata PT_LOAD FLAGS(4) /* Read */;
data PT_LOAD FLAGS(6) /* Read | Write */;
dyn PT_DYNAMIC;
}
SECTIONS
{
/* =========== CODE section =========== */
PROVIDE(__start__ = 0x0);
. = __start__;
.crt0 :
{
KEEP (*(.crt0))
. = ALIGN(8);
} :code
.init :
{
KEEP( *(.init) )
. = ALIGN(8);
} :code
.plt :
{
*(.plt)
*(.iplt)
. = ALIGN(8);
} :code
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
. = ALIGN(8);
} :code
.fini :
{
KEEP( *(.fini) )
. = ALIGN(8);
} :code
/* =========== RODATA section =========== */
. = ALIGN(0x1000);
.rodata :
{
*(.rodata .rodata.* .gnu.linkonce.r.*)
. = ALIGN(8);
} :rodata
.eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } :rodata
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } :rodata
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } :rodata
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } : rodata
.dynamic : { *(.dynamic) } :rodata :dyn
.dynsym : { *(.dynsym) } :rodata
.dynstr : { *(.dynstr) } :rodata
.rela.dyn : { *(.rela.*) } :rodata
.interp : { *(.interp) } :rodata
.hash : { *(.hash) } :rodata
.gnu.hash : { *(.gnu.hash) } :rodata
.gnu.version : { *(.gnu.version) } :rodata
.gnu.version_d : { *(.gnu.version_d) } :rodata
.gnu.version_r : { *(.gnu.version_r) } :rodata
.note.gnu.build-id : { *(.note.gnu.build-id) } :rodata
/* =========== DATA section =========== */
. = ALIGN(0x1000);
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } :data
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } :data
.gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } : data
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } :data
.tdata ALIGN(8) :
{
__tdata_lma = .;
*(.tdata .tdata.* .gnu.linkonce.td.*)
. = ALIGN(8);
__tdata_lma_end = .;
} :data
.tbss ALIGN(8) :
{
*(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon)
. = ALIGN(8);
} :data
.preinit_array ALIGN(8) :
{
PROVIDE (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE (__preinit_array_end = .);
} :data
.init_array ALIGN(8) :
{
PROVIDE (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE (__init_array_end = .);
} :data
.fini_array ALIGN(8) :
{
PROVIDE (__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE (__fini_array_end = .);
} :data
.ctors ALIGN(8) :
{
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} :data
.dtors ALIGN(8) :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} :data
__got_start__ = .;
.got : { *(.got) *(.igot) } :data
.got.plt : { *(.got.plt) *(.igot.plt) } :data
__got_end__ = .;
.data ALIGN(8) :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
} :data
__bss_start__ = .;
.bss ALIGN(8) :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(8);
/* Reserve space for the TLS segment of the main thread */
__tls_start = .;
. += + SIZEOF(.tdata) + SIZEOF(.tbss);
__tls_end = .;
} : data
__bss_end__ = .;
__end__ = ABSOLUTE(.) ;
. = ALIGN(0x1000);
__argdata__ = ABSOLUTE(.) ;
/* ==================
==== Metadata ====
================== */
/* Discard sections that difficult post-processing */
/DISCARD/ : { *(.group .comment .note) }
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
}

View File

@@ -0,0 +1,4 @@
%rename link old_link
*link:
%(old_link) -T %:getenv(ARCH_MAKE_DIR /linker.ld) -pie --gc-sections -z text -z nodynamic-undefined-weak --build-id=sha1

View File

@@ -0,0 +1,5 @@
BOARD_SETTING := -mtune=cortex-a57
BOARD_DEFINES := -DMESOSPHERE_BOARD_NINTENDO_SWITCH -DMESOSPHERE_BOARD_COMMON_ARM_ARM64_CLOCK
BOARD_CFLAGS :=
BOARD_CXXFLAGS :=
BOARD_SOURCE_DIRS :=

View File

@@ -0,0 +1,9 @@
COMMON_DEFINES := -DBOOST_DISABLE_ASSERTS
COMMON_SOURCES_DIRS := source/core source/interfaces source/interrupts source/kresources\
source/processes source/threading source
COMMON_SETTING := -fPIE -g -nostdlib
COMMON_CFLAGS := -Wall -Werror -Os -ffunction-sections -fdata-sections -fno-strict-aliasing -fwrapv\
-fno-asynchronous-unwind-tables -fno-unwind-tables -fno-stack-protector
COMMON_CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++17
COMMON_ASFLAGS :=
COMMON_LDFLAGS := -Wl,-Map,out.map

View File

@@ -0,0 +1,37 @@
#---------------------------------------------------------------------------------
%.a:
#---------------------------------------------------------------------------------
@echo $(notdir $@)
@rm -f $@
$(AR) -rc $@ $^
#---------------------------------------------------------------------------------
%.o: %.cpp
@echo $(notdir $<)
$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER)
#---------------------------------------------------------------------------------
%.o: %.c
@echo $(notdir $<)
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) -c $< -o $@ $(ERROR_FILTER)
#---------------------------------------------------------------------------------
%.o: %.s
@echo $(notdir $<)
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER)
#---------------------------------------------------------------------------------
%.o: %.S
@echo $(notdir $<)
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER)
#---------------------------------------------------------------------------------
# canned command sequence for binary data
#---------------------------------------------------------------------------------
define bin2o
bin2s $< | $(AS) -o $(@)
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' -e 's/[^A-Za-z0-9_]/_/g')`"_end[];" > `(echo $(<F) | tr . _)`.h
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' -e 's/[^A-Za-z0-9_]/_/g')`"[];" >> `(echo $(<F) | tr . _)`.h
echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' -e 's/[^A-Za-z0-9_]/_/g')`_size";" >> `(echo $(<F) | tr . _)`.h
endef

View File

@@ -0,0 +1,11 @@
#pragma once
#if 1 //defined MESOSPHERE_ARCH_ARM64
#include <mesosphere/arch/arm64/KInterruptMaskGuard.hpp>
#else
//#error "No arch defined"
#endif

View File

@@ -0,0 +1,11 @@
#pragma once
#if 1 //defined MESOSPHERE_ARCH_ARM64
#include <mesosphere/arch/arm64/KSpinLock.hpp>
#else
//#error "No arch defined"
#endif

View File

@@ -0,0 +1,11 @@
#pragma once
#if 1 //defined MESOSPHERE_ARCH_ARM64
#include <mesosphere/arch/arm64/arch.hpp>
#else
//#error "No arch defined"
#endif

View File

@@ -0,0 +1,41 @@
#pragma once
#include <mesosphere/core/util.hpp>
#include <mesosphere/arch/arm64/arch.hpp>
namespace mesosphere
{
inline namespace arch
{
inline namespace arm64
{
// Dummy. Should be platform-independent:
class KInterruptMaskGuard final {
public:
using FlagsType = u64;
KInterruptMaskGuard()
{
flags = MaskInterrupts();
}
~KInterruptMaskGuard()
{
RestoreInterrupts(flags);
}
KInterruptMaskGuard(const KInterruptMaskGuard &) = delete;
KInterruptMaskGuard(KInterruptMaskGuard &&) = delete;
KInterruptMaskGuard &operator=(const KInterruptMaskGuard &) = delete;
KInterruptMaskGuard &operator=(KInterruptMaskGuard &&) = delete;
private:
u64 flags = 0;
};
}
}
}

View File

@@ -0,0 +1,103 @@
#pragma once
#include <mutex>
namespace mesosphere
{
inline namespace arch
{
inline namespace arm64
{
// This largely uses the Linux kernel spinlock code, which is more efficient than Nintendo's (serializing two u16s into an u32).
class KSpinLock {
private:
struct alignas(4) Ticket {
u16 owner, next;
};
Ticket ticket;
public:
bool try_lock()
{
u32 tmp;
Ticket lockval;
asm volatile(
" prfm pstl1strm, %2\n"
"1: ldaxr %w0, %2\n"
" eor %w1, %w0, %w0, ror #16\n"
" cbnz %w1, 2f\n"
" add %w0, %w0, %3\n"
" stxr %w1, %w0, %2\n"
" cbnz %w1, 1b\n"
"2:"
: "=&r" (lockval), "=&r" (tmp), "+Q" (ticket)
: "I" (1 << 16)
: "memory"
);
return !tmp;
}
void lock()
{
u32 tmp;
Ticket lockval, newval;
asm volatile(
// Atomically increment the next ticket.
" prfm pstl1strm, %3\n"
"1: ldaxr %w0, %3\n"
" add %w1, %w0, %w5\n"
" stxr %w2, %w1, %3\n"
" cbnz %w2, 1b\n"
// Did we get the lock?
" eor %w1, %w0, %w0, ror #16\n"
" cbz %w1, 3f\n"
/*
No: spin on the owner. Send a local event to avoid missing an
unlock before the exclusive load.
*/
" sevl\n"
"2: wfe\n"
" ldaxrh %w2, %4\n"
" eor %w1, %w2, %w0, lsr #16\n"
" cbnz %w1, 2b\n"
// We got the lock. Critical section starts here.
"3:"
: "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*&ticket)
: "Q" (ticket.owner), "I" (1 << 16)
: "memory"
);
}
void unlock()
{
u64 tmp;
asm volatile(
" ldrh %w1, %0\n"
" add %w1, %w1, #1\n"
" stlrh %w1, %0"
: "=Q" (ticket.owner), "=&r" (tmp)
:
: "memory"
);
}
KSpinLock() = default;
KSpinLock(const KSpinLock &) = delete;
KSpinLock(KSpinLock &&) = delete;
KSpinLock &operator=(const KSpinLock &) = delete;
KSpinLock &operator=(KSpinLock &&) = delete;
};
}
}
}

View File

@@ -0,0 +1,101 @@
#pragma once
#include <boost/preprocessor.hpp>
#include <mesosphere/core/types.hpp>
#define MESOSPHERE_READ_SYSREG(r) ({\
u64 __val; \
asm volatile("mrs %0, " BOOST_PP_STRINGIZE(r) : "=r" (__val)); \
__val; \
})
#define MESOSPHERE_WRITE_SYSREG(v, r) do { \
u64 __val = (u64)v; \
asm volatile("msr " BOOST_PP_STRINGIZE(r) ", %0" \
:: "r" (__val) : "memory"); \
} while (false)
#define MESOSPHERE_DAIF_BIT(v) (((u64)(v)) >> 6)
namespace mesosphere
{
class KCoreContext;
inline namespace arch
{
inline namespace arm64
{
enum PsrMode {
PSR_MODE_EL0t = 0x0u,
PSR_MODE_EL1t = 0x4u,
PSR_MODE_EL1h = 0x5u,
PSR_MODE_EL2t = 0x8u,
PSR_MODE_EL2h = 0x9u,
PSR_MODE_EL3t = 0xCu,
PSR_MODE_EL3h = 0xDu,
PSR_MODE_MASK = 0xFu,
PSR_MODE32_BIT = 0x10u,
};
enum PsrInterruptBit {
PSR_F_BIT = 1u << 6,
PSR_I_BIT = 1u << 7,
PSR_A_BIT = 1u << 8,
PSR_D_BIT = 1u << 9,
};
enum PsrStatusBit {
PSR_PAN_BIT = 1u << 22,
PSR_UAO_BIT = 1u << 23,
};
enum PsrFlagBit {
PSR_V_BIT = 1u << 28,
PSR_C_BIT = 1u << 29,
PSR_Z_BIT = 1u << 30,
PSR_N_BIT = 1u << 31,
};
enum PsrBitGroup {
PSR_c = 0x000000FFu,
PSR_x = 0x0000FF00u,
PSR_s = 0x00FF0000u,
PSR_f = 0xFF000000u,
};
using InterruptFlagsType = u64;
static inline InterruptFlagsType MaskInterrupts()
{
InterruptFlagsType flags = MESOSPHERE_READ_SYSREG(daif);
MESOSPHERE_WRITE_SYSREG(flags | PSR_I_BIT, daif);
return flags;
}
static inline void RestoreInterrupts(InterruptFlagsType flags)
{
MESOSPHERE_WRITE_SYSREG(MESOSPHERE_READ_SYSREG(daif) | (flags & PSR_I_BIT), daif);
}
static inline KCoreContext &GetCurrentCoreContextInstance()
{
register KCoreContext *x18 asm ("x18");
return *x18;
}
static inline void ReloadCurrentCoreContextInstance()
{
asm volatile("mrs x18, tpidr_el1" ::: "x18", "memory");
}
static inline void SetCurrentCoreContextInstance(KCoreContext &cctx)
{
MESOSPHERE_WRITE_SYSREG((uiptr)&cctx, tpidr_el1);
ReloadCurrentCoreContextInstance();
}
}
}
}

View File

@@ -0,0 +1,11 @@
#pragma once
#if 1 //defined MESOSPHERE_ARCH_ARM64
#include <mesosphere/board/common/arm/arm64/timer/KSystemClock.hpp>
#else
//#error "No arch defined"
#endif

View File

@@ -0,0 +1,83 @@
#pragma once
#include <chrono>
#include <mesosphere/core/util.hpp>
#include <mesosphere/arch/arm64/arch.hpp>
#ifndef MESOSPHERE_SYSTEM_CLOCK_RATE // NEEDS to be defined; depends on cntfreq
#define MESOSPHERE_SYSTEM_CLOCK_RATE 192000000ull
#endif
// Architectural aarch64 armv8 timer
namespace mesosphere
{
inline namespace board
{
inline namespace common
{
inline namespace arm
{
inline namespace arm64
{
// Dummy implementation
// Needs to be changed for platform stuff
using namespace std::chrono_literals;
/// Fulfills Clock named requirements
class KSystemClock {
public:
using rep = s64;
using period = std::ratio<1, MESOSPHERE_SYSTEM_CLOCK_RATE>;
using duration = std::chrono::duration<rep, period>;
using time_point = std::chrono::time_point<KSystemClock>;
static constexpr bool is_steady = true;
static time_point now()
{
return time_point{duration::zero()};
}
static constexpr bool isCorePrivate = true;
static constexpr duration forever = duration{-1};
static constexpr time_point never = time_point{forever};
static constexpr uint GetIrqId() { return 30; }
static void Disable()
{
// Note: still continues counting.
MESOSPHERE_WRITE_SYSREG(0, cntp_ctl_el0);
}
static void SetInterruptMasked(bool maskInterrupts)
{
u64 val = maskInterrupts ? 3 : 1; // Note: also enables the timer.
MESOSPHERE_WRITE_SYSREG(val, cntp_ctl_el0);
}
static void SetAlarm(const time_point &when)
{
u64 val = (u64)when.time_since_epoch().count();
MESOSPHERE_WRITE_SYSREG(val, cntp_cval_el0);
SetInterruptMasked(false);
}
static void Initialize()
{
MESOSPHERE_WRITE_SYSREG(1, cntkctl_el1); // Trap register accesses from el0.
Disable();
MESOSPHERE_WRITE_SYSREG(UINT64_MAX, cntp_cval_el0);
SetInterruptMasked(true);
}
};
}
}
}
}
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <mesosphere/core/types.hpp>
namespace mesosphere
{
class Handle final {
public:
constexpr bool IsAliasOrFree() const { return isAlias || id < 0; }
constexpr bool operator==(const Handle &other) const
{
return index == other.index && id == other.id && isAlias == other.isAlias;
}
constexpr bool operator!=(const Handle &other) const { return !(*this == other); }
constexpr Handle() : index{0}, id{0}, isAlias{false} {}
private:
friend class KHandleTable;
constexpr Handle(u16 index, s16 id, bool isAlias = false) : index{index}, id{id}, isAlias{isAlias} {}
u32 index : 15;
s32 id : 16;
u32 isAlias : 1;
};
}

View File

@@ -0,0 +1,165 @@
#pragma once
#include <mesosphere/core/util.hpp>
#include <atomic>
#include <type_traits>
#define MESOSPHERE_AUTO_OBJECT_TRAITS(BaseId, DerivedId)\
using BaseClass = K##BaseId ;\
static constexpr KAutoObject::TypeId typeId = KAutoObject::TypeId::DerivedId;\
virtual ushort GetClassToken() const\
{\
return KAutoObject::GenerateClassToken<K##DerivedId >();\
}\
#define MESOSPHERE_AUTO_OBJECT_FW_DECL(BaseId)\
class K##BaseId;\
void intrusive_ptr_add_ref(K##BaseId *obj);\
void intrusive_ptr_release(K##BaseId *obj);
#define MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(BaseId)\
inline void intrusive_ptr_add_ref(K##BaseId *obj) { intrusive_ptr_add_ref((KAutoObject *)obj); }\
inline void intrusive_ptr_release(K##BaseId *obj) { intrusive_ptr_release((KAutoObject *)obj); }
namespace mesosphere
{
MESOSPHERE_AUTO_OBJECT_FW_DECL(Process);
MESOSPHERE_AUTO_OBJECT_FW_DECL(ResourceLimit);
MESOSPHERE_AUTO_OBJECT_FW_DECL(Thread);
MESOSPHERE_AUTO_OBJECT_FW_DECL(Event);
MESOSPHERE_AUTO_OBJECT_FW_DECL(ReadableEvent);
MESOSPHERE_AUTO_OBJECT_FW_DECL(WritableEvent);
MESOSPHERE_AUTO_OBJECT_FW_DECL(InterruptEvent);
MESOSPHERE_AUTO_OBJECT_FW_DECL(LightSession);
MESOSPHERE_AUTO_OBJECT_FW_DECL(LightClientSession);
MESOSPHERE_AUTO_OBJECT_FW_DECL(LightServerSession);
MESOSPHERE_AUTO_OBJECT_FW_DECL(Port);
MESOSPHERE_AUTO_OBJECT_FW_DECL(ClientPort);
MESOSPHERE_AUTO_OBJECT_FW_DECL(ServerPort);
MESOSPHERE_AUTO_OBJECT_FW_DECL(Debug);
class KAutoObject {
public:
/// Class token for polymorphic type checking
virtual ushort GetClassToken() const
{
return 0;
}
/// Comparison key for KObjectAllocator
virtual u64 GetComparisonKey() const
{
return (u64)(uiptr)this;
}
/// Virtual destructor
virtual ~KAutoObject();
/// Check if the offset is base class of T or T itself
template<typename T>
bool IsInstanceOf() const
{
ushort btoken = GenerateClassToken<T>();
ushort dtoken = GetClassToken();
return (dtoken & btoken) == btoken;
}
// Explicitely disable copy and move, and add default ctor
KAutoObject() = default;
KAutoObject(const KAutoObject &) = delete;
KAutoObject(KAutoObject &&) = delete;
KAutoObject &operator=(const KAutoObject &) = delete;
KAutoObject &operator=(KAutoObject &&) = delete;
/// Type order as found in official kernel
enum class TypeId : ushort {
AutoObject = 0,
SynchronizationObject,
ReadableEvent,
FinalClassesMin = 3,
InterruptEvent = 3,
Debug,
ClientSession,
Thread,
Process,
Session,
ServerPort,
ResourceLimit,
SharedMemory,
LightClientSession,
ServerSession,
LightSession,
Event,
LightServerSession,
DeviceAddressSpace,
ClientPort,
Port,
WritableEvent,
TransferMemory,
SessionRequest,
CodeMemory, // JIT
Max = CodeMemory + 1,
};
private:
std::atomic<ulong> referenceCount{0}; // official kernel has u32 for this
friend void intrusive_ptr_add_ref(KAutoObject *obj);
friend void intrusive_ptr_release(KAutoObject *obj);
protected:
template<typename T>
static constexpr ushort GenerateClassToken()
{
/* The token follows these following properties:
* Multiple inheritance is not supported
* (BaseToken & DerivedToken) == BaseToken
* The token for KAutoObject is 0
* Not-final classes have a token of (1 << (typeid - 1))
* Final derived classes have a unique token part of Seq[typeid - DerivedClassMin] | 0x100,
where Seq is (in base 2) 11, 101, 110, 1001, 1010, and so on...
*/
if constexpr (std::is_same_v<T, KAutoObject>) {
return 0;
} else if constexpr (!std::is_final_v<T>) {
static_assert(T::typeId >= TypeId::SynchronizationObject && T::typeId < TypeId::FinalClassesMin, "Invalid type ID!");
return (1 << ((ushort)T::typeId - 1)) | GenerateClassToken<typename T::BaseClass>();
} else {
static_assert(T::typeId >= TypeId::FinalClassesMin && T::typeId < TypeId::Max, "Invalid type ID!");
ushort off = (ushort)T::typeId - (ushort)TypeId::FinalClassesMin;
return ((ushort)detail::A038444(off) << 9) | 0x100u | GenerateClassToken<typename T::BaseClass>();
}
}
};
inline void intrusive_ptr_add_ref(KAutoObject *obj)
{
ulong oldval = obj->referenceCount.fetch_add(1);
kassert(oldval + 1 != 0);
}
inline void intrusive_ptr_release(KAutoObject *obj)
{
ulong oldval = obj->referenceCount.fetch_sub(1);
if (oldval - 1 == 0) {
delete obj;
}
}
template <typename T>
inline SharedPtr<T> DynamicObjectCast(SharedPtr<KAutoObject> object) {
if (object != nullptr && object->IsInstanceOf<T>()) {
return boost::static_pointer_cast<T>(object);
}
return nullptr;
}
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include <array>
#include <mesosphere/core/util.hpp>
#include <mesosphere/arch/arch.hpp>
namespace mesosphere
{
class KProcess;
class KThread;
class KScheduler;
class KAlarm;
class KCoreContext {
public:
static KCoreContext &GetInstance(uint coreId) { return instances[coreId]; };
static KCoreContext &GetCurrentInstance() { return GetCurrentCoreContextInstance(); };
KThread *GetCurrentThread() const { return currentThread; }
KProcess *GetCurrentProcess() const { return currentProcess; }
KScheduler *GetScheduler() const { return scheduler; }
KAlarm *GetAlarm() const { return alarm; }
KCoreContext(KScheduler *scheduler) : scheduler(scheduler) {}
private:
KThread *volatile currentThread = nullptr;
KProcess *volatile currentProcess = nullptr;
KScheduler *volatile scheduler = nullptr;
KAlarm *volatile alarm = nullptr;
// more stuff
static std::array<KCoreContext, MAX_CORES> instances;
};
}

View File

@@ -0,0 +1,708 @@
#pragma once
#include <iterator>
#include <utility>
#include <algorithm>
#include <initializer_list>
#include <functional>
#include <type_traits>
#include <mesosphere/core/util.hpp>
#include <mesosphere/interfaces/ISlabAllocated.hpp>
namespace mesosphere
{
template<typename T>
class KLinkedList final {
private:
struct List final {
struct Node final : public ISlabAllocated<Node> {
struct Link final {
Link *prev = nullptr;
Link *next = nullptr;
Node &parent()
{
return *detail::GetParentFromMember(this, &Node::link);
}
const Node &parent() const
{
return *detail::GetParentFromMember(this, &Node::link);
}
T &data() { return parent().data; }
const T &data() const { return parent().data; }
};
Link link{};
T data{};
Node() = default;
Node(const Node &other) = default;
Node(Node &&other) = default;
explicit Node(const T &data) : ISlabAllocated<Node>(), data{data} {}
explicit Node(const T &&data) : ISlabAllocated<Node>(), data{data} {}
template<typename ...Args>
explicit Node(Args&& ...args) : ISlabAllocated<Node>(), data{std::forward<Args>(args)...} {}
};
mutable typename Node::Link link{};
typename Node::Link *last() const { return link.prev; }
typename Node::Link *first() const { return link.next; }
size_t size = 0;
};
List list;
void insert_node_after(typename List::Node::Link *pos, typename List::Node::Link *nd)
{
// if pos is last & list is empty, ->next writes to first, etc.
pos->next->prev = nd;
nd->prev = pos;
nd->next = pos->next;
pos->next = nd;
++list.size;
}
void insert_node_before(typename List::Node::Link *pos, typename List::Node::Link *nd)
{
pos->prev->next = nd;
nd->prev = pos->prev;
nd->next = pos;
pos->prev = nd;
++list.size;
}
void remove_node(typename List::Node::Link *nd)
{
nd->prev->next = nd->next;
nd->next->prev = nd->prev;
--list.size;
}
public:
template<bool isConst>
class Iterator {
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<
isConst,
typename KLinkedList::const_pointer,
typename KLinkedList::pointer
>::type;
using reference = typename std::conditional<
isConst,
typename KLinkedList::const_reference,
typename KLinkedList::reference
>::type;
bool operator==(const Iterator &other) const
{
return node == other.node;
}
bool operator!=(const Iterator &other) const
{
return !(*this == other);
}
reference operator*()
{
return node->data();
}
pointer operator->()
{
return &node->data();
}
Iterator &operator++()
{
node = node->next;
return *this;
}
Iterator &operator--() {
node = node->prev;
return *this;
}
Iterator &operator++(int) {
const Iterator v{*this};
++(*this);
return v;
}
Iterator &operator--(int) {
const Iterator v{*this};
--(*this);
return v;
}
// allow implicit const->non-const
Iterator(const Iterator<false> &other) : node{other.node} {}
friend class Iterator<true>;
Iterator() = default;
private:
friend class KLinkedList;
typename KLinkedList::List::Node::Link *node;
explicit Iterator(typename KLinkedList::List::Node::Link *node) : node{node} {}
};
using pointer = T *;
using const_pointer = const T *;
using reference = T &;
using const_reference = const T &;
using void_pointer = void *;
using const_void_ptr = const void *;
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
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>;
KLinkedList() : list{{&list.link, &list.link}} {};
explicit KLinkedList(size_t count, const T &value) : KLinkedList()
{
for (size_t i = 0; i < count; i++) {
auto *nd = new typename List::Node{value};
kassert(nd != nullptr);
insert_node_after(list.last(), &nd->link);
}
}
explicit KLinkedList(size_t count) : KLinkedList()
{
for (size_t i = 0; i < count; i++) {
auto *nd = new typename List::Node;
kassert(nd != nullptr);
insert_node_after(list.last(), &nd->link);
}
}
template<typename InputIt, typename = std::enable_if_t<!std::is_integral_v<InputIt>>>
KLinkedList(InputIt first, InputIt last) : KLinkedList()
{
for (InputIt it = first; it != last; ++it) {
auto *nd = new typename List::Node{*it};
kassert(nd != nullptr);
insert_node_after(list.last(), &nd->link);
}
}
void swap(KLinkedList &other) noexcept
{
using std::swap; // Enable ADL
swap(list.link, other.list.link);
swap(list.size, other.list.size);
list.first()->prev = list.last()->next = &list.link;
other.list.first()->prev = other.list.last()->next = &other.list.link;
}
KLinkedList(KLinkedList &&other) noexcept : KLinkedList()
{
swap(other);
}
KLinkedList(std::initializer_list<T> ilist) : KLinkedList(ilist.begin(), ilist.end()) {}
void clear() noexcept
{
typename List::Node::Link *nxt;
for (typename List::Node::Link *nd = list.first(); nd != &list.link; nd = nxt) {
nxt = nd->next;
delete &nd->parent();
}
list.size = 0;
}
~KLinkedList()
{
clear();
}
KLinkedList &operator=(KLinkedList other)
{
swap(other);
return *this;
}
KLinkedList &operator=(std::initializer_list<T> ilist)
{
KLinkedList tmp{ilist};
swap(tmp);
return *this;
}
void assign(size_t count, const T &value)
{
KLinkedList tmp{count, value};
swap(tmp);
}
template<typename InputIt, typename = std::enable_if_t<!std::is_integral_v<InputIt>>>
void assign(InputIt first, InputIt last)
{
KLinkedList tmp{first, last};
swap(tmp);
}
void assign(std::initializer_list<T> ilist)
{
KLinkedList tmp{ilist};
swap(tmp);
}
T &front() { return list.first()->data(); }
const T &front() const { return list.first()->data(); }
T &back() { return list.last()->data(); }
const T &back() const { return list.last()->data(); }
const_iterator cbegin() const noexcept { return const_iterator{list.first()}; }
const_iterator cend() const noexcept { return const_iterator{&list.link}; }
const_iterator begin() const noexcept { return cbegin(); }
const_iterator end() const noexcept { return cend(); }
iterator begin() noexcept { return iterator{list.first()}; }
iterator end() noexcept { return iterator{&list.link}; }
const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{list.last()}; }
const_reverse_iterator crend() const noexcept { return const_reverse_iterator{&list.link}; }
const_reverse_iterator rbegin() const noexcept { return crbegin(); }
const_reverse_iterator rend() const noexcept { return crend(); }
reverse_iterator rbegin() noexcept { return reverse_iterator{list.last()}; }
reverse_iterator rend() noexcept { return reverse_iterator{&list.link}; }
KLinkedList(const KLinkedList &other) : KLinkedList(other.cbegin(), other.cend()) {}
constexpr size_t size() const noexcept { return list.size; }
constexpr bool empty() const noexcept { return list.size == 0; }
iterator insert(const_iterator pos, const T &value)
{
auto *nd = new typename List::Node{value};
kassert(nd != nullptr);
insert_node_after(pos.node, &nd->link);
}
iterator insert(const_iterator pos, T &&value)
{
auto *nd = new typename List::Node{value};
kassert(nd != nullptr);
insert_node_before(pos.node, &nd->link);
return iterator{&nd->link};
}
iterator insert(const_iterator pos, size_t count, const T &value)
{
iterator ret = pos;
for (size_t i = 0; i < count; i++) {
ret = insert(ret, value);
}
return ret;
}
template<typename InputIt, typename = std::enable_if_t<!std::is_integral_v<InputIt>>>
iterator insert(const_iterator pos, InputIt first, InputIt last)
{
// Note: our list definition allows --begin() to be well defined
typename List::Node::Link *f = nullptr;
typename List::Node::Link *p = pos.node->prev;
for(InputIt it = first; it != last; ++it) {
auto *nd = new typename List::Node{*it};
kassert(nd != nullptr);
insert_node_after(p, &nd->link);
p = &nd->link;
f = f == nullptr ? p : f;
}
return iterator{f};
}
iterator insert(const_iterator pos, std::initializer_list<T> ilist)
{
return insert(pos, ilist.begin(), ilist.end());
}
template<typename ...Args>
iterator emplace(const_iterator pos, Args &&...args)
{
auto *nd = new typename List::Node{std::forward<Args>(args)...};
kassert(nd != nullptr);
insert_node_before(pos.node, &nd->link);
return iterator{&nd->link};
}
iterator erase(const_iterator pos)
{
iterator ret{pos.node->next};
remove_node(pos.node);
delete &pos.node->parent();
return ret;
}
iterator erase(const_iterator first, const_iterator last)
{
const_iterator next;
for (const_iterator it = first; it != last; it = next) {
next = erase(it);
}
return iterator{next.node};
}
void push_back(const T &value)
{
auto *nd = new typename List::Node{value};
kassert(nd != nullptr);
insert_node_after(list.last(), &nd->link);
}
void push_back(T &&value)
{
auto *nd = new typename List::Node{value};
kassert(nd != nullptr);
insert_node_after(list.last(), &nd->link);
}
template< class... Args>
T &emplace_back(Args&&... args)
{
auto *nd = new typename List::Node{std::forward<Args>(args)...};
kassert(nd != nullptr);
insert_node_after(list.last(), &nd->link);
return nd->data;
}
template< class... Args>
T *emplace_back_or_fail(Args&&... args)
{
auto *nd = new typename List::Node{std::forward<Args>(args)...};
if (nd != nullptr) {
insert_node_after(list.last(), &nd->link);
return &nd->data;
} else {
return nullptr;
}
}
void pop_back()
{
auto *nd = list.last();
remove_node(nd);
delete &nd->parent();
}
void push_front(const T &value)
{
auto *nd = new typename List::Node{value};
kassert(nd != nullptr);
insert_node_before(list.first(), &nd->link);
}
void push_front(T &&value)
{
auto *nd = new typename List::Node{value};
kassert(nd != nullptr);
insert_node_before(list.first(), &nd->link);
}
template< class... Args>
T &emplace_front(Args&&... args)
{
auto *nd = new typename List::Node{std::forward<Args>(args)...};
kassert(nd != nullptr);
insert_node_before(list.first(), &nd->link);
return nd->data;
}
void pop_front()
{
auto *nd = list.first();
remove_node(nd);
delete &nd->parent();
}
void resize(size_t count)
{
if (count < list.size) {
while (count < list.size) {
pop_back();
}
} else {
size_t s = list.size;
for (size_t i = 0; i < count - s; i++) {
auto *nd = new typename List::Node;
kassert(nd != nullptr);
insert_node_after(list.last(), &nd->link);
}
}
}
void resize(size_t count, const T &value)
{
if (count < list.size) {
while (count < list.size) {
pop_back();
}
} else {
size_t s = list.size;
for (size_t i = 0; i < count - s; i++) {
auto *nd = new typename List::Node{value};
kassert(nd != nullptr);
insert_node_after(list.last(), &nd->link);
}
}
}
void splice(const_iterator pos, KLinkedList &&other)
{
//auto *current = pos.node;
auto *before = pos.node->prev;
auto *after = pos.node; //current == &list.link ? current : pos.node->next;
before->next = other.list.first();
before->next->prev = before;
after->prev = other.list.last();
after->prev->next = after;
list.size += other.list.size;
other.list.size = 0;
other.list.link.prev = other.list.link.next = &other.list.link;
}
void splice(const_iterator pos, KLinkedList &other)
{
splice(pos, std::move(other));
}
void splice(const_iterator pos, KLinkedList &&other, const_iterator it)
{
other.remove_node(it.node);
insert_node_before(pos.node, it.node);
}
void splice(const_iterator pos, KLinkedList &other, const_iterator it)
{
splice(pos, std::move(other), it);
}
void splice(const_iterator pos, KLinkedList &&other, const_iterator first, const_iterator last)
{
if (*this == other) {
auto *current = pos.node;
auto *before = pos.node->prev;
auto *after = current == &list.link ? current : pos.node->next;
before->next = first.node;
before->next->prev = before;
after->prev = last.node;
after->prev->next = after;
} else {
// Note: the first, last version can't be O(1) because std::distance is O(n)...
const_iterator next;
for (const_iterator it = first; it != last; it = next) {
next = it;
++next;
splice(pos, other, it);
++pos;
}
}
}
void splice(const_iterator pos, KLinkedList &other, const_iterator first, const_iterator last)
{
splice(pos, std::move(other), first, last);
}
size_t remove(const T &value)
{
size_t n = 0;
const_iterator next;
for (const_iterator it = cbegin(); it != cend(); ) {
if (*it == value) {
it = erase(it);
++n;
} else {
++it;
}
}
return n;
}
template<typename UnaryPredicate>
size_t remove_if(UnaryPredicate p)
{
const_iterator next;
size_t n = 0;
for (const_iterator it = cbegin(); it != cend(); ) {
if (p(*it)) {
it = erase(it);
++n;
} else {
++it;
}
}
return n;
}
template<typename Compare>
void merge(KLinkedList &&other, Compare p)
{
typename List::Node::Link hd{};
auto *cur = &hd;
size_t n = 0;
while (list.size > 0 && other.list.size > 0) {
if (p(list.first()->data(), other.list.first()->data())) {
cur->next = list.first();
remove_node(list.first());
} else {
cur->next = other.list.first();
other.remove_node(other.list.first());
}
cur->next->prev = cur;
cur = cur->next;
n++;
}
// Steal the remaining elements
if (list.size > 0) {
cur->next = list.first();
list.first()->prev = cur;
cur = list.last();
n += list.size;
} else if (other.list.size > 0) {
cur->next = other.list.first();
other.list.first()->prev = cur;
cur = other.list.last();
n += other.list.size;
}
// Reset the other list to put it in a valid state
other.list.link.prev = other.list.link.next = &other.list.link;
other.list.size = 0;
// Finally, normalize the result and assign it to this
list.link.next = hd.next;
list.link.prev = cur;
list.size = n;
list.first()->prev = list.last()->next = &list.link;
}
void merge(KLinkedList &&other)
{
merge(other, std::less<T>{});
}
template<typename Compare>
void merge(KLinkedList &other, Compare p)
{
merge(std::move(other), p);
}
void merge(KLinkedList &other)
{
merge(other, std::less<T>{});
}
void reverse() noexcept
{
typename List::Node::Link hd{};
auto *cur = &hd;
size_t n = 0;
while (list.size > 0) {
cur->next = list.last();
remove_node(list.last());
cur->next->prev = cur;
n++;
cur = cur->next;
}
list.link.next = hd.next;
list.link.prev = cur;
list.size = n;
list.first()->prev = list.last()->next = &list.link;
}
template<typename BinaryPredicate>
size_t unique(BinaryPredicate p)
{
typename List::Node::Link *nxt;
size_t n = 0;
for (auto *nd = list.first(); nd != &list.link; nd = nxt) {
nxt = nd->next;
for (auto *nd2 = nxt; nd2 != &list.link && p(nd->data(), nd2->data()); nd2 = nxt) {
nxt = nd2->next;
remove_node(nd2);
delete &nd2->parent();
++n;
}
}
return n;
}
size_t unique()
{
return unique(std::equal_to<T>{});
}
// sort: a PITA to implement and not needed anyway
friend bool operator==(const KLinkedList &lhs, const KLinkedList &rhs)
{
return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());
}
friend bool operator!=(const KLinkedList &lhs, const KLinkedList &rhs)
{
return !(lhs == rhs);
}
friend bool operator<(const KLinkedList &lhs, const KLinkedList &rhs)
{
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::less<T>{});
}
friend bool operator>(const KLinkedList &lhs, const KLinkedList &rhs)
{
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::greater<T>{});
}
friend bool operator<=(const KLinkedList &lhs, const KLinkedList &rhs)
{
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::less_equal<T>{});
}
friend bool operator>=(const KLinkedList &lhs, const KLinkedList &rhs)
{
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::greater_equal<T>{});
}
friend void swap(KLinkedList &lhs, KLinkedList &rhs)
{
lhs.swap(rhs);
}
};
template<typename InputIt>
KLinkedList(InputIt b, InputIt e) -> KLinkedList<typename std::iterator_traits<InputIt>::value_type>;
}

View File

@@ -0,0 +1,43 @@
#pragma once
#include <mesosphere/core/KAutoObject.hpp>
#include <mesosphere/core/KLinkedList.hpp>
#include <mesosphere/core/Result.hpp>
#include <mesosphere/threading/KMutex.hpp>
#include <cstring>
namespace mesosphere
{
class KObjectRegistry {
public:
static KObjectRegistry &GetInstance() { return instance; }
SharedPtr<KAutoObject> Find(const char *name) const;
Result Register(SharedPtr<KAutoObject> obj, const char *name);
Result Unregister(const char *name);
private:
struct Node {
SharedPtr<KAutoObject> obj{};
char name[12] = {0};
Node() = default;
Node(SharedPtr<KAutoObject> &&obj, const char *name) : obj{obj}
{
std::strncpy(this->name, name, sizeof(this->name));
}
};
const Node *FindImpl(const char *name) const;
Node *FindImpl(const char *name);
KLinkedList<Node> nameNodes{};
mutable KMutex mutex{};
static KObjectRegistry instance;
};
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include <mesosphere/core/KAutoObject.hpp>
#include <mesosphere/core/KLinkedList.hpp>
namespace mesosphere
{
class KSynchronizationObject : public KAutoObject {
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(AutoObject, SynchronizationObject);
virtual ~KSynchronizationObject();
virtual bool IsSignaled() const = 0;
void NotifyWaiters(); // Note: NotifyWaiters() with !IsSignaled() is no-op
KLinkedList<KThread *>::const_iterator AddWaiter(KThread &thread);
void RemoveWaiter(KLinkedList<KThread *>::const_iterator it);
private:
KLinkedList<KThread *> waiters{};
};
MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(SynchronizationObject);
}

View File

@@ -0,0 +1,143 @@
#pragma once
#include <mesosphere/core/types.hpp>
namespace mesosphere
{
enum class ResultModule : uint {
None = 0,
Kernel = 1,
/* Other modules not included. */
};
class ResultHelper {
public:
using BaseType = uint;
static constexpr BaseType SuccessValue = BaseType();
static constexpr BaseType ModuleBits = 9;
static constexpr BaseType DescriptionBits = 13;
template<ResultModule module, BaseType description>
struct MakeResult : public std::integral_constant<BaseType, ((static_cast<BaseType>(module)) | (description << ModuleBits))> {
static_assert(static_cast<BaseType>(module) < 1 << (ModuleBits + 1), "Invalid Module");
static_assert(description < 1 << (DescriptionBits + 1), "Invalid Description");
};
static constexpr ResultModule GetModule(BaseType value) {
return static_cast<ResultModule>(value & ~(~BaseType() << ModuleBits));
}
static constexpr BaseType GetDescription(BaseType value) {
return ((value >> ModuleBits) & ~(~BaseType() << DescriptionBits));
}
};
/* Use CRTP for Results. */
template<typename Self>
class ResultBase {
public:
using BaseType = typename ResultHelper::BaseType;
static constexpr BaseType SuccessValue = ResultHelper::SuccessValue;
constexpr bool IsSuccess() const { return static_cast<const Self *>(this)->GetValue() == SuccessValue; }
constexpr bool IsFailure() const { return !IsSuccess(); }
constexpr operator bool() const { return IsSuccess(); }
constexpr bool operator !() const { return IsFailure(); }
constexpr ResultModule GetModule() const { return static_cast<const Self *>(this)->GetValue(); }
constexpr BaseType GetDescription() const { return static_cast<const Self *>(this)->GetValue(); }
};
/* Actual result type. */
class Result final : public ResultBase<Result> {
public:
using BaseType = typename ResultBase<Result>::BaseType;
static constexpr BaseType SuccessValue = ResultBase<Result>::SuccessValue;
constexpr Result() : value(SuccessValue) {}
constexpr BaseType GetValue() const { return this->value; }
constexpr bool operator==(const Result &other) const { return value == other.value; }
constexpr bool operator!=(const Result &other) const { return value != other.value; }
static constexpr Result MakeResult(BaseType v) { return Result(v); }
private:
BaseType value;
constexpr explicit Result(BaseType v) : value(v) {}
};
static_assert(sizeof(Result) == sizeof(Result::BaseType), "Bad Result definition!");
/* Successful result class. */
class ResultSuccess final : public ResultBase<ResultSuccess> {
public:
using BaseType = typename ResultBase<ResultSuccess>::BaseType;
static constexpr BaseType SuccessValue = ResultBase<ResultSuccess>::SuccessValue;
constexpr operator Result() { return Result::MakeResult(SuccessValue); }
constexpr BaseType GetValue() const { return SuccessValue; }
};
/* Error result class. */
template<ResultModule module, ResultHelper::BaseType description>
class ResultError : public ResultBase<ResultError<module, description>> {
public:
using BaseType = typename ResultBase<ResultError<module, description>>::BaseType;
static constexpr BaseType SuccessValue = ResultBase<ResultError<module, description>>::SuccessValue;
static constexpr BaseType Value = ResultHelper::MakeResult<module, description>::value;
static_assert(Value != SuccessValue, "Invalid ResultError");
constexpr operator Result() { return Result::MakeResult(Value); }
constexpr BaseType GetValue() const { return Value; }
};
#define DEFINE_RESULT(module, name, description) class Result##module##name final : public ResultError<ResultModule::module, description> {}
DEFINE_RESULT(Kernel, OutOfSessions, 7);
DEFINE_RESULT(Kernel, InvalidCapabilityDescriptor, 14);
DEFINE_RESULT(Kernel, NotImplemented, 33);
DEFINE_RESULT(Kernel, ThreadTerminating, 59);
DEFINE_RESULT(Kernel, OutOfDebugEvents, 70);
DEFINE_RESULT(Kernel, InvalidSize, 101);
DEFINE_RESULT(Kernel, InvalidAddress, 102);
DEFINE_RESULT(Kernel, ResourceExhausted, 103);
DEFINE_RESULT(Kernel, OutOfMemory, 104);
DEFINE_RESULT(Kernel, OutOfHandles, 105);
DEFINE_RESULT(Kernel, InvalidMemoryState, 106);
DEFINE_RESULT(Kernel, InvalidMemoryPermissions, 108);
DEFINE_RESULT(Kernel, InvalidMemoryRange, 110);
DEFINE_RESULT(Kernel, InvalidPriority, 112);
DEFINE_RESULT(Kernel, InvalidCoreId, 113);
DEFINE_RESULT(Kernel, InvalidHandle, 114);
DEFINE_RESULT(Kernel, InvalidUserBuffer, 115);
DEFINE_RESULT(Kernel, InvalidCombination, 116);
DEFINE_RESULT(Kernel, TimedOut, 117);
DEFINE_RESULT(Kernel, Cancelled, 118);
DEFINE_RESULT(Kernel, OutOfRange, 119);
DEFINE_RESULT(Kernel, InvalidEnumValue, 120);
DEFINE_RESULT(Kernel, NotFound, 121);
DEFINE_RESULT(Kernel, AlreadyExists, 122);
DEFINE_RESULT(Kernel, ConnectionClosed, 123);
DEFINE_RESULT(Kernel, UnhandledUserInterrupt, 124);
DEFINE_RESULT(Kernel, InvalidState, 125);
DEFINE_RESULT(Kernel, ReservedValue, 126);
DEFINE_RESULT(Kernel, InvalidHwBreakpoint, 127);
DEFINE_RESULT(Kernel, FatalUserException, 128);
DEFINE_RESULT(Kernel, OwnedByAnotherProcess, 129);
DEFINE_RESULT(Kernel, ConnectionRefused, 131);
DEFINE_RESULT(Kernel, OutOfResource, 132);
DEFINE_RESULT(Kernel, IpcMapFailed, 259);
DEFINE_RESULT(Kernel, IpcCmdbufTooSmall, 260);
DEFINE_RESULT(Kernel, NotDebugged, 520);
}

View File

@@ -0,0 +1,118 @@
#pragma once
#include <mesosphere/core/KCoreContext.hpp>
#include <mesosphere/threading/KThread.hpp>
#include <mesosphere/processes/KProcess.hpp>
#include <mesosphere/kresources/KResourceLimit.hpp>
#include <mesosphere/interfaces/IClientServerParent.hpp>
#include <type_traits>
namespace mesosphere
{
template<typename T, typename ...Args>
auto MakeObjectRaw(Args&& ...args)
{
Result res = ResultSuccess();
KCoreContext &cctx = KCoreContext::GetCurrentInstance();
auto reslimit = cctx.GetCurrentProcess()->GetResourceLimit();
bool doReslimitCleanup = false;
T *obj = nullptr;
if constexpr (std::is_base_of_v<ILimitedResource<T>, T>) {
if (reslimit != nullptr) {
if (reslimit->Reserve(KResourceLimit::categoryOf<T>, 1, T::maxResourceAcqWaitTime)) {
doReslimitCleanup = true;
} else {
return std::tuple<Result, T *>{ResultKernelOutOfResource(), nullptr};
}
}
}
obj = new T;
if (obj == nullptr) {
res = ResultKernelResourceExhausted();
goto cleanup;
}
res = obj->Initialize(std::forward<Args>(args)...);
if (res.IsSuccess()) {
doReslimitCleanup = false;
if constexpr (std::is_base_of_v<ISetAllocated<T>, T>) {
obj->AddToAllocatedSet();
}
} else {
if constexpr (std::is_base_of_v<IClientServerParentTag, T>) {
delete &obj->GetClient();
delete &obj->GetServer();
} else {
delete obj;
}
obj = nullptr;
}
cleanup:
if (doReslimitCleanup) {
reslimit->Release(KResourceLimit::categoryOf<T>, 1, 1);
}
return std::tuple{res, obj};
}
template<typename T, typename std::enable_if_t<!std::is_base_of_v<IClientServerParentTag, T>> * = nullptr, typename ...Args>
auto MakeObject(Args&& ...args)
{
auto [res, obj] = MakeObjectRaw<T>(std::forward<Args>(args)...);
return std::tuple<Result, SharedPtr<T>>{res, SharedPtr<T>{obj}};
}
template<typename T, typename std::enable_if_t<std::is_base_of_v<IClientServerParentTag, T>> * = nullptr, typename ...Args>
auto MakeObject(Args&& ...args)
{
// Bug in type inference?
using RetType = std::tuple<Result, SharedPtr<typename T::ServerClass>, SharedPtr<typename T::ClientClass>>;
auto [res, obj] = MakeObjectRaw<T>(std::forward<Args>(args)...);
return res.IsSuccess() ? RetType{res, &obj->GetServer(), &obj->GetClient()} : RetType{res, nullptr, nullptr};
}
template<typename T, typename std::enable_if_t<!std::is_base_of_v<IClientServerParentTag, T>> * = nullptr, typename ...Args>
auto MakeObjectWithHandle(Args&& ...args)
{
KCoreContext &cctx = KCoreContext::GetCurrentInstance();
KProcess *currentProcess = cctx.GetCurrentProcess();
KHandleTable &tbl = currentProcess->GetHandleTable();
auto [res, obj] = MakeObjectRaw<T>(std::forward<Args>(args)...);
if (res.IsFailure()) {
return std::tuple{res, Handle{}};
}
return tbl.Generate(obj);
}
template<typename T, typename std::enable_if_t<std::is_base_of_v<IClientServerParentTag, T>> * = nullptr, typename ...Args>
auto MakeObjectWithHandle(Args&& ...args)
{
KCoreContext &cctx = KCoreContext::GetCurrentInstance();
KProcess *currentProcess = cctx.GetCurrentProcess();
KHandleTable &tbl = currentProcess->GetHandleTable();
auto [res, obj] = MakeObjectRaw<T>(std::forward<Args>(args)...);
if (res.IsFailure()) {
return std::tuple{res, Handle{}, Handle{}};
}
auto [res2, serverHandle] = tbl.Generate(&obj->GetServer());
if (res2.IsSuccess()) {
auto [res3, clientHandle] = tbl.Generate(&obj->GetClient());
if (res3.IsSuccess()) {
return std::tuple{res3, serverHandle, clientHandle};
} else {
tbl.Close(serverHandle);
return std::tuple{res3, Handle{}, Handle{}};
}
} else {
return std::tuple{res2, Handle{}, Handle{}};
}
}
}

View File

@@ -0,0 +1,48 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <climits>
#include <chrono>
#include <boost/smart_ptr/intrusive_ptr.hpp>
#define MAX_CORES 4
namespace mesosphere
{
using namespace std::chrono_literals;
using ushort = unsigned short;
using uint = unsigned int;
using ulong = unsigned long;
using std::size_t;
using uiptr = std::uintptr_t;
using iptr = std::intptr_t;
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using s8 = int8_t;
using s16 = int16_t;
using s32 = int32_t;
using s64 = int64_t;
using vu8 = volatile uint8_t;
using vu16 = volatile uint16_t;
using vu32 = volatile uint32_t;
using vu64 = volatile uint64_t;
using vs8 = volatile int8_t;
using vs16 = volatile int16_t;
using vs32 = volatile int32_t;
using vs64 = volatile int64_t;
template <typename T>
using SharedPtr = boost::intrusive_ptr<T>;
}

View File

@@ -0,0 +1,109 @@
#pragma once
#include <utility>
#include <array>
#include <boost/assert.hpp>
#include <mesosphere/core/types.hpp>
/*
Boost doesn't provide get_parent_from members for arrays so we have to implement this manually
for arrays, for gcc at leadt.
Thanks fincs.
*/
#define kassert(cond) ((void)(cond))
namespace mesosphere
{
namespace
{
template <typename ClassT, typename MemberT>
union __my_offsetof {
const MemberT ClassT::* ptr;
iptr offset;
};
// Thanks neobrain
template<typename T, size_t N, typename... Args, size_t... Indexes>
static constexpr std::array<T, N> MakeArrayOfHelper(Args&&... args, std::index_sequence<Indexes...>) {
// There are two parameter pack expansions here:
// * The inner expansion is over "t"
// * The outer expansion is over "Indexes"
//
// This function will always be called with sizeof...(Indexes) == N,
// so the outer expansion generates exactly N copies of the constructor call
return std::array<T, N> { ((void)Indexes, T { args... })... };
}
// Thanks neobrain
template<typename T, typename F, size_t N, typename... Args, size_t... Indexes>
static constexpr std::array<T, N> MakeArrayWithFactorySequenceOfHelper(Args&&... args, std::index_sequence<Indexes...>) {
return std::array<T, N> { T { F{}(std::integral_constant<size_t, Indexes>{}), args... }... };
}
}
namespace detail
{
template <typename ClassT, typename MemberT, size_t N>
constexpr ClassT* GetParentFromArrayMember(MemberT* member, size_t index, const MemberT (ClassT::* ptr)[N]) noexcept {
member -= index;
return (ClassT*)((iptr)member - __my_offsetof<ClassT,MemberT[N]> { ptr }.offset);
return nullptr;
}
template <typename ClassT, typename MemberT, size_t N>
constexpr const ClassT* GetParentFromArrayMember(const MemberT* member, size_t index, const MemberT (ClassT::* ptr)[N]) noexcept {
member -= index;
return (const ClassT*)((iptr)member - __my_offsetof<ClassT,MemberT[N]> { ptr }.offset);
return nullptr;
}
template <typename ClassT, typename MemberT>
constexpr ClassT* GetParentFromMember(MemberT* member, const MemberT ClassT::* ptr) noexcept {
return (ClassT*)((iptr)member - __my_offsetof<ClassT, MemberT> { ptr }.offset);
return nullptr;
}
template <typename ClassT, typename MemberT>
constexpr const ClassT* GetParentFromMember(const MemberT* member, const MemberT ClassT::* ptr) noexcept {
return (const ClassT*)((iptr)member - __my_offsetof<ClassT, MemberT> { ptr }.offset);
return nullptr;
}
template<typename T, size_t N, typename... Args>
constexpr std::array<T, N> MakeArrayOf(Args&&... args) {
return MakeArrayOfHelper<T, N, Args...>(std::forward<Args>(args)..., std::make_index_sequence<N>{});
}
template<typename T, typename F, size_t N, typename... Args>
constexpr std::array<T, N> MakeArrayWithFactorySequenceOf(Args&&... args) {
return MakeArrayWithFactorySequenceOfHelper<T, F, N, Args...>(std::forward<Args>(args)..., std::make_index_sequence<N>{});
}
/// Sequence of two distinc powers of 2
constexpr ulong A038444(ulong n)
{
if (n == 0) {
return 3;
}
ulong v = A038444(n - 1);
ulong m1 = 1 << (63 - __builtin_clzl(v));
ulong m2 = 1 << (63 - __builtin_clzl(v&~m1));
if (m2 << 1 == m1) {
m2 = 1;
m1 <<= 1;
} else {
m2 <<= 1;
}
return m1 | m2;
}
}
}

View File

@@ -0,0 +1,61 @@
#pragma once
#include <boost/intrusive/set.hpp>
#include <mesosphere/board/KSystemClock.hpp>
namespace mesosphere
{
struct KAlarm;
struct AlarmableSetTag;
using AlarmableSetBaseHook = boost::intrusive::set_base_hook<
boost::intrusive::tag<AlarmableSetTag>,
boost::intrusive::link_mode<boost::intrusive::normal_link>
>;
class IAlarmable : public AlarmableSetBaseHook {
public:
struct Comparator {
constexpr bool operator()(const IAlarmable &lhs, const IAlarmable &rhs) const {
return lhs.alarmTime < rhs.alarmTime;
}
};
virtual void OnAlarm() = 0;
constexpr KSystemClock::time_point GetAlarmTime() const { return alarmTime; }
/// Precondition: alarm has not been set
template<typename Clock, typename Duration>
void SetAlarmTime(const std::chrono::time_point<Clock, Duration> &alarmTime)
{
SetAlarmTimeImpl(alarmTime);
}
template<typename Rep, typename Period>
void SetAlarmIn(const std::chrono::duration<Rep, Period> &alarmTimeOffset)
{
SetAlarmTimeImpl(KSystemClock::now() + alarmTimeOffset);
}
void ClearAlarm();
private:
void SetAlarmTimeImpl(const KSystemClock::time_point &alarmTime);
KSystemClock::time_point alarmTime = KSystemClock::time_point{};
friend class KAlarm;
};
using AlarmableSetType =
boost::intrusive::make_set<
IAlarmable,
boost::intrusive::base_hook<AlarmableSetBaseHook>,
boost::intrusive::compare<IAlarmable::Comparator>
>::type;
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include <utility>
#include <mesosphere/core/types.hpp>
#include <mesosphere/interfaces/IClientServerParent.hpp>
#define MESOSPHERE_CLIENT_TRAITS(ParentId) using ParentClass = K##ParentId;
namespace mesosphere
{
struct IClientTag {};
template<typename Parent, typename Client, typename Server>
class IClient : public IClientTag {
public:
using ParentClass = Parent;
using ClientClass = Client;
using ServerClass = Server;
void *operator new(size_t sz) noexcept = delete;
void operator delete(void *ptr) noexcept {}
ParentClass *GetParent() const { return parent.get(); }
protected:
friend class IClientServerParent<ParentClass, ClientClass, ServerClass>;
SharedPtr<ParentClass> parent{};
};
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include <mesosphere/core/types.hpp>
#define MESOSPHERE_CLIENT_SERVER_PARENT_TRAITS(ClientId, ServerId)\
using ClientClass = K##ClientId;\
using ServerClass = K##ServerId;
namespace mesosphere
{
struct IClientServerParentTag {};
template<typename Parent, typename Client, typename Server>
class IClientServerParent : public IClientServerParentTag {
public:
using ParentClass = Parent;
using ClientClass = Client;
using ServerClass = Server;
ClientClass &GetClient() { return client; }
ServerClass &GetServer() { return server; }
protected:
void SetClientServerParent()
{
ParentClass *par = (ParentClass *)this;
client.parent = par;
server.parent = par;
}
ClientClass client{};
ServerClass server{};
};
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include <mesosphere/core/util.hpp>
namespace mesosphere
{
class IWork;
class IInterruptible {
public:
/// Top half in Linux jargon
virtual IWork *HandleInterrupt(uint interruptId) = 0;
};
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <mesosphere/interfaces/IWork.hpp>
#include <mesosphere/interfaces/IInterruptible.hpp>
namespace mesosphere
{
class IInterruptibleWork : public IInterruptible, public IWork {
public:
virtual IWork *HandleInterrupt(uint interruptId) override;
};
}

View File

@@ -0,0 +1,49 @@
#pragma once
// circular dep: #include "resource_limit.h"
#include <mesosphere/core/KAutoObject.hpp>
#include <tuple>
#define MESOSPHERE_LIMITED_RESOURCE_TRAITS(maxTime) static constexpr auto maxResourceAcqWaitTime = maxTime;
namespace mesosphere
{
namespace detail
{
void ReleaseResource(const SharedPtr<KProcess> &owner, KAutoObject::TypeId typeId, size_t count, size_t realCount);
void ReleaseResource(const SharedPtr<KResourceLimit> &reslimit, KAutoObject::TypeId typeId, size_t count, size_t realCount);
}
template<typename Derived>
class ILimitedResource {
public:
const SharedPtr<KProcess>& GetResourceOwner() const { return resourceOwner; }
void SetResourceOwner(SharedPtr<KProcess> owner)
{
resourceOwner = std::move(owner);
isLimitedResourceActive = true;
}
virtual std::tuple<size_t, size_t> GetResourceCount()
{
return {1, 1}; // current, real
}
~ILimitedResource()
{
if (isLimitedResourceActive) {
auto [cur, real] = GetResourceCount();
detail::ReleaseResource(resourceOwner, Derived::typeId, cur, real);
}
}
private:
SharedPtr<KProcess> resourceOwner{};
bool isLimitedResourceActive = false;
};
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include <utility>
#include <mesosphere/core/types.hpp>
#include <mesosphere/interfaces/IClientServerParent.hpp>
#define MESOSPHERE_SERVER_TRAITS(ParentId) using ParentClass = K##ParentId;
namespace mesosphere
{
struct IServerTag {};
template<typename Parent, typename Client, typename Server>
class IServer : public IServerTag {
public:
using ParentClass = Parent;
using ClientClass = Client;
using ServerClass = Server;
void *operator new(size_t sz) noexcept = delete;
void operator delete(void *ptr) noexcept {};
ParentClass *GetParent() const { return parent.get(); }
protected:
friend class IClientServerParent<ParentClass, ClientClass, ServerClass>;
SharedPtr<ParentClass> parent{};
};
}

View File

@@ -0,0 +1,60 @@
#pragma once
#include <mesosphere/kresources/KObjectAllocator.hpp>
namespace mesosphere
{
template<typename Derived>
class ISetAllocated : public KObjectAllocator<Derived>::AllocatedSetHookType
{
public:
static void InitializeAllocator(void *buffer, size_t capacity) noexcept
{
allocator.GetSlabHeap().initialize(buffer, capacity);
}
void *operator new(size_t sz) noexcept
{
kassert(sz == sizeof(Derived));
return allocator.GetSlabHeap().allocate();
}
void operator delete(void *ptr) noexcept
{
allocator.GetSlabHeap().deallocate((Derived *)ptr);
}
void AddToAllocatedSet() noexcept
{
Derived *d = (Derived *)this;
allocator.RegisterObject(*d);
isRegisteredToAllocator = true;
}
protected:
void RemoveFromAllocatedSet() noexcept
{
Derived *d = (Derived *)this;
allocator.UnregisterObject(*d);
}
virtual ~ISetAllocated()
{
if (isRegisteredToAllocator) {
RemoveFromAllocatedSet();
isRegisteredToAllocator = false;
}
}
private:
bool isRegisteredToAllocator = false;
protected:
static KObjectAllocator<Derived> allocator;
};
template<typename Derived>
KObjectAllocator<Derived> ISetAllocated<Derived>::allocator{};
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include <mesosphere/kresources/KSlabHeap.hpp>
namespace mesosphere
{
template<typename Derived>
class ISlabAllocated
{
public:
static void InitializeSlabHeap(void *buffer, size_t capacity) noexcept
{
slabHeap.initialize(buffer, capacity);
}
void *operator new(size_t sz) noexcept
{
kassert(sz == sizeof(Derived));
return slabHeap.allocate();
}
void operator delete(void *ptr) noexcept
{
slabHeap.deallocate((Derived *)ptr);
}
protected:
static KSlabHeap<Derived> slabHeap;
};
template<typename Derived>
KSlabHeap<Derived> ISlabAllocated<Derived>::slabHeap{};
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <mesosphere/core/util.hpp>
#include <boost/intrusive/slist.hpp>
namespace mesosphere
{
struct WorkSListTag;
using WorkSListBaseHook = boost::intrusive::slist_base_hook<
boost::intrusive::tag<WorkSListTag>,
boost::intrusive::link_mode<boost::intrusive::normal_link>
>;
/// Bottom half in Linux jargon
class IWork : public WorkSListBaseHook {
public:
virtual void DoWork() = 0;
};
using WorkSList = boost::intrusive::make_slist<
IWork,
boost::intrusive::base_hook<WorkSListBaseHook>,
boost::intrusive::cache_last<true>,
boost::intrusive::constant_time_size<false>
>::type;
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include <mesosphere/interfaces/IInterruptibleWork.hpp>
#include <mesosphere/interfaces/IAlarmable.hpp>
#include <mesosphere/interrupts/KInterruptSpinLock.hpp>
#include <mesosphere/board/KSystemClock.hpp>
namespace mesosphere
{
class KAlarm final : public IInterruptibleWork {
public:
//KAlarm() = default;
/// Precondition: alarmable not already added
void AddAlarmable(IAlarmable &alarmable);
/// Precondition: alarmable is present
void RemoveAlarmable(const IAlarmable &alarmable);
void HandleAlarm();
KAlarm(const KAlarm &) = delete;
KAlarm(KAlarm &&) = delete;
KAlarm &operator=(const KAlarm &) = delete;
KAlarm &operator=(KAlarm &&) = delete;
private:
mutable KInterruptSpinLock<false> spinlock{};
AlarmableSetType alarmables{};
};
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include <mesosphere/core/KCoreContext.hpp>
namespace mesosphere
{
class KThread;
inline void IncrementThreadInterruptBottomHalfLockCount(KThread &thread);
inline void DecrementThreadInterruptBottomHalfLockCount(KThread &thread);
class KInterruptBottomHalfGuard final {
public:
KInterruptBottomHalfGuard()
{
KThread *curThread = KCoreContext::GetCurrentInstance().GetCurrentThread();
IncrementInterruptBottomHalfLockCount(*curThread);
}
~KInterruptBottomHalfGuard()
{
KThread *curThread = KCoreContext::GetCurrentInstance().GetCurrentThread();
DecrementInterruptBottomHalfLockCount(*curThread);
}
KInterruptBottomHalfGuard(const KInterruptBottomHalfGuard &) = delete;
KInterruptBottomHalfGuard(KInterruptBottomHalfGuard &&) = delete;
KInterruptBottomHalfGuard &operator=(const KInterruptBottomHalfGuard &) = delete;
KInterruptBottomHalfGuard &operator=(KInterruptBottomHalfGuard &&) = delete;
};
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include <mesosphere/processes/KReadableEvent.hpp>
#include <mesosphere/interfaces/ISetAllocated.hpp>
namespace mesosphere
{
class KInterruptEvent final : public KReadableEvent, public ISetAllocated<KInterruptEvent> {
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(ReadableEvent, InterruptEvent);
void *operator new(size_t sz) noexcept { return ISetAllocated<KInterruptEvent>::operator new(sz); }
void operator delete(void *ptr) noexcept { ISetAllocated<KInterruptEvent>::operator delete(ptr); }
virtual ~KInterruptEvent();
Result Initialize(int irqId, u32 flags);
private:
// TODO: receiver
int irqId = -1;
};
inline void intrusive_ptr_add_ref(KInterruptEvent *obj)
{
intrusive_ptr_add_ref((KAutoObject *)obj);
}
inline void intrusive_ptr_release(KInterruptEvent *obj)
{
intrusive_ptr_release((KAutoObject *)obj);
}
}

View File

@@ -0,0 +1,86 @@
#pragma once
#include <mesosphere/core/KCoreContext.hpp>
#include <mesosphere/arch/KInterruptMaskGuard.hpp>
#include <mesosphere/arch/KSpinLock.hpp>
namespace mesosphere
{
class KThread;
inline void IncrementThreadInterruptBottomHalfLockCount(KThread &thread);
inline void DecrementThreadInterruptBottomHalfLockCount(KThread &thread);
template<bool disableInterrupts = false>
class KInterruptSpinLock : public KSpinLock {
public:
bool try_lock()
{
KThread *curThread = KCoreContext::GetCurrentInstance().GetCurrentThread();
IncrementThreadInterruptBottomHalfLockCount(*curThread);
if (!KSpinLock::try_lock()) {
DecrementThreadInterruptBottomHalfLockCount(*curThread);
return false;
}
return true;
}
void lock()
{
KThread *curThread = KCoreContext::GetCurrentInstance().GetCurrentThread();
IncrementThreadInterruptBottomHalfLockCount(*curThread);
KSpinLock::lock();
}
void unlock()
{
KThread *curThread = KCoreContext::GetCurrentInstance().GetCurrentThread();
KSpinLock::unlock();
DecrementThreadInterruptBottomHalfLockCount(*curThread);
}
KInterruptSpinLock() = default;
KInterruptSpinLock(const KInterruptSpinLock &) = delete;
KInterruptSpinLock(KInterruptSpinLock &&) = delete;
KInterruptSpinLock &operator=(const KInterruptSpinLock &) = delete;
KInterruptSpinLock &operator=(KInterruptSpinLock &&) = delete;
};
template<>
class KInterruptSpinLock<true> : public KSpinLock {
public:
bool try_lock()
{
flags = MaskInterrupts();
if (!KSpinLock::try_lock()) {
RestoreInterrupts(flags);
return false;
}
return true;
}
void lock()
{
flags = MaskInterrupts();
KSpinLock::lock();
}
void unlock()
{
KSpinLock::unlock();
RestoreInterrupts(flags);
}
KInterruptSpinLock() = default;
KInterruptSpinLock(const KInterruptSpinLock &) = delete;
KInterruptSpinLock(KInterruptSpinLock &&) = delete;
KInterruptSpinLock &operator=(const KInterruptSpinLock &) = delete;
KInterruptSpinLock &operator=(KInterruptSpinLock &&) = delete;
private:
InterruptFlagsType flags = 0;
};
}

View File

@@ -0,0 +1,27 @@
#pragma once
#include <mesosphere/interfaces/IWork.hpp>
#include <mesosphere/core/KAutoObject.hpp>
namespace mesosphere
{
class KWorkQueue final {
public:
void AddWork(IWork &work);
void Initialize();
void HandleWorkQueue();
KWorkQueue(const KWorkQueue &) = delete;
KWorkQueue(KWorkQueue &&) = delete;
KWorkQueue &operator=(const KWorkQueue &) = delete;
KWorkQueue &operator=(KWorkQueue &&) = delete;
private:
WorkSList workQueue{};
SharedPtr<KThread> handlerThread{};
};
}

View File

@@ -0,0 +1,85 @@
#pragma once
#include <boost/intrusive/set.hpp>
#include <mesosphere/core/util.hpp>
#include <mesosphere/kresources/KSlabHeap.hpp>
#include <mesosphere/threading/KMutex.hpp>
namespace mesosphere
{
template<typename T>
class KObjectAllocator {
private:
struct Comparator {
constexpr bool operator()(const T &lhs, const T &rhs) const
{
return lhs.GetComparisonKey() < rhs.GetComparisonKey();
}
};
struct ComparatorEqual {
constexpr u64 operator()(const T &val) const
{
return val.GetComparisonKey();
}
};
public:
struct HookTag;
using AllocatedSetHookType = boost::intrusive::set_base_hook<
boost::intrusive::tag<HookTag>,
boost::intrusive::link_mode<boost::intrusive::normal_link>
>;
using AllocatedSetType = typename
boost::intrusive::make_set<
T,
boost::intrusive::base_hook<AllocatedSetHookType>,
boost::intrusive::compare<Comparator>
>::type;
using pointer = T *;
using const_pointer = const T *;
using void_pointer = void *;
using const_void_ptr = const void *;
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
AllocatedSetType &GetAllocatedSet()
{
return allocatedSet;
}
KSlabHeap<T> &GetSlabHeap()
{
return slabHeap;
}
void RegisterObject(T &obj) noexcept
{
std::scoped_lock guard{mutex};
allocatedSet.insert(obj);
}
void UnregisterObject(T &obj) noexcept
{
std::scoped_lock guard{mutex};
allocatedSet.erase(obj);
}
SharedPtr<T> FindObject(u64 comparisonKey) noexcept
{
std::scoped_lock guard{mutex};
auto it = allocatedSet.find(comparisonKey, ComparatorEqual{});
return it != allocatedSet.end() ? &*it : nullptr;
}
private:
AllocatedSetType allocatedSet{};
KSlabHeap<T> slabHeap{};
mutable KMutex mutex{};
};
}

View File

@@ -0,0 +1,74 @@
#pragma once
#include <mesosphere/threading/KConditionVariable.hpp>
namespace mesosphere
{
class KTransferMemory;
class KResourceLimit final :
public KAutoObject,
public ISetAllocated<KResourceLimit>
{
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(AutoObject, ResourceLimit);
enum class Category : uint {
Memory = 0,
Threads,
Events,
TransferMemories,
Sessions,
Max,
};
static constexpr Category GetCategory(KAutoObject::TypeId typeId) {
switch (typeId) {
case KAutoObject::TypeId::Thread: return Category::Threads;
case KAutoObject::TypeId::Event: return Category::Events;
case KAutoObject::TypeId::TransferMemory: return Category::TransferMemories;
case KAutoObject::TypeId::Session: return Category::Sessions;
case KAutoObject::TypeId::LightSession: return Category::Sessions;
default: return Category::Max;
}
}
template<typename T> static constexpr Category categoryOf = GetCategory(T::typeId);
static KResourceLimit &GetDefaultInstance() { return defaultInstance; }
size_t GetCurrentValue(Category category) const;
size_t GetLimitValue(Category category) const;
size_t GetRemainingValue(Category category) const;
bool SetLimitValue(Category category, size_t value);
template<typename Rep, typename Period>
bool Reserve(Category category, size_t count, const std::chrono::duration<Rep, Period>& timeout)
{
return ReserveDetail(category, count, KSystemClock::now() + timeout);
}
void Release(Category category, size_t count, size_t realCount);
private:
static KResourceLimit defaultInstance;
bool ReserveDetail(Category category, size_t count, const KSystemClock::time_point &timeoutTime);
// Signed in official kernel
size_t limitValues[(size_t)Category::Max] = {};
// Current value: real value + dangling resources about to be released
size_t currentValues[(size_t)Category::Max] = {};
size_t realValues[(size_t)Category::Max] = {};
mutable KConditionVariable condvar{};
};
MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(ResourceLimit);
}

View File

@@ -0,0 +1,55 @@
#pragma once
#include <mesosphere/kresources/KSlabStack.hpp>
namespace mesosphere
{
template<typename T>
class KSlabHeap {
public:
using pointer = T *;
using const_pointer = const T *;
using void_pointer = void *;
using const_void_ptr = const void *;
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
private:
KSlabStack<T> stack{};
size_t capacity = 0;
T *bufferStart = nullptr;
public:
T *allocate() noexcept
{
return stack.pop();
}
void deallocate(T *elem) noexcept
{
kassert(elem >= bufferStart && elem < bufferStart + capacity);
stack.push(elem);
}
constexpr size_t size() const
{
return capacity;
}
KSlabHeap() noexcept = default;
void initialize(void *buffer, size_t capacity)
{
this->capacity = capacity;
this->bufferStart = (T *)buffer;
stack.initialize(buffer, capacity);
}
KSlabHeap(void *buffer, size_t capacity) noexcept : stack(buffer, capacity), capacity(capacity), bufferStart((T *)buffer)
{
}
};
}

View File

@@ -0,0 +1,78 @@
#pragma once
#include <mesosphere/core/util.hpp>
#include <atomic>
namespace mesosphere
{
template<typename T>
class KSlabStack {
public:
using pointer = T *;
using const_pointer = const T *;
using void_pointer = void *;
using const_void_ptr = const void *;
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
private:
struct Node {
Node *next;
};
std::atomic<Node *> head;
public:
void push(T *data) noexcept
{
Node *newHead = (Node *)data;
Node *oldHead = head.load();
do {
newHead->next = oldHead;
} while(!head.compare_exchange_weak(oldHead, newHead));
}
T *pop() noexcept
{
Node *newHead;
Node *oldHead = head.load();
if (oldHead == nullptr) {
return nullptr;
} else {
do {
newHead = oldHead == nullptr ? oldHead : oldHead->next;
} while(!head.compare_exchange_weak(oldHead, newHead));
return (T *)oldHead;
}
}
KSlabStack() noexcept = default;
// Not reentrant (unlike NN's init function)
void initialize(void *buffer, size_t size) noexcept
{
T *ar = (T *)buffer;
if (size == 0) {
return;
}
Node *ndlast = (Node *)&ar[size - 1];
ndlast->next = nullptr;
for (size_t i = 0; i < size - 1; i++) {
Node *nd = (Node *)&ar[i];
Node *ndnext = (Node *)&ar[i + 1];
nd->next = ndnext;
}
Node *ndfirst = (Node *)&ar[0];
head.store(ndfirst);
}
KSlabStack(void *buffer, size_t size) { initialize(buffer, size); }
};
}

View File

@@ -0,0 +1,38 @@
#pragma once
#include <mesosphere/core/KSynchronizationObject.hpp>
#include <mesosphere/interfaces/IClient.hpp>
#include <mesosphere/threading/KThread.hpp>
#include <tuple>
namespace mesosphere
{
class KPort;
class KServerPort;
class KClientPort final :
public KSynchronizationObject,
public IClient<KPort, KClientPort, KServerPort> {
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(SynchronizationObject, ClientPort);
virtual ~KClientPort();
virtual bool IsSignaled() const override;
std::tuple<Result, SharedPtr<KLightClientSession>> ConnectLight();
private:
friend class KPort;
std::atomic<int> numSessions{0};
std::atomic<int> peakNumNormalSessions{0};
int maxSessions = 0;
};
MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(ClientPort);
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include <mesosphere/core/util.hpp>
#include <mesosphere/core/Result.hpp>
#include <mesosphere/core/KAutoObject.hpp>
#include <mesosphere/interfaces/ISetAllocated.hpp>
#include <mesosphere/interfaces/ILimitedResource.hpp>
#include <mesosphere/interfaces/IClientServerParent.hpp>
#include <mesosphere/processes/KReadableEvent.hpp>
#include <mesosphere/processes/KWritableEvent.hpp>
namespace mesosphere
{
class KEvent final :
public KAutoObject,
public IClientServerParent<KEvent, KReadableEvent, KWritableEvent>,
public ISetAllocated<KEvent>,
public ILimitedResource<KEvent> {
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(AutoObject, Event);
MESOSPHERE_CLIENT_SERVER_PARENT_TRAITS(ReadableEvent, WritableEvent);
MESOSPHERE_LIMITED_RESOURCE_TRAITS(10s);
virtual ~KEvent();
Result Initialize();
private:
};
MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(Event);
}

View File

@@ -0,0 +1,78 @@
#pragma once
#include <mesosphere/core/util.hpp>
#include <mesosphere/core/Handle.hpp>
#include <mesosphere/core/Result.hpp>
#include <mesosphere/core/KAutoObject.hpp>
#include <mesosphere/interrupts/KInterruptSpinLock.hpp>
#include <array>
#include <tuple>
namespace mesosphere
{
class KThread;
class KProcess;
class KHandleTable final {
public:
static constexpr size_t capacityLimit = 1024;
static constexpr Handle selfThreadAlias{0, -1, true};
static constexpr Handle selfProcessAlias{1, -1, true};
template<typename T>
SharedPtr<T> Get(Handle handle, bool allowAlias = true) const
{
if constexpr (std::is_same_v<T, KAutoObject>) {
(void)allowAlias;
return GetAutoObject(handle);
} else if constexpr (std::is_same_v<T, KThread>) {
return GetThread(handle, allowAlias);
} else if constexpr (std::is_same_v<T, KProcess>) {
return GetProcess(handle, allowAlias);
} else {
return DynamicObjectCast<T>(GetAutoObject(handle));
}
}
std::tuple<Result, Handle> Generate(SharedPtr<KAutoObject> obj);
/// For deferred-init
Result Set(SharedPtr<KAutoObject> obj, Handle handle);
bool Close(Handle handle);
void Destroy();
constexpr size_t GetNumActive() const { return numActive; }
constexpr size_t GetSize() const { return size; }
constexpr size_t GetCapacity() const { return capacity; }
Result Initialize(size_t capacity); // TODO: implement!
~KHandleTable();
private:
bool IsValid(Handle handle) const;
SharedPtr<KAutoObject> GetAutoObject(Handle handle) const;
SharedPtr<KThread> GetThread(Handle handle, bool allowAlias = true) const;
SharedPtr<KProcess> GetProcess(Handle handle, bool allowAlias = true) const;
struct Entry {
SharedPtr<KAutoObject> object{};
s16 id = 0;
};
std::array<Entry, capacityLimit> entries{};
// Here the official kernel uses pointer, Yuzu and ourselves are repurposing a field in Entry instead.
s16 firstFreeIndex = 0;
s16 idCounter = 1;
u16 numActive = 0, size = 0, capacity = 0;
mutable KInterruptSpinLock<false> spinlock;
};
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include <mesosphere/core/util.hpp>
#include <mesosphere/core/Result.hpp>
#include <mesosphere/core/KAutoObject.hpp>
#include <mesosphere/interfaces/IClient.hpp>
namespace mesosphere
{
class KLightSession;
class KClientPort;
struct LightSessionRequest;
class KLightClientSession final : public KAutoObject, public IClient<KLightSession, KLightClientSession, KLightServerSession> {
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(AutoObject, LightClientSession);
virtual ~KLightClientSession();
Result SendSyncRequest(LightSessionRequest *request);
private:
friend class KLightSession;
SharedPtr<KClientPort> parentClientPort = nullptr;
};
MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(LightClientSession);
}

View File

@@ -0,0 +1,56 @@
#pragma once
#include <mesosphere/core/util.hpp>
#include <mesosphere/core/Result.hpp>
#include <mesosphere/core/KAutoObject.hpp>
#include <mesosphere/interfaces/IServer.hpp>
#include <mesosphere/threading/KThread.hpp>
#include <boost/intrusive/list.hpp>
namespace mesosphere
{
class KLightClientSession;
class KLightSession;
class KClientPort;
struct LightSessionRequest;
struct LightServerSessionListTag;
using LightServerSessionListBaseHook = boost::intrusive::list_base_hook<boost::intrusive::tag<LightServerSessionListTag> >;
class KLightServerSession final :
public KAutoObject,
public IServer<KLightSession, KLightClientSession, KLightServerSession>,
public LightServerSessionListBaseHook {
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(AutoObject, LightServerSession);
using List = typename boost::intrusive::make_list<
KLightServerSession,
boost::intrusive::base_hook<LightServerSessionListBaseHook>,
boost::intrusive::constant_time_size<false>
>::type;
virtual ~KLightServerSession();
/// Needs to be called from critical section
Result HandleSyncRequest(KThread &sender);
Result ReplyAndReceive(LightSessionRequest *request);
private:
friend class KLightSession;
void Terminate(bool fromServer);
KThread::WaitList senderThreads{}, receiverThreads{};
SharedPtr<KThread> currentSender{};
KThread *currentReceiver = nullptr;
};
MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(LightServerSession);
}

View File

@@ -0,0 +1,46 @@
#pragma once
#include <mesosphere/core/util.hpp>
#include <mesosphere/core/Result.hpp>
#include <mesosphere/interfaces/IClientServerParent.hpp>
#include <mesosphere/interfaces/ISetAllocated.hpp>
#include <mesosphere/interfaces/ILimitedResource.hpp>
#include <mesosphere/processes/KLightClientSession.hpp>
#include <mesosphere/processes/KLightServerSession.hpp>
namespace mesosphere
{
class KPort;
struct LightSessionRequest {
s32 cmdId;
u32 data[6];
};
class KLightSession final :
public KAutoObject,
public ISetAllocated<KLightSession>,
public ILimitedResource<KLightSession>,
public IClientServerParent<KLightSession, KLightClientSession, KLightServerSession> {
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(AutoObject, LightSession);
MESOSPHERE_LIMITED_RESOURCE_TRAITS(10s);
virtual ~KLightSession();
Result Initialize(KPort *parentPort = nullptr);
private:
friend class KLightClientSession;
friend class KLightServerSession;
void Terminate(bool fromServer);
bool isClientAlive = false;
bool isServerAlive = false;
};
MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(LightSession);
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include <mesosphere/core/util.hpp>
#include <mesosphere/core/Result.hpp>
#include <mesosphere/interfaces/IClientServerParent.hpp>
#include <mesosphere/interfaces/ISetAllocated.hpp>
#include <mesosphere/processes/KClientPort.hpp>
#include <mesosphere/processes/KServerPort.hpp>
#include <mesosphere/processes/KLightSession.hpp>
namespace mesosphere
{
class KPort final :
public KAutoObject,
public ISetAllocated<KPort>,
public IClientServerParent<KPort, KClientPort, KServerPort> {
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(AutoObject, Port);
virtual ~KPort();
Result Initialize(int maxSessions, bool isLight);
Result AddLightServerSession(KLightServerSession &lightServerSession);
private:
friend class KClientPort;
friend class KServerPort;
bool isClientAlive = false;
bool isServerAlive = false;
bool isLight = false;
};
MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(Port);
}

View File

@@ -0,0 +1,79 @@
#pragma once
class KThread;
class KResourceLimit;
#include <mesosphere/core/util.hpp>
#include <mesosphere/core/KSynchronizationObject.hpp>
#include <mesosphere/interfaces/ISetAllocated.hpp>
#include <mesosphere/processes/KHandleTable.hpp>
#include <mesosphere/threading/KThread.hpp>
namespace mesosphere
{
class KProcess final : public KSynchronizationObject /* FIXME */ {
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(SynchronizationObject, Process);
enum class State : uint {
Created = 0,
CreatedAttached,
Started,
Crashed,
StartedAttached,
Exiting,
Exited,
DebugSuspended,
};
virtual bool IsSignaled() const override;
constexpr long GetSchedulerOperationCount() const { return schedulerOperationCount; }
void IncrementSchedulerOperationCount() { ++schedulerOperationCount; }
void SetLastThreadAndIdleSelectionCount(KThread *thread, ulong idleSelectionCount);
const SharedPtr<KResourceLimit> &GetResourceLimit() const { return reslimit; }
KHandleTable &GetHandleTable() { return handleTable; }
constexpr State GetState() const { return state; }
void SetDebugPauseState(bool pause);
KDebug *GetDebug() const { return debug; }
void SetDebug(KDebug *debug);
void ClearDebug(State attachState);
template<typename F, typename ...Args>
void ForEachThread(F f, Args &&...args)
{
std::scoped_lock s{mutex};
std::scoped_lock s2{threadingMutex};
for (KThread &t : threadList) {
f(t, std::forward(args)...);
}
}
private:
KThread::ProcessList threadList{};
KThread *lastThreads[MAX_CORES]{nullptr};
ulong lastIdleSelectionCount[MAX_CORES]{0};
long schedulerOperationCount = -1;
State state = State::Created;
bool stateChanged = false;
KDebug *debug = nullptr;
SharedPtr<KResourceLimit> reslimit{};
KHandleTable handleTable{};
mutable KMutex mutex{}, threadingMutex{};
};
MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(Process);
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include <mesosphere/core/util.hpp>
#include <mesosphere/core/Result.hpp>
#include <mesosphere/core/KSynchronizationObject.hpp>
#include <mesosphere/interfaces/IClient.hpp>
namespace mesosphere
{
class KWritableEvent;
class KEvent;
// Inherited by KInterruptEvent
class KReadableEvent : public KSynchronizationObject, public IClient<KEvent, KReadableEvent, KWritableEvent> {
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(SynchronizationObject, ReadableEvent);
MESOSPHERE_CLIENT_TRAITS(Event);
virtual ~KReadableEvent();
Result Signal();
Result Clear();
Result Reset();
virtual bool IsSignaled() const override;
private:
bool isSignaled = false;
};
MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(ReadableEvent);
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include <mesosphere/core/KSynchronizationObject.hpp>
#include <mesosphere/processes/KLightServerSession.hpp>
namespace mesosphere
{
class KPort;
class KClientPort;
class KServerPort final :
public KSynchronizationObject,
public IServer<KPort, KClientPort, KServerPort> {
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(SynchronizationObject, ServerPort);
virtual ~KServerPort();
virtual bool IsSignaled() const override;
private:
friend class KPort;
Result AddLightServerSession(KLightServerSession &lightServerSession);
KLightServerSession::List lightServerSessions{};
};
MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(ServerPort);
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include <mesosphere/core/util.hpp>
#include <mesosphere/core/Result.hpp>
#include <mesosphere/core/KAutoObject.hpp>
#include <mesosphere/interfaces/ISetAllocated.hpp>
#include <mesosphere/interfaces/IServer.hpp>
namespace mesosphere
{
class KReadableEvent;
class KEvent;
class KWritableEvent final : public KAutoObject, public IServer<KEvent, KReadableEvent, KWritableEvent> {
public:
MESOSPHERE_AUTO_OBJECT_TRAITS(AutoObject, WritableEvent);
MESOSPHERE_SERVER_TRAITS(Event);
virtual ~KWritableEvent();
Result Signal();
Result Clear();
private:
friend class KEvent;
SharedPtr<KReadableEvent> client{};
};
MESOSPHERE_AUTO_OBJECT_DEFINE_INCREF(WritableEvent);
}

View File

@@ -0,0 +1,78 @@
#pragma once
#include <mesosphere/threading/KThread.hpp>
#include <mesosphere/threading/KMutex.hpp>
namespace mesosphere
{
/// Provides an interface similar to std::condition_variable
class KConditionVariable final {
public:
using native_handle_type = uiptr;
KConditionVariable() = default;
KConditionVariable(const KConditionVariable &) = delete;
KConditionVariable(KConditionVariable &&) = delete;
KConditionVariable &operator=(const KConditionVariable &) = delete;
KConditionVariable &operator=(KConditionVariable &&) = delete;
native_handle_type native_handle() { return mutex_.native_handle(); }
KMutex &mutex() { return mutex_; }
void wait() noexcept
{
wait_until_impl(KSystemClock::never);
}
template<typename Predicate>
void wait(Predicate pred)
{
while (!pred()) {
wait();
}
}
template<typename Clock, typename Duration>
void wait_until(const std::chrono::time_point<Clock, Duration> &timeoutPoint) noexcept
{
wait_until_impl(timeoutPoint);
}
template<typename Clock, typename Duration, typename Predicate>
bool wait_until(const std::chrono::time_point<Clock, Duration> &timeoutPoint, Predicate pred)
{
while (!pred()) {
wait_until(timeoutPoint);
if (Clock::now() >= timeoutPoint) {
return pred();
}
}
return true;
}
template<typename Rep, typename Period>
void wait_for(const std::chrono::duration<Rep, Period>& timeout) noexcept
{
wait_until(KSystemClock::now() + timeout);
}
template<typename Rep, typename Period, typename Predicate>
bool wait_for(const std::chrono::duration<Rep, Period>& timeout, Predicate pred)
{
return wait_until(KSystemClock::now() + timeout, std::move(pred));
}
void notify_one() noexcept;
void notify_all() noexcept;
private:
void wait_until_impl(const KSystemClock::time_point &timeoutPoint) noexcept;
KMutex mutex_{};
KThread::WaitList waiterList{};
};
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include <mesosphere/interrupts/KInterruptSpinLock.hpp>
namespace mesosphere
{
class KCriticalSection final : public KInterruptSpinLock<false> {
public:
bool try_lock();
void lock();
void unlock();
KCriticalSection() = default;
KCriticalSection(const KCriticalSection &) = delete;
KCriticalSection(KCriticalSection &&) = delete;
KCriticalSection &operator=(const KCriticalSection &) = delete;
KCriticalSection &operator=(KCriticalSection &&) = delete;
private:
KThread *lockingThread = nullptr;
ulong lockCount = 0;
};
}

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