Compare commits

..

72 Commits

Author SHA1 Message Date
Michael Scire
90a38ca30e make: dependency fixes 2020-05-08 03:21:47 -07:00
Michael Scire
66c410e696 whoosh, your code now uses pre-compiled headers 2020-05-08 03:12:51 -07:00
Michael Scire
c72614f768 fusee/sept: update for gcc10 2020-05-07 18:49:46 -07:00
Michael Scire
232203f4c0 ams: take care of most TODO C++20s 2020-05-06 22:47:28 -07:00
Michael Scire
13bfeed2d5 remove mno-outline-atomics 2020-05-06 22:47:28 -07:00
Michael Scire
492a9e1849 ams: update to build with gcc10/c++20 2020-05-06 22:47:28 -07:00
Michael Scire
17b6bcfd37 loader: correct anti-downgrade tables for new version scheme 2020-05-06 22:39:11 -07:00
Michael Scire
0e289461bb ams: use psc acknowledge_ex on 5.1.0+ (fixes wake-from-sleep on 5.1.0) 2020-05-06 22:34:34 -07:00
Michael Scire
8e75a4169d ams: revamp target firmware 2020-05-06 22:29:07 -07:00
Michael Scire
85cd2c97a0 ams:bpc: allow programatically setting reboot payload 2020-05-04 23:29:54 -07:00
hexkyz
3e6031b8f4 docs: fix wrong link (thanks @jul2003) 2020-05-03 15:49:23 +01:00
Michael Scire
9ddc6e596b kern: fix link error 2020-05-02 22:30:34 -07:00
hexkyz
b56f9966b7 Merge pull request #929 from hexkyz/master
docs: re-write documentation
2020-05-01 18:10:56 +01:00
Michael Scire
3bc7c52ade pm: correct extra application thread allocation counts 2020-05-01 05:23:37 -07:00
SciresM
e819f3dbce exefs.nsp 2020-04-29 14:13:34 -07:00
SciresM
4d78b834cb ldr: add technical semantics for redirection 2020-04-29 11:45:58 -07:00
Michael Scire
f670949ca9 os: oh geez look at the time 2020-04-29 00:41:51 -07:00
Michael Scire
72f1e85aba git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "292a8ad4"
upstream:
  origin:   "https://github.com/m4xw/emuMMC"
  branch:   "develop"
  commit:   "292a8ad4"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-28 00:14:42 -07:00
Michael Scire
491ba8fdcf emummc: fix console reinitialize on 10.x
10.x FS now receives a transfer memory to wipe BIS with and maps it.

This requires SVCs that emummc did not give itself access to.

This commit adds them, which prevents a FS process abort on re-init.
2020-04-28 00:11:42 -07:00
hexkyz
67b91cfa13 docs: minor style fix 2020-04-27 18:52:53 +01:00
hexkyz
7361fa25a9 Merge branch 'master' of https://github.com/Atmosphere-NX/Atmosphere 2020-04-27 18:44:07 +01:00
hexkyz
793bde256c Merge branch 'master' of https://github.com/hexkyz/Atmosphere 2020-04-27 18:41:11 +01:00
hexkyz
234c83522a docs: address review commentary 2020-04-27 18:40:22 +01:00
Michael Scire
0bfbc6e6eb git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "6913aa52"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "6913aa52"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-27 10:34:30 -07:00
Michael Scire
2dfe5b192e result: add R_CATCH_MODULE 2020-04-27 10:33:51 -07:00
SciresM
aca2992c68 Add up-to-date roadmap. 2020-04-27 09:35:23 -07:00
hexkyz
39f5933600 Merge branch 'master' of https://github.com/Atmosphere-NX/Atmosphere 2020-04-27 16:28:17 +01:00
Michael Scire
52c89a76b2 kern: fix KLinkedList dtor 2020-04-27 03:56:12 -07:00
hexkyz
faaef5eff5 docs: hid_mitm is disabled by default 2020-04-26 21:01:54 +01:00
hexkyz
a9cc74da34 docs: remove misleading sentence in fatal module 2020-04-26 20:59:29 +01:00
hexkyz
93e855a293 docs: document exefs PFS0 replacement 2020-04-26 20:56:12 +01:00
hexkyz
a61fdc8d65 docs: correct "nogc" description 2020-04-26 20:49:14 +01:00
hexkyz
9622912059 docs: remove switch-freetype dependency 2020-04-26 20:43:32 +01:00
hexkyz
59ea93e9cd docs: style fixes 2020-04-26 19:18:49 +01:00
hexkyz
57ac153671 docs: initial re-write of all documentation 2020-04-26 19:06:59 +01:00
Michael Scire
71d266f867 kern: implement SvcSetUnsafeLimit 2020-04-26 02:49:59 -07:00
Michael Scire
970b85bf9a kern: implement KUnsafeMemory 2020-04-26 02:35:10 -07:00
Michael Scire
7bc0250cea exosphere: correct reencryption of rsa private keys 2020-04-24 17:36:37 -07:00
Michael Scire
524da78b0e git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "bb40dae3"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "bb40dae3"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-24 17:29:50 -07:00
Michael Scire
7458879555 ams: bump version to 0.12.0 2020-04-24 17:28:57 -07:00
Michael Scire
1d40a08ef9 dmnt: move stuff around slightly, add client bindings 2020-04-24 17:24:15 -07:00
SciresM
be07035954 Dmnt: Add break/continue commands, add static register api. (#899)
* dmnt: implement break/continue, static reg commands

* dmnt: revise per WerWolv's feedback.
2020-04-24 17:00:43 -07:00
Pika
b7c4dae899 docs: fix Behemoth's username (#922) 2020-04-23 17:23:19 -07:00
jhNsXO
94d0d06660 Update building.md (#916)
add dependency needed since 90d754f920
2020-04-22 19:30:20 -07:00
Michael Scire
2e4e59dbda docs: right 2020-04-22 17:59:03 -07:00
Michael Scire
0fb528836c note that we support 10.0.1 2020-04-22 17:56:13 -07:00
Michael Scire
4a01ae8b9d docs: yeah this is kinda too big a changelog 2020-04-22 17:54:19 -07:00
Michael Scire
5bec9395b1 docs: Add a bunch of 0.11.2's changelog ahead of time.
0.11.2 will release sometime in the next week or two or so.

I am writing this now while I remember all the things that have happened,
so that I don't forget about them when release comes.

There is also a PR for dmnt changes that will be merged into 0.11.2 not included here,
and there may be more changes before the release occurs.
2020-04-22 17:49:52 -07:00
SciresM
3bc2d79384 PRODINFO: Revamp blanking/write disallow policy. (#913)
* exo/fusee: hookup new prodinfo settings

* fusee: new scheme doesn't need FLAGS_DEFAULT

* fusee: fix c/p errors

* ams.mitm: completely revamp prodinfo backup mechanism

* ams.mitm: Implement revamped blanking/write policy

* strat: make early boot more debuggable

* exo: condense flag logic
2020-04-22 16:22:14 -07:00
Michael Scire
6ac1ff6f24 creport: Try to take screenshot of application crashes on 9.x+ 2020-04-22 14:50:16 -07:00
Michael Scire
93e0c9194d erpt: fix access to time service on versions where it is disallowed 2020-04-22 12:03:55 -07:00
Michael Scire
6ad0f0e7f2 kern/kldr: fix bugs in physical randomization 2020-04-22 03:45:21 -07:00
Michael Scire
4f50f57bb7 os: bug fixes after re-review of rwlock code 2020-04-21 22:40:45 -07:00
Michael Scire
97cba5e881 os: implement ReadWriteLock 2020-04-21 20:23:50 -07:00
Michael Scire
6eb77e69c4 refactor jpegdec implementation into libstrat (thanks again, Behemoth!) 2020-04-20 04:37:08 -07:00
HookedBehemoth
90d754f920 jpegdec reimplementation (#912)
* add jpegdec reimplementation

* reduce work memory

* fix color space

* jpegdec: cleanup results to use atmosphere style

* fix outdated comments, correct do/while bug

Co-authored-by: Michael Scire <SciresM@gmail.com>
2020-04-20 02:07:37 -07:00
Michael Scire
b39b6f0d5b kern: implement 10.x perm change, fix many page table bugs 2020-04-19 17:16:19 -07:00
Michael Scire
dcfb3bc9b5 kern: randomize dynamic slab heaps to reflect 10.x changes 2020-04-19 00:35:05 -07:00
Michael Scire
b4d003b4b9 kern: fix suboptimal mapping choices by kernel/kernelldr 2020-04-19 00:01:06 -07:00
Michael Scire
bc1d3ccc91 kern: Update init to reflect 10.0.0 changes 2020-04-18 22:19:09 -07:00
Michael Scire
152a945561 kern: Update page bitmaps/alloc to reflect 10.0.0 changes 2020-04-18 17:10:26 -07:00
Michael Scire
3da0cda4ae ams: centralize system thread definitions 2020-04-17 01:06:07 -07:00
Michael Scire
d77fe98203 sf: properly support preservation of inline context 2020-04-16 23:51:42 -07:00
Michael Scire
94ec9ae41b hos: change initialization API
This was needed to make stratosphere buildable with debugging on.

os:: assertions rely on GetCurrentThread() working, and this requires
the global os resource manager to be constructed. However, __appInit executes
before global constructors. We now require that hos::InitializeForStratosphere()
be called before anything else is done. This initializes the os resource manager,
sets the hos version for libnx, and may do more things in the future.

TODO: Consider replacing __appInit/__appExit with ams:: namespace functions in general,
and wrap them so that we guarantee hos::InitializeForStratosphere is called first, and
generally ensure a consistent stratosphere environment.
2020-04-16 22:57:01 -07:00
Michael Scire
332dbdd497 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "c1fe12fc"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "c1fe12fc"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-16 20:06:20 -07:00
SciresM
98cc051387 pgl: Reimplement the pgl sysmodule (#896)
* pgl: add skeleton folder to stratosphere

* pgl: Add service interface for IShellInterface

* pgl: begin skeletoning shell service, implement two commands.

* pgl: Implement three more commands.

* pgl: implement bool tracking commands

* pgl: Implement TriggerApplicationSnapShotDumper

* pgl: implement InitializeProcessControlTask

* pgl: Implement pgl::srv::Initialize

* pgl: Implement main()

* pgl: Implement (Get)ShellEventObserver

* pgl: implement LaunchProgramFromHost, GetHostContentMetaInfo

* pgl: Implement ProcessControlTask

* settings: fix duplicate object name

* pgl: fix minor bugs in impl
2020-04-16 19:55:47 -07:00
Michael Scire
f2944d36ba kern: amend syntax 2020-04-16 18:00:42 -07:00
Michael Scire
46d79387e8 mesosphere: implement KMemoryBlockManager::UpdateLock 2020-04-16 17:58:51 -07:00
Michael Scire
0bb2c0a04f licensing: update exemptions (approved by contributors). 2020-04-16 17:33:04 -07:00
Michael Scire
eca2b453ae pgl: update with client C++ bindings 2020-04-15 20:07:20 -07:00
Michael Scire
e14dc18bd3 pgl: skeleton api 2020-04-15 17:37:11 -07:00
Michael Scire
c7743c6098 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "96825c75"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "96825c75"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-15 11:55:50 -07:00
538 changed files with 11510 additions and 3076 deletions

View File

@@ -63,6 +63,7 @@ dist-no-debug: all
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034 mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036 mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037 mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000003C
mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors
mkdir -p atmosphere-$(AMSVER)/atmosphere/config_templates mkdir -p atmosphere-$(AMSVER)/atmosphere/config_templates
mkdir -p atmosphere-$(AMSVER)/atmosphere/config mkdir -p atmosphere-$(AMSVER)/atmosphere/config
@@ -88,6 +89,7 @@ dist-no-debug: all
cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034/exefs.nsp cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034/exefs.nsp
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036/exefs.nsp cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036/exefs.nsp
cp stratosphere/ro/ro.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/exefs.nsp cp stratosphere/ro/ro.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/exefs.nsp
cp stratosphere/jpegdec/jpegdec.nsp atmosphere-$(AMSVER)/atmosphere/contents/010000000000003C/exefs.nsp
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/flags mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/flags
touch atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/flags/boot2.flag touch atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/flags/boot2.flag
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/flags mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/flags
@@ -136,6 +138,7 @@ dist: dist-no-debug
cp stratosphere/sm/sm.elf atmosphere-$(AMSVER)-debug/sm.elf cp stratosphere/sm/sm.elf atmosphere-$(AMSVER)-debug/sm.elf
cp stratosphere/spl/spl.elf atmosphere-$(AMSVER)-debug/spl.elf cp stratosphere/spl/spl.elf atmosphere-$(AMSVER)-debug/spl.elf
cp stratosphere/erpt/erpt.elf atmosphere-$(AMSVER)-debug/erpt.elf cp stratosphere/erpt/erpt.elf atmosphere-$(AMSVER)-debug/erpt.elf
cp stratosphere/jpegdec/jpegdec.elf atmosphere-$(AMSVER)-debug/jpegdec.elf
cd atmosphere-$(AMSVER)-debug; zip -r ../atmosphere-$(AMSVER)-debug.zip ./*; cd ../; cd atmosphere-$(AMSVER)-debug; zip -r ../atmosphere-$(AMSVER)-debug.zip ./*; cd ../;
rm -r atmosphere-$(AMSVER)-debug rm -r atmosphere-$(AMSVER)-debug
mv atmosphere-$(AMSVER)-debug.zip out/atmosphere-$(AMSVER)-debug.zip mv atmosphere-$(AMSVER)-debug.zip out/atmosphere-$(AMSVER)-debug.zip

View File

@@ -27,7 +27,7 @@ This software is licensed under the terms of the GPLv2, with exemptions for spec
You can find a copy of the license in the [LICENSE file](LICENSE). You can find a copy of the license in the [LICENSE file](LICENSE).
Exemptions: 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. * The [yuzu Nintendo Switch emulator](https://github.com/yuzu-emu/yuzu) and the [Ryujinx Team and Contributors](https://github.com/orgs/Ryujinx) are exempt from GPLv2 licensing. They are permitted, each at their individual discretion, to instead license any source code authored for the Atmosphère project as either GPLv2 or later or the [MIT license](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/licensing_exemptions/MIT_LICENSE). In doing so, they may alter, supplement, or entirely remove the copyright notice for each file they choose to relicense. Neither the Atmosphère project nor its individual contributors shall assert their moral rights against any of the aforementioned projects.
* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the Atmosphère project under the Zero-Clause BSD license. * [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the Atmosphère project under the Zero-Clause BSD license.
Credits Credits

View File

@@ -5,16 +5,6 @@ stage2_mtc_path = atmosphere/fusee-mtc.bin
stage2_addr = 0xF0000000 stage2_addr = 0xF0000000
stage2_entrypoint = 0xF0000000 stage2_entrypoint = 0xF0000000
[exosphere]
; 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
; Note: It's currently unknown what effects enabling the usermode PMU register access may have on official code.
enable_user_pmu_access = 0
[stratosphere] [stratosphere]
; To force-enable nogc, add nogc = 1 ; To force-enable nogc, add nogc = 1
; To force-disable nogc, add nogc = 0 ; To force-disable nogc, add nogc = 0

View File

@@ -0,0 +1,45 @@
# Key: debugmode, default: 1.
# Desc: Controls whether kernel is debug mode.
# Disabling this may break Atmosphere's debugger in a future release.
# Key: debugmode_user, default: 0.
# Desc: Controls whether userland is debug mode.
# Key: disable_user_exception_handlers, default: 0.
# Desc: Controls whether user exception handlers are executed on error.
# NOTE: This will cause atmosphere to not fail gracefully.
# Support may not be provided to users tho disable these.
# If you do not know what you are doing, leave them on.
# Key: enable_user_pmu_access, default: 0.
# Desc: Controls whether userland has access to the PMU registers.
# NOTE: It is unknown what effects this has on official code.
# Key: blank_prodinfo_sysmmc, default: 0.
# Desc: Controls whether PRODINFO should be blanked in sysmmc.
# This will cause the system to see dummied out keys and
# serial number information.
# NOTE: This is not known to be safe, as data may be
# cached elsewhere in the system. Usage is not encouraged.
# Key: blank_prodinfo_emummc, default: 0.
# Desc: Controls whether PRODINFO should be blanked in emummc.
# NOTE: This is not known to be safe, as data may be
# cached elsewhere in the system. Usage is not encouraged.
# Key: allow_writing_to_cal_sysmmc, default: 0.
# Desc: Controls whether PRODINFO can be written by homebrew in sysmmc.
# NOTE: Usage of this setting is strongly discouraged without
# a safe backup elsewhere. Turning this on will also cause Atmosphere
# to ensure a safe backup of calibration data is stored in unused
# mmc space, encrypted to prevent detection. This backup can be used
# to prevent unrecoverable edits in emergencies.
[exosphere]
debugmode=1
debugmode_user=0
disable_user_exception_handlers=0
enable_user_pmu_access=0
blank_prodinfo_sysmmc=0
blank_prodinfo_emummc=0
allow_writing_to_cal_sysmmc=0

View File

@@ -1,8 +1,27 @@
# Building Atmosphère # Building Atmosphère
The process for building Atmosphère is similar to building Fusée Gelée payloads and other Switch apps. Building Atmosphère is a very straightforward process that relies almost exclusively on tools provided by the [devkitPro](https://devkitpro.org) organization.
In order to build Atmosphère you must have devkitARM and devkitA64 installed on your computer. You can find instructions on how to install and setup devkitARM and devkitA64 on various OSes [here](https://devkitpro.org/wiki/Getting_Started). You'll need to install the following packages via (dkp-)pacman: switch-dev switch-freetype devkitARM devkitarm-rules ## Dependencies
+ [devkitA64](https://devkitpro.org)
+ [devkitARM](https://devkitpro.org)
+ [Python 2 or 3](https://www.python.org) (optional)
+ [PyCryptodome](https://pypi.org/project/pycryptodome) (optional)
sept requires you have python installed with the pycryptodome PyPi packages (`pip install pycryptodome`). You may also want to install the zip package from your package manager of choice to support the `make dist` recipe. ## Instructions
1. Follow the guide located [here](https://devkitpro.org/wiki/Getting_Started) to install and configure all the tools necessary for the build process.
Once you have finished installing the devkitPro-provided toolchain/libraries, python, and the dependencies, simply clone the Atmosphère repo (clone with the -r flag), change your directory to it and run `make`. 2. Install the following packages via (dkp-)pacman:
+ `switch-dev`
+ `switch-libjpeg-turbo`
+ `devkitARM`
+ `devkitarm-rules`
3. (Optional) In order to build [sept](components/sept.md) the pycryptodome PyPi package is required, which can be installed by running `pip install pycryptodome` under the installed Python environment of your choice or by installing the complete zip package to support the `make dist` recipe. This is an optional step included for advanced users who have the ability to provide the necessary encryption/signing keys themselves.
4. It is, instead, possible to build [sept](components/sept.md) by providing previously encrypted/signed binaries distributed by official Atmosphère release packages. In order to do so, export the following variables in your current environment:
+ `SEPT_00_ENC_PATH` (must point to the `sept-secondary_00.enc` file)
+ `SEPT_01_ENC_PATH` (must point to the `sept-secondary_01.enc` file)
+ `SEPT_DEV_00_ENC_PATH` (must point to the `sept-secondary_dev_00.enc` file)
+ `SEPT_DEV_01_ENC_PATH` (must point to the `sept-secondary_dev_01.enc` file)
5. Finally, clone the Atmosphère repository and run `make` under its root directory.

View File

@@ -1,4 +1,54 @@
# Changelog # Changelog
## 0.12.0
+ Configuration for exosphere was moved to sd:/exosphere.ini.
+ This is to facilitate BIS protection changes described below.
+ Hopefully having this outside of the Atmosphere folder will prevent accidental deletion, since this now contains important settings.
+ Atmosphere's bis protection policy for the PRODINFO partition was substantially reworked.
+ Support was added for "automatically" performing a "blanking" operation to PRODINFO without actually modifying NAND.
+ This is equivalent to using the "incognito" homebrew tool, but NAND is never actually modified.
+ This can be turned on in sysmmc by setting `blank_prodinfo_sysmmc=1` in exosphere.ini, and in emummc by setting `blank_prodinfo_emummc=1` in exosphere.ini.
+ **Please note**: This is not known to be safe. There is a lack of research on whether the information blanked out is cached elsewhere in the system.
+ Usage of this option is not encouraged for this reason.
+ Support was added for writing to the PRODINFO partition, if a verified encrypted backup has been made.
+ PRODINFO is the only system data that cannot be recovered if not backed up, and thus Atmosphere has backed it up to the SD card on boot for some time now.
+ Users who wish to modify their calibration data may now do so unconditionally in emummc, and in sysmmc if `allow_writing_to_cal_sysmmc=1` is set in exosphere.ini.
+ **Please note**: This is heavily discouraged, and the typical user will almost never want to do this.
+ Setting this option will cause Atmosphere to attempt to verify (or create) an encrypted backup of the PRODINFO data to an unused region in the partition.
+ The backup is encrypted with per-console keys that Atmosphere's developers do not know.
+ If the backup is not verified or created, writes will not work. Users who have corrupted their PRODINFO in the past are encouraged to flash a good backup to allow use of this setting.
+ Reads and writes to the region used for the securely encrypted backup will appear to succeed, but will actually read/write from a buffer filled with garbage in memory.
+ Support will be investigated in the future for supporting booting with fully blanked calibration.
+ This is desirable to allow boot to succeed for users who lost their calibration data due to bricking homebrew before bis protection was implemented.
+ `creport` has been updated to use the new screenshot APIs added in 9.0.0+.
+ On 10.0.0+, if a crash occurs in an application (not applet or sysmodule) a screenshot will now be automatically saved to the SD card.
+ If the user applies a patch to vi on 9.0.0 (as the command this uses was previously for dev-units only), this can also work on 9.0.0.
+ The new sysmodule `pgl` added in 10.0.0 was reimplemented.
+ `pgl` ("Program Launcher", probably) is responsible for managing launched user-processes, previously this was handled by NS.
+ The most exciting thing about pgl is that it finally provides an API for multiple clients to subscribe to process events.
+ Using these new APIs, system modules / other homebrew can subscribe to be notified whenever a process event occurs.
+ This means action can be taken on process launch, process exit, process crash, etc.
+ A slight concern with Nintendo's implementation is that each subscriber object uses 0x448 bytes of memory, and N only reserves 8KB for all allocations in pgl.
+ Atmosphere's implementation uses a 32KB heap, which should not be exhaustible.
+ Atmosphere's implementation has a total memory footprint roughly 0x28000 bytes smaller than Nintendo's.
+ A reimplementation was added for the `jpegdec` system module (thanks @HookedBehemoth)!
+ This allows two sessions instead of 1, so homebrew can now use it for software jpeg decoding in addition to the OS itself.
+ As usual the implementation has a very slightly smaller memory footprint than Nintendo's.
+ `dmnt`'s Cheat VM was extended to add three new opcodes.
+ The first new opcode, "ReadWriteStaticRegister", allows for cheats to read from a bank of 128 read-only static registers, and write to a bank of 128 write-only static registers.
+ This can be used in concert with new IPC commands that allow a cheat manager to read or write the value of these static registers to have "dynamic" cheats.
+ As an example, a cheat manager could write a value to a static register that a cheat to control how many of an item to give in a game.
+ As another example, a cheat manager could read a static register that a cheat writes to to learn how many items a player has.
+ The second and third opcodes are a pair, "PauseProcess" and "ResumeProcess".
+ Executing pause process in a cheat will pause the game (it will be frozen) until a resume process opcode is used.
+ These are also available over IPC, for cheat managers or system modules that want to pause or resume the attached cheat process.
+ This allows a cheat to know that the game won't modify or access data the cheat is accessing.
+ For example, this can be used to prevent Pokemon from seeing a pokemon a cheat is in the middle of injecting and turning it into a bad egg.
+ A bug was fixed that would cause the console to crash when connected to Wi-Fi on versions between 3.0.0 and 4.1.0 inclusive.
+ A bug was fixed that could cause boot to fail sporadically due to cache/tlb mismanagement when doing physical ASLR of the kernel.
+ A number of other minor issues were addressed (and more of Atmosphere was updated to reflect other changes in 10.0.x).
+ General system stability improvements to enhance the user's experience.
## 0.11.1 ## 0.11.1
+ A bug was fixed that could cause owls to flicker under certain circumstances. + A bug was fixed that could cause owls to flicker under certain circumstances.
+ For those interested in technical details, in 10.0.0 kernelldr/kernel no longer set cpuactlr_el1, assuming that it was set correctly by the secure monitor. + For those interested in technical details, in 10.0.0 kernelldr/kernel no longer set cpuactlr_el1, assuming that it was set correctly by the secure monitor.
@@ -6,6 +56,7 @@
+ This caused a variety of highly erratic symptoms, including causing basically any game to crash seemingly randomly. + This caused a variety of highly erratic symptoms, including causing basically any game to crash seemingly randomly.
+ A number of other major inaccuracies in exosphere were corrected. + A number of other major inaccuracies in exosphere were corrected.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.11.0 ## 0.11.0
+ Support was added for 10.0.0. + Support was added for 10.0.0.
+ Exosphere has been updated to reflect the new key import semantics in 10.0.0. + Exosphere has been updated to reflect the new key import semantics in 10.0.0.
@@ -29,6 +80,7 @@
+ In particular, code implementing the os namespace is significantly more accurate. + In particular, code implementing the os namespace is significantly more accurate.
+ In addition, Nintendo's allocators were implemented, allowing for identical memory efficiency versus Nintendo's implementations. + In addition, Nintendo's allocators were implemented, allowing for identical memory efficiency versus Nintendo's implementations.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.10.5 ## 0.10.5
+ Changes were made to the way fs.mitm builds images when providing a layeredfs romfs. + Changes were made to the way fs.mitm builds images when providing a layeredfs romfs.
+ Building romfs metadata previously had a memory cost of about ~4-5x the file table size. + Building romfs metadata previously had a memory cost of about ~4-5x the file table size.
@@ -41,6 +93,7 @@
+ Romfs building can be made even more memory efficient, but unless games show up with even more absurdly huge file tables it seems not worth the speed trade-off. + Romfs building can be made even more memory efficient, but unless games show up with even more absurdly huge file tables it seems not worth the speed trade-off.
+ A bug was fixed that caused Atmosphere's fatal error context to not dump TLS for certain processes. + A bug was fixed that caused Atmosphere's fatal error context to not dump TLS for certain processes.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.10.4 ## 0.10.4
+ With major thanks to @Adubbz for his work, the NCM system module has now been re-implemented. + With major thanks to @Adubbz for his work, the NCM system module has now been re-implemented.
+ This was a major stepping stone towards the goal of having implementations everything in the Switch's package1/package2 firmware. + This was a major stepping stone towards the goal of having implementations everything in the Switch's package1/package2 firmware.
@@ -63,6 +116,7 @@
+ Atmosphere's fatal error context now dumps 0x100 of TLS. + Atmosphere's fatal error context now dumps 0x100 of TLS.
+ This will make it much easier to fix bugs when an error report is dumped for whatever caused the crash. + This will make it much easier to fix bugs when an error report is dumped for whatever caused the crash.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.10.3 ## 0.10.3
+ Support was added for 9.2.0. + Support was added for 9.2.0.
+ Support was added for redirecting manual html content for games. + Support was added for redirecting manual html content for games.
@@ -77,6 +131,7 @@
+ `ro` has been updated to reflect changes made in 9.1.0. + `ro` has been updated to reflect changes made in 9.1.0.
+ The temporary auto-migration added in 0.10.0 has been removed, since the transitionary period is well over. + The temporary auto-migration added in 0.10.0 has been removed, since the transitionary period is well over.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.10.2 ## 0.10.2
+ hbl configuration was made more flexible. + hbl configuration was made more flexible.
+ Up to eight specific program ids can now be specified to have their own override keys. + Up to eight specific program ids can now be specified to have their own override keys.
@@ -111,6 +166,7 @@
+ For now, users may re-enable this mitm by use of a custom setting (`atmosphere!enable_deprecated_hid_mitm`) to ease the transition process some. + For now, users may re-enable this mitm by use of a custom setting (`atmosphere!enable_deprecated_hid_mitm`) to ease the transition process some.
+ Please note: support for this setting may be removed to save memory in a future atmosphere release. + Please note: support for this setting may be removed to save memory in a future atmosphere release.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.10.1 ## 0.10.1
+ A bug was fixed that caused memory reallocation to the system pool to work improperly on firmware 5.0.0 and above. + A bug was fixed that caused memory reallocation to the system pool to work improperly on firmware 5.0.0 and above.
+ Atmosphere was always trying to deallocate memory away from the applet pool and towards the system pool. + Atmosphere was always trying to deallocate memory away from the applet pool and towards the system pool.
@@ -139,6 +195,7 @@
+ Please ensure your homebrew is updated. + Please ensure your homebrew is updated.
+ Random number generation now uses TinyMT instead of XorShift. + Random number generation now uses TinyMT instead of XorShift.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.10.0 ## 0.10.0
+ Support was added for 9.1.0 + Support was added for 9.1.0
+ **Please note**: The temporary hid-mitm added in Atmosphere 0.9.0 will be removed in Atmosphere 0.10.1. + **Please note**: The temporary hid-mitm added in Atmosphere 0.9.0 will be removed in Atmosphere 0.10.1.
@@ -203,6 +260,7 @@
+ An off-by-one was fixed that could cause memory corruption in server memory management. + An off-by-one was fixed that could cause memory corruption in server memory management.
+ ... and too many more bugs fixed to reasonably list them all :) + ... and too many more bugs fixed to reasonably list them all :)
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.9.4 ## 0.9.4
+ Support was added for 9.0.0. + Support was added for 9.0.0.
+ **Please note**: 9.0.0 made a number of changes that may cause some issues with homebrew. Details: + **Please note**: 9.0.0 made a number of changes that may cause some issues with homebrew. Details:
@@ -222,6 +280,7 @@
+ Newer hardware uses new, per-firmware device key to generate BIS keys instead of the first device key, so previously the wrong keys were generated as backup. + Newer hardware uses new, per-firmware device key to generate BIS keys instead of the first device key, so previously the wrong keys were generated as backup.
+ This only affects units manufactured after ~5.0.0. + This only affects units manufactured after ~5.0.0.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.9.3 ## 0.9.3
+ Thanks to hexkyz, fusee's boot sequence has been greatly optimized. + Thanks to hexkyz, fusee's boot sequence has been greatly optimized.
+ Memory training is now managed by a separate binary (`fusee-mtc`, loaded by fusee-primary before fusee-secondary). + Memory training is now managed by a separate binary (`fusee-mtc`, loaded by fusee-primary before fusee-secondary).
@@ -245,6 +304,7 @@
+ Incorrect display output ("2000-0000") has been fixed. Fatal will now correctly show 2162-0002 when this occurs. + Incorrect display output ("2000-0000") has been fixed. Fatal will now correctly show 2162-0002 when this occurs.
+ A longstanding bug in how fatal manages the displays has been fixed, and official display init behavior is now matched precisely. + A longstanding bug in how fatal manages the displays has been fixed, and official display init behavior is now matched precisely.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.9.2 ## 0.9.2
+ A number of emummc bugfixes were added (all thanks to @m4xw's hard work). The following is a summary of emummc changes: + A number of emummc bugfixes were added (all thanks to @m4xw's hard work). The following is a summary of emummc changes:
+ Support for file-based emummc instances was fixed. + Support for file-based emummc instances was fixed.
@@ -268,10 +328,12 @@
+ The rewritten modules consistently have lower memory footprints, and should be easier to maintain going forwards. + The rewritten modules consistently have lower memory footprints, and should be easier to maintain going forwards.
+ The `sm`, `boot`, `spl`, `ro`, and `loader` modules have been tackled so far. + The `sm`, `boot`, `spl`, `ro`, and `loader` modules have been tackled so far.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.9.1 ## 0.9.1
+ Support was added for 8.1.0. + Support was added for 8.1.0.
+ Please note, emummc is still considered **beta/experimental** -- this is not the inevitable bugfix update for it, although some number of bugs have been fixed. :) + Please note, emummc is still considered **beta/experimental** -- this is not the inevitable bugfix update for it, although some number of bugs have been fixed. :)
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.9.0 ## 0.9.0
+ Creport output was improved significantly. + Creport output was improved significantly.
+ Thread names are now dumped on crash in addition to 0x100 of TLS from each thread. + Thread names are now dumped on crash in addition to 0x100 of TLS from each thread.
@@ -296,6 +358,7 @@
+ This can be set to any arbitrary directory by setting `emummc!emummc_nintendo_path`. + This can be set to any arbitrary directory by setting `emummc!emummc_nintendo_path`.
+ To create a backup usable for emummc, users may use tools provided by the [hekate](https://github.com/CTCaer/hekate) project. + To create a backup usable for emummc, users may use tools provided by the [hekate](https://github.com/CTCaer/hekate) project.
+ If, when using emummc, you encounter a bug, *please be sure to report it* -- that's the only way we can fix it. :) + If, when using emummc, you encounter a bug, *please be sure to report it* -- that's the only way we can fix it. :)
## 0.8.10 ## 0.8.10
+ A bug was fixed that could cause incorrect system memory allocation on 5.0.0. + 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. + 5.0.0 should now correctly have an additional 12 MiB allocated for sysmodules.
@@ -312,6 +375,7 @@
+ NAND repair occurs when an unexpected shutdown or error happens during a system update. + 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. + 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. + General system stability improvements to enhance the user's experience.
## 0.8.9 ## 0.8.9
+ A number of bugs were fixed, including: + A number of bugs were fixed, including:
+ A data abort was fixed when mounting certain partitions on NAND. + A data abort was fixed when mounting certain partitions on NAND.
@@ -337,6 +401,7 @@
+ `spl` (Secure Platform Services) is responsible for cryptographic operations, including all communications with the secure monitor (exosphère). + `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. + 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. + General system stability improvements to enhance the user's experience.
## 0.8.8 ## 0.8.8
+ Support was added for firmware version 8.0.0. + Support was added for firmware version 8.0.0.
+ Custom exception handlers were added to stratosphere modules. + Custom exception handlers were added to stratosphere modules.
@@ -344,6 +409,7 @@
+ A bug was fixed in creport that caused games to hang when crashing under certain circumstances. + 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+. + A bug was fixed that prevented maintenance mode from booting on 7.0.0+.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.8.7 ## 0.8.7
+ A few bugs were fixed that could cause fatal to fail to show an error under certain circumstances. + 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). + A bug was fixed that caused an error when launching certain games (e.g. Hellblade: Senua's Sacrifice).
@@ -359,6 +425,7 @@
+ Please note, this feature is **experimental**, and may cause problems. Please use at your own risk (and back up your saves before enabling it), as it still needs testing. + Please note, this feature is **experimental**, and may cause problems. Please use at your own risk (and back up your saves before enabling it), as it still needs testing.
+ This can be enabled by setting `atmosphere!fsmitm_redirect_saves_to_sd` to 1 in `system_settings.ini`. + This can be enabled by setting `atmosphere!fsmitm_redirect_saves_to_sd` to 1 in `system_settings.ini`.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.8.6 ## 0.8.6
+ A number of bugs were fixed, including: + A number of bugs were fixed, including:
+ A case of inverted logic was fixed in fs.mitm which prevented the flags system from working correctly. + A case of inverted logic was fixed in fs.mitm which prevented the flags system from working correctly.
@@ -396,6 +463,7 @@
+ fs.mitm will also now cause requests to mount the HtmlDocument content for HBL's title to open the `sdmc:/atmosphere/hbl_html` folder. + fs.mitm will also now cause requests to mount the HtmlDocument content for HBL's title to open the `sdmc:/atmosphere/hbl_html` folder.
+ By default, this just contains a URL whitelist. + By default, this just contains a URL whitelist.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.8.5 ## 0.8.5
+ Support was added for overriding content on a per-title basis, separate from HBL override. + Support was added for overriding content on a per-title basis, separate from HBL override.
+ This allows for using mods on the same title that one uses to launch HBL. + This allows for using mods on the same title that one uses to launch HBL.
@@ -417,6 +485,7 @@
+ A bug was fixed that would cause Atmosphère's fatal screen to not show on 1.0.0-2.3.0. + A bug was fixed that would cause Atmosphère's fatal screen to not show on 1.0.0-2.3.0.
+ A bug was fixed that caused Atmosphère's automatic ProdInfo backups to be corrupt. + A bug was fixed that caused Atmosphère's automatic ProdInfo backups to be corrupt.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.8.4 ## 0.8.4
+ Support for 7.0.0/7.0.1 was added. + Support for 7.0.0/7.0.1 was added.
+ This is facilitated through a new payload, `sept`, which can be signed, encrypted, and then loaded by Nintendo's TSEC firmware. + This is facilitated through a new payload, `sept`, which can be signed, encrypted, and then loaded by Nintendo's TSEC firmware.
@@ -432,6 +501,7 @@
+ Performing a reboot from the reboot menu now reboots to atmosphere. This can be configured via `system_settings.ini`. + Performing a reboot from the reboot menu now reboots to atmosphere. This can be configured via `system_settings.ini`.
+ Performing a shutdown from the reboot menu now works properly with AutoRCM, and does a real shutdown. + Performing a shutdown from the reboot menu now works properly with AutoRCM, and does a real shutdown.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.8.3 ## 0.8.3
+ A custom warmboot firmware was implemented, which does not perform anti-downgrade fuse checks. + A custom warmboot firmware was implemented, which does not perform anti-downgrade fuse checks.
+ This fixes sleep mode when using a downgraded NAND. + This fixes sleep mode when using a downgraded NAND.
@@ -452,6 +522,7 @@
+ Fatal will now use this to reboot to sdmc:/atmosphere/reboot_payload.bin if present, when a vol button is pressed. + Fatal will now use this to reboot to sdmc:/atmosphere/reboot_payload.bin if present, when a vol button is pressed.
+ An example homebrew ("reboot_to_payload") was also written and is now included with Atmosphère. + An example homebrew ("reboot_to_payload") was also written and is now included with Atmosphère.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.8.2 ## 0.8.2
+ A number of bugs were fixed causing users to sometimes see `Key Derivation Failed!`. + A number of bugs were fixed causing users to sometimes see `Key Derivation Failed!`.
+ KFUSE clock enable timings have been adjusted to allow time to stabilize before TSEC is granted access. + KFUSE clock enable timings have been adjusted to allow time to stabilize before TSEC is granted access.
@@ -461,6 +532,7 @@
+ A bug was fixed causing sleep mode to not work with debugmode enabled. + A bug was fixed causing sleep mode to not work with debugmode enabled.
+ As a result, debugmode is now enabled in the default BCT.ini. + As a result, debugmode is now enabled in the default BCT.ini.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.8.1 ## 0.8.1
+ A bug was fixed causing users to see `Failed to enable SMMU!` if fusee had previously rebooted. + A bug was fixed causing users to see `Failed to enable SMMU!` if fusee had previously rebooted.
+ This message will still occur sporadically if fusee is not launched from coldboot, but it can never happen twice in a row. + This message will still occur sporadically if fusee is not launched from coldboot, but it can never happen twice in a row.
@@ -482,6 +554,7 @@
+ On fatal error, the user can now choose to perform a standard reboot via the power button, or a reboot into RCM via either volume button. + On fatal error, the user can now choose to perform a standard reboot via the power button, or a reboot into RCM via either volume button.
+ A custom message was added to `fatal` for when an Atmosphère API version mismatch is detected (2495-1623). + A custom message was added to `fatal` for when an Atmosphère API version mismatch is detected (2495-1623).
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.8.0 ## 0.8.0
+ A custom `fatal` system module was added. + A custom `fatal` system module was added.
+ This re-implements and extends Nintendo's fatal module, with the following features: + This re-implements and extends Nintendo's fatal module, with the following features:
@@ -515,6 +588,7 @@
+ By default, new keys will automatically be derived without user input. + By default, new keys will automatically be derived without user input.
+ Support is also present for loading new keys from `atmosphere/prod.keys` or `atmosphere/dev.keys` + Support is also present for loading new keys from `atmosphere/prod.keys` or `atmosphere/dev.keys`
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.7.5 ## 0.7.5
+ DRAM training was added to fusee-secondary, courtesy @hexkyz. + DRAM training was added to fusee-secondary, courtesy @hexkyz.
+ This greatly improves the speed of memory accesses during boot, resulting in a boot time that is ~200-400% faster. + This greatly improves the speed of memory accesses during boot, resulting in a boot time that is ~200-400% faster.
@@ -523,6 +597,7 @@
+ This matches the improvement Nintendo added to official creport in 6.1.0. + This matches the improvement Nintendo added to official creport in 6.1.0.
+ The code region detection heuristic was further improved by checking whether an address points to .rodata or .rwdata, instead of just .text. + The code region detection heuristic was further improved by checking whether an address points to .rodata or .rwdata, instead of just .text.
+ This means that a crash appears in a loaded NRO (or otherwise discontiguous) code region, creport will be able to detect all active code regions, and not just that one. + This means that a crash appears in a loaded NRO (or otherwise discontiguous) code region, creport will be able to detect all active code regions, and not just that one.
## 0.7.4 ## 0.7.4
+ [libstratosphere](https://github.com/Atmosphere-NX/libstratosphere) has been completely refactored/rewritten, and split into its own, separate submodule. + [libstratosphere](https://github.com/Atmosphere-NX/libstratosphere) has been completely refactored/rewritten, and split into its own, separate submodule.
+ While this is mostly "under the hood" for end-users, the refactor is faster (improving both boot-time and runtime performance), more accurate (many of the internal IPC structures are now bug-for-bug compatible with Nintendo's implementations), and significantly more stable (it fixes a large number of bugs present in the old library). + While this is mostly "under the hood" for end-users, the refactor is faster (improving both boot-time and runtime performance), more accurate (many of the internal IPC structures are now bug-for-bug compatible with Nintendo's implementations), and significantly more stable (it fixes a large number of bugs present in the old library).
@@ -543,11 +618,13 @@
+ PM now only gives full FS permissions to the active KIPs. This fixes a potential crash where new processes might be unable to be registered with FS. + PM now only gives full FS permissions to the active KIPs. This fixes a potential crash where new processes might be unable to be registered with FS.
+ The `make dist` target now includes the branch in the generated zip name. + The `make dist` target now includes the branch in the generated zip name.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.7.3 ## 0.7.3
+ Loader and fs.mitm now try to reload loader.ini before reading it. This allows for changing the override button combination/HBL title id at runtime. + Loader and fs.mitm now try to reload loader.ini before reading it. This allows for changing the override button combination/HBL title id at runtime.
+ Added a MitM between set:sys and qlaunch, used to override the system version string displayed in system settings. + Added a MitM between set:sys and qlaunch, used to override the system version string displayed in system settings.
+ The displayed system version will now display `<Actual version> (AMS <x>.<y>.<z>)`. + The displayed system version will now display `<Actual version> (AMS <x>.<y>.<z>)`.
+ General system stability improvements to enhance the user's experience. + General system stability improvements to enhance the user's experience.
## 0.7.2 ## 0.7.2
+ Fixed a bug in fs.mitm's LayeredFS read implementation that caused some games to crash when trying to read files. + Fixed a bug in fs.mitm's LayeredFS read implementation that caused some games to crash when trying to read files.
+ Fixed a bug affecting 1.0.0 that caused games to crash with fatal error 2001-0106 on boot. + Fixed a bug affecting 1.0.0 that caused games to crash with fatal error 2001-0106 on boot.

View File

@@ -0,0 +1,4 @@
# emummc
emummc is a collaborative project that provides eMMC storage emulation.
Please refer to the project's repository [here](https://github.com/m4xw/emuMMC) for detailed instructions and documentation.

View File

@@ -1,10 +1,76 @@
# Exosphère # exosphère
Exosphère is a reimplementation of Arm's TrustZone (TZ), also known as Secure Monitor (Secure_Monitor.bin). It has the highest privilege mode available on the Switchs processor, and has access to everything on the console. exosphère is a customized reimplementation of the Horizon OS's Secure Monitor.
The Secure Monitor follows the same design principle as Arm's TrustZone and both terms can be used interchangeably in this context. It runs at the highest privilege mode (EL3) available to the main processor and is responsible for all the sensitive cryptographic operations needed by the system as well as power management for each CPU.
Exosphère will potentially play a big role in Jamais Vu and Déja Vu, which are upcoming software exploits for the Switch, allowing one to launch Atmosphère on a Fusée-Gélee patched (ipatched) Switch console, and will also enable one to launch into CFW directly from the Switch itself without the use of any sort of external device, such as a computer or RCM jig, provided they are on a low enough system firmware.
## TrustZone/Secure Monitor
TrustZone is responsible for all the cryptographic operations on the Switch. The idea behind the way it operates is that all the keys stay in the TrustZone, and userspace only gets "handles" to them. This would make sure that keydata never leaks and is kept secure. It also has a few more responsibilities, such as power management, providing a source of random numbers, and providing access to various pieces of information that are stored in the fuses.
## Extensions ## Extensions
Exosphère currently only contains one extension, an SMC allowing homebrew to find which version of Atmosphère is currently running, in order to find out what extensions are allowed to be used. exosphère expands the original Secure Monitor design by providing custom SMCs (Secure Monitor Calls) necessary to the homebrew ecosystem. Currently, these are:
```
uint32_t smc_ams_iram_copy(smc_args_t *args);
uint32_t smc_ams_write_address(smc_args_t *args);
uint32_t smc_ams_get_emummc_config(smc_args_t *args);
```
Additionally, exosphère expands the functionality of two SMCs provided by the Horizon OS for getting/setting configuration items. The following custom configuration items are provided by exosphère:
```
CONFIGITEM_EXOSPHERE_VERSION = 65000,
CONFIGITEM_NEEDS_REBOOT = 65001,
CONFIGITEM_NEEDS_SHUTDOWN = 65002,
CONFIGITEM_EXOSPHERE_VERHASH = 65003,
CONFIGITEM_HAS_RCM_BUG_PATCH = 65004,
CONFIGITEM_SHOULD_BLANK_PRODINFO = 65005,
CONFIGITEM_ALLOW_CAL_WRITES = 65006,
```
### smc_ams_iram_copy
This function implements a copy of up to one page between DRAM and IRAM. Its arguments are:
```
args->X[1] = DRAM address (translated by kernel), must be 4-byte aligned.
args->X[2] = IRAM address, must be 4-byte aligned.
args->X[3] = Size (must be <= 0x1000 and 4-byte aligned).
args->X[4] = 0 for read, 1 for write.
```
### smc_ams_write_address
This function implements a write to a DRAM page. Its arguments are:
```
args->X[1] = Virtual address, must be size-bytes aligned and readable by EL0.
args->X[2] = Value.
args->X[3] = Size (must be 1, 2, 4, or 8).
```
### smc_ams_get_emummc_config
This function retrieves configuration for the current [emummc](emummc.md) context. Its arguments are:
```
args->X[1] = MMC id, must be size-bytes aligned and readable by EL0.
args->X[2] = Pointer to output (for paths for filebased + nintendo dir), must be at least 0x100 bytes.
```
### CONFIGITEM_EXOSPHERE_VERSION
This custom configuration item gets information about the current exosphere version.
### CONFIGITEM_NEEDS_REBOOT
This custom configuration item is used to issue a system reboot into RCM or into a warmboot payload leveraging a secondary vulnerability to achieve code execution from warm booting.
### CONFIGITEM_NEEDS_SHUTDOWN
This custom configuration item is used to issue a system shutdown with a warmboot payload leveraging a secondary vulnerability to achieve code execution from warm booting.
### CONFIGITEM_EXOSPHERE_VERHASH
This custom configuration item gets information about the current exosphere git commit hash.
### CONFIGITEM_HAS_RCM_BUG_PATCH
This custom configuration item gets whether the unit has the CVE-2018-6242 vulnerability patched.
### CONFIGITEM_SHOULD_BLANK_PRODINFO
This custom configuration item gets whether the unit should simulate a "blanked" PRODINFO. See [here](../features/configurations.md) for more information.
### CONFIGITEM_ALLOW_CAL_WRITES
This custom configuration item gets whether the unit should allow writing to the calibration partition.
## lp0fw
This is a small, built-in payload that is responsible for waking up the system during a warm boot.
## sc7fw
This is a small, built-in payload that is responsible for putting the system to sleep during a warm boot.
## rebootstub
This is a small, built-in payload that provides functionality to reboot the system into any payload of choice.

22
docs/components/fusee.md Normal file
View File

@@ -0,0 +1,22 @@
# fusée
fusée is a custom bootloader used to start the Atmosphère environment.
It is divided into three sub-components: fusée-primary, fusée-mtc and fusée-secondary.
fusée is also capable of chainloading other payloads (e.g.: Android).
fusée's behavior can be configured via the [BCT.ini](../features/configurations.md) file located on the SD card.
## fusée-primary
fusée-primary is the first piece of Atmosphère's code that runs on the hardware.
It is distributed as a standalone payload designed to be launched via RCM by abusing the CVE-2018-6242 vulnerability.
This payload is responsible for all the low-level hardware initialization required by the Nintendo Switch, plus the extra task of initializing the SD card and reading the next fusée sub-components from it.
## fusée-mtc
fusée-mtc is an optional, but heavily recommended sub-component that performs DRAM memory training.
This ensures a proper environment for running the final fusée sub-component.
## fusée-secondary
fusée-secondary is the last fusée sub-component that runs on the system.
It is responsible for configuring and bootstrapping the Atmosphère environment by mimicking the Horizon OS's design.
This includes setting up the cryptosystem, mounting or emulating the eMMC, injecting or patching system modules and launching the exosphère component.

View File

@@ -1,73 +0,0 @@
# BCT.ini
BCT.ini is the configuration file used by fusée-primary and fusée-secondary. It is read by fusee-primary.bin to setup and boot fusee-secondary.bin and is also read by fusee-secondary.bin to configure Exosphère, specify the environment it should boot, or configure other miscellaneous options such as setting a custom boot splashscreen.
## Configuration
This file is located in the `atmosphere` folder on your SD card. The default configuration file will look similar to this.
```
BCT0
[stage1]
stage2_path = atmosphere/fusee-secondary.bin
stage2_addr = 0xF0000000
stage2_entrypoint = 0xF0000000
[exosphere]
; Note: Disabling debugmode will cause parts of ams.tma to not work, in the future.
debugmode = 1
debugmode_user = 0
[stratosphere]
; To force-enable nogc, add nogc = 1
; To force-disable nogc, add nogc = 0
```
## Adding a Custom Boot Splashscreen
Add the following lines to BCT.ini and change the value of `custom_splash` to the actual path and filename of your boot splashscreen.
```
[stage2]
custom_splash = /path/to/your/bootlogo.bmp
```
The boot splashscreen must be a BMP file, it must be 720x1280 (1280x720 rotated 90 degrees left/counterclockwise/anti-clockwise) resolution, and be in 32-bit ARGB format. You can use image editing software such as GIMP or Photoshop to export the image in this format.
## Configuring "nogc" Protection
Nogc is a feature provided by fusée-secondary which disables the Nintendo Switch's Game Card reader. Its purpose is to prevent the reader from being updated when the console has been updated without burning fuses from a firmware lower than 4.0.0, to a newer firmware that is at least 4.0.0 or higher. By default, Atmosphère will protect the Game Card reader automatically, but you are free to change it.
To change its functionality, add the following line to the `stratosphere` section and change the value of `X` according to the following list.
```
nogc = X
```
```
1 = force-enable nogc, so Atmosphère will always disable the Game Card reader.
0 = force-disable nogc, so Atmosphère will always enable the Game Card reader.
```
## Changing Target Firmware
Add the following line to the `exosphere` section and replace the `X` according to the following list if you have trouble booting past the firmware version detection.
`target_firmware` is the OFW major version.
```
target_firmware = X
```
```
1.0.0 = 1
2.X.X = 2
3.X.X = 3
4.X.X = 4
5.X.X = 5
6.X.X = 6
6.2.0 = 7
7.X.X = 8
```
Note that 6.X.X indicates 6.0.0 through 6.1.0.
## Configuring Debugging Modes
By default, Atmosphère signals to the Horizon kernel that debugging is enabled while leaving usermode debugging disabled, since this can cause undesirable side-effects. If you wish to change these behaviours, go to the `exosphere` section and change the value of `X` according to the following list.
```
debugmode = X
debugmode_user = X
```
```
1 = enable
0 = disable
```

View File

@@ -1,20 +0,0 @@
# Fusée
Fusée (not to be confused with Fusée Gelée) is a custom bootloader needed to start Atmosphère and replaces Nintendo's Package1loader/bootloader. It currently utilizes the [Tegra X1 RCM Vulnerability](https://nvidia.custhelp.com/app/answers/detail/a_id/4660/~/security-notice%3A-nvidia-tegra-rcm-vulnerability) in order to function.
Fusée is split into two separate parts: fusée-primary and fusée-secondary. This is due to the RCM Vulnerability only allowing payloads of a limited filesize to be sent to the device.
As of June 2018, there are new Switch systems being sold that prevent Fusée (or any payload that requires the Fusée Gelée exploit) from working due to having an ipatched bootrom. All ipatched systems share the HAC-S-JXE-C3 product code. While Fusée cannot work on these ipatched units, they still come on firmware 4.1.0, which is vulnerable to the upcoming Déja Vu software exploit. Note that if you update past 4.1.0 on one of these ipatched units, your odds of being able to install Atmosphère or run any homebrew become practically non-existent.
Additionally, a hardware revision of the Switch known as “Mariko” is believed to be in development. No such units have been seen in stores yet, but it is expected Nintendo will roll them out silently. The Mariko units will most likely patch the bootrom vulnerability Fusée Gelée, which is currently used to access CFW, and will likely have their own proprietary bootloader.
## Fusée-Primary
Fusée-primary is the payload file (fusee-primary.bin) sent to the Switch from an external device. Once sent, fusée-primary makes initial preparations before loading fusée-secondary from the Switchs SD Card.
Fusée-primary can be configured via the [BCT.ini](../fusee/BCT.md) file located on the Switchs SD card.
## Fusée-Secondary
Fusée-secondary is a payload file that stays on the root of the Switchs SD Card (fusee-secondary.bin). It is automatically launched once fusée-primary has finished, and is responsible for preparing the Switchs hardware for future running environments, such as the homebrew menu. Fusée-secondary is also responsible for validating and launching Exosphère.
Fusée-secondary contains various [.kip modules](/docs/main.md#modules). These modules modify existing features in the OS, and can also add new ones.
Fusée is also capable of chainloading other payloads such as Linux.

View File

@@ -1,15 +0,0 @@
# sept
Sept is a payload that facilitates booting Atmosphère when targeting firmware version 7.0.0+.
It consists of a primary and a secondary payload.
## Sept-Primary
Sept-primary is essentially a stand-in for Nintendo's package1ldr, on 7.0.0+. To use it, the caller (normally Fusée-secondary) loads the sept-primary binary to `0x4003F000`,
loads the 7.0.0+ TSEC firmware to `0x40010F00`, and loads a signed, encrypted payload to `0x40016FE0`.
This signed, encrypted payload is normally Sept-secondary.
## Sept-Secondary
Sept-secondary is a payload that performs 7.0.0+ key derivation, and then chainloads to `sept/payload.bin`.
It is normally stored encrypted/signed; if one wishes to build sept-secondary instead of using release builds, one must bring his/her own keys.

View File

@@ -0,0 +1,11 @@
# libraries
This is a collection of libraries for doing operating system development for the Nintendo Switch.
## libmesosphere
libmesosphere is a work-in-progress C++ library implementing functionality for the Horizon Kernel.
## libstratosphere
libstratosphere is a work-in-progress C++ library for development of system modules for the Nintendo Switch.
## libvapours
Common boilerplate code for various purposes.

View File

@@ -0,0 +1,3 @@
# mesosphère
mesosphère is a work in progress customized kernel reimplementation.
The Horizon OS's kernel follows microkernel design principles and runs at the EL1 level. It is currently subdivided into a loader (kernel_ldr) and the main kernel code.

View File

@@ -0,0 +1,35 @@
# ams_mitm
This module provides methods to intercept services provided by other system modules. It is further sub-divided according to the service it targets.
## bpc_mitm
bpc_mitm enables intercepting requests to power control services. It currently intercepts:
+ `am` system module (to intercept the Reboot/Power buttons in the overlay menu)
+ `fatal` system module (to simplify payload reboot logic significantly)
+ [nx-hbloader](https://github.com/switchbrew/nx-hbloader) (to allow homebrew to take advantage of the feature)
## fs_mitm
fs_mitm enables intercepting file system operations. It can deny, delay, replace, or redirect any request made to the file system. It enables LayeredFS to function, which allows for replacement of game assets.
## hid_mitm
hid_mitm enables intercepting requests to controller device services. It is currently disabled by default. If enabled, it intercepts:
+ [nx-hbloader](https://github.com/switchbrew/nx-hbloader) (to help homebrew not need to be recompiled due to a breaking change introduced in the past)
Note that hid_mitm is currently deprecated and might be removed entirely in the future.
## ns_mitm
ns_mitm enables intercepting requests to application control services. It currently intercepts:
+ Web Applets (to facilitate nx-hbloader web browser launching)
## set_mitm
set_mitm enables intercepting requests to the system settings service. It currently intercepts:
+ `ns` system module and games (to allow for overriding game locales)
+ All firmware debug settings requests (to allow modification of system settings not directly exposed to the user)
### Firmware Version
set_mitm intercepts the `GetFirmwareVersion` command, if the requester is `qlaunch` or `maintenance`.
It modifies the `display_version` field of the returned system version, causing the version to display
in settings as `#.#.#|AMS #.#.#|?` with `? = S` when running under system eMMC or `? = E` when running under emulated eMMC. This allows users to easily verify what version of Atmosphère and what eMMC environment they are running.
### System Settings
set_mitm intercepts the `GetSettingsItemValueSize` and `GetSettingsItemValue` commands for all requesters.
It does so in order to enable user configuration of system settings, which are parsed from `/atmosphere/system_settings.ini` on boot. See [here](../../features/configurations.md) for more information on the system settings format.

View File

@@ -0,0 +1,4 @@
# boot
This module is a reimplementation of the Horizon OS's `boot` system module, which is responsible for initializing and configuring hardware.
Atmosphère's reimplementation displays its own black and white splash screen and battery icons as replacements for the original assets used during display initialization.

View File

@@ -0,0 +1,4 @@
# boot2
This module is a reimplementation of the Horizon OS's `boot2` system module, which is responsible for launching all the other necessary system modules.
Atmosphère's reimplementation allows launching user provided system modules from the SD card. See [here](../../features/configurations.md) for more information.

View File

@@ -0,0 +1,4 @@
# creport
This module is a reimplementation of the Horizon OS's `creport` system module, which is responsible for managing crash reports.
Atmosphère's reimplementation redirects writing of generated crash reports to the SD card under the folder `/atmosphere/crash_reports/`. It also prevents the automatic uploading of said crash reports.

View File

@@ -0,0 +1,42 @@
# dmnt
This module is a reimplementation of the Horizon OS's `dmnt` system module, which provides a debug monitor.
## Extensions
Atmosphère implements an extension to provide cheat code functionality.
### Cheat Service
A HIPC service API is provided for interacting with the cheat code manager through the service `dmnt:cht`. See [here](../../features/cheats.md) for more information on the cheat code format.
The SwIPC definition for `dmnt:cht` follows:
```
interface ams::dmnt::cheat::CheatService is dmnt:cht {
[65000] HasCheatProcess() -> sf::Out<bool> out;
[65001] GetCheatProcessEvent() -> sf::OutCopyHandle out_event;
[65002] GetCheatProcessMetadata() -> sf::Out<CheatProcessMetadata> out_metadata;
[65003] ForceOpenCheatProcess();
[65004] PauseCheatProcess();
[65005] ResumeCheatProcess();
[65100] GetCheatProcessMappingCount() -> sf::Out<u64> out_count;
[65101] GetCheatProcessMappings(u64 offset) -> sf::OutArray<MemoryInfo> &mappings, sf::Out<u64> out_count;
[65102] ReadCheatProcessMemory(u64 address, u64 out_size) -> sf::OutBuffer &buffer;
[65103] WriteCheatProcessMemory(sf::InBuffer &buffer, u64 address, u64 in_size);
[65104] QueryCheatProcessMemory(u64 address) -> sf::Out<MemoryInfo> mapping;
[65200] GetCheatCount() -> sf::Out<u64> out_count;
[65201] GetCheats(u64 offset) -> sf::OutArray<CheatEntry> &cheats, sf::Out<u64> out_count;
[65202] GetCheatById(u32 cheat_id) -> sf::Out<CheatEntry> cheat;
[65203] ToggleCheat(u32 cheat_id);
[65204] AddCheat(CheatDefinition &cheat, bool enabled) -> sf::Out<u32> out_cheat_id;
[65205] RemoveCheat(u32 cheat_id);
[65206] ReadStaticRegister(u8 which) -> sf::Out<u64> out;
[65207] WriteStaticRegister(u8 which, u64 value);
[65208] ResetStaticRegisters();
[65300] GetFrozenAddressCount() -> sf::Out<u64> out_count;
[65301] GetFrozenAddresses(u64 offset) ->sf::OutArray<FrozenAddressEntry> &addresses, sf::Out<u64> out_count;
[65302] GetFrozenAddress(u64 address) -> sf::Out<FrozenAddressEntry> entry;
[65303] EnableFrozenAddress(u64 address, u64 width) -> sf::Out<u64> out_value;
[65304] DisableFrozenAddress(u64 address);
}
```

View File

@@ -0,0 +1,4 @@
# eclct.stub
This module is a reimplementation of the Horizon OS's `eclct` system module, which collects error reports.
Atmosphère's reimplementation is a stub to remove any and all functionality pertaining to error report collection.

View File

@@ -0,0 +1,4 @@
# erpt
This module is a reimplementation of the Horizon OS's `erpt` system module, which is responsible for managing error reports.
Atmosphère's reimplementation redirects writing of generated error reports to the SD card under the folder `/atmosphere/erpt_reports/`.

View File

@@ -0,0 +1,4 @@
# fatal
This module is a reimplementation of the Horizon OS's `fatal` system module, which is responsible for managing fatal reports.
Atmosphère's reimplementation prevents error report creation and draws a custom error screen, showing registers and a backtrace. It also attempts to gather debugging info for any and all crashes and tries to save reports to the SD card under the folder `/atmosphere/fatal_reports/`.

View File

@@ -0,0 +1,4 @@
# jpegdec
This module is a reimplementation of the Horizon OS's `jpegdec` system module, which is responsible for JPEG format decoding.
Atmosphère's reimplementation allows two sessions instead of 1, so homebrew can use it for software JPEG decoding in addition to the OS itself.

View File

@@ -0,0 +1,106 @@
# loader
This module is a reimplementation of the Horizon OS's `ldr` system module, which is responsible for creating processes from executable NSO images and registering their access control.
## Extensions
Atmosphère extends this module to allow executables to be replaced or patched by files stored on the SD card. Note that a few services are required for SD card access and therefore cannot be replaced or patched in this manner.
### Exefs Replacement
Atmosphère's reimplementation allows replacing executable files in the file system.
#### Partition Replacement
It is possible to replace the full exefs partition at once with a PFS0 file. In that case, Atmosphère will load the following file:
```
/atmosphere/contents/<program id>/exefs.nsp
```
#### File Replacement
When a process is created, loader will search for several NSO filenames in the program's exefs directory.
These filenames are, in this order:
- rtld
- main
- subsdk0
- subsdk1
- ...
- subsdk9
- sdk
Each NSO that is found will be loaded into the process contiguously. The process's entrypoint is at the first NSO to be loaded, usually `rtld` or `main`.
Additionally, when a process is loaded, loader will search for a `main.npdm` file in the exefs directory specifying the program's permissions.
Atmosphère extends this functionality by also searching for these files on the SD card. When searching for a file, loader will first check if it exists on the SD card. If it does, that file will be used instead. Otherwise, it will use the copy located in the exefs, if that is present. The following directory will be searched:
```
/atmosphere/contents/<program id>/exefs/
```
This allows the replacement of applets, system modules, or even games with homebrew versions.
##### File Stubbing
In order to prevent an NSO from being loaded even if it exists in the exefs, loader will also check if a stub file exists. If such a file exists, the NSO will not be loaded. The files should be named like `rtld.stub`, `main.stub`, etc. and may be empty.
##### Technical Semantics
loader's semantics for content override can (as you may observe from reading the above) be complicated to understand. The following is an abbreviated description of the very technical semantics by which loader decides what content to read when trying to read a file for a program id.
* If an external content filesystem exists for the program id, the external content filesystem is used directly with no further redirection.
* Otherwise, if the program ID is being overridden with [nx-hbloader](https://github.com/switchbrew/nx-hbloader/releases) (see Homebrew Support below), the nsp filesystem for hbl is used directly with no further redirection.
* Otherwise, if content redirection is enabled for the program ID (controlled by a configurable button combination) and a loose file exists on the SD card, the loose file is used.
* Otherwise, if a stub file exists, a "Not Found" error is returned.
* Otherwise, if an SD card executable filesystem ("exefs.nsp") exists, it is used without further redirection.
* Finally, the "real"/base code file system is used without further redirection.
In addition, there are a few other technical details relevant to Atmosphere's redirection:
* When overriding with nx-hbloader, the real code filesystem must exist. When "main.npdm" (a program capabilities descriptor file) is read, the content from the real code filesystem is read in order to determine whether an applet or an application is being overridden. This allows nx-hbloader to automatically support both applet and application environments.
* When overriding applications, the real code filesystem must exist and contain valid content. This is required to perform accurate-to-Nintendo content verification procedures.
* When programs are launched, both a program id and a "storage id" are specified by the launch requester. When the storage id specified is "none" (normally always invalid), Atmosphere assumes that a custom system module is attempting to be launched. This removes the aforementioned requirement on base content validity; the above procedure is still used to determine how to redirect content, however reads to the "real"/base code file system may return "Not Found" errors if the real/base code file system does not exist.
### NSO Patching
When an NSO is loaded, Atmosphère's reimplementation will search for IPS patch files on the SD card in the following locations.
```
/atmosphere/exefs_patches/<patchset name>/<nso build id>.ips
```
This organization allows patch sets affecting multiple NSOs to be distributed as a single directory and also allows patches from multiple patch sets to be stacked. Patches will be searched for in each patch set directory. The name of each patch file should match the hexadecimal build ID of the NSO to affect, except that trailing zero bytes may be left off. Because the NSO build ID is unique for every NSO, this means patches will only apply to the files they are meant to apply to.
Patch files are accepted in either IPS format or IPS32 format.
Because NSO files are compressed, patch files are not made between the original version of a compressed NSO and the modified version of such an NSO. Instead, they are made between the uncompressed version of an NSO and the modified (and still uncompressed) version of that NSO. This also means that a patch file cannot be manually applied to the compressed version of an NSO; it must be applied to the uncompressed version. Atmosphère's reimplementation will correctly apply these patches while loading the process regardless of whether the NSO it finds is compressed or not.
When authoring patches, [hactool](https://github.com/SciresM/hactool) can be used to find an NSO's build ID and to uncompress NSOs. Recent versions of the [ReSwitched IDA loaders](https://github.com/reswitched/loaders) can be used to load uncompressed NSOs into IDA in such a way that you can [apply patches to the input file](https://www.hex-rays.com/products/ida/support/idadoc/1618.shtml). From there, any IPS tool can be used to create the patch between the original NSO and the patched NSO. Note that if the NSO you are patching is larger than 16 MiB, you will have to use a tool that supports IPS32.
### Homebrew Support
Atmosphère provides first class support for [nx-hbloader](https://github.com/switchbrew/nx-hbloader/releases) and [nx-hbmenu](https://github.com/switchbrew/nx-hbmenu/releases).
Launching of the nx-hbloader process is controlled by configurable button inputs. See [here](../../features/configurations.md) for more detailed information.
In addition, loader has extensions to enable homebrew to launch web applets. This normally requires the application launching the applet to have HTML Manual content inside an installed NCA. Atmosphère's reimplementation will automatically ensure that the commands used to check this succeed, and will redirect the relevant file system to the `/atmosphere/hbl_html/` subdirectory.
### IPC Commands
Atmosphère's reimplementation extends the HIPC loader services' API with several custom commands.
The SwIPC definition for the `ldr:pm` extension commands follows:
```
interface ams::ldr::pm::ProcessManagerInterface is ldr:pm {
...
[65000] AtmosphereHasLaunchedProgram(ncm::ProgramId program_id) -> sf::Out<bool> out;
[65001] AtmosphereGetProgramInfo(ncm::ProgramLocation &loc) -> sf::Out<ProgramInfo> out_program_info, sf::Out<cfg::OverrideStatus> out_status;
[65002] AtmospherePinProgram(ncm::ProgramLocation &loc, cfg::OverrideStatus &override_status) -> sf::Out<PinId> out_id;
}
```
The SwIPC definition for the `ldr:dmnt` extension commands follows:
```
interface ams::ldr::dmnt::DebugMonitorInterface is ldr:dmnt {
...
[65000] AtmosphereHasLaunchedProgram(ncm::ProgramId program_id) -> sf::Out<bool> out;
}
```
The SwIPC definition for the `ldr:shel` extension commands follows:
```
interface ams::ldr::shell::ShellInterface is ldr:shel {
...
[65000] AtmosphereRegisterExternalCode(ncm::ProgramId program_id) -> sf::OutMoveHandle out;
[65001] AtmosphereUnregisterExternalCode(ncm::ProgramId program_id);
}
```

View File

@@ -0,0 +1,4 @@
# ncm
This module is a reimplementation of the Horizon OS's `ncm` system module, which is responsible for content management.
Atmosphère's reimplementation is currently opt-in only. See [here](../../features/configurations.md) for more information.

View File

@@ -0,0 +1,4 @@
# pgl
This module is a reimplementation of the Horizon OS's `pgl` system module, which is responsible for launching programs and was introduced by firmware version `10.0.0`.
Currently, Atmosphère's reimplementation doesn't backport this module's functionalities to firmware versions lower than `10.0.0`.

View File

@@ -0,0 +1,30 @@
# pm
This module is a reimplementation of the Horizon OS's `pm` system module, which is responsible for tracking running processes on the system, and managing resource limits.
## Extensions
Atmosphère extends this module with extra IPC commands and memory restriction changes.
### IPC Commands
Atmosphère's reimplementation extends the HIPC loader services' API with several custom commands.
The SwIPC definition for the `pm:dmnt` extension commands follows:
```
interface ams::pm::dmnt::DebugMonitorServiceBase is pm:dmnt {
...
[65000] AtmosphereGetProcessInfo(os::ProcessId process_id) -> sf::OutCopyHandle out_process_handle, sf::Out<ncm::ProgramLocation> out_loc, sf::Out<cfg::OverrideStatus> out_status;
[65001] AtmosphereGetCurrentLimitInfo(u32 group, u32 resource) -> sf::Out<s64> out_cur_val, sf::Out<s64> out_lim_val;
}
```
The SwIPC definition for the `pm:info` extension commands follows:
```
interface ams::pm::info::InformationService is pm:info {
...
[65000] AtmosphereGetProcessId(ncm::ProgramId program_id) -> sf::Out<os::ProcessId> out;
[65001] AtmosphereHasLaunchedProgram(ncm::ProgramId program_id) -> sf::Out<bool> out;
[65002] AtmosphereGetProcessInfo(os::ProcessId process_id) -> sf::Out<ncm::ProgramLocation> out_loc, sf::Out<cfg::OverrideStatus> out_status;
}
```
### Extra System Memory
Atmosphère's reimplementation shrinks the APPLET memory pool by 24 MiB by default, giving this memory to the SYSTEM pool. This allows custom system modules to use more memory without hitting the SYSTEM memory limit.

View File

@@ -0,0 +1,16 @@
# ro
This module is a reimplementation of the Horizon OS's `ro` system module, which is responsible for loading dynamic libraries and was introduced by firmware version `3.0.0`.
Atmosphère's reimplementation backports this module's functionalities to firmware versions lower than `3.0.0` where said functionalities were provided by the `ldr` system module instead.
## Extensions
Atmosphère extends this module to allow libraries to be patched by files stored on the SD card.
### NRO Patching
When an NRO is loaded, Atmosphère's reimplementation will search for IPS patch files on the SD card in the following locations.
```
/atmosphere/nro_patches/<patchset name>/<nro build id>.ips
```
This organization allows patch sets affecting multiple NROs to be distributed as a single directory. Patches will be searched for in each patch set directory. The name of each patch file should match the hexadecimal build ID of the NRO to affect, except that trailing zero bytes may be left off. Because the NRO build ID is unique for every NRO, this means patches will only apply to the files they are meant to apply to.
Patch files are accepted in either IPS format or IPS32 format.

View File

@@ -0,0 +1,47 @@
# sm
This module is a reimplementation of the Horizon OS's `sm` system module, which is responsible for service management.
## Extensions
Atmosphère extends this module with extra IPC commands and new services.
### Debug Monitor
Atmosphère's reimplementation provides an interface `sm:dmnt` to allow a debug monitor to query the service manager's state.
The SwIPC definition for `sm:dmnt` follows:
```
interface ams::sm::DmntService is sm:dmnt {
[65000] AtmosphereGetRecord(ServiceName service) -> sf::Out<ServiceRecord> record;
[65001] AtmosphereListRecords(u64 offset) -> sf::OutArray<ServiceRecord> &records, sf::Out<u64> out_count;
[65002] AtmosphereGetRecordSize() -> sf::Out<u64> record_size;
}
```
### IPC Commands
Atmosphère's reimplementation extends the HIPC loader services' API with several custom commands.
The SwIPC definition for the `sm:` extension commands follows:
```
interface ams::sm::UserService is sm: {
...
[65000] AtmosphereInstallMitm(ServiceName service) -> sf::OutMoveHandle srv_h, sf::OutMoveHandle qry_h;
[65001] AtmosphereUninstallMitm(ServiceName service);
[65002] Deprecated_AtmosphereAssociatePidTidForMitm();
[65003] AtmosphereAcknowledgeMitmSession(ServiceName service) -> sf::Out<MitmProcessInfo> client_info, sf::OutMoveHandle fwd_h;
[65004] AtmosphereHasMitm(ServiceName service) -> sf::Out<bool> out;
[65005] AtmosphereWaitMitm(ServiceName service);
[65006] AtmosphereDeclareFutureMitm(ServiceName service);
[65100] AtmosphereHasService(ServiceName service) -> sf::Out<bool> out;
[65101] AtmosphereWaitService(ServiceName service);
}
```
The SwIPC definition for the `sm:m` extension commands follows:
```
interface ams::sm::ManagerService is sm:m {
...
[65000] AtmosphereEndInitDefers(os::ProcessId process_id, sf::InBuffer &acid_sac, sf::InBuffer &aci_sac);
[65001] AtmosphereHasMitm(ServiceName service) -> sf::Out<bool> out;
[65002] AtmosphereRegisterProcess(os::ProcessId process_id, ncm::ProgramId program_id, cfg::OverrideStatus override_status, sf::InBuffer &acid_sac, sf::InBuffer &aci_sac);
}
```

View File

@@ -0,0 +1,2 @@
# spl
This module is a reimplementation of the Horizon OS's `spl` system module, which is responsible for providing secure platform services such as cryptographic operations.

14
docs/components/sept.md Normal file
View File

@@ -0,0 +1,14 @@
# sept
Sept is a payload that facilitates booting Atmosphère when targeting firmware version 7.0.0+.
It consists of a primary and a secondary payload.
## sept-primary
sept-primary is essentially a stand-in for Nintendo's package1ldr, on 7.0.0+. To use it, the caller (normally fusée-secondary) loads the sept-primary binary to `0x4003F000`, loads the 7.0.0+ TSEC firmware to `0x40010F00`, and loads a signed, encrypted payload to `0x40016FE0`.
This signed, encrypted payload is normally sept-secondary.
## sept-secondary
sept-secondary is a payload that performs 7.0.0+ key derivation, and then chainloads to `sept/payload.bin`.
It is normally stored encrypted/signed. Therefore, if one wishes to build sept-secondary instead of using release builds, one must bring their own keys.

View File

@@ -1,10 +1,21 @@
# Stratosphère # stratosphère
Stratosphère allows customization of the Horizon OS and Switch kernel. It includes custom sysmodules that extend the kernel and provide new features. It also includes a reimplementation of the loader sysmodules to hook important system actions. stratosphère provides customization of the Horizon OS at the system level. This includes a reimplementation of several system modules and additional, custom system modules that extend or add a variety of features.
The sysmodules that Stratosphère includes are: ## Modules
+ [boot](../modules/boot.md): This module boots the system and initalizes hardware. The modules currently provided by stratosphère are:
+ [creport](../modules/creport.md): Reimplementation of Nintendos crash report system. Dumps all error logs to the SD card instead of saving them to the NAND and sending them to Nintendo. + [ams_mitm](modules/ams_mitm.md)
+ [fs_mitm](../modules/fs_mitm.md): This module can log, deny, delay, replace, and redirect any request made to the File System. + [boot](modules/boot.md)
+ [loader](../modules/loader.md): Enables modifying the code of binaries that are not stored inside the kernel. + [boot2](modules/boot2.md)
+ [pm](../modules/pm.md): Reimplementation of Nintendos Process Manager. + [creport](modules/creport.md)
+ [sm](../modules/sm.md): Reimplementation of Nintendos Service Manager. + [dmnt](modules/dmnt.md)
+ [eclct.stub](modules/eclct.stub.md)
+ [erpt](modules/erpt.md)
+ [fatal](modules/fatal.md)
+ [jpegdec](modules/jpegdec.md)
+ [loader](modules/loader.md)
+ [ncm](modules/ncm.md)
+ [pgl](modules/pgl.md)
+ [pm](modules/pm.md)
+ [ro](modules/ro.md)
+ [sm](modules/sm.md)
+ [spl](modules/spl.md)

View File

@@ -1,4 +1,3 @@
# Thermosphère # thermosphère
Thermosphère is a hypervisor based implementation of emuNAND. thermosphère is a work in progress hypervisor implementation.
This aims to provide functionality at the EL2 level which remains unused by the Horizon OS.
Thermosphère is currently planned to be included in a future release of Atmosphère.

View File

@@ -1,2 +1,5 @@
# Troposphère # troposphère
Troposphère contains various application-level modifications to the OS, such as launching homebrew directly from the homemenu or executing cheat/gameshark codes, similar to Luma3DS. Troposphère is not yet implemented in Atmosphère. troposphère provides customization of the Horizon OS at the application level.
## reboot_to_payload
Sample application to perform a system reboot into a payload of choice.

View File

@@ -6,25 +6,24 @@ By default, Atmosphère will do the following when deciding whether to attach to
+ Retrieve information about the new application process from `pm` and `loader`. + Retrieve information about the new application process from `pm` and `loader`.
+ Check whether a user-defined key combination is held, and stop if not. + Check whether a user-defined key combination is held, and stop if not.
+ This defaults to "L is not held", and can be configured the same way as `fs.mitm` override keys. + This defaults to "L is not held", but can be configured with override keys.
+ The ini key to configure this is `cheat_enable_key`. + The ini key to configure this is `cheat_enable_key`.
+ Check whether the process is a real application, and stop if not. + Check whether the process is a real application, and stop if not.
+ This guards against applying cheat codes to the homebrew loader. + This guards against applying cheat codes to the Homebrew Loader.
+ Attempt to load cheats from `atmosphere/titles/<title_id>/cheats/<build_id>.txt`, where `build_id` is the hexadecimal representation of the first 8 bytes of the application's main executable's build id. + Attempt to load cheats from `/atmosphere/contents/<program_id>/cheats/<build_id>.txt`, where `build_id` is the hexadecimal representation of the first 8 bytes of the application's main executable's build id.
+ If no cheats are found, then the cheat manager will stop. + If no cheats are found, then the cheat manager will stop.
+ Open a kernel debug session for the new application process. + Open a kernel debug session for the new application process.
+ Signal to a system event that a new cheat process has been attached to. + Signal to a system event that a new cheat process has been attached to.
This behavior ensures that cheat codes are only loaded when the user would want them to. This behavior ensures that cheat codes are only loaded when the user would want them to.
In cases where dmnt has not activated the cheat manager, but the user wants to make it do so anyway, the cheat manager's service API provides a `ForceOpenCheatProcess` command that homebrew can use. This command will cause the cheat manager to try to force itself to attach to the process. In cases where `dmnt` has not activated the cheat manager, but the user wants to make it do so anyway, the cheat manager's service API provides a `ForceOpenCheatProcess` command that homebrew can use. This command will cause the cheat manager to try to force itself to attach to the process.
By default, all cheat codes listed in the loaded .txt file will be toggled on. This is configurable by the user, and the default can be set to toggled off by editing the `atmosphere!dmnt_cheats_enabled_by_default` entry to 0 instead of 1. By default, all cheat codes listed in the loaded .txt file will be toggled on. This is configurable by the user by editing the `atmosphere!dmnt_cheats_enabled_by_default` [system setting](configurations.md).
Users may use homebrew programs to toggle cheats on and off at runtime via the cheat manager's service API. Users may use homebrew programs to toggle cheats on and off at runtime via the cheat manager's service API.
## Cheat Code Compatibility ## Cheat Code Compatibility
Atmosphère manages cheat code through the execution of a small, custom virtual machine. Care has been taken to ensure that Atmosphère's cheat code format is fully backwards compatible with the pre-existing cheat code format, though new features have been added and bugs in the pre-existing cheat code applier have been fixed. Here is a short summary of the changes from the pre-existing format: Atmosphère manages cheat code through the execution of a small, custom virtual machine. Care has been taken to ensure that Atmosphère's cheat code format is fully backwards compatible with the pre-existing cheat code format, though new features have been added and bugs in the pre-existing cheat code applier have been fixed. Here is a short summary of the changes from the pre-existing format:
+ A number of bugs were fixed in the processing of conditional instructions. + A number of bugs were fixed in the processing of conditional instructions.
@@ -37,21 +36,18 @@ Atmosphère manages cheat code through the execution of a small, custom virtual
+ The pre-existing implementation did not correctly synchronize with the application process, and thus would cause heavy lag under certain circumstances (especially around loading screens). This has been fixed in Atmosphère's implementation. + The pre-existing implementation did not correctly synchronize with the application process, and thus would cause heavy lag under certain circumstances (especially around loading screens). This has been fixed in Atmosphère's implementation.
## Cheat Code Format ## Cheat Code Format
The following provides documentation of the instruction format for the virtual machine used to manage cheat codes. The following provides documentation of the instruction format for the virtual machine used to manage cheat codes.
Typically, instruction type is encoded in the upper nybble of the first instruction u32. Typically, instruction type is encoded in the upper nybble of the first instruction u32.
### Code Type 0: Store Static Value to Memory ### Code Type 0: Store Static Value to Memory
Code type 0 allows writing a static value to a memory address. Code type 0 allows writing a static value to a memory address.
#### Encoding #### Encoding
`0TMR00AA AAAAAAAA VVVVVVVV (VVVVVVVV)` `0TMR00AA AAAAAAAA VVVVVVVV (VVVVVVVV)`
+ T: width of memory write (1, 2, 4, or 8 bytes) + T: Width of memory write (1, 2, 4, or 8 bytes).
+ M: memory region to write to (0 = Main NSO, 1 = Heap) + M: Memory region to write to (0 = Main NSO, 1 = Heap).
+ R: Register to use as an offset from memory region base. + R: Register to use as an offset from memory region base.
+ A: Immediate offset to use from memory region base. + A: Immediate offset to use from memory region base.
+ V: Value to write. + V: Value to write.
@@ -59,23 +55,20 @@ Code type 0 allows writing a static value to a memory address.
--- ---
### Code Type 1: Begin Conditional Block ### Code Type 1: Begin Conditional Block
Code type 1 performs a comparison of the contents of memory to a static value. Code type 1 performs a comparison of the contents of memory to a static value.
If the condition is not met, all instructions until the appropriate conditional block terminator are skipped. If the condition is not met, all instructions until the appropriate conditional block terminator are skipped.
#### Encoding #### Encoding
`1TMC00AA AAAAAAAA VVVVVVVV (VVVVVVVV)` `1TMC00AA AAAAAAAA VVVVVVVV (VVVVVVVV)`
+ T: width of memory write (1, 2, 4, or 8 bytes) + T: Width of memory write (1, 2, 4, or 8 bytes).
+ M: memory region to write to (0 = Main NSO, 1 = Heap) + M: Memory region to write to (0 = Main NSO, 1 = Heap).
+ C: Condition to use, see below. + C: Condition to use, see below.
+ A: Immediate offset to use from memory region base. + A: Immediate offset to use from memory region base.
+ V: Value to compare to. + V: Value to compare to.
#### Conditions #### Conditions
+ 1: > + 1: >
+ 2: >= + 2: >=
+ 3: < + 3: <
@@ -86,28 +79,23 @@ If the condition is not met, all instructions until the appropriate conditional
--- ---
### Code Type 2: End Conditional Block ### Code Type 2: End Conditional Block
Code type 2 marks the end of a conditional block (started by Code Type 1 or Code Type 8). Code type 2 marks the end of a conditional block (started by Code Type 1 or Code Type 8).
#### Encoding #### Encoding
`20000000` `20000000`
--- ---
### Code Type 3: Start/End Loop ### Code Type 3: Start/End Loop
Code type 3 allows for iterating in a loop a fixed number of times. Code type 3 allows for iterating in a loop a fixed number of times.
#### Start Loop Encoding #### Start Loop Encoding
`300R0000 VVVVVVVV` `300R0000 VVVVVVVV`
+ R: Register to use as loop counter. + R: Register to use as loop counter.
+ V: Number of iterations to loop. + V: Number of iterations to loop.
#### End Loop Encoding #### End Loop Encoding
`310R0000` `310R0000`
+ R: Register to use as loop counter. + R: Register to use as loop counter.
@@ -115,11 +103,9 @@ Code type 3 allows for iterating in a loop a fixed number of times.
--- ---
### Code Type 4: Load Register with Static Value ### Code Type 4: Load Register with Static Value
Code type 4 allows setting a register to a constant value. Code type 4 allows setting a register to a constant value.
#### Encoding #### Encoding
`400R0000 VVVVVVVV VVVVVVVV` `400R0000 VVVVVVVV VVVVVVVV`
+ R: Register to use. + R: Register to use.
@@ -128,38 +114,33 @@ Code type 4 allows setting a register to a constant value.
--- ---
### Code Type 5: Load Register with Memory Value ### Code Type 5: Load Register with Memory Value
Code type 5 allows loading a value from memory into a register, either using a fixed address or by dereferencing the destination register. Code type 5 allows loading a value from memory into a register, either using a fixed address or by dereferencing the destination register.
#### Load From Fixed Address Encoding #### Load From Fixed Address Encoding
`5TMR00AA AAAAAAAA` `5TMR00AA AAAAAAAA`
+ T: width of memory read (1, 2, 4, or 8 bytes) + T: Width of memory read (1, 2, 4, or 8 bytes).
+ M: memory region to write to (0 = Main NSO, 1 = Heap) + M: Memory region to write to (0 = Main NSO, 1 = Heap).
+ R: Register to load value into. + R: Register to load value into.
+ A: Immediate offset to use from memory region base. + A: Immediate offset to use from memory region base.
#### Load from Register Address Encoding #### Load from Register Address Encoding
`5TMR10AA AAAAAAAA` `5TMR10AA AAAAAAAA`
+ T: width of memory read (1, 2, 4, or 8 bytes) + T: Width of memory read (1, 2, 4, or 8 bytes).
+ M: memory region to write to (0 = Main NSO, 1 = Heap) + M: Memory region to write to (0 = Main NSO, 1 = Heap).
+ R: Register to load value into. + R: Register to load value into.
+ A: Immediate offset to use from register R. + A: Immediate offset to use from register R.
--- ---
### Code Type 6: Store Static Value to Register Memory Address ### Code Type 6: Store Static Value to Register Memory Address
Code type 6 allows writing a fixed value to a memory address specified by a register. Code type 6 allows writing a fixed value to a memory address specified by a register.
#### Encoding #### Encoding
`6T0RIor0 VVVVVVVV VVVVVVVV` `6T0RIor0 VVVVVVVV VVVVVVVV`
+ T: width of memory write (1, 2, 4, or 8 bytes) + T: Width of memory write (1, 2, 4, or 8 bytes).
+ R: Register used as base memory address. + R: Register used as base memory address.
+ I: Increment register flag (0 = do not increment R, 1 = increment R by T). + I: Increment register flag (0 = do not increment R, 1 = increment R by T).
+ o: Offset register enable flag (0 = do not add r to address, 1 = add r to address). + o: Offset register enable flag (0 = do not add r to address, 1 = add r to address).
@@ -169,22 +150,19 @@ Code type 6 allows writing a fixed value to a memory address specified by a regi
--- ---
### Code Type 7: Legacy Arithmetic ### Code Type 7: Legacy Arithmetic
Code type 7 allows performing arithmetic on registers. Code type 7 allows performing arithmetic on registers.
However, it has been deprecated by Code type 9, and is only kept for backwards compatibility. However, it has been deprecated by Code type 9, and is only kept for backwards compatibility.
#### Encoding #### Encoding
`7T0RC000 VVVVVVVV` `7T0RC000 VVVVVVVV`
+ T: width of arithmetic operation (1, 2, 4, or 8 bytes) + T: Width of arithmetic operation (1, 2, 4, or 8 bytes).
+ R: Register to apply arithmetic to. + R: Register to apply arithmetic to.
+ C: Arithmetic operation to apply, see below. + C: Arithmetic operation to apply, see below.
+ V: Value to use for arithmetic operation. + V: Value to use for arithmetic operation.
#### Arithmetic Types #### Arithmetic Types
+ 0: Addition + 0: Addition
+ 1: Subtraction + 1: Subtraction
+ 2: Multiplication + 2: Multiplication
@@ -194,11 +172,9 @@ However, it has been deprecated by Code type 9, and is only kept for backwards c
--- ---
### Code Type 8: Begin Keypress Conditional Block ### Code Type 8: Begin Keypress Conditional Block
Code type 8 enters or skips a conditional block based on whether a key combination is pressed. Code type 8 enters or skips a conditional block based on whether a key combination is pressed.
#### Encoding #### Encoding
`8kkkkkkk` `8kkkkkkk`
+ k: Keypad mask to check against, see below. + k: Keypad mask to check against, see below.
@@ -206,7 +182,6 @@ Code type 8 enters or skips a conditional block based on whether a key combinati
Note that for multiple button combinations, the bitmasks should be ORd together. Note that for multiple button combinations, the bitmasks should be ORd together.
#### Keypad Values #### Keypad Values
Note: This is the direct output of `hidKeysDown()`. Note: This is the direct output of `hidKeysDown()`.
+ 0000001: A + 0000001: A
@@ -239,31 +214,27 @@ Note: This is the direct output of `hidKeysDown()`.
--- ---
### Code Type 9: Perform Arithmetic ### Code Type 9: Perform Arithmetic
Code type 9 allows performing arithmetic on registers. Code type 9 allows performing arithmetic on registers.
#### Register Arithmetic Encoding #### Register Arithmetic Encoding
`9TCRS0s0` `9TCRS0s0`
+ T: width of arithmetic operation (1, 2, 4, or 8 bytes) + T: Width of arithmetic operation (1, 2, 4, or 8 bytes).
+ C: Arithmetic operation to apply, see below. + C: Arithmetic operation to apply, see below.
+ R: Register to store result in. + R: Register to store result in.
+ S: Register to use as left-hand operand. + S: Register to use as left-hand operand.
+ s: Register to use as right-hand operand. + s: Register to use as right-hand operand.
#### Immediate Value Arithmetic Encoding #### Immediate Value Arithmetic Encoding
`9TCRS100 VVVVVVVV (VVVVVVVV)` `9TCRS100 VVVVVVVV (VVVVVVVV)`
+ T: width of arithmetic operation (1, 2, 4, or 8 bytes) + T: Width of arithmetic operation (1, 2, 4, or 8 bytes).
+ C: Arithmetic operation to apply, see below. + C: Arithmetic operation to apply, see below.
+ R: Register to store result in. + R: Register to store result in.
+ S: Register to use as left-hand operand. + S: Register to use as left-hand operand.
+ V: Value to use as right-hand operand. + V: Value to use as right-hand operand.
#### Arithmetic Types #### Arithmetic Types
+ 0: Addition + 0: Addition
+ 1: Subtraction + 1: Subtraction
+ 2: Multiplication + 2: Multiplication
@@ -278,14 +249,12 @@ Code type 9 allows performing arithmetic on registers.
--- ---
### Code Type 10: Store Register to Memory Address ### Code Type 10: Store Register to Memory Address
Code type 10 allows writing a register to memory. Code type 10 allows writing a register to memory.
#### Encoding #### Encoding
`ATSRIOxa (aaaaaaaa)` `ATSRIOxa (aaaaaaaa)`
+ T: width of memory write (1, 2, 4, or 8 bytes) + T: Width of memory write (1, 2, 4, or 8 bytes).
+ S: Register to write to memory. + S: Register to write to memory.
+ R: Register to use as base address. + R: Register to use as base address.
+ I: Increment register flag (0 = do not increment R, 1 = increment R by T). + I: Increment register flag (0 = do not increment R, 1 = increment R by T).
@@ -294,23 +263,21 @@ Code type 10 allows writing a register to memory.
+ a: Value used as offset when O is 2, 4 or 5. + a: Value used as offset when O is 2, 4 or 5.
#### Offset Types #### Offset Types
+ 0: No Offset + 0: No Offset
+ 1: Use Offset Register + 1: Use Offset Register
+ 2: Use Fixed Offset + 2: Use Fixed Offset
+ 3: Memory Region + Base Register + 3: Memory Region + Base Register
+ 4: Memory Region + Relative Address (ignore address register) + 4: Memory Region + Relative Address (ignore address register)
+ 5: Memory Region + Relative Address + Offset Register + 5: Memory Region + Relative Address + Offset Register
--- ---
### Code Type 11: Reserved ### Code Type 11: Reserved
Code Type 11 is currently reserved for future use. Code Type 11 is currently reserved for future use.
--- ---
### Code Type 12-15: Extended-Width Instruction ### Code Type 12-15: Extended-Width Instruction
Code Types 12-15 signal to the VM to treat the upper two nybbles of the first dword as instruction type, instead of just the upper nybble. Code Types 12-15 signal to the VM to treat the upper two nybbles of the first dword as instruction type, instead of just the upper nybble.
This reserves an additional 64 opcodes for future use. This reserves an additional 64 opcodes for future use.
@@ -318,13 +285,11 @@ This reserves an additional 64 opcodes for future use.
--- ---
### Code Type 0xC0: Begin Register Conditional Block ### Code Type 0xC0: Begin Register Conditional Block
Code type 0xC0 performs a comparison of the contents of a register and another value. This code support multiple operand types, see below. Code type 0xC0 performs a comparison of the contents of a register and another value. This code support multiple operand types, see below.
If the condition is not met, all instructions until the appropriate conditional block terminator are skipped. If the condition is not met, all instructions until the appropriate conditional block terminator are skipped.
#### Encoding #### Encoding
``` ```
C0TcSX## C0TcSX##
C0TcS0Ma aaaaaaaa C0TcS0Ma aaaaaaaa
@@ -335,19 +300,18 @@ C0TcS400 VVVVVVVV (VVVVVVVV)
C0TcS5X0 C0TcS5X0
``` ```
+ T: width of memory write (1, 2, 4, or 8 bytes) + T: Width of memory write (1, 2, 4, or 8 bytes).
+ c: Condition to use, see below. + c: Condition to use, see below.
+ S: Source Register + S: Source Register.
+ X: Operand Type, see below. + X: Operand Type, see below.
+ M: Memory Type (operand types 0 and 1) + M: Memory Type (operand types 0 and 1).
+ R: Address Register (operand types 2 and 3) + R: Address Register (operand types 2 and 3).
+ a: Relative Address (operand types 0 and 2) + a: Relative Address (operand types 0 and 2).
+ r: Offset Register (operand types 1 and 3) + r: Offset Register (operand types 1 and 3).
+ X: Other Register (used for operand type 5) + X: Other Register (operand type 5).
+ V: Value to compare to (operand type 4) + V: Value to compare to (operand type 4).
#### Operand Type #### Operand Type
+ 0: Memory Base + Relative Offset + 0: Memory Base + Relative Offset
+ 1: Memory Base + Offset Register + 1: Memory Base + Offset Register
+ 2: Register + Relative Offset + 2: Register + Relative Offset
@@ -356,10 +320,109 @@ C0TcS5X0
+ 5: Other Register + 5: Other Register
#### Conditions #### Conditions
+ 1: > + 1: >
+ 2: >= + 2: >=
+ 3: < + 3: <
+ 4: <= + 4: <=
+ 5: == + 5: ==
+ 6: != + 6: !=
---
### Code Type 0xC1: Save or Restore Register
Code type 0xC1 performs saving or restoring of registers.
#### Encoding
`C10D0Sx0`
+ D: Destination index.
+ S: Source index.
+ x: Operand Type, see below.
#### Operand Type
+ 0: Restore register
+ 1: Save register
+ 2: Clear saved value
+ 3: Clear register
---
### Code Type 0xC2: Save or Restore Register with Mask
Code type 0xC2 performs saving or restoring of multiple registers using a bitmask.
#### Encoding
`C2x0XXXX`
+ x: Operand Type, see below.
+ X: 16-bit bitmask, bit i == save or restore register i.
#### Operand Type
+ 0: Restore register
+ 1: Save register
+ 2: Clear saved value
+ 3: Clear register
---
### Code Type 0xC3: Read or Write Static Register
Code type 0xC3 reads or writes a static register with a given register.
#### Encoding
`C3000XXx`
+ XX: Static register index, 0x00 to 0x7F for reading or 0x80 to 0xFF for writing.
+ x: Register index.
---
### Code Type 0xF0: Double Extended-Width Instruction
Code Type 0xF0 signals to the VM to treat the upper three nybbles of the first dword as instruction type, instead of just the upper nybble.
This reserves an additional 16 opcodes for future use.
---
### Code Type 0xFF0: Pause Process
Code type 0xFF0 pauses the current process.
#### Encoding
`FF0?????`
---
### Code Type 0xFF1: Resume Process
Code type 0xFF1 resumes the current process.
#### Encoding
`FF1?????`
---
### Code Type 0xFFF: Debug Log
Code type 0xFFF writes a debug log to the SD card under the folder `/atmosphere/cheat_vm_logs/`.
#### Encoding
```
FFFTIX##
FFFTI0Ma aaaaaaaa
FFFTI1Mr
FFFTI2Ra aaaaaaaa
FFFTI3Rr
FFFTI4X0
```
+ T: Width of memory write (1, 2, 4, or 8 bytes).
+ I: Log id.
+ X: Operand Type, see below.
+ M: Memory Type (operand types 0 and 1).
+ R: Address Register (operand types 2 and 3).
+ a: Relative Address (operand types 0 and 2).
+ r: Offset Register (operand types 1 and 3).
+ X: Value Register (operand type 4).
#### Operand Type
+ 0: Memory Base + Relative Offset
+ 1: Memory Base + Offset Register
+ 2: Register + Relative Offset
+ 3: Register + Offset Register
+ 4: Register Value

View File

@@ -0,0 +1,153 @@
# Configurations
Atmosphère provides a variety of customizable configurations to better adjust to users' needs.
## BCT.ini
This is the configuration file used by fusée.
This file is located under the `/atmosphere/config/` folder on your SD card and a default template can be found inside the `/atmosphere/config_templates/` folder.
### Adding a Custom Boot Splashscreen
Atmosphère provides its own default splashscreen which is displayed at boot time. However, this can be replaced at will.
The boot splashscreen must be a BMP file, it must be 720x1280 (1280x720 rotated 90 degrees left/counterclockwise/anti-clockwise) resolution, and be in 32-bit ARGB format. You can use image editing software such as GIMP or Photoshop to export the image in this format.
Add the following lines to BCT.ini and change the value of `custom_splash` to the actual path and filename of your boot splashscreen:
```
[stage2]
custom_splash = /path/to/your/bootlogo.bmp
```
### Configuring "nogc" Protection
"nogc" is a feature provided by fusée-secondary which disables the Nintendo Switch's Game Card reader. Its purpose is to prevent the reader from being updated when the console has been updated, without burning fuses, from a lower firmware version. More specifically, from firmware versions 4.0.0 or 9.0.0 which introduced updates to the Game Card reader's firmware. By default, Atmosphère will protect the Game Card reader automatically, but you are free to change it.
To change its functionality, add the following line to the `stratosphere` section and change the value of `X` according to the following list:
```
[stratosphere]
nogc = X
```
```
1 = force-enable nogc, so Atmosphère will always disable the Game Card reader.
0 = force-disable nogc, so Atmosphère will always enable the Game Card reader.
```
### NCM opt-in
Atmosphère provides a reimplementation of the [ncm](../components/modules/ncm.md) system module, but currently this is not enabled by default. If you wish to enable this reimplementation add the following line to the `stratosphere` section:
```
[stratosphere]
enable_ncm = 1
```
### Logging
This is an advanced feature aimed at developers trying to debug boot time issues. It enables logging of the fusée stages to be displayed on screen.
Add the following lines to BCT.ini and change the value of `X` according to the following list:
```
[config]
log_level = X
```
```
0 = NONE
1 = ERROR
2 = WARNING
3 = MANDATORY
4 = INFO
5 = DEBUG
```
A special level is also provided to prevent prefix creation. To use it, do a bitwise OR with this mask:
`0x100 = NO_PREFIX`
## emummc.ini
This is the configuration file used for the [emummc](../components/emummc.md) component.
This file is located under the `/emuMMC/` folder on your SD card.
Please refer to the project's repository [here](https://github.com/m4xw/emuMMC) for detailed instructions and documentation.
## exosphere.ini
This is the configuration file used by exosphère.
This file is located in the root of your SD card and a default template can be found inside the `/atmosphere/config_templates/` folder.
### Configuring Debugging Modes
By default, Atmosphère signals to the Horizon kernel that debugging is enabled while leaving usermode debugging disabled, but this can cause undesirable side-effects. If you wish to change this behavior, go to the `exosphere` section and change the value of `X` according to the following list.
```
[exosphere]
debugmode = X
debugmode_user = X
```
```
1 = enable
0 = disable
```
### Blanking PRODINFO
Atmosphère provides a way for users to blank their factory installed calibration data (known as PRODINFO) in either emulated or system eMMC environments. You can find more detailed information on this inside the respective template file. Usage of this configuration is not encouraged.
## override_config.ini
This file is located under the `/atmosphere/config/` folder on your SD card and a default template can be found inside the `/atmosphere/config_templates/` folder.
### Overrides Format
Overrides are parsed from the `/atmosphere/config/override_config.ini` file during the boot process.
By default `override_config.ini` is not configured. It can be used to select the behavior of certain buttons and bind them to functionalities such as launching the Homebrew Menu or enabling the cheat code manager.
You can modify the override_key entries in `override_config.ini` with this list of valid buttons:
| Formal Name | .ini Name |
| ----------- | --------- |
| A Button | A |
| B Button | B |
| X Button | X |
| Y Button | Y |
| Left Stick | LS |
| Right Stick | RS |
| L Button | L |
| R Button | R |
| ZL Button | ZL |
| ZR Button | ZR |
| + Button | PLUS |
| - Button | MINUS |
| Left Dpad | DLEFT |
| Up Dpad | DUP |
| Right Dpad | DRIGHT |
| Down Dpad | DDOWN |
| SL Button | SL |
| SR Button | SR |
To invert the behavior of the override key, place an exclamation point in front of whatever button you wish to use. It will launch the actual game while holding down that button, instead of going into the Homebrew Menu. For example, `override_key=!R` will run the game only while holding down R when launching it, otherwise it will boot into the Homebrew Menu. Afterwards you may reinsert your SD card into your Switch and boot into Atmosphère as you normally would. You should now be able to boot into the Homebrew Menu by launching your designated program of choice.
## system_settings.ini
This file is located under the `/atmosphere/config/` folder on your SD card and a default template can be found inside the `/atmosphere/config_templates/` folder.
### Settings Format
Atmosphère provides a way to override the firmware debug settings used by the system. These can be parsed from the `/atmosphere/config/system_settings.ini` file during the boot process. This file is a normal ini file, with some specific interpretations.
The standard representation of a setting's identifier takes the form `name!key`. This is represented within `system_settings.ini` as a section `name`, with an entry `key`. For example:
```
[name]
key = ...
```
Settings can have variable types (strings, integral values, byte arrays, etc). To accommodate this, `system_settings.ini` must store values as a `type_identifier!value_store` pair. A number of different types are supported, with identifiers detailed below.
Please note that a malformed value string will cause a fatal error to occur on boot. A full example of a custom setting is given below (setting `eupld!upload_enabled = 0`), for posterity:
```
[eupld]
upload_enabled = u8!0x0
```
#### Supported Types
* Strings
* Type identifiers: `str`, `string`
* The value string is used directly as the setting, with null terminator appended.
* Integral types
* Type identifiers: `u8`, `u16`, `u32`, `u64`
* The value string is parsed via a call to `strtoul(value, NULL, 0)`.
* Setting bitwidth is determined by the identifier (8 for 1 byte, 16 for 2 bytes, and so on).
* Raw bytes
* Type identifiers: `hex`, `bytes`
* The value string is parsed as a hexadecimal string.
* The value string must be of even length, or a fatal error will be thrown on parse.
## Content Specific Flags
Atmosphère supports customizing CFW behavior based on the presence of `flags` on the SD card.
The following flags are supported on a per-program basis, by placing `<flag_name>.flag` inside `/atmosphere/contents/<program_id>/flags/`:
+ `boot2`, which indicates that the program should be launched during the `boot2` process.
+ `redirect_save`, which indicates that the program wants its savedata to be redirected to the SD card.

View File

@@ -1,12 +0,0 @@
# Flags
Atmosphère supports customizing CFW behavior based on the presence of `flags` on the SD card.
The following flags are supported on a per-title basis, by placing `<flag_name>.flag` inside `/atmosphere/titles/<title_id>/flags/`:
+ `boot2`, which indicates to PM that the title should be launched during the `boot2` process.
+ `fsmitm`, which indicates that `fs.mitm` should override contents for the title even if it otherwise wouldn't.
+ `fsmitm_disable`, which indicates that `fs.mitm` should not override contents for the title, even it it otherwise would.
+ `bis_write`, which indicates that `fs.mitm` should allow the title to write to BIS partitions.
+ `cal_read`, which indicates that `fs.mitm` should allow the title to read the CAL0/PRODINFO partition.
The following global flags are supported, by placing `<flag name>.flag` inside `/atmosphere/flags/`:
+ `hbl_bis_write` and `hbl_cal_read` enable the BIS write and CAL0 read functionality for HBL, without needing to specify its title id.

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018-2020 Atmosphère-NX
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,29 +1,30 @@
# Atmosphère # Atmosphère
Atmosphère is a work-in-progress customized firmware for the Nintendo Switch. Atmosphère consists of several different components, each in charge of performing different system functions of the Nintendo Switch. Atmosphère is a work-in-progress customized firmware for the Nintendo Switch. Its design principle consists of a multi-layered approach where each layer replaces/modifies a different component of the Nintendo Switch's system.
The components of Atmosphère are: ## Components
+ [Fusée](../docs/components/fusee/fusee.md), a custom bootloader. Atmosphère provides six core components, mimicking to some degree the various layers of the Earth's atmosphere:
+ [Exosphère](../docs/components/exosphere.md), a fully-featured custom secure monitor. + [fusée](components/fusee.md)
+ [Stratosphère](../docs/components/stratosphere.md), a set of custom system modules. + [exosphère](components/exosphere.md)
+ [Thermosphère](../docs/components/thermosphere.md), a hypervisor-based emuNAND implementation. This component has not been implemented yet. + [thermosphère](components/thermosphere.md)
+ [Troposphère](../docs/components/troposphere.md), Application-level patches to the Horizon OS. This component has also not been implemented yet. + [mesosphère](components/mesosphere.md)
+ [stratosphère](components/stratosphere.md)
+ [troposphère](components/troposphere.md)
### Modules Additionally, Atmosphère also provides the following secondary components:
The Stratosphère component of Atmosphère contains various modules. These have a `.kip` extension. They provide custom features, extend existing features, or replace Nintendo sysmodules. + [emummc](components/emummc.md)
+ [sept](components/sept.md)
+ [libraries](components/libraries.md)
Stratosphère's modules include: ## Features
+ [boot](../docs/modules/boot.md) Atmosphère provides several original features which add or expand functionalities for the customized firmware environment:
+ [creport](../docs/modules/creport.md) + [Cheats](features/cheats.md)
+ [fs_mitm](../docs/modules/fs_mitm.md) + [Configurations](features/configurations.md)
+ [loader](../docs/modules/loader.md)
+ [pm](../docs/modules/pm.md)
+ [sm](../docs/modules/sm.md)
### Building Atmosphère ## Building Atmosphère
A guide to building Atmosphère can be found [here](../docs/building.md). A guide to building Atmosphère can be found [here](building.md).
### Upcoming Features ## Upcoming Features
A list of planned features for Atmosphère can be found [here](../docs/roadmap.md). A list of planned features for Atmosphère can be found [here](roadmap.md).
### Release History ## Release History
A changelog of previous versions of Atmosphère can be found [here](../docs/changelog.md). A changelog of previous versions of Atmosphère can be found [here](changelog.md).

View File

@@ -1,2 +0,0 @@
# boot
The boot module is responsible for booting the system and initalizing hardware. A second boot module known as boot2 is integrated with the [pm (process manager)](../modules/pm.md) sysmodule in Atmosphère, and launches other processes.

View File

@@ -1,2 +0,0 @@
# creport
creport is a reimplementation of Nintendo's crash reporter. Atmosphère's creport catches all error logs that would have been saved to the NAND and instead saves them to the SD card for debugging purposes. This is helpful because the errors no longer go to Nintendo and developers of homebrew can still see the errors to help with the debugging process. creport catches system errors, game crashes, and homebrew crashes.

View File

@@ -1,38 +0,0 @@
# dmnt
dmnt is a reimplementation of Nintendo's debug monitor. It provides Atmosphère a rich set of debugging functionality, so that users can easily analyze the behaviors of programs. In addition, Atmosphère implements an extension in dmnt to provide cheat code functionality.
## Atmosphère Cheat Extension
In addition to the functionality provided by Nintendo's debug monitor, Atmosphère's dmnt has an extension for providing cheat code functionality. A HIPC Service API is provided for interacting with the cheat code manager, through the service `dmnt:cht`.
Those looking for more information on the cheat code functionality may wish to read `cheats.md`.
The SwIPC definition for `dmnt:cht` follows.
```
interface DmntCheatService is dmnt:cht {
[65000] HasCheatProcess() -> bool;
[65001] GetCheatProcessEvent() -> KObject;
[65002] GetCheatProcessMetadata() -> CheatProcessMetadata;
[65003] ForceOpenCheatProcess();
[65100] GetCheatProcessMappingCount() -> u64;
[65101] GetCheatProcessMappings(u64 offset) -> buffer<MemoryInfo, 6>, u64 count;
[65102] ReadCheatProcessMemory(u64 address, u64 size) -> buffer<u8, 6> data;
[65103] WriteCheatProcessMemory(u64 address, u64 size, buffer<u8, 5> data);
[65104] QueryCheatProcessMemory(u64 address) -> MemoryInfo;
[65200] GetCheatCount() -> u64;
[65201] GetCheats(u64 offset) -> buffer<CheatEntry, 6>, u64 count;
[65202] GetCheatById(u32 cheat_id) -> buffer<CheatEntry, 6> cheat;
[65203] ToggleCheat(u32 cheat_id);
[65204] AddCheat(buffer<CheatDefinition, 5> cheat, bool enabled) -> u32 cheat_id;
[65203] RemoveCheat(u32 cheat_id);
[65300] GetFrozenAddressCount() -> u64;
[65301] GetFrozenAddresses(u64 offset) -> buffer<FrozenAddressEntry, 6>, u64 count;
[65302] GetFrozenAddress(u64 address) -> FrozenAddressEntry;
[65303] EnableFrozenAddress(u64 address, u64 width) -> u64 value;
[65304] DisableFrozenAddress(u64 address);
}
```

View File

@@ -1,2 +0,0 @@
# fs_mitm
fs_mitm is a sysmodule that enables intercepting file system operations. This module can log, deny, delay, replace, or redirect any request made to the filesystem. It enables LayeredFS to function, which allows for replacement of game assets.

View File

@@ -1,126 +0,0 @@
# loader
loader is a reimplementation of the loader sysmodule. This module is responsible for creating processes from executable NSO images and registering their access control with the kernel, sm, and fs.
## Atmosphère Extensions
Atmosphère extends this module to allow executables to be replaced or patched by files stored on the SD card. Note that a few services are required for SD card access and therefore cannot be replaced or patched in this manner. This includes psc, bus, and pcv.
### Exefs Replacement
TODO: details on buttons affecting this.
When a process is created, loader will search for several NSO filenames in the title's exefs directory.
These filenames are, in this order:
- rtld
- main
- subsdk0
- subsdk1
- ...
- subsdk9
- sdk
Each NSO that is found will be loaded into the process contiguously. The process's entrypoint is at the first NSO to be loaded, usually `rtld` or `main`.
Additionally, when a process is loaded, loader will search for a `main.npdm` file in the exefs directory specifying the title's permissions.
Atmosphère extends this functionality by also searching for these files on the SD card. When searching for a file, loader will first check if it exists on the SD card. If it does, that file will be used instead. Otherwise, it will use the copy located in the exefs, if that is present. The following directory will be searched.
```
sdmc:/atmosphere/titles/<title id>/exefs/
```
This allows the replacement of applets, sysmodules, or even games with homebrew versions.
In order to prevent an NSO from being loaded even if it exists in the exefs, loader will also check if a stub file exists. If such a file exists, the NSO will not be loaded. The files should be named like `rtld.stub`, `main.stub`, etc. and may be empty.
### NSO Patching
TODO: details on buttons affecting this.
When an NSO is loaded, the stratosphere implementatin of loader will search for IPS patch files on the SD card in the following locations.
```
sdmc:/atmosphere/exefs_patches/<patchset name>/<nso build id>.ips
```
This organization allows patchsets affecting multiple NSOs to be distributed as a single directory. Patches will be searched for in each patchset directory. The name of each patch file should match the hexadecimal build ID of the NSO to affect, except that trailing zero bytes may be left off. Because the NSO build ID is unique for every NSO, this means patches will only apply to the files they are meant to apply to.
Patch files are accepted in either IPS format or IPS32 format.
Because NSO files are compressed, patch files are not made between the original version of a compressed NSO and the modified version of such an NSO. Instead, they are made between the uncompressed version of an NSO and the modified (and still uncompressed) version of that NSO. This also means that a patch file cannot be manually applied to the compressed version of an NSO; it must be applied to the uncompressed version. The Stratosphere implementation of loader will correctly apply these patches while loading the process regardless of whether the NSO it finds is compressed or not.
When authoring patches, [hactool](https://github.com/SciresM/hactool) can be used to find an NSO's build ID and to uncompress NSOs. Recent versions of the [ReSwitched IDA loaders](https://github.com/reswitched/loaders) can be used to load uncompressed NSOs into IDA in such a way that you can [apply patches to the input file](https://www.hex-rays.com/products/ida/support/idadoc/1618.shtml). From there, any IPS tool can be used to create the patch between the original NSO and the patched NSO. Note that if the NSO you are patching is larger than 16 MiB, you will have to use a tool that supports IPS32.
### HBL Support
Atmosphère can use the loader module in order to turn any game on your Switch's home menu into a launchpoint for the Homebrew Menu, rather than launching it through the album applet. This allows one to launch the Homebrew Menu with access to the ~3.2GB of RAM that the Switch reserves for games and applications, as opposed to the 442MB of RAM we are limited to when launching the Homebrew Menu from the album. This also means that it is no longer necessary to install homebrew as `.nsp` files on your Switch so long as you are using this method, as the only reason to do so is to allow the homebrew to access all of the Switch's available memory.
In order to setup this method you will need the latest release of [hbmenu](https://github.com/switchbrew/nx-hbmenu/releases), and the latest release of [hbloader](https://github.com/switchbrew/nx-hbloader/releases). Place `hbmenu.nro` on the root of your Switch's SD Card, and place `hbl.nsp` in the atmosphere folder. From there, simply launch any title while holding the button specified in `loader.ini`.
In addition, loader has extensions to enable homebrew to launch web applets. This normally requires the application launching the applet have HTML Manual content inside an installed NCA; Atmosphère's loader will automatically ensure that the commands used to check this succeed, and will (in tandem with `fs.mitm`) redirect the relevant filesystem to the `sdmc:/atmosphere/hbl_html/` subdirectory.
### Button Overrides
By default `loader.ini` is configured to launch the Homebrew Menu when launching any game while holding down the override key (defaults to R). If you wish to change this, you can modify the override_key section of `loader.ini`. Alternatively, if you would like to only allow hbmenu on a specific app, configure `loader.ini` in the atmosphere folder by replacing the Title ID in the ini (title_id in the [hbl_config] section, it is the Title ID for the album by default) with the Title ID of whatever game you wish to use to launch the Homebrew Menu, and set override_any_app to false. A list of Title IDs for Switch Games can be found [here](https://switchbrew.org/wiki/Title_list/Games).
To invert the behaviour of the override key, place an exclamation point in front of whatever button you wish to use. It will launch the actual game while holding down that button, instead of going into the Homebrew Menu. For example, `override_key=!R` will run the game only while holding down R when launching it, otherwise it will boot into the Homebrew Menu. Afterwards you may reinsert your SD Card into your Switch and boot into Atmosphère as you normally would. You should now be able to boot into the Homebrew Menu by launching your designated title of choice.
A list of valid buttons can be found here:
| Formal Name | .ini Name |
| ----------- | --------- |
| A Button | A |
| B Button | B |
| X Button | X |
| Y Button | Y |
| Left Stick | LS |
| Right Stick | RS |
| L Button | L |
| R Button | R |
| ZL Button | ZL |
| ZR Button | ZR |
| + Button | PLUS |
| - Button | MINUS |
| Left Dpad | DLEFT |
| Up Dpad | DUP |
| Right Dpad | DRIGHT |
| Down Dpad | DDOWN |
| SL Button | SL |
| SR Button | SR |
### SM MITM Integration
When the Stratosphere implementation of loader creates a new process, it notifies [sm](sm.md) through the `AtmosphereAssociatePidTidForMitm` command to notify any MITM services of new processes' identities.
### IPC: AtmosphereSetExternalContentSource and AtmosphereClearExternalContentSource
Two additional commands are added to the [`ldr:shel`](https://reswitched.github.io/SwIPC/ifaces.html#nn::ro::detail::ILdrShellInterface) interface, called `AtmosphereSetExternalContentSource` and `AtmosphereClearExternalContentSource`.
Their command IDs are `65000` and `65001` on all system firmware versions.
`AtmosphereSetExternalContentSource` takes a `u64 tid` and returns a server-side session handle.
The client is expected to implement the `IFileSystem` interface on the returned handle. The next
time the title specified by the given title ID is launched, its ExeFS contents will be loaded from
the custom `IFileSystem` instead of from SD card or original ExeFS. NSOs loaded from external
content source may still be subject to exefs IPS patches. After the title is launched successfuly,
the `IFileSystem` is closed and the external content source override is removed. If
`AtmosphereSetExternalContentSource` is called on a title that already has an external content
source set for it, the existing one will be removed and replaced with the new one. It is illegal to
call `AtmosphereSetExternalContentSource` while the title is being launched.
If title launching fails, the external content source remains registered. The
`AtmosphereClearExternalContentSource` command can be used to clear an external content source if
title launch fails.
The `IFileSystem` only needs to implement `OpenFile` and `GetFileTimeStampRaw`. The paths received
by the `IFileSystem`'s `OpenFile` command begin with slashes, as in `/main`, `/rtld`, and `/main.npdm`.
A result code of 0x202 should be returned if the file does not exist. `GetFileTimeStampRaw` can just
be a stub. The `IFile`s returned from `OpenFile` only need to implement `Read` and `GetSize`.
The SwIPC definitions for the extension commands follow.
```
interface nn::ldr::detail::IShellInterface is ldr:shel {
...
[65000] AtmosphereSetExternalContentSource(u64 tid) -> handle<copy, session_server> ifilesystem_handle;
[65001] AtmosphereClearExternalContentSource(u64 tid);
}
```

View File

@@ -1,23 +0,0 @@
# pm
pm is a reimplementation of Nintendo's process manager. This module is responsible for tracking running processes on the system, and managing resource limits. pm is also required to create and manage processes for homebrew applications.
## Atmosphère Extensions
There are a few ways in which the Stratosphere implementation of pm differs intentionally from the stock pm.
### IPC: AtmosphereGetProcessHandle
The Stratosphere implementation of pm adds an additional command to the [`pm:dmnt`](https://reswitched.github.io/SwIPC/ifaces.html#nn::pm::detail::IDebugMonitorInterface) interface, called `AtmosphereGetProcessHandle`. Its command ID is `65000` on all system firmware versions. It takes a `u64 process_id` and returns a process handle for the specified process, if that process is known. Notable exceptions include KIPs, which are not known to pm. If the specified process cannot be found, error code 0x20F is returned.
The SwIPC definition for this command follows.
```
interface nn::pm::detail::IDebugMonitorInterface is pm:dmnt {
...
[65000] AtmosphereGetProcessInfo(u64 pid) -> handle<copy, process> process_handle, u64 title_id, u64 storage_id;
}
```
### Extra System Memory for Sysmodules
The Stratosphere implementation of pm shrinks the APPLET memory pool by 24 MiB by default, giving this memory to the SYSTEM pool. This allows custom sysmodules to use more memory without hitting the SYSTEM memory limit.

View File

@@ -1,79 +0,0 @@
# set_mitm
set_mitm is a sysmodule that enables intercepting requests to the system settings service.
## Atmosphère Extensions
set_mitm intercepts the `GetFirmwareVersion` command, if the requester is `qlaunch` or `maintenance`.\
It modifies the `display_version` field of the returned system version, causing the version to display\
in settings as `#.#.# (AMS #.#.#)`. This allows users to easily verify what version of Atmosphère they are running.
set_mitm also intercepts the `GetSettingsItemValueSize` and `GetSettingsItemValue` commands for all requesters.\
It does so in order to enable user configuration of system settings, which are parsed from `atmosphere/system_settings.ini` on boot.\
The format for settings is described below.
### Atmosphère Settings Format
Settings are parsed from the `atmosphere/system_settings.ini` file during the boot process. This file is a normal ini file,\
with some specific interpretations.
The standard representation of a system setting's identifier takes the form `name!key`. This is represented within\
`system_settings.ini` as a section `name`, with an entry `key`. For example:
```
[name]
key = ...
```
System settings can have variable types (strings, integral values, byte arrays, etc). To accommodate this, `system_settings.ini`\
must store values as a `type_identifier!value_store` pair. A number of different types are supported, with identifiers detailed below.\
Please note that a malformed value string will cause a fatal error to occur on boot. A full example of a custom setting is given below\
(setting `eupld!upload_enabled = 0`), for posterity:
```
[eupld]
upload_enabled = u8!0x0
```
### Supported Types
* Strings
* Type identifiers: `str`, `string`
* The value string is used directly as the setting, with null terminator appended.
* Integral types
* Type identifiers: `u8`, `u16`, `u32`, `u64`
* The value string is parsed via a call to `strtoul(value, NULL, 0)`.
* Setting bitwidth is determined by the identifier (8 for 1 byte, 16 for 2 bytes, and so on).
* Raw bytes
* Type identifiers: `hex`, `bytes`
* The value string is parsed as a hexadecimal string.
* The value string must be of even length, or a fatal error will be thrown on parse.
### Atmosphère Custom Settings
At the time of writing, Atmosphère implements two custom settings, found in the `atmosphere` section.\
While not used for set_mitm, `power_menu_reboot_function` is loaded and controls the reboot behaviour of the console. By default, this value\
is "payload", where the console will automatically reboot into the RCM payload stored in `sdmc:/atmosphere/reboot_payload.bin`.\
(This payload is also used for fatal, upon a serious crash.) Setting the value to "rcm" reboots directly into RCM, and setting the value\
to "normal" skips these behaviours.
```
[atmosphere]
power_menu_reboot_function = str!payload
```
`dmnt_cheats_enabled_by_default` controls the behaviour of dmnt's cheat functionality. By default, this value is "0x1", enabling any cheats\
defined by the user. Check [cheats](../cheats.md) for more information about Atmosphère's cheat functionality.
```
[atmosphere]
dmnt_cheats_enabled_by_default = u8!0x1
```
`dmnt_always_save_cheat_toggles` controls the behaviour of dmnt's cheat toggle functionality. By default, this value is "0x0", causing toggles to\
only be saved on game quit if a toggle file existed on game boot. Check [cheats](../cheats.md) for more information about Atmosphère's cheat functionality.
```
[atmosphere]
dmnt_always_save_cheat_toggles = u8!0x0
```

View File

@@ -1,125 +0,0 @@
# sm
sm is a reimplementation of Nintendo's service manager. It allows Atmosphère to add or remove process handle limits, add new services, or intercept service calls. This allows high-level intercepting of Horizon OS functionality.
## Atmosphère Extensions
There are a few ways in which the Stratosphere implementation of sm differs intentionally from the stock sm.
### IPC: MITM Commands
The Stratosphere implementation of sm adds a few additional commands to the [`sm:`](https://reswitched.github.io/SwIPC/ifaces.html#nn::sm::detail::IUserInterface) port session.
Their SwIPC definitions follow.
```
interface nn::sm::detail::IUserInterface is sm: {
...
[65000] AtmosphereInstallMitm(ServiceName service) -> handle<port, move> service, handle<server_session, move> query;
[65001] AtmosphereUninstallMitm(ServiceName service);
[65002] AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid);
}
```
Additionally, an interface `sm:dmnt` has been created to allow a debug monitor to query sm's state.
Its SwIPC definition follows.
```
interface nn::sm::detail::IDebugMonitorInterface is sm:dmnt {
[65000] AtmosphereGetServiceRecord(ServiceName name) -> SmServiceRecord;
[65001] AtmosphereListServiceRecords(u64 offset) -> buffer<SmServiceRecord, 6>, u64 count;
[65002] AtmosphereGetServiceRecordSize() -> u64 record_size;
}
```
#### AtmosphereInstallMitm
This command alters the registration for the named service, in order to allow services to intercept communication between client processes and their intended services. It is used by [fs_mitm](fs_mitm.md).
It takes the name of the service to install an MITM for, and returns two handles. The first is a port handle, similar to those returned from the [RegisterService](https://reswitched.github.io/SwIPC/ifaces.html#nn::sm::detail::IUserInterface(2)) command. The second is the server side of a session, called the query session. This session will used by sm to determine whether or not a new session should be intercepted, and to inform the MITM service of the identity of new processes.
The query session is expected to implement the following interface.
```
interface MitmQueryService {
[65000] ShouldMitm(u64 pid) -> u64 should_mitm;
[65001] AssociatePidTid(u64 pid, u64 tid);
}
```
The `ShouldMitm` command is invoked whenever a process attempts to make a new connection to the MITM'd service. It should return `0` if the process's connection should not be intercepted. Any other value will cause the process's connection to be intercepted. If the command returns an error code, the process's connection will not be intercepted.
The `AssociatePidTid` command is invoked on all MITM query sessions whenever a new process is created, in order to inform those services of the identity of a newly created process before it attempts to connect to any services.
If the process that installed the MITM attempts to connect to the service, it will always connect to the original service.
This command requires that the session be initialized, returning error code 0x415 if it is not.\
If the given service name is invalid, error code 0xC15 is returned.\
If the user does not have service registration permission for the named service, error code 0x1015 is returned.\
If the service already has an MITM installed, error code 0x815 is returned.\
If the service has not yet been registered, the request will be deferred until the service is registered in the same manner as IUserInterface::GetService.
#### AtmosphereUninstallMitm
Removes any installed MITM for the named service.
This command requires that the session be initialized, returning error code 0x415 if it is not.
#### AtmosphereAssociatePidTidForMitm
This command is used internally by the Stratosphere implementation of the [loader](loader.md) sysmodule, when a new process is created. It will call the `AssociatePidTid` command on every registered MITM query session.
If the given process ID refers to a kernel internal process, error code 0x1015 is returned. This command requires that the session be initialized, returning error code 0x415 if it is not.
#### AtmosphereGetServiceRecordSize
Retrieves `sizeof(SmServiceRecord)` for a service. The current format of `SmServiceRecord` structure follows.
```
struct SmServiceRecord {
uint64_t service_name;
uint64_t owner_pid;
uint64_t max_sessions;
uint64_t mitm_pid;
uint64_t mitm_waiting_ack_pid;
bool is_light;
bool mitm_waiting_ack;
};
```
#### AtmosphereGetServiceRecord
Retrieves a service registration record for a service.
#### AtmosphereListServiceRecords
Provides a list of service registrations records.
The command will return an array of `SmServiceRecord`s, skipping `offset` records. The number of records returned is indicated by `count`.
If `count` is less than the size of the buffer divided by `sizeof(SmServiceRecord)` (the buffer was not completely filled), the end of the service registration list has been reached. Otherwise, client code
should increment `offset` by `count` and call again. Client code should retrieve a record size using `AtmosphereGetServiceRecordSize`, and either make sure that the size of a record matches what it expects,
or should make sure to use the correct size as the stride while iterating over the array of returned records. Example pseudocode is shown below.
```
offset = 0;
record_size = AtmosphereGetServiceRecordSize();
do {
SmServiceRecord records[16];
count = AtmosphereListServiceRecords(offset, buffer(records));
for (i = 0; i < count; i++) {
SmServiceRecord record = {0};
memcpy(&record, &records[i], min(record_size, sizeof(SmServiceRecord));
/* process record */
offset++;
}
} while(count == sizeof(records) / record_size);
```
### Minimum Session Limit
When a service is registered, the sysmodule registering it must specify a limit on the number of sessions that are allowed to be active for that service at a time. This is used to ensure that services like `fs-pr`, `fs-ldr`, and `ldr:pm` can only be connected to once, adding an additional layer of safety over the regular service verification to ensure that those services are only connected to by the highly priveleged process they are intended to be used by.
By default, the Stratosphere implementation of PM will raise any session limits to at least 8, meaning that for services like `fs-pr` and those mentioned above, up to 8 processes will be able to connect to those sessions, leaving 7 sessions for homebrew to use.
### 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 does not implement this vulnerability, and initialization is required on all firmware versions.

View File

@@ -1,16 +1,49 @@
# Planned Features # Planned Features
The following features are planned to be added in future versions of Atmosphère: atmosphère has a number of features that are either works-in-progress or planned. Please note that while time-estimates are given, they are loose, and things may be completed sooner or later than advertised.
+ Thermosphère, a hypervisor-based emunand implementation.
+ A feature-rich debugging toolset (a component of Stratosphère). The following descriptions were last updated in late April of 2020.
+ A custom debug monitor system module, providing an API for debugging Switch's processes. This may not be a reimplementation of Nintendo's own debug monitor.
+ This should include a gdbstub implementation, possibly borrowing from Luma3DS's. ## system updater api
+ This API should be additionally usable for RAM Editing/"Cheat Engine" purposes. * **Description**: A planned extension api for stratosphere (tenatively `ams:su`), this will provide an interface for homebrew to safely install system upgrades or downgrades. This will allow for much more easily transitioning safely between different versions of the operating system.
+ A custom shell system module, providing an means for users to perform various RPC (with support for common/interesting functionality) on their Switch remotely. This may not be a reimplementation of Nintendo's own shell. * **Development Status**: Under active development by SciresM
+ This should support client connections over both Wi-Fi and USB. * **Estimated Time**: May 2020
+ A custom logging system module, providing a means for other Atmosphère components (and possibly Nintendo's own system modules) to log debug output.
+ This should support logging to the SD card, over Wi-Fi, and over USB. ## settings reimplementation
+ An application-level plugin system. * **Description**: A planned reimplementation of the settings system module, and with it a removal of the settings mitm. This will greatly simplify atmosphère's boot process, and will allow much more flexible control over the various system settings.
+ This will, ideally, work somewhat like NTR-CFW's plugin system on the 3DS, allowing users to run their own code in a game's process in their own thread. * **Development Status**: Undergoing research/initial development by Adubbz.
+ An AR Code/Gameshark analog implementation, allowing for easy sharing/development of cheat codes to run on device. * **Estimated Time**: Mid 2020
+ Further extensions to existing Atmosphère components.
+ General system stability improvements to enhance the user's experience. ## mesosphere
* **Description**: mesosphère is a reimplementation of the Horizon operating system's Kernel. It aims to provide an open-source reference for Nintendo's code.
* **Development Status**: Under semi-active development by SciresM; temporarily on pause while the System Updater API is completed.
* **Estimated Time**: Mid-to-Late 2020
## exosphere re-write
* **Description**: exosphère, atmosphère's reimplementation of Horizon's Secure Monitor, was the first component authored for the project in early 2018. It is written in C, and in a style very different from the rest of atmosphère's code. In addition, exosphère was written to conform to constraints that no longer apply in an environment where it is not launched from the web browser, and where using a custom firmware image to orchestrate wake-from-sleep is possible. exosphère currently uses all but 1 KB of the space available to it, putting it at risk of breaking as future firmware updates are supported. A re-write will solve these issues.
* **Development Status**: Planned.
* **Estimated Time**: 2020-2021.
## tma reimplementation
* **Description** tma ("target manager agent") is a system module that manages communication between the Switch and a client PC. Atmosphere's implementation will allow homebrew on the switch to communicate with a connected PC to do various operations such as exchanging data or interacting with files. It will also serve as the communicator for Atmosphère's planned debugger. This will also include PC-side software for interacting with the Switch.
* **Development Status**: Planned. Switch-side code is fully implemented but needs heavy refactoring/rebasing, as the code was originally authored in 2018.
* **Estimated Time**: Late 2020-2021.
## dmnt.gen2 reimplementation
* **Description**: A reimplementation of the Switch's debug monitor, dmnt will provide an interface for debugging applications or system modules running on the Switch. This will include a gdbstub for debugging actively-running system components or applications.
* **Development Status**: Planned
* **Estimated Time**: 2021
## fs reimplementation
* **Description**: Following mesosphère's completion, atmosphère will have reimplemented all components of the BootImagePackage firmware except for the filesystem services system module. Reimplementing fs will allow for fixing Nintendo bugs (such as corruption when using exFAT filesystems and encoding inconsistencies with UTF-8 and Shift-JIS).
* **Development Status**: Planned.
* **Estimated Time**: 2021-2022.
## thermosphère
* **Description**: A general-purpose hypervisor, thermosphère will enable the virtualization of the Switch's operating system; this is planned to enable debugging of the Switch's kernel.
* **Development Status**: Under semi-active development by TuxSH.
* **Estimated Time**: 2020-2021.
## other planned features
* **Description**: General system stability improvements to enhance the user's experience.
* **Development Status**: Undergoing active development by all members of the atmosphère team.
* **Estimated Time**: June 15th.

View File

@@ -6,7 +6,7 @@
[subrepo] [subrepo]
remote = https://github.com/m4xw/emuMMC remote = https://github.com/m4xw/emuMMC
branch = develop branch = develop
commit = b168ddf5fbb31013ff529a4859110c82b11eb361 commit = 292a8ad42c8e9f4c9a474b46a5a3190398581131
parent = c07f54f3709a4710e0aead6c91139fa0893b5e5c parent = 491ba8fdcfd39a503bedd21b282991fc19aec7d4
method = rebase method = rebase
cmdver = 0.4.1 cmdver = 0.4.1

View File

@@ -117,6 +117,8 @@
"svcReplyAndReceiveWithUserBuffer": "0x44", "svcReplyAndReceiveWithUserBuffer": "0x44",
"svcCreateEvent": "0x45", "svcCreateEvent": "0x45",
"svcReadWriteRegister": "0x4E", "svcReadWriteRegister": "0x4E",
"svcMapTransferMemory": "0x51",
"svcUnmapTransferMemory": "0x52",
"svcCreateInterruptEvent": "0x53", "svcCreateInterruptEvent": "0x53",
"svcQueryIoMapping": "0x55", "svcQueryIoMapping": "0x55",
"svcCreateDeviceAddressSpace": "0x56", "svcCreateDeviceAddressSpace": "0x56",

View File

@@ -156,6 +156,8 @@ $(OUTPUT).bin : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES) $(OUTPUT).elf : $(OFILES)
my_libc.o: CFLAGS += -fno-builtin
%.elf: %.elf:
@echo linking $(notdir $@) @echo linking $(notdir $@)
$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "utils.h" #include "utils.h"
#include "lp0.h" #include "lp0.h"
#include "mc.h" #include "mc.h"
@@ -41,56 +41,56 @@ void lp0_entry_main(warmboot_metadata_t *meta) {
if (meta->magic != WARMBOOT_MAGIC || target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX) { if (meta->magic != WARMBOOT_MAGIC || target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX) {
reboot(); reboot();
} }
/* [4.0.0+] First thing warmboot does is disable BPMP access to memory. */ /* [4.0.0+] First thing warmboot does is disable BPMP access to memory. */
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
disable_bpmp_access_to_dram(); disable_bpmp_access_to_dram();
} }
/* Configure debugging depending on FUSE_PRODUCTION_MODE */ /* Configure debugging depending on FUSE_PRODUCTION_MODE */
misc_configure_device_dbg_settings(); misc_configure_device_dbg_settings();
/* Check for downgrade. */ /* Check for downgrade. */
/* NOTE: We implemented this as "return false" */ /* NOTE: We implemented this as "return false" */
if (fuse_check_downgrade_status()) { if (fuse_check_downgrade_status()) {
reboot(); reboot();
} }
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_300) { if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
/* Nintendo's firmware checks APBDEV_PMC_SECURE_SCRATCH32_0 against a per-warmboot binary value here. */ /* Nintendo's firmware checks APBDEV_PMC_SECURE_SCRATCH32_0 against a per-warmboot binary value here. */
/* We won't bother with that. */ /* We won't bother with that. */
if (false /* APBDEV_PMC_SECURE_SCRATCH32_0 == WARMBOOT_MAGIC_NUMBER */) { if (false /* APBDEV_PMC_SECURE_SCRATCH32_0 == WARMBOOT_MAGIC_NUMBER */) {
reboot(); reboot();
} }
} }
/* TODO: Check that we're running at the correct physical address. */ /* TODO: Check that we're running at the correct physical address. */
/* Setup fuses, disable bypass. */ /* Setup fuses, disable bypass. */
fuse_configure_fuse_bypass(); fuse_configure_fuse_bypass();
/* Configure oscillators/timing in CAR. */ /* Configure oscillators/timing in CAR. */
car_configure_oscillators(); car_configure_oscillators();
/* Restore RAM configuration. */ /* Restore RAM configuration. */
misc_restore_ram_svop(); misc_restore_ram_svop();
emc_configure_pmacro_training(); emc_configure_pmacro_training();
/* Setup clock output for all devices, working around mbist bug. */ /* Setup clock output for all devices, working around mbist bug. */
car_mbist_workaround(); car_mbist_workaround();
/* Initialize the CPU cluster. */ /* Initialize the CPU cluster. */
cluster_initialize_cpu(); cluster_initialize_cpu();
secmon_restore_to_tzram(target_firmware); secmon_restore_to_tzram(target_firmware);
/* Power on the CPU cluster. */ /* Power on the CPU cluster. */
cluster_power_on_cpu(); cluster_power_on_cpu();
/* Nintendo clears most of warmboot.bin out of IRAM here. We're not gonna bother. */ /* Nintendo clears most of warmboot.bin out of IRAM here. We're not gonna bother. */
/* memset( ... ); */ /* memset( ... ); */
const uint32_t halt_val = (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_400) ? 0x40000000 : 0x50000000; const uint32_t halt_val = (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) ? 0x40000000 : 0x50000000;
while (true) { while (true) {
/* Halt the BPMP. */ /* Halt the BPMP. */
FLOW_CTLR_HALT_COP_EVENTS_0 = halt_val; FLOW_CTLR_HALT_COP_EVENTS_0 = halt_val;

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdint.h> #include <stdint.h>
#include "utils.h" #include "utils.h"
@@ -30,13 +30,13 @@ static void secmon_decrypt_saved_image(void *dst, const void *src, size_t size);
void secmon_restore_to_tzram(const uint32_t target_firmware) { void secmon_restore_to_tzram(const uint32_t target_firmware) {
/* Newer warmboot binaries clear the untouched keyslots for safety. */ /* Newer warmboot binaries clear the untouched keyslots for safety. */
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
secmon_clear_unused_keyslots(); secmon_clear_unused_keyslots();
} }
/* Decrypt Secure Monitor from DRAM into TZRAM. */ /* Decrypt Secure Monitor from DRAM into TZRAM. */
void *tzram_src = (void *)(0x80010000); void *tzram_src = (void *)(0x80010000);
void *tzram_dst = (void *)(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_500 ? 0x7C012000 : 0x7C010000); void *tzram_dst = (void *)(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0 ? 0x7C012000 : 0x7C010000);
const size_t tzram_size = 0xE000; const size_t tzram_size = 0xE000;
secmon_decrypt_saved_image(tzram_dst, tzram_src, tzram_size); secmon_decrypt_saved_image(tzram_dst, tzram_src, tzram_size);

View File

@@ -52,7 +52,7 @@ void setup_dram_magic_numbers(void) {
unsigned int target_fw = exosphere_get_target_firmware(); unsigned int target_fw = exosphere_get_target_firmware();
(*(volatile uint32_t *)(0x8005FFFC)) = 0xC0EDBBCC; /* Access test value. */ (*(volatile uint32_t *)(0x8005FFFC)) = 0xC0EDBBCC; /* Access test value. */
flush_dcache_range((void *)0x8005FFFC, (void *)0x80060000); flush_dcache_range((void *)0x8005FFFC, (void *)0x80060000);
if (ATMOSPHERE_TARGET_FIRMWARE_600 <= target_fw) { if (ATMOSPHERE_TARGET_FIRMWARE_6_0_0 <= target_fw) {
(*(volatile uint32_t *)(0x8005FF00)) = 0x00000083; /* SKU code. */ (*(volatile uint32_t *)(0x8005FF00)) = 0x00000083; /* SKU code. */
(*(volatile uint32_t *)(0x8005FF04)) = 0x00000002; (*(volatile uint32_t *)(0x8005FF04)) = 0x00000002;
(*(volatile uint32_t *)(0x8005FF08)) = 0x00000210; /* Tegra210 code. */ (*(volatile uint32_t *)(0x8005FF08)) = 0x00000210; /* Tegra210 code. */
@@ -81,7 +81,7 @@ void bootup_misc_mmio(void) {
se_generate_random_key(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY); se_generate_random_key(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY);
se_generate_srk(KEYSLOT_SWITCH_SRKGENKEY); se_generate_srk(KEYSLOT_SWITCH_SRKGENKEY);
if (!g_has_booted_up && (ATMOSPHERE_TARGET_FIRMWARE_600 > exosphere_get_target_firmware())) { if (!g_has_booted_up && (ATMOSPHERE_TARGET_FIRMWARE_6_0_0 > exosphere_get_target_firmware())) {
setup_dram_magic_numbers(); setup_dram_magic_numbers();
} }
@@ -116,7 +116,7 @@ void bootup_misc_mmio(void) {
configure_default_carveouts(); configure_default_carveouts();
/* Mark registers secure world only. */ /* Mark registers secure world only. */
if (exosphere_get_target_firmware() == ATMOSPHERE_TARGET_FIRMWARE_100) { if (exosphere_get_target_firmware() == ATMOSPHERE_TARGET_FIRMWARE_1_0_0) {
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 = APB_SSER0_SATA_AUX | APB_SSER0_DTV | APB_SSER0_QSPI | APB_SSER0_SATA | APB_SSER0_LA; APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 = APB_SSER0_SATA_AUX | APB_SSER0_DTV | APB_SSER0_QSPI | APB_SSER0_SATA | APB_SSER0_LA;
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 = APB_SSER1_SPI1 | APB_SSER1_SPI2 | APB_SSER1_SPI3 | APB_SSER1_SPI5 | APB_SSER1_SPI6 | APB_SSER1_I2C4 | APB_SSER1_I2C6; APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 = APB_SSER1_SPI1 | APB_SSER1_SPI2 | APB_SSER1_SPI3 | APB_SSER1_SPI5 | APB_SSER1_SPI6 | APB_SSER1_I2C4 | APB_SSER1_I2C6;
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 = 1 << 4 | 1 << 5 | APB_SSER2_DDS; /* bits 4 and 5 are not labeled in 21.1.7.3 */ APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 = 1 << 4 | 1 << 5 | APB_SSER2_DDS; /* bits 4 and 5 are not labeled in 21.1.7.3 */
@@ -133,7 +133,7 @@ void bootup_misc_mmio(void) {
/* Also mark I2C4 secure only, */ /* Also mark I2C4 secure only, */
sec_disable_1 |= APB_SSER1_I2C4; sec_disable_1 |= APB_SSER1_I2C4;
} }
if (hardware_type != 0 && exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (hardware_type != 0 && exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
/* Starting on 4.x on non-dev units, mark UARTB, UARTC, SPI4, I2C3 secure only. */ /* Starting on 4.x on non-dev units, mark UARTB, UARTC, SPI4, I2C3 secure only. */
sec_disable_1 |= APB_SSER1_UART_B | APB_SSER1_UART_C | APB_SSER1_SPI4 | APB_SSER1_I2C3; sec_disable_1 |= APB_SSER1_UART_B | APB_SSER1_UART_C | APB_SSER1_SPI4 | APB_SSER1_I2C3;
/* Starting on 4.x on non-dev units, mark SDMMC1 secure only. */ /* Starting on 4.x on non-dev units, mark SDMMC1 secure only. */
@@ -151,7 +151,7 @@ void bootup_misc_mmio(void) {
MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_4) = 0xFFFFFFFF; MAKE_MC_REG(MC_SMMU_TRANSLATION_ENABLE_4) = 0xFFFFFFFF;
/* Set SMMU ASID security registers. */ /* Set SMMU ASID security registers. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
MAKE_MC_REG(MC_SMMU_ASID_SECURITY) = 0xE; MAKE_MC_REG(MC_SMMU_ASID_SECURITY) = 0xE;
} else { } else {
MAKE_MC_REG(MC_SMMU_ASID_SECURITY) = 0x0; MAKE_MC_REG(MC_SMMU_ASID_SECURITY) = 0x0;
@@ -164,7 +164,7 @@ void bootup_misc_mmio(void) {
MAKE_MC_REG(MC_SMMU_ASID_SECURITY_6) = 0; MAKE_MC_REG(MC_SMMU_ASID_SECURITY_6) = 0;
MAKE_MC_REG(MC_SMMU_ASID_SECURITY_7) = 0; MAKE_MC_REG(MC_SMMU_ASID_SECURITY_7) = 0;
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
MAKE_MC_REG(MC_SMMU_PTB_ASID) = 0; MAKE_MC_REG(MC_SMMU_PTB_ASID) = 0;
} }
MAKE_MC_REG(MC_SMMU_PTB_DATA) = 0; MAKE_MC_REG(MC_SMMU_PTB_DATA) = 0;
@@ -180,7 +180,7 @@ void bootup_misc_mmio(void) {
/* Clear RESET Vector, setup CPU Secure Boot RESET Vectors. */ /* Clear RESET Vector, setup CPU Secure Boot RESET Vectors. */
uint32_t reset_vec; uint32_t reset_vec;
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
reset_vec = TZRAM_GET_SEGMENT_5X_PA(TZRAM_SEGMENT_ID_WARMBOOT_CRT0_AND_MAIN); reset_vec = TZRAM_GET_SEGMENT_5X_PA(TZRAM_SEGMENT_ID_WARMBOOT_CRT0_AND_MAIN);
} else { } else {
reset_vec = TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_WARMBOOT_CRT0_AND_MAIN); reset_vec = TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_WARMBOOT_CRT0_AND_MAIN);
@@ -206,7 +206,7 @@ void bootup_misc_mmio(void) {
intr_set_cpu_mask(INTERRUPT_ID_SECURITY_ENGINE, 8); intr_set_cpu_mask(INTERRUPT_ID_SECURITY_ENGINE, 8);
intr_set_edge_level(INTERRUPT_ID_SECURITY_ENGINE, 0); intr_set_edge_level(INTERRUPT_ID_SECURITY_ENGINE, 0);
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
intr_set_priority(INTERRUPT_ID_ACTIVITY_MONITOR_4X, 0); intr_set_priority(INTERRUPT_ID_ACTIVITY_MONITOR_4X, 0);
intr_set_group(INTERRUPT_ID_ACTIVITY_MONITOR_4X, 0); intr_set_group(INTERRUPT_ID_ACTIVITY_MONITOR_4X, 0);
intr_set_enabled(INTERRUPT_ID_ACTIVITY_MONITOR_4X, 1); intr_set_enabled(INTERRUPT_ID_ACTIVITY_MONITOR_4X, 1);
@@ -221,14 +221,14 @@ void bootup_misc_mmio(void) {
uart_init(UART_A, 115200); uart_init(UART_A, 115200);
intr_register_handler(INTERRUPT_ID_SECURITY_ENGINE, se_operation_completed); intr_register_handler(INTERRUPT_ID_SECURITY_ENGINE, se_operation_completed);
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
intr_register_handler(INTERRUPT_ID_ACTIVITY_MONITOR_4X, actmon_interrupt_handler); intr_register_handler(INTERRUPT_ID_ACTIVITY_MONITOR_4X, actmon_interrupt_handler);
} }
for (unsigned int core = 1; core < NUM_CPU_CORES; core++) { for (unsigned int core = 1; core < NUM_CPU_CORES; core++) {
set_core_is_active(core, false); set_core_is_active(core, false);
} }
g_has_booted_up = true; g_has_booted_up = true;
} else if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_400) { } else if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
/* Disable AHB redirect. */ /* Disable AHB redirect. */
MAKE_MC_REG(MC_IRAM_BOM) = 0xFFFFF000; MAKE_MC_REG(MC_IRAM_BOM) = 0xFFFFF000;
MAKE_MC_REG(MC_IRAM_TOM) = 0; MAKE_MC_REG(MC_IRAM_TOM) = 0;
@@ -238,7 +238,7 @@ void bootup_misc_mmio(void) {
} }
void setup_4x_mmio(void) { void setup_4x_mmio(void) {
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_600) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
configure_gpu_ucode_carveout(); configure_gpu_ucode_carveout();
} }
@@ -361,9 +361,9 @@ void identity_unmap_iram_cd_tzram(void) {
} }
void secure_additional_devices(void) { void secure_additional_devices(void) {
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_200) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 |= APB_SSER0_PMC; /* make PMC secure-only (2.x+) */ APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 |= APB_SSER0_PMC; /* make PMC secure-only (2.x+) */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 |= APB_SSER1_MC0 | APB_SSER1_MC1 | APB_SSER1_MCB; /* make MC0, MC1, MCB secure-only (4.x+) */ APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 |= APB_SSER1_MC0 | APB_SSER1_MC1 | APB_SSER1_MCB; /* make MC0, MC1, MCB secure-only (4.x+) */
} }
} }

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h> #include <string.h>
#include "utils.h" #include "utils.h"
#include "arm.h" #include "arm.h"
@@ -26,7 +26,7 @@
#undef MAILBOX_NX_BOOTLOADER_BASE #undef MAILBOX_NX_BOOTLOADER_BASE
#undef TIMERS_BASE #undef TIMERS_BASE
#define MAILBOX_NX_BOOTLOADER_BASE(targetfw) (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) ? (MMIO_GET_DEVICE_7X_PA(MMIO_DEVID_NXBOOTLOADER_MAILBOX)) : (MMIO_GET_DEVICE_PA(MMIO_DEVID_NXBOOTLOADER_MAILBOX)) #define MAILBOX_NX_BOOTLOADER_BASE(targetfw) (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) ? (MMIO_GET_DEVICE_7X_PA(MMIO_DEVID_NXBOOTLOADER_MAILBOX)) : (MMIO_GET_DEVICE_PA(MMIO_DEVID_NXBOOTLOADER_MAILBOX))
#define TIMERS_BASE (MMIO_GET_DEVICE_PA(MMIO_DEVID_TMRs_WDTs)) #define TIMERS_BASE (MMIO_GET_DEVICE_PA(MMIO_DEVID_TMRs_WDTs))
extern const uint8_t __start_cold[]; extern const uint8_t __start_cold[];
@@ -52,11 +52,11 @@ static void mmio_map_all_devices(uintptr_t *mmu_l3_tbl, unsigned int target_firm
static const uintptr_t pas[] = { TUPLE_FOLD_LEFT_0(EVAL(MMIO_DEVID_MAX), _MMAPDEV, COMMA) }; static const uintptr_t pas[] = { TUPLE_FOLD_LEFT_0(EVAL(MMIO_DEVID_MAX), _MMAPDEV, COMMA) };
static const size_t sizes[] = { TUPLE_FOLD_LEFT_1(EVAL(MMIO_DEVID_MAX), _MMAPDEV, COMMA) }; static const size_t sizes[] = { TUPLE_FOLD_LEFT_1(EVAL(MMIO_DEVID_MAX), _MMAPDEV, COMMA) };
static const bool is_secure[] = { TUPLE_FOLD_LEFT_2(EVAL(MMIO_DEVID_MAX), _MMAPDEV, COMMA) }; static const bool is_secure[] = { TUPLE_FOLD_LEFT_2(EVAL(MMIO_DEVID_MAX), _MMAPDEV, COMMA) };
static const uintptr_t pas_7x[] = { TUPLE_FOLD_LEFT_0(EVAL(MMIO_DEVID_MAX), _MMAPDEV7X, COMMA) }; static const uintptr_t pas_7x[] = { TUPLE_FOLD_LEFT_0(EVAL(MMIO_DEVID_MAX), _MMAPDEV7X, COMMA) };
for(size_t i = 0, offset = 0; i < MMIO_DEVID_MAX; i++) { for(size_t i = 0, offset = 0; i < MMIO_DEVID_MAX; i++) {
uintptr_t pa = (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) ? pas[i] : pas_7x[i]; uintptr_t pa = (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) ? pas[i] : pas_7x[i];
mmio_map_device(mmu_l3_tbl, MMIO_BASE + offset, pa, sizes[i], is_secure[i]); mmio_map_device(mmu_l3_tbl, MMIO_BASE + offset, pa, sizes[i], is_secure[i]);
offset += sizes[i]; offset += sizes[i];
offset += 0x1000; offset += 0x1000;
@@ -92,9 +92,9 @@ static void tzram_map_all_segments(uintptr_t *mmu_l3_tbl, unsigned int target_fi
static const bool is_executable[] = { TUPLE_FOLD_LEFT_3(EVAL(TZRAM_SEGMENT_ID_MAX), _MMAPTZS, COMMA) }; static const bool is_executable[] = { TUPLE_FOLD_LEFT_3(EVAL(TZRAM_SEGMENT_ID_MAX), _MMAPTZS, COMMA) };
static const uintptr_t offs_5x[] = { TUPLE_FOLD_LEFT_0(EVAL(TZRAM_SEGMENT_ID_MAX), _MMAPTZ5XS, COMMA) }; static const uintptr_t offs_5x[] = { TUPLE_FOLD_LEFT_0(EVAL(TZRAM_SEGMENT_ID_MAX), _MMAPTZ5XS, COMMA) };
for(size_t i = 0, offset = 0; i < TZRAM_SEGMENT_ID_MAX; i++) { for(size_t i = 0, offset = 0; i < TZRAM_SEGMENT_ID_MAX; i++) {
uintptr_t off = (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_500) ? offs[i] : offs_5x[i]; uintptr_t off = (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_5_0_0) ? offs[i] : offs_5x[i];
tzram_map_segment(mmu_l3_tbl, TZRAM_SEGMENT_BASE + offset, 0x7C010000ull + off, sizes[i], is_executable[i]); tzram_map_segment(mmu_l3_tbl, TZRAM_SEGMENT_BASE + offset, 0x7C010000ull + off, sizes[i], is_executable[i]);
offset += increments[i]; offset += increments[i];
} }
@@ -102,9 +102,9 @@ static void tzram_map_all_segments(uintptr_t *mmu_l3_tbl, unsigned int target_fi
static void configure_ttbls(unsigned int target_firmware) { static void configure_ttbls(unsigned int target_firmware) {
uintptr_t *mmu_l1_tbl; uintptr_t *mmu_l1_tbl;
uintptr_t *mmu_l2_tbl; uintptr_t *mmu_l2_tbl;
uintptr_t *mmu_l3_tbl; uintptr_t *mmu_l3_tbl;
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_500) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
mmu_l1_tbl = (uintptr_t *)(TZRAM_GET_SEGMENT_PA(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800 - 64); mmu_l1_tbl = (uintptr_t *)(TZRAM_GET_SEGMENT_PA(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800 - 64);
mmu_l2_tbl = (uintptr_t *)TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_L2_TRANSLATION_TABLE); mmu_l2_tbl = (uintptr_t *)TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_L2_TRANSLATION_TABLE);
mmu_l3_tbl = (uintptr_t *)TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_L3_TRANSLATION_TABLE); mmu_l3_tbl = (uintptr_t *)TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_L3_TRANSLATION_TABLE);
@@ -154,12 +154,12 @@ uintptr_t get_coldboot_crt0_temp_stack_address(void) {
} }
uintptr_t get_coldboot_crt0_stack_address(void) { uintptr_t get_coldboot_crt0_stack_address(void) {
if (exosphere_get_target_firmware_for_init() < ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware_for_init() < ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
return TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x800; return TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x800;
} else { } else {
return TZRAM_GET_SEGMENT_5X_PA(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x800; return TZRAM_GET_SEGMENT_5X_PA(TZRAM_SEGMENT_ID_CORE3_STACK) + 0x800;
} }
} }
void coldboot_init(coldboot_crt0_reloc_list_t *reloc_list, uintptr_t start_cold) { void coldboot_init(coldboot_crt0_reloc_list_t *reloc_list, uintptr_t start_cold) {
@@ -196,7 +196,7 @@ void coldboot_init(coldboot_crt0_reloc_list_t *reloc_list, uintptr_t start_cold)
init_dma_controllers(g_exosphere_target_firmware_for_init); init_dma_controllers(g_exosphere_target_firmware_for_init);
configure_ttbls(g_exosphere_target_firmware_for_init); configure_ttbls(g_exosphere_target_firmware_for_init);
if (g_exosphere_target_firmware_for_init < ATMOSPHERE_TARGET_FIRMWARE_500) { if (g_exosphere_target_firmware_for_init < ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
set_memory_registers_enable_mmu_1x_ttbr0(); set_memory_registers_enable_mmu_1x_ttbr0();
} else { } else {
set_memory_registers_enable_mmu_5x_ttbr0(); set_memory_registers_enable_mmu_5x_ttbr0();

View File

@@ -203,7 +203,7 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
break; break;
case CONFIGITEM_BOOTREASON: case CONFIGITEM_BOOTREASON:
/* For some reason, Nintendo removed it on 4.0 */ /* For some reason, Nintendo removed it on 4.0 */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
*p_outvalue = bootconfig_get_boot_reason(); *p_outvalue = bootconfig_get_boot_reason();
} else { } else {
result = 2; result = 2;
@@ -238,7 +238,7 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
break; break;
case CONFIGITEM_ISQUESTUNIT: case CONFIGITEM_ISQUESTUNIT:
/* Added on 3.0, used to determine whether console is a kiosk unit. */ /* Added on 3.0, used to determine whether console is a kiosk unit. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_300) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
*p_outvalue = (fuse_get_reserved_odm(4) >> 10) & 1; *p_outvalue = (fuse_get_reserved_odm(4) >> 10) & 1;
} else { } else {
result = 2; result = 2;
@@ -246,7 +246,7 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
break; break;
case CONFIGITEM_NEWHARDWARETYPE_5X: case CONFIGITEM_NEWHARDWARETYPE_5X:
/* Added in 5.x, currently hardcoded to 0. */ /* Added in 5.x, currently hardcoded to 0. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
*p_outvalue = 0; *p_outvalue = 0;
} else { } else {
result = 2; result = 2;
@@ -254,7 +254,7 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
break; break;
case CONFIGITEM_NEWKEYGENERATION_5X: case CONFIGITEM_NEWKEYGENERATION_5X:
/* Added in 5.x. */ /* Added in 5.x. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
*p_outvalue = fuse_get_5x_key_generation(); *p_outvalue = fuse_get_5x_key_generation();
} else { } else {
result = 2; result = 2;
@@ -262,7 +262,7 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
break; break;
case CONFIGITEM_PACKAGE2HASH_5X: case CONFIGITEM_PACKAGE2HASH_5X:
/* Added in 5.x. */ /* Added in 5.x. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500 && bootconfig_is_recovery_boot()) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0 && bootconfig_is_recovery_boot()) {
bootconfig_get_package2_hash_for_recovery(p_outvalue); bootconfig_get_package2_hash_for_recovery(p_outvalue);
} else { } else {
result = 2; result = 2;
@@ -270,11 +270,11 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
break; break;
case CONFIGITEM_EXOSPHERE_VERSION: case CONFIGITEM_EXOSPHERE_VERSION:
/* UNOFFICIAL: Gets information about the current exosphere version. */ /* UNOFFICIAL: Gets information about the current exosphere version. */
*p_outvalue = ((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 32ull) | *p_outvalue = ((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56ull) |
((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 24ull) | ((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48ull) |
((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 16ull) | ((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40ull) |
((uint64_t)(exosphere_get_target_firmware() & 0xFF) << 8ull) | ((uint64_t)(mkey_get_revision() & 0xFF) << 32ull) |
((uint64_t)(mkey_get_revision() & 0xFF) << 0ull); ((uint64_t)(exosphere_get_target_firmware()) << 0ull);
break; break;
case CONFIGITEM_NEEDS_REBOOT: case CONFIGITEM_NEEDS_REBOOT:
/* UNOFFICIAL: The fact that we are executing means we aren't in the process of rebooting. */ /* UNOFFICIAL: The fact that we are executing means we aren't in the process of rebooting. */
@@ -290,7 +290,15 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
break; break;
case CONFIGITEM_HAS_RCM_BUG_PATCH: case CONFIGITEM_HAS_RCM_BUG_PATCH:
/* UNOFFICIAL: Gets whether this unit has the RCM bug patched. */ /* UNOFFICIAL: Gets whether this unit has the RCM bug patched. */
*p_outvalue = (int)(fuse_has_rcm_bug_patch());; *p_outvalue = (int)(fuse_has_rcm_bug_patch());
break;
case CONFIGITEM_SHOULD_BLANK_PRODINFO:
/* UNOFFICIAL: Gets whether this unit should simulate a "blanked" PRODINFO. */
*p_outvalue = exosphere_should_blank_prodinfo();
break;
case CONFIGITEM_ALLOW_CAL_WRITES:
/* UNOFFICIAL: Gets whether this unit should allow writing to the calibration partition. */
*p_outvalue = exosphere_should_allow_writing_to_cal();
break; break;
default: default:
result = 2; result = 2;

View File

@@ -45,6 +45,8 @@ typedef enum {
CONFIGITEM_NEEDS_SHUTDOWN = 65002, CONFIGITEM_NEEDS_SHUTDOWN = 65002,
CONFIGITEM_EXOSPHERE_VERHASH = 65003, CONFIGITEM_EXOSPHERE_VERHASH = 65003,
CONFIGITEM_HAS_RCM_BUG_PATCH = 65004, CONFIGITEM_HAS_RCM_BUG_PATCH = 65004,
CONFIGITEM_SHOULD_BLANK_PRODINFO = 65005,
CONFIGITEM_ALLOW_CAL_WRITES = 65006,
} ConfigItem; } ConfigItem;
#define REBOOT_KIND_NO_REBOOT 0 #define REBOOT_KIND_NO_REBOOT 0

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "arm.h" #include "arm.h"
@@ -99,8 +99,8 @@ uint32_t cpu_on(uint32_t core, uintptr_t entrypoint_addr, uint64_t argument) {
static const uint32_t status_masks[NUM_CPU_CORES] = {0x4000, 0x200, 0x400, 0x800}; static const uint32_t status_masks[NUM_CPU_CORES] = {0x4000, 0x200, 0x400, 0x800};
static const uint32_t toggle_vals[NUM_CPU_CORES] = {0xE, 0x9, 0xA, 0xB}; static const uint32_t toggle_vals[NUM_CPU_CORES] = {0xE, 0x9, 0xA, 0xB};
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
/* Reset the core */ /* Reset the core */
CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET_0 = (1 << (core + 0x10)) | (1 << core); CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET_0 = (1 << (core + 0x10)) | (1 << core);
} }
@@ -133,11 +133,11 @@ uint32_t cpu_on(uint32_t core, uintptr_t entrypoint_addr, uint64_t argument) {
} }
CPU_ON_SUCCESS: CPU_ON_SUCCESS:
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
/* Start the core */ /* Start the core */
CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR_0 = (1 << (core + 0x10)) | (1 << core); CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR_0 = (1 << (core + 0x10)) | (1 << core);
} }
return 0; return 0;
} }

View File

@@ -27,6 +27,9 @@ static bool g_has_loaded_config = false;
#define EXOSPHERE_CHECK_FLAG(flag) ((g_exosphere_cfg.flags & flag) != 0) #define EXOSPHERE_CHECK_FLAG(flag) ((g_exosphere_cfg.flags & flag) != 0)
static unsigned int exosphere_is_emummc() {
return g_exosphere_cfg.emummc_cfg.base_cfg.magic == MAGIC_EMUMMC_CONFIG && g_exosphere_cfg.emummc_cfg.base_cfg.type != EMUMMC_TYPE_NONE;
}
/* Read config out of IRAM, return target firmware version. */ /* Read config out of IRAM, return target firmware version. */
unsigned int exosphere_load_config(void) { unsigned int exosphere_load_config(void) {
@@ -92,6 +95,26 @@ unsigned int exosphere_should_enable_usermode_pmu_access(void) {
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS); return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS);
} }
unsigned int exosphere_should_blank_prodinfo(void) {
if (!g_has_loaded_config) {
generic_panic();
}
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_BLANK_PRODINFO);
}
unsigned int exosphere_should_allow_writing_to_cal(void) {
if (!g_has_loaded_config) {
generic_panic();
}
if (exosphere_is_emummc()) {
return 1;
} else {
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC);
}
}
const exo_emummc_config_t *exosphere_get_emummc_config(void) { const exo_emummc_config_t *exosphere_get_emummc_config(void) {
if (!g_has_loaded_config) { if (!g_has_loaded_config) {
generic_panic(); generic_panic();

View File

@@ -41,6 +41,8 @@
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u) #define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u) #define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
#define EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS (1 << 4u) #define EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS (1 << 4u)
#define EXOSPHERE_FLAG_BLANK_PRODINFO (1 << 5u)
#define EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC (1 << 6u)
#define EXOSPHERE_FLAGS_DEFAULT (EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV) #define EXOSPHERE_FLAGS_DEFAULT (EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV)
typedef struct { typedef struct {
@@ -60,6 +62,8 @@ unsigned int exosphere_should_override_debugmode_priv(void);
unsigned int exosphere_should_override_debugmode_user(void); unsigned int exosphere_should_override_debugmode_user(void);
unsigned int exosphere_should_disable_usermode_exception_handlers(void); unsigned int exosphere_should_disable_usermode_exception_handlers(void);
unsigned int exosphere_should_enable_usermode_pmu_access(void); unsigned int exosphere_should_enable_usermode_pmu_access(void);
unsigned int exosphere_should_blank_prodinfo(void);
unsigned int exosphere_should_allow_writing_to_cal(void);
const exo_emummc_config_t *exosphere_get_emummc_config(void); const exo_emummc_config_t *exosphere_get_emummc_config(void);

View File

@@ -196,7 +196,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1)); uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1));
/* Firmware from versions 1.0.0 to 3.0.2. */ /* Firmware from versions 1.0.0 to 3.0.2. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
if (hardware_type >= 1) { if (hardware_type >= 1) {
return (hardware_type > 2) ? 3 : hardware_type - 1; return (hardware_type > 2) ? 3 : hardware_type - 1;
@@ -205,7 +205,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
} else { } else {
return 3; return 3;
} }
} else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) { /* Firmware versions from 4.0.0 to 6.2.0. */ } else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */
static const uint32_t types[] = {0,1,4,3}; static const uint32_t types[] = {0,1,4,3};
hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C); hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C);
hardware_type--; hardware_type--;
@@ -262,30 +262,39 @@ uint32_t fuse_get_5x_key_generation(void) {
/* Returns the fuse version expected for the firmware. */ /* Returns the fuse version expected for the firmware. */
uint32_t fuse_get_expected_fuse_version(uint32_t target_firmware) { uint32_t fuse_get_expected_fuse_version(uint32_t target_firmware) {
static const uint8_t expected_versions[ATMOSPHERE_TARGET_FIRMWARE_COUNT+1] = { if (fuse_get_retail_type() != 0) {
[ATMOSPHERE_TARGET_FIRMWARE_100] = 1, if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0) {
[ATMOSPHERE_TARGET_FIRMWARE_200] = 2, return 13;
[ATMOSPHERE_TARGET_FIRMWARE_300] = 3, } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_9_1_0) {
/* [ATMOSPHERE_TARGET_FIRMWARE_302] = 4, */ return 12;
[ATMOSPHERE_TARGET_FIRMWARE_400] = 5, } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_9_0_0) {
[ATMOSPHERE_TARGET_FIRMWARE_500] = 6, return 11;
[ATMOSPHERE_TARGET_FIRMWARE_600] = 7, } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) {
[ATMOSPHERE_TARGET_FIRMWARE_620] = 8, return 10;
[ATMOSPHERE_TARGET_FIRMWARE_700] = 9, } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
[ATMOSPHERE_TARGET_FIRMWARE_800] = 9, return 9;
[ATMOSPHERE_TARGET_FIRMWARE_810] = 10, } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
[ATMOSPHERE_TARGET_FIRMWARE_900] = 11, return 8;
[ATMOSPHERE_TARGET_FIRMWARE_910] = 12, } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
[ATMOSPHERE_TARGET_FIRMWARE_1000] = 13, return 7;
}; } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
return 6;
if (target_firmware > ATMOSPHERE_TARGET_FIRMWARE_COUNT) { } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
generic_panic(); return 5;
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_3_0_2) {
return 4;
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
return 3;
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
return 2;
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_1_0_0) {
return 1;
} else {
return 0;
}
} else {
return (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_3_0_0) ? 1 : 0;
} }
if (fuse_get_retail_type() != 0)
return expected_versions[target_firmware];
else
return (target_firmware > ATMOSPHERE_TARGET_FIRMWARE_200) ? 1 : 0;
} }
/* Check for RCM bug patches. */ /* Check for RCM bug patches. */

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@@ -83,7 +83,7 @@ static void ghash(void *dst, const void *data, size_t data_size, const void *j_b
/* H = aes_ecb_encrypt(zeroes) */ /* H = aes_ecb_encrypt(zeroes) */
se_aes_128_ecb_encrypt_block(KEYSLOT_SWITCH_TEMPKEY, h, 0x10, x, 0x10); se_aes_128_ecb_encrypt_block(KEYSLOT_SWITCH_TEMPKEY, h, 0x10, x, 0x10);
size_t total_size = data_size; size_t total_size = data_size;
while (data_size >= 0x10) { while (data_size >= 0x10) {
@@ -103,7 +103,7 @@ static void ghash(void *dst, const void *data, size_t data_size, const void *j_b
if (data_size & 0xF) { if (data_size & 0xF) {
gf128_mul(x, x, h); gf128_mul(x, x, h);
} }
uint64_t xor_size = total_size << 3; uint64_t xor_size = total_size << 3;
xor_size = __builtin_bswap64(xor_size); xor_size = __builtin_bswap64(xor_size);
@@ -113,9 +113,9 @@ static void ghash(void *dst, const void *data, size_t data_size, const void *j_b
} else { } else {
p_x[1] ^= xor_size; p_x[1] ^= xor_size;
} }
gf128_mul(x, x, h); gf128_mul(x, x, h);
/* If final output block, XOR with encrypted J block. */ /* If final output block, XOR with encrypted J block. */
if (encrypt) { if (encrypt) {
se_aes_128_ecb_encrypt_block(KEYSLOT_SWITCH_TEMPKEY, h, 0x10, j_block, 0x10); se_aes_128_ecb_encrypt_block(KEYSLOT_SWITCH_TEMPKEY, h, 0x10, j_block, 0x10);
@@ -140,22 +140,22 @@ size_t gcm_decrypt_key(void *dst, size_t dst_size, const void *src, size_t src_s
generic_panic(); generic_panic();
} }
} }
uint8_t intermediate_buf[0x400] = {0}; uint8_t intermediate_buf[0x400] = {0};
/* Unwrap the key */ /* Unwrap the key */
unseal_key(KEYSLOT_SWITCH_TEMPKEY, sealed_kek, kek_size, usecase); unseal_key(KEYSLOT_SWITCH_TEMPKEY, sealed_kek, kek_size, usecase);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, KEYSLOT_SWITCH_TEMPKEY, wrapped_key, key_size); decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, KEYSLOT_SWITCH_TEMPKEY, wrapped_key, key_size);
/* Decrypt the GCM keypair, AES-CTR with CTR = blob[:0x10]. */ /* Decrypt the GCM keypair, AES-CTR with CTR = blob[:0x10]. */
se_aes_ctr_crypt(KEYSLOT_SWITCH_TEMPKEY, intermediate_buf, dst_size, src + 0x10, src_size - 0x10, src, 0x10); se_aes_ctr_crypt(KEYSLOT_SWITCH_TEMPKEY, intermediate_buf, dst_size, src + 0x10, src_size - 0x10, src, 0x10);
if (!is_personalized) { if (!is_personalized) {
/* Devkit non-personalized keys have no further authentication. */ /* Devkit non-personalized keys have no further authentication. */
memcpy(dst, intermediate_buf, src_size - 0x10); memcpy(dst, intermediate_buf, src_size - 0x10);
memset(intermediate_buf, 0, sizeof(intermediate_buf)); memset(intermediate_buf, 0, sizeof(intermediate_buf));
return src_size - 0x10; return src_size - 0x10;
} }
/* J = GHASH(CTR); */ /* J = GHASH(CTR); */
uint8_t j_block[0x10]; uint8_t j_block[0x10];
@@ -166,7 +166,7 @@ size_t gcm_decrypt_key(void *dst, size_t dst_size, const void *src, size_t src_s
/* It is supposed to be over the ciphertext. */ /* It is supposed to be over the ciphertext. */
uint8_t calc_mac[0x10]; uint8_t calc_mac[0x10];
ghash(calc_mac, intermediate_buf, src_size - 0x20, j_block, true); ghash(calc_mac, intermediate_buf, src_size - 0x20, j_block, true);
/* Const-time memcmp. */ /* Const-time memcmp. */
const uint8_t *src_bytes = src; const uint8_t *src_bytes = src;
int different = 0; int different = 0;
@@ -184,7 +184,7 @@ size_t gcm_decrypt_key(void *dst, size_t dst_size, const void *src, size_t src_s
if (out_deviceid_high != NULL) { if (out_deviceid_high != NULL) {
*out_deviceid_high = intermediate_buf[src_size - 0x28]; *out_deviceid_high = intermediate_buf[src_size - 0x28];
} }
memcpy(dst, intermediate_buf, src_size - 0x30); memcpy(dst, intermediate_buf, src_size - 0x30);
memset(intermediate_buf, 0, sizeof(intermediate_buf)); memset(intermediate_buf, 0, sizeof(intermediate_buf));
return src_size - 0x30; return src_size - 0x30;
@@ -205,10 +205,12 @@ void gcm_encrypt_key(void *dst, size_t dst_size, const void *src, size_t src_siz
se_generate_random(KEYSLOT_SWITCH_RNGKEY, intermediate_buf, 0x10); se_generate_random(KEYSLOT_SWITCH_RNGKEY, intermediate_buf, 0x10);
flush_dcache_range(intermediate_buf, intermediate_buf + 0x10); flush_dcache_range(intermediate_buf, intermediate_buf + 0x10);
/* Copy in the src. */
memcpy(intermediate_buf + 0x10, src, src_size);
/* Write Device ID. */ /* Write Device ID. */
write64be(intermediate_buf, src_size + 0x18, fuse_get_device_id() | (deviceid_high << 56)); write64be(intermediate_buf, src_size + 0x18, fuse_get_device_id() | (deviceid_high << 56));
/* J = GHASH(CTR); */ /* J = GHASH(CTR); */
uint8_t j_block[0x10]; uint8_t j_block[0x10];
ghash(j_block, intermediate_buf, 0x10, NULL, false); ghash(j_block, intermediate_buf, 0x10, NULL, false);

View File

@@ -47,7 +47,7 @@ void configure_gpu_ucode_carveout(void) {
carveout->size_big_pages = 2; /* 0x40000 */ carveout->size_big_pages = 2; /* 0x40000 */
carveout->client_access_0 = 0; carveout->client_access_0 = 0;
carveout->client_access_1 = 0; carveout->client_access_1 = 0;
carveout->client_access_2 = (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_600) ? (BIT(CSR_GPUSRD) | BIT(CSW_GPUSWR) | BIT(CSR_TSECSRD)) : (BIT(CSR_GPUSRD) | BIT(CSW_GPUSWR)); carveout->client_access_2 = (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) ? (BIT(CSR_GPUSRD) | BIT(CSW_GPUSWR) | BIT(CSR_TSECSRD)) : (BIT(CSR_GPUSRD) | BIT(CSW_GPUSWR));
carveout->client_access_3 = 0; carveout->client_access_3 = 0;
carveout->client_access_4 = (BIT(CSR_GPUSRD2) | BIT(CSW_GPUSWR2)); carveout->client_access_4 = (BIT(CSR_GPUSRD2) | BIT(CSW_GPUSWR2));
carveout->client_force_internal_access_0 = 0; carveout->client_force_internal_access_0 = 0;
@@ -77,7 +77,7 @@ void configure_default_carveouts(void) {
carveout->config = 0x4000006; carveout->config = 0x4000006;
/* Configure Carveout 2 (GPU UCODE) */ /* Configure Carveout 2 (GPU UCODE) */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_600) { if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
configure_gpu_ucode_carveout(); configure_gpu_ucode_carveout();
} }
@@ -99,7 +99,7 @@ void configure_default_carveouts(void) {
carveout->config = 0x4401E7E; carveout->config = 0x4401E7E;
/* Configure default Kernel carveouts based on 2.0.0+. */ /* Configure default Kernel carveouts based on 2.0.0+. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_200) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
/* Configure Carveout 4 (KERNEL_BUILTINS) */ /* Configure Carveout 4 (KERNEL_BUILTINS) */
configure_kernel_carveout(4, g_saved_carveouts[0].address, g_saved_carveouts[0].size); configure_kernel_carveout(4, g_saved_carveouts[0].address, g_saved_carveouts[0].size);
@@ -140,11 +140,11 @@ void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint6
carveout->size_big_pages = (uint32_t)(size >> 17); 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_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_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));
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_810) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) {
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW)); 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_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR)); 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_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR)); carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR));
} else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) { } else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_8_0_0) {
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW)); 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_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)); carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR) | BIT(CSR_TSECSRDB) | BIT(CSW_TSECSWRB));
@@ -153,10 +153,10 @@ void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint6
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_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_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_0 = ((exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) && (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_1 = ((exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) && (carveout_id == 4)) ? BIT(CSW_AVPCARM7W) : 0;
carveout->client_force_internal_access_2 = 0; carveout->client_force_internal_access_2 = 0;
carveout->client_force_internal_access_3 = 0; carveout->client_force_internal_access_3 = 0;
carveout->client_force_internal_access_4 = 0; carveout->client_force_internal_access_4 = 0;
carveout->config = (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) ? 0x4CB : 0x8B; carveout->config = (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_8_0_0) ? 0x4CB : 0x8B;
} }

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef EXOSPHERE_MMU_H #ifndef EXOSPHERE_MMU_H
#define EXOSPHERE_MMU_H #define EXOSPHERE_MMU_H
@@ -134,7 +134,7 @@
#define TCR_EL2_RSVD (BIT(31) | BIT(23)) #define TCR_EL2_RSVD (BIT(31) | BIT(23))
#define TCR_EL3_RSVD (BIT(31) | BIT(23)) #define TCR_EL3_RSVD (BIT(31) | BIT(23))
static inline void mmu_init_table(uintptr_t *tbl, size_t num_entries) { static inline void mmu_init_table(volatile uintptr_t *tbl, size_t num_entries) {
for(size_t i = 0; i < num_entries / 8; i++) { for(size_t i = 0; i < num_entries / 8; i++) {
tbl[i] = MMU_PTE_TYPE_FAULT; tbl[i] = MMU_PTE_TYPE_FAULT;
} }

View File

@@ -75,7 +75,7 @@ __libc_fini_array (void)
{ {
size_t count; size_t count;
size_t i; size_t i;
count = __fini_array_end - __fini_array_start; count = __fini_array_end - __fini_array_start;
for (i = count; i > 0; i--) for (i = count; i > 0; i--)
__fini_array_start[i-1] (); __fini_array_start[i-1] ();
@@ -170,7 +170,7 @@ memmove (void *dst_void,
} }
else else
{ {
/* Use optimizing algorithm for a non-destructive copy to closely /* Use optimizing algorithm for a non-destructive copy to closely
match memcpy. If the size is small or either SRC or DST is unaligned, match memcpy. If the size is small or either SRC or DST is unaligned,
then punt into the byte copy loop. This should be rare. */ then punt into the byte copy loop. This should be rare. */
if (!TOO_SMALL(length) && !UNALIGNED (src, dst)) if (!TOO_SMALL(length) && !UNALIGNED (src, dst))
@@ -561,7 +561,7 @@ memcmp (const void *m1,
s2++; s2++;
} }
return 0; return 0;
#else #else
unsigned char *s1 = (unsigned char *) m1; unsigned char *s1 = (unsigned char *) m1;
unsigned char *s2 = (unsigned char *) m2; unsigned char *s2 = (unsigned char *) m2;
unsigned long *a1; unsigned long *a1;
@@ -572,13 +572,13 @@ memcmp (const void *m1,
not turn up in inner loops. */ not turn up in inner loops. */
if (!TOO_SMALL(n) && !UNALIGNED(s1,s2)) if (!TOO_SMALL(n) && !UNALIGNED(s1,s2))
{ {
/* Otherwise, load and compare the blocks of memory one /* Otherwise, load and compare the blocks of memory one
word at a time. */ word at a time. */
a1 = (unsigned long*) s1; a1 = (unsigned long*) s1;
a2 = (unsigned long*) s2; a2 = (unsigned long*) s2;
while (n >= LBLOCKSIZE) while (n >= LBLOCKSIZE)
{ {
if (*a1 != *a2) if (*a1 != *a2)
break; break;
a1++; a1++;
a2++; a2++;
@@ -703,7 +703,7 @@ strchr (const char *s1,
/* /*
FUNCTION FUNCTION
<<strcmp>>---character string compare <<strcmp>>---character string compare
INDEX INDEX
strcmp strcmp
SYNOPSIS SYNOPSIS
@@ -736,7 +736,7 @@ QUICKREF
int int
strcmp (const char *s1, strcmp (const char *s1,
const char *s2) const char *s2)
{ {
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
while (*s1 != '\0' && *s1 == *s2) while (*s1 != '\0' && *s1 == *s2)
{ {
@@ -751,7 +751,7 @@ strcmp (const char *s1,
/* If s1 or s2 are unaligned, then compare bytes. */ /* If s1 or s2 are unaligned, then compare bytes. */
if (!UNALIGNED (s1, s2)) if (!UNALIGNED (s1, s2))
{ {
/* If s1 and s2 are word-aligned, compare them a word at a time. */ /* If s1 and s2 are word-aligned, compare them a word at a time. */
a1 = (unsigned long*)s1; a1 = (unsigned long*)s1;
a2 = (unsigned long*)s2; a2 = (unsigned long*)s2;
@@ -915,7 +915,7 @@ strlen (const char *str)
/* /*
FUNCTION FUNCTION
<<strncmp>>---character string compare <<strncmp>>---character string compare
INDEX INDEX
strncmp strncmp
SYNOPSIS SYNOPSIS
@@ -944,7 +944,7 @@ QUICKREF
#define UNALIGNED(X, Y) \ #define UNALIGNED(X, Y) \
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
int int
strncmp (const char *s1, strncmp (const char *s1,
const char *s2, const char *s2,
size_t n) size_t n)
@@ -1103,10 +1103,10 @@ strncpy (char *__restrict dst0,
#endif /* not PREFER_SIZE_OVER_SPEED */ #endif /* not PREFER_SIZE_OVER_SPEED */
} }
/* /*
FUNCTION FUNCTION
<<strnlen>>---character string length <<strnlen>>---character string length
INDEX INDEX
strnlen strnlen
SYNOPSIS SYNOPSIS

View File

@@ -82,7 +82,7 @@ static void derive_new_device_keys(unsigned int keygen_keyslot) {
break; break;
} else if (relative_revision == mkey_get_revision()) { } else if (relative_revision == mkey_get_revision()) {
/* On 7.0.0, sept will have derived this key for us already. */ /* On 7.0.0, sept will have derived this key for us already. */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_700) { if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10); decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
} }
} else { } else {
@@ -133,25 +133,15 @@ static void setup_se(void) {
mkey_detect_revision(); mkey_detect_revision();
/* Derive new device keys. */ /* Derive new device keys. */
switch (exosphere_get_target_firmware()) { {
case ATMOSPHERE_TARGET_FIRMWARE_100: const uint32_t target_fw = exosphere_get_target_firmware();
case ATMOSPHERE_TARGET_FIRMWARE_200: if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
case ATMOSPHERE_TARGET_FIRMWARE_300:
break;
case ATMOSPHERE_TARGET_FIRMWARE_400:
derive_new_device_keys(KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY);
break;
case ATMOSPHERE_TARGET_FIRMWARE_500:
case ATMOSPHERE_TARGET_FIRMWARE_600:
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY); derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
break; } else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
derive_new_device_keys(KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY);
} else {
/* No new keys to derive */
}
} }
se_initialize_rng(KEYSLOT_SWITCH_DEVICEKEY); se_initialize_rng(KEYSLOT_SWITCH_DEVICEKEY);
@@ -176,7 +166,7 @@ static void setup_boot_config(void) {
bootconfig_clear(); bootconfig_clear();
} else { } else {
void *bootconfig_ptr = NX_BOOTLOADER_BOOTCONFIG_POINTER; void *bootconfig_ptr = NX_BOOTLOADER_BOOTCONFIG_POINTER;
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_600) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
bootconfig_ptr = NX_BOOTLOADER_BOOTCONFIG_POINTER_6X; bootconfig_ptr = NX_BOOTLOADER_BOOTCONFIG_POINTER_6X;
} }
flush_dcache_range((uint8_t *)bootconfig_ptr, (uint8_t *)bootconfig_ptr + sizeof(bootconfig_t)); flush_dcache_range((uint8_t *)bootconfig_ptr, (uint8_t *)bootconfig_ptr + sizeof(bootconfig_t));
@@ -447,30 +437,20 @@ static void load_package2_sections(package2_meta_t *metadata, uint32_t master_ke
static void copy_warmboot_bin_to_dram() { static void copy_warmboot_bin_to_dram() {
uint8_t *warmboot_src; uint8_t *warmboot_src;
switch (exosphere_get_target_firmware()) {
case ATMOSPHERE_TARGET_FIRMWARE_100: {
case ATMOSPHERE_TARGET_FIRMWARE_200: const uint32_t target_fw = exosphere_get_target_firmware();
case ATMOSPHERE_TARGET_FIRMWARE_300: if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
default:
generic_panic();
break;
case ATMOSPHERE_TARGET_FIRMWARE_400:
case ATMOSPHERE_TARGET_FIRMWARE_500:
warmboot_src = (uint8_t *)0x4003B000;
break;
case ATMOSPHERE_TARGET_FIRMWARE_600:
case ATMOSPHERE_TARGET_FIRMWARE_620:
warmboot_src = (uint8_t *)0x4003D800;
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
warmboot_src = (uint8_t *)0x4003E000; warmboot_src = (uint8_t *)0x4003E000;
break; } else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
warmboot_src = (uint8_t *)0x4003D800;
} else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
warmboot_src = (uint8_t *)0x4003B000;
} else {
return;
}
} }
uint8_t *warmboot_dst = (uint8_t *)0x8000D000; uint8_t *warmboot_dst = (uint8_t *)0x8000D000;
const size_t warmboot_size = 0x2000; const size_t warmboot_size = 0x2000;
@@ -522,40 +502,31 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
setup_se(); setup_se();
/* Perform initial PMC register writes, if relevant. */ /* Perform initial PMC register writes, if relevant. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000; MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000;
MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF; MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF;
MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE; MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE;
MAKE_REG32(PMC_BASE + 0x334) |= 0x10; MAKE_REG32(PMC_BASE + 0x334) |= 0x10;
switch (exosphere_get_target_firmware()) {
case ATMOSPHERE_TARGET_FIRMWARE_400: const uint32_t target_fw = exosphere_get_target_firmware();
MAKE_REG32(PMC_BASE + 0x360) = 0x105; if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0) {
break; MAKE_REG32(PMC_BASE + 0x360) = 0x105;
case ATMOSPHERE_TARGET_FIRMWARE_500: } else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_9_1_0) {
MAKE_REG32(PMC_BASE + 0x360) = 6; MAKE_REG32(PMC_BASE + 0x360) = 0x18C;
break; } else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_9_0_0) {
case ATMOSPHERE_TARGET_FIRMWARE_600: MAKE_REG32(PMC_BASE + 0x360) = 0x16B;
MAKE_REG32(PMC_BASE + 0x360) = 0x87; } else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) {
break; MAKE_REG32(PMC_BASE + 0x360) = 0x14A;
case ATMOSPHERE_TARGET_FIRMWARE_620: } else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
MAKE_REG32(PMC_BASE + 0x360) = 0xA8; MAKE_REG32(PMC_BASE + 0x360) = 0x129;
break; } else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
case ATMOSPHERE_TARGET_FIRMWARE_700: MAKE_REG32(PMC_BASE + 0x360) = 0x0A8;
case ATMOSPHERE_TARGET_FIRMWARE_800: } else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
MAKE_REG32(PMC_BASE + 0x360) = 0x129; MAKE_REG32(PMC_BASE + 0x360) = 0x087;
break; } else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
case ATMOSPHERE_TARGET_FIRMWARE_810: MAKE_REG32(PMC_BASE + 0x360) = 0x006;
MAKE_REG32(PMC_BASE + 0x360) = 0x14A; } else if (target_fw >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
break; MAKE_REG32(PMC_BASE + 0x360) = 0x105;
case ATMOSPHERE_TARGET_FIRMWARE_900:
MAKE_REG32(PMC_BASE + 0x360) = 0x16B;
break;
case ATMOSPHERE_TARGET_FIRMWARE_910:
MAKE_REG32(PMC_BASE + 0x360) = 0x18C;
break;
case ATMOSPHERE_TARGET_FIRMWARE_1000:
MAKE_REG32(PMC_BASE + 0x360) = 0x1AD;
break;
} }
} }
@@ -587,7 +558,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
setup_boot_config(); setup_boot_config();
/* Set sysctr0 registers based on bootconfig. */ /* Set sysctr0 registers based on bootconfig. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
uint64_t sysctr0_val = bootconfig_get_value_for_sysctr0(); uint64_t sysctr0_val = bootconfig_get_value_for_sysctr0();
MAKE_SYSCTR0_REG(0x8) = (uint32_t)((sysctr0_val >> 0) & 0xFFFFFFFFULL); MAKE_SYSCTR0_REG(0x8) = (uint32_t)((sysctr0_val >> 0) & 0xFFFFFFFFULL);
MAKE_SYSCTR0_REG(0xC) = (uint32_t)((sysctr0_val >> 32) & 0xFFFFFFFFULL); MAKE_SYSCTR0_REG(0xC) = (uint32_t)((sysctr0_val >> 32) & 0xFFFFFFFFULL);
@@ -595,10 +566,10 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
} }
/* Synchronize with NX BOOTLOADER. */ /* Synchronize with NX BOOTLOADER. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X); sync_with_nx_bootloader(NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X);
copy_warmboot_bin_to_dram(); copy_warmboot_bin_to_dram();
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_600) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
setup_dram_magic_numbers(); setup_dram_magic_numbers();
} }
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_LOADED_PACKAGE2_4X); sync_with_nx_bootloader(NX_BOOTLOADER_STATE_LOADED_PACKAGE2_4X);
@@ -651,7 +622,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
} }
/* Synchronize with NX BOOTLOADER. */ /* Synchronize with NX BOOTLOADER. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_FINISHED_4X); sync_with_nx_bootloader(NX_BOOTLOADER_STATE_FINISHED_4X);
setup_4x_mmio(); setup_4x_mmio();
} else { } else {

View File

@@ -26,7 +26,7 @@
/* Physaddr 0x40002EF8 */ /* Physaddr 0x40002EF8 */
static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) { static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_NXBOOTLOADER_MAILBOX) + ((targetfw >= ATMOSPHERE_TARGET_FIRMWARE_700) ? (0x000ull) : (0xE00ull)); return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_NXBOOTLOADER_MAILBOX) + ((targetfw >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) ? (0x000ull) : (0xE00ull));
} }
#define MAILBOX_NX_BOOTLOADER_BASE(targetfw) (get_nx_bootloader_mailbox_base(targetfw)) #define MAILBOX_NX_BOOTLOADER_BASE(targetfw) (get_nx_bootloader_mailbox_base(targetfw))

View File

@@ -90,14 +90,14 @@ static void mitigate_jamais_vu(void) {
} }
/* For debugging, make this check always pass. */ /* For debugging, make this check always pass. */
if ((exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_400 || (get_debug_authentication_status() & 3) == 3)) { if ((exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_4_0_0 || (get_debug_authentication_status() & 3) == 3)) {
FLOW_CTLR_HALT_COP_EVENTS_0 = 0x50000000; FLOW_CTLR_HALT_COP_EVENTS_0 = 0x50000000;
} else { } else {
FLOW_CTLR_HALT_COP_EVENTS_0 = 0x40000000; FLOW_CTLR_HALT_COP_EVENTS_0 = 0x40000000;
} }
/* Jamais Vu mitigation #2: Ensure the BPMP is halted. */ /* Jamais Vu mitigation #2: Ensure the BPMP is halted. */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_400 || (get_debug_authentication_status() & 3) == 3) { if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_4_0_0 || (get_debug_authentication_status() & 3) == 3) {
/* BPMP should just be plainly halted, in debugging conditions. */ /* BPMP should just be plainly halted, in debugging conditions. */
if (FLOW_CTLR_HALT_COP_EVENTS_0 != 0x50000000) { if (FLOW_CTLR_HALT_COP_EVENTS_0 != 0x50000000) {
generic_panic(); generic_panic();
@@ -167,7 +167,7 @@ static void save_tzram_state(void) {
uint8_t *tzram_encryption_dst = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_ENCRYPTED_TZRAM)); uint8_t *tzram_encryption_dst = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_ENCRYPTED_TZRAM));
uint8_t *tzram_encryption_src = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM)); uint8_t *tzram_encryption_src = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM));
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
tzram_encryption_src += 0x2000ull; tzram_encryption_src += 0x2000ull;
} }
uint8_t *tzram_store_address = (uint8_t *)(WARMBOOT_GET_RAM_SEGMENT_ADDRESS(WARMBOOT_RAM_SEGMENT_ID_TZRAM)); uint8_t *tzram_store_address = (uint8_t *)(WARMBOOT_GET_RAM_SEGMENT_ADDRESS(WARMBOOT_RAM_SEGMENT_ID_TZRAM));
@@ -204,7 +204,7 @@ static void save_tzram_state(void) {
APBDEV_PMC_SEC_DISABLE8_0 = 0x550000; APBDEV_PMC_SEC_DISABLE8_0 = 0x550000;
/* Perform pre-2.0.0 PMC writes. */ /* Perform pre-2.0.0 PMC writes. */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_200) { if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
/* TODO: Give these writes appropriate defines in pmc.h */ /* TODO: Give these writes appropriate defines in pmc.h */
/* Save Encrypted context location + lock scratch register. */ /* Save Encrypted context location + lock scratch register. */
@@ -272,7 +272,7 @@ uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argumen
notify_pmic_shutdown(); notify_pmic_shutdown();
/* Validate that the shutdown has correct context. */ /* Validate that the shutdown has correct context. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_200) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
mitigate_jamais_vu(); mitigate_jamais_vu();
} }
@@ -280,7 +280,7 @@ uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argumen
configure_pmc_for_deep_powerdown(); configure_pmc_for_deep_powerdown();
/* Ensure that BPMP SC7 firmware is active. */ /* Ensure that BPMP SC7 firmware is active. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_200) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
setup_bpmp_sc7_firmware(); setup_bpmp_sc7_firmware();
} }
@@ -294,7 +294,7 @@ uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argumen
/* Ensure that other cores are already asleep. */ /* Ensure that other cores are already asleep. */
if (!(APBDEV_PMC_PWRGATE_STATUS_0 & 0xE00)) { if (!(APBDEV_PMC_PWRGATE_STATUS_0 & 0xE00)) {
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_200) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
call_with_stack_pointer(get_smc_core012_stack_address(), save_se_and_power_down_cpu); call_with_stack_pointer(get_smc_core012_stack_address(), save_se_and_power_down_cpu);
} else { } else {
save_se_and_power_down_cpu(); save_se_and_power_down_cpu();

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@@ -37,7 +37,7 @@ static const uint8_t g_seal_key_sources[CRYPTOUSECASE_MAX_5X][0x10] = {
}; };
bool usecase_is_invalid(unsigned int usecase) { bool usecase_is_invalid(unsigned int usecase) {
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
return usecase >= CRYPTOUSECASE_MAX_5X; return usecase >= CRYPTOUSECASE_MAX_5X;
} else { } else {
return usecase >= CRYPTOUSECASE_MAX; return usecase >= CRYPTOUSECASE_MAX;
@@ -59,7 +59,7 @@ void seal_titlekey(void *dst, size_t dst_size, const void *src, size_t src_size)
if (dst_size != 0x10 || src_size != 0x10) { if (dst_size != 0x10 || src_size != 0x10) {
generic_panic(); generic_panic();
} }
seal_key_internal(dst, src, g_titlekey_seal_key_source); seal_key_internal(dst, src, g_titlekey_seal_key_source);
} }
@@ -68,7 +68,7 @@ void unseal_titlekey(unsigned int keyslot, const void *src, size_t src_size) {
if (src_size != 0x10) { if (src_size != 0x10) {
generic_panic(); generic_panic();
} }
unseal_key_internal(keyslot, src, g_titlekey_seal_key_source); unseal_key_internal(keyslot, src, g_titlekey_seal_key_source);
} }
@@ -77,8 +77,8 @@ void seal_key(void *dst, size_t dst_size, const void *src, size_t src_size, unsi
if (usecase_is_invalid(usecase) || dst_size != 0x10 || src_size != 0x10) { if (usecase_is_invalid(usecase) || dst_size != 0x10 || src_size != 0x10) {
generic_panic(); generic_panic();
} }
seal_key_internal(dst, src, g_seal_key_sources[usecase]); seal_key_internal(dst, src, g_seal_key_sources[usecase]);
} }
@@ -86,6 +86,6 @@ void unseal_key(unsigned int keyslot, const void *src, size_t src_size, unsigned
if (usecase_is_invalid(usecase) || src_size != 0x10) { if (usecase_is_invalid(usecase) || src_size != 0x10) {
generic_panic(); generic_panic();
} }
unseal_key_internal(keyslot, src, g_seal_key_sources[usecase]); unseal_key_internal(keyslot, src, g_seal_key_sources[usecase]);
} }

View File

@@ -169,36 +169,23 @@ void set_suspend_for_debug(void) {
} }
void set_version_specific_smcs(void) { void set_version_specific_smcs(void) {
switch (exosphere_get_target_firmware()) { const uint32_t target_firmware = exosphere_get_target_firmware();
case ATMOSPHERE_TARGET_FIRMWARE_100: if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
/* 1.0.0 doesn't have ConfigureCarveout or ReadWriteRegister. */ /* No more LoadSecureExpModKey. */
g_smc_priv_table[7].handler = NULL; g_smc_user_table[0xE].handler = NULL;
g_smc_priv_table[8].handler = NULL; g_smc_user_table[0xC].id = 0xC300D60C;
/* 1.0.0 doesn't have UnwrapAesWrappedTitlekey. */ g_smc_user_table[0xC].handler = smc_encrypt_rsa_key_for_import;
g_smc_user_table[0x12].handler = NULL; g_smc_user_table[0xD].handler = smc_decrypt_or_import_rsa_key;
break; } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
case ATMOSPHERE_TARGET_FIRMWARE_200: /* Nothing to do. */
case ATMOSPHERE_TARGET_FIRMWARE_300: } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_1_0_0) {
case ATMOSPHERE_TARGET_FIRMWARE_400: /* 1.0.0 doesn't have ConfigureCarveout or ReadWriteRegister. */
/* Do nothing. */ g_smc_priv_table[7].handler = NULL;
break; g_smc_priv_table[8].handler = NULL;
case ATMOSPHERE_TARGET_FIRMWARE_500: /* 1.0.0 doesn't have UnwrapAesWrappedTitlekey. */
case ATMOSPHERE_TARGET_FIRMWARE_600: g_smc_user_table[0x12].handler = NULL;
case ATMOSPHERE_TARGET_FIRMWARE_620: } else {
case ATMOSPHERE_TARGET_FIRMWARE_700: panic_predefined(0xA);
case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
/* No more LoadSecureExpModKey. */
g_smc_user_table[0xE].handler = NULL;
g_smc_user_table[0xC].id = 0xC300D60C;
g_smc_user_table[0xC].handler = smc_encrypt_rsa_key_for_import;
g_smc_user_table[0xD].handler = smc_decrypt_or_import_rsa_key;
break;
default:
panic_predefined(0xA);
} }
} }
@@ -306,7 +293,7 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
#endif #endif
/* Call function. */ /* Call function. */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_800 || if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_8_0_0 ||
(g_smc_tables[handler_id].handlers[smc_id].blacklist_mask & g_smc_blacklist_mask) == 0) { (g_smc_tables[handler_id].handlers[smc_id].blacklist_mask & g_smc_blacklist_mask) == 0) {
args->X[0] = smc_handler(args); args->X[0] = smc_handler(args);
} else { } else {
@@ -636,7 +623,7 @@ uint32_t smc_read_write_register(smc_args_t *args) {
return 2; return 2;
} }
} else { } else {
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
static const uint8_t mc_whitelist_5x[0xD00/(sizeof(uint32_t) * 8)] = { static const uint8_t mc_whitelist_5x[0xD00/(sizeof(uint32_t) * 8)] = {
0x9F, 0x31, 0x30, 0x00, 0xF0, 0xFF, 0xF7, 0x01, 0x9F, 0x31, 0x30, 0x00, 0xF0, 0xFF, 0xF7, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -687,7 +674,7 @@ uint32_t smc_read_write_register(smc_args_t *args) {
break; break;
} }
} }
} else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { } else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
if (MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) <= address && address < MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) + 0xD00) { if (MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) <= address && address < MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) + 0xD00) {
/* Memory Controller RW supported only on 4.0.0+ */ /* Memory Controller RW supported only on 4.0.0+ */
static const uint8_t mc_whitelist[0x68] = { static const uint8_t mc_whitelist[0x68] = {
@@ -730,7 +717,7 @@ uint32_t smc_read_write_register(smc_args_t *args) {
/* Return old value. */ /* Return old value. */
args->X[1] = old_value; args->X[1] = old_value;
return 0; return 0;
} else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400 && (address == 0x7001923C || address == 0x70019298)) { } else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0 && (address == 0x7001923C || address == 0x70019298)) {
/* These addresses are not allowed by the whitelist. */ /* These addresses are not allowed by the whitelist. */
/* They correspond to SMMU DISABLE for the BPMP, and for APB-DMA. */ /* They correspond to SMMU DISABLE for the BPMP, and for APB-DMA. */
/* However, smcReadWriteRegister returns 0 for these addresses despite not actually performing the write. */ /* However, smcReadWriteRegister returns 0 for these addresses despite not actually performing the write. */
@@ -759,7 +746,7 @@ uint32_t smc_configure_carveout(smc_args_t *args) {
} }
/* Configuration is one-shot, and cannot be done multiple times. */ /* Configuration is one-shot, and cannot be done multiple times. */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_300) { if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
if (g_configured_carveouts[carveout_id]) { if (g_configured_carveouts[carveout_id]) {
return 2; return 2;
} }

View File

@@ -122,23 +122,10 @@ static void validate_rsa_result(unsigned int which) {
} }
static bool is_user_keyslot_valid(unsigned int keyslot) { static bool is_user_keyslot_valid(unsigned int keyslot) {
switch (exosphere_get_target_firmware()) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
case ATMOSPHERE_TARGET_FIRMWARE_100: return keyslot <= 5;
case ATMOSPHERE_TARGET_FIRMWARE_200: } else {
case ATMOSPHERE_TARGET_FIRMWARE_300: return keyslot <= 3;
case ATMOSPHERE_TARGET_FIRMWARE_400:
case ATMOSPHERE_TARGET_FIRMWARE_500:
return keyslot <= 3;
case ATMOSPHERE_TARGET_FIRMWARE_600:
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
default:
return keyslot <= 5;
} }
} }
@@ -262,7 +249,7 @@ uint32_t user_generate_aes_kek(smc_args_t *args) {
uint8_t mask_id = (uint8_t)((packed_options >> 1) & 3); uint8_t mask_id = (uint8_t)((packed_options >> 1) & 3);
/* Switches the output based on how it will be used. */ /* Switches the output based on how it will be used. */
uint8_t usecase = (uint8_t)((packed_options >> 5) & (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500 ? 7 : 3)); uint8_t usecase = (uint8_t)((packed_options >> 5) & (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0 ? 7 : 3));
/* Switched the output based on whether it should be console unique. */ /* Switched the output based on whether it should be console unique. */
bool is_personalized = (int)(packed_options & 1); bool is_personalized = (int)(packed_options & 1);
@@ -270,7 +257,7 @@ uint32_t user_generate_aes_kek(smc_args_t *args) {
bool is_recovery_boot = configitem_is_recovery_boot(); bool is_recovery_boot = configitem_is_recovery_boot();
/* 5.0.0+ Bounds checking. */ /* 5.0.0+ Bounds checking. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
if (is_personalized) { if (is_personalized) {
if (master_key_rev >= MASTERKEY_REVISION_MAX || (MASTERKEY_REVISION_300 <= master_key_rev && master_key_rev < MASTERKEY_REVISION_400_410)) { if (master_key_rev >= MASTERKEY_REVISION_MAX || (MASTERKEY_REVISION_300 <= master_key_rev && master_key_rev < MASTERKEY_REVISION_400_410)) {
return 2; return 2;
@@ -324,9 +311,9 @@ uint32_t user_generate_aes_kek(smc_args_t *args) {
unsigned int keyslot; unsigned int keyslot;
if (is_personalized) { if (is_personalized) {
/* Behavior changed in 4.0.0, and in 5.0.0. */ /* Behavior changed in 4.0.0, and in 5.0.0. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
keyslot = devkey_get_keyslot(master_key_rev); keyslot = devkey_get_keyslot(master_key_rev);
} else if (exosphere_get_target_firmware() == ATMOSPHERE_TARGET_FIRMWARE_400) { } else if (exosphere_get_target_firmware() == ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
if (master_key_rev >= 1) { if (master_key_rev >= 1) {
keyslot = KEYSLOT_SWITCH_DEVICEKEY; /* New device key, 4.x. */ keyslot = KEYSLOT_SWITCH_DEVICEKEY; /* New device key, 4.x. */
} else { } else {
@@ -399,7 +386,7 @@ uint32_t user_crypt_aes(smc_args_t *args) {
uint32_t keyslot = args->X[1] & 3; uint32_t keyslot = args->X[1] & 3;
uint32_t mode = (args->X[1] >> 4) & 3; uint32_t mode = (args->X[1] >> 4) & 3;
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_600) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
keyslot = args->X[1] & 7; keyslot = args->X[1] & 7;
} }
@@ -415,7 +402,7 @@ uint32_t user_crypt_aes(smc_args_t *args) {
return 2; return 2;
} }
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
/* Disallow dma lists outside of safe range. */ /* Disallow dma lists outside of safe range. */
if (in_ll_paddr - 0x80000000 >= 0x3FF7F5) { if (in_ll_paddr - 0x80000000 >= 0x3FF7F5) {
return 2; return 2;
@@ -463,7 +450,7 @@ uint32_t user_generate_specific_aes_key(smc_args_t *args) {
if (master_key_rev > 0) { if (master_key_rev > 0) {
master_key_rev -= 1; master_key_rev -= 1;
} }
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
master_key_rev = 0; master_key_rev = 0;
} }
@@ -479,9 +466,9 @@ uint32_t user_generate_specific_aes_key(smc_args_t *args) {
unsigned int keyslot; unsigned int keyslot;
/* Behavior changed in 5.0.0. */ /* Behavior changed in 5.0.0. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
keyslot = devkey_get_keyslot(master_key_rev); keyslot = devkey_get_keyslot(master_key_rev);
} else if (exosphere_get_target_firmware() == ATMOSPHERE_TARGET_FIRMWARE_400) { } else if (exosphere_get_target_firmware() == ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
if (master_key_rev >= 1) { if (master_key_rev >= 1) {
keyslot = KEYSLOT_SWITCH_DEVICEKEY; /* New device key, 4.x. */ keyslot = KEYSLOT_SWITCH_DEVICEKEY; /* New device key, 4.x. */
} else { } else {
@@ -560,7 +547,7 @@ uint32_t user_load_rsa_oaep_key(smc_args_t *args) {
upage_ref_t page_ref; upage_ref_t page_ref;
/* This function no longer exists in 5.x+. */ /* This function no longer exists in 5.x+. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
generic_panic(); generic_panic();
} }
@@ -609,7 +596,7 @@ uint32_t user_decrypt_rsa_private_key(smc_args_t *args) {
upage_ref_t page_ref; upage_ref_t page_ref;
/* This function no longer exists in 5.x+. */ /* This function no longer exists in 5.x+. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
generic_panic(); generic_panic();
} }
@@ -667,7 +654,7 @@ uint32_t user_load_secure_exp_mod_key(smc_args_t *args) {
upage_ref_t page_ref; upage_ref_t page_ref;
/* This function no longer exists in 5.x+. */ /* This function no longer exists in 5.x+. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
generic_panic(); generic_panic();
} }
@@ -723,7 +710,7 @@ uint32_t user_secure_exp_mod(smc_args_t *args) {
void *user_modulus = (void *)args->X[2]; void *user_modulus = (void *)args->X[2];
unsigned int exponent_id = 1; unsigned int exponent_id = 1;
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
switch (args->X[3]) { switch (args->X[3]) {
case 0: case 0:
exponent_id = 1; exponent_id = 1;
@@ -753,7 +740,7 @@ uint32_t user_secure_exp_mod(smc_args_t *args) {
set_exp_mod_result(3); set_exp_mod_result(3);
/* Hardcode RSA keyslot 0. */ /* Hardcode RSA keyslot 0. */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_1000) { if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_10_0_0) {
set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[exponent_id], 0x100); set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[exponent_id], 0x100);
se_exp_mod(0, input, 0x100, exp_mod_done_handler); se_exp_mod(0, input, 0x100, exp_mod_done_handler);
} else if (load_imported_rsa_keypair(0, exponent_id)) { } else if (load_imported_rsa_keypair(0, exponent_id)) {
@@ -780,7 +767,7 @@ uint32_t user_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
unsigned int option = (unsigned int)args->X[7]; unsigned int option = (unsigned int)args->X[7];
unsigned int master_key_rev; unsigned int master_key_rev;
unsigned int titlekey_type; unsigned int titlekey_type;
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_600) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
master_key_rev = option & 0x3F; master_key_rev = option & 0x3F;
titlekey_type = (option >> 6) & 1; titlekey_type = (option >> 6) & 1;
} else { } else {
@@ -792,7 +779,7 @@ uint32_t user_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
master_key_rev -= 1; master_key_rev -= 1;
} }
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_300) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
if (master_key_rev >= MASTERKEY_REVISION_MAX) { if (master_key_rev >= MASTERKEY_REVISION_MAX) {
return 2; return 2;
} }
@@ -857,7 +844,7 @@ uint32_t user_unwrap_aes_wrapped_titlekey(smc_args_t *args) {
if (master_key_rev > 0) { if (master_key_rev > 0) {
master_key_rev -= 1; master_key_rev -= 1;
} }
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_300) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
if (master_key_rev >= MASTERKEY_REVISION_MAX) { if (master_key_rev >= MASTERKEY_REVISION_MAX) {
return 2; return 2;
} }
@@ -953,7 +940,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
upage_ref_t page_ref; upage_ref_t page_ref;
/* This function only exists in 5.x+. */ /* This function only exists in 5.x+. */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_500) { if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
generic_panic(); generic_panic();
} }
@@ -1019,7 +1006,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
} }
/* Modulus import isn't implemented on < 10.0.0. */ /* Modulus import isn't implemented on < 10.0.0. */
import_modulus &= (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_1000); import_modulus &= (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0);
/* Import the key. */ /* Import the key. */
import_rsa_exponent(exponent_id, user_data, 0x100); import_rsa_exponent(exponent_id, user_data, 0x100);

View File

@@ -40,7 +40,7 @@ void tkey_set_master_key_rev(unsigned int master_key_rev) {
} }
static void tkey_validate_type(unsigned int type) { static void tkey_validate_type(unsigned int type) {
if (type > TITLEKEY_TYPE_MAX || (type > 0 && exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_600)) { if (type > TITLEKEY_TYPE_MAX || (type > 0 && exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_6_0_0)) {
generic_panic(); generic_panic();
} }
} }

View File

@@ -25,7 +25,7 @@
#undef MC_BASE #undef MC_BASE
#define MC_BASE (MMIO_GET_DEVICE_PA(MMIO_DEVID_MC)) #define MC_BASE (MMIO_GET_DEVICE_PA(MMIO_DEVID_MC))
#define WARMBOOT_GET_TZRAM_SEGMENT_PA(x) ((g_exosphere_target_firmware_for_init < ATMOSPHERE_TARGET_FIRMWARE_500) \ #define WARMBOOT_GET_TZRAM_SEGMENT_PA(x) ((g_exosphere_target_firmware_for_init < ATMOSPHERE_TARGET_FIRMWARE_5_0_0) \
? TZRAM_GET_SEGMENT_PA(x) : TZRAM_GET_SEGMENT_5X_PA(x)) ? TZRAM_GET_SEGMENT_PA(x) : TZRAM_GET_SEGMENT_5X_PA(x))
/* start.s */ /* start.s */
@@ -53,7 +53,7 @@ void warmboot_crt0_critical_section_enter(volatile critical_section_t *critical_
} }
void init_dma_controllers(unsigned int target_firmware) { void init_dma_controllers(unsigned int target_firmware) {
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
/* Set some unknown registers in HOST1X. */ /* Set some unknown registers in HOST1X. */
MAKE_REG32(0x500038F8) &= 0xFFFFFFFE; MAKE_REG32(0x500038F8) &= 0xFFFFFFFE;
MAKE_REG32(0x50003300) = 0; MAKE_REG32(0x50003300) = 0;
@@ -213,7 +213,7 @@ void warmboot_init(void) {
/*identity_remap_tzram();*/ /*identity_remap_tzram();*/
/* Nintendo pointlessly fully invalidate the TLB & invalidate the data cache on the modified ranges here */ /* Nintendo pointlessly fully invalidate the TLB & invalidate the data cache on the modified ranges here */
if (g_exosphere_target_firmware_for_init < ATMOSPHERE_TARGET_FIRMWARE_500) { if (g_exosphere_target_firmware_for_init < ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
set_memory_registers_enable_mmu_1x_ttbr0(); set_memory_registers_enable_mmu_1x_ttbr0();
} else { } else {
set_memory_registers_enable_mmu_5x_ttbr0(); set_memory_registers_enable_mmu_5x_ttbr0();

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "utils.h" #include "utils.h"
#include "mmu.h" #include "mmu.h"
#include "memory_map.h" #include "memory_map.h"
@@ -53,7 +53,7 @@ void __attribute__((noreturn)) warmboot_main(void) {
- warmboot (core 3) - warmboot (core 3)
- cpu_on - cpu_on
*/ */
if (is_core_active(get_core_id())) { if (is_core_active(get_core_id())) {
panic(0xF7F00009); /* invalid CPU context */ panic(0xF7F00009); /* invalid CPU context */
} }
@@ -70,7 +70,7 @@ void __attribute__((noreturn)) warmboot_main(void) {
clkrst_reboot(CARDEVICE_UARTA); clkrst_reboot(CARDEVICE_UARTA);
uart_init(UART_A, 115200); uart_init(UART_A, 115200);
} }
if (!configitem_is_retail()) { if (!configitem_is_retail()) {
uart_send(UART_A, "OHAYO", 6); uart_send(UART_A, "OHAYO", 6);
uart_wait_idle(UART_A, UART_VENDOR_STATE_TX_IDLE); uart_wait_idle(UART_A, UART_VENDOR_STATE_TX_IDLE);
@@ -87,15 +87,15 @@ void __attribute__((noreturn)) warmboot_main(void) {
/* Make PMC (2.x+), MC (4.x+) registers secure-only */ /* Make PMC (2.x+), MC (4.x+) registers secure-only */
secure_additional_devices(); secure_additional_devices();
if ((exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_400) || if ((exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) ||
((exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_800) && configitem_get_hardware_type() == 0) || ((exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_8_0_0) && configitem_get_hardware_type() == 0) ||
(configitem_is_hiz_mode_enabled())) { (configitem_is_hiz_mode_enabled())) {
warmboot_configure_hiz_mode(); warmboot_configure_hiz_mode();
} }
clear_user_smc_in_progress(); clear_user_smc_in_progress();
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
setup_4x_mmio(); setup_4x_mmio();
} }
} }

View File

@@ -206,7 +206,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1)); uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1));
/* Firmware from versions 1.0.0 to 3.0.2. */ /* Firmware from versions 1.0.0 to 3.0.2. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
if (hardware_type >= 1) { if (hardware_type >= 1) {
return (hardware_type > 2) ? 3 : hardware_type - 1; return (hardware_type > 2) ? 3 : hardware_type - 1;
@@ -215,7 +215,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
} else { } else {
return 3; return 3;
} }
} else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) { /* Firmware versions from 4.0.0 to 6.2.0. */ } else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */
static const uint32_t types[] = {0,1,4,3}; static const uint32_t types[] = {0,1,4,3};
hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C); hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C);
hardware_type--; hardware_type--;

View File

@@ -119,7 +119,7 @@ all: check_rebootstub $(BUILD)
check_rebootstub: check_rebootstub:
@$(MAKE) -C $(AMS)/exosphere/rebootstub all @$(MAKE) -C $(AMS)/exosphere/rebootstub all
$(BUILD): $(BUILD): check_rebootstub
@[ -d $@ ] || mkdir -p $@ @[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile

View File

@@ -23,13 +23,16 @@ FATFS sd_fs;
static bool g_sd_mounted = false; static bool g_sd_mounted = false;
static bool g_sd_initialized = false; static bool g_sd_initialized = false;
static bool g_ahb_redirect_enabled = false; static bool g_ahb_redirect_enabled = false;
sdmmc_t g_sd_sdmmc;
sdmmc_device_t g_sd_device;
bool mount_sd(void) bool mount_sd(void)
{ {
/* Already mounted. */ /* Already mounted. */
if (g_sd_mounted) if (g_sd_mounted)
return true; return true;
/* Enable AHB redirection if necessary. */ /* Enable AHB redirection if necessary. */
if (!g_ahb_redirect_enabled) { if (!g_ahb_redirect_enabled) {
mc_enable_ahb_redirect(); mc_enable_ahb_redirect();
@@ -41,7 +44,7 @@ bool mount_sd(void)
if (sdmmc_device_sd_init(&g_sd_device, &g_sd_sdmmc, SDMMC_BUS_WIDTH_4BIT, SDMMC_SPEED_UHS_SDR104)) if (sdmmc_device_sd_init(&g_sd_device, &g_sd_sdmmc, SDMMC_BUS_WIDTH_4BIT, SDMMC_SPEED_UHS_SDR104))
{ {
g_sd_initialized = true; g_sd_initialized = true;
/* Mount SD. */ /* Mount SD. */
if (f_mount(&sd_fs, "", 1) == FR_OK) { if (f_mount(&sd_fs, "", 1) == FR_OK) {
print(SCREEN_LOG_LEVEL_INFO, "Mounted SD card!\n"); print(SCREEN_LOG_LEVEL_INFO, "Mounted SD card!\n");
@@ -63,7 +66,7 @@ void unmount_sd(void)
sdmmc_device_finish(&g_sd_device); sdmmc_device_finish(&g_sd_device);
g_sd_mounted = false; g_sd_mounted = false;
} }
/* Disable AHB redirection if necessary. */ /* Disable AHB redirection if necessary. */
if (g_ahb_redirect_enabled) { if (g_ahb_redirect_enabled) {
mc_disable_ahb_redirect(); mc_disable_ahb_redirect();
@@ -81,13 +84,13 @@ uint32_t get_file_size(const char *filename)
FIL f; FIL f;
if (f_open(&f, filename, FA_READ) != FR_OK) if (f_open(&f, filename, FA_READ) != FR_OK)
return 0; return 0;
/* Get the file size. */ /* Get the file size. */
uint32_t file_size = f_size(&f); uint32_t file_size = f_size(&f);
/* Close the file. */ /* Close the file. */
f_close(&f); f_close(&f);
return file_size; return file_size;
} }
@@ -101,10 +104,10 @@ int read_from_file(void *dst, uint32_t dst_size, const char *filename)
FIL f; FIL f;
if (f_open(&f, filename, FA_READ) != FR_OK) if (f_open(&f, filename, FA_READ) != FR_OK)
return 0; return 0;
/* Sync. */ /* Sync. */
f_sync(&f); f_sync(&f);
/* Read from file. */ /* Read from file. */
UINT br = 0; UINT br = 0;
int res = f_read(&f, dst, dst_size, &br); int res = f_read(&f, dst, dst_size, &br);
@@ -118,7 +121,7 @@ int write_to_file(void *src, uint32_t src_size, const char *filename)
/* SD card hasn't been mounted yet. */ /* SD card hasn't been mounted yet. */
if (!g_sd_mounted) if (!g_sd_mounted)
return 0; return 0;
/* Open the file for writing. */ /* Open the file for writing. */
FIL f; FIL f;
if (f_open(&f, filename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) if (f_open(&f, filename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef FUSEE_FS_UTILS_H #ifndef FUSEE_FS_UTILS_H
#define FUSEE_FS_UTILS_H #define FUSEE_FS_UTILS_H
@@ -23,8 +23,8 @@
#include "sdmmc/sdmmc.h" #include "sdmmc/sdmmc.h"
#include "utils.h" #include "utils.h"
sdmmc_t g_sd_sdmmc; extern sdmmc_t g_sd_sdmmc;
sdmmc_device_t g_sd_device; extern sdmmc_device_t g_sd_device;
bool mount_sd(void); bool mount_sd(void);
void unmount_sd(void); void unmount_sd(void);

View File

@@ -206,7 +206,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1)); uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1));
/* Firmware from versions 1.0.0 to 3.0.2. */ /* Firmware from versions 1.0.0 to 3.0.2. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
if (hardware_type >= 1) { if (hardware_type >= 1) {
return (hardware_type > 2) ? 3 : hardware_type - 1; return (hardware_type > 2) ? 3 : hardware_type - 1;
@@ -215,7 +215,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
} else { } else {
return 3; return 3;
} }
} else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) { /* Firmware versions from 4.0.0 to 6.2.0. */ } else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */
static const uint32_t types[] = {0,1,4,3}; static const uint32_t types[] = {0,1,4,3};
hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C); hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C);
hardware_type--; hardware_type--;

View File

@@ -70,7 +70,10 @@ static char* find_chars_or_comment(const char* s, const char* chars)
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ /* Version of strncpy that ensures dest (size bytes) is null-terminated. */
static char* strncpy0(char* dest, const char* src, size_t size) static char* strncpy0(char* dest, const char* src, size_t size)
{ {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
strncpy(dest, src, size - 1); strncpy(dest, src, size - 1);
#pragma GCC diagnostic pop
dest[size - 1] = '\0'; dest[size - 1] = '\0';
return dest; return dest;
} }

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef FUSEE_DEVICE_PARTITION_H #ifndef FUSEE_DEVICE_PARTITION_H
#define FUSEE_DEVICE_PARTITION_H #define FUSEE_DEVICE_PARTITION_H
@@ -50,6 +50,7 @@ typedef struct device_partition_t {
device_partition_cipher_t read_cipher; /* Cipher for read operations. */ device_partition_cipher_t read_cipher; /* Cipher for read operations. */
device_partition_cipher_t write_cipher; /* Cipher for write operations. */ device_partition_cipher_t write_cipher; /* Cipher for write operations. */
DevicePartitionCryptoMode crypto_mode; /* Mode to use for cryptographic operations. */ DevicePartitionCryptoMode crypto_mode; /* Mode to use for cryptographic operations. */
size_t crypto_sector_size;
device_partition_initializer_t initializer; /* Initializer. */ device_partition_initializer_t initializer; /* Initializer. */
device_partition_finalizer_t finalizer; /* Finalizer. */ device_partition_finalizer_t finalizer; /* Finalizer. */
@@ -65,7 +66,7 @@ typedef struct device_partition_t {
uint8_t __attribute__((aligned(16))) keys[DEVPART_KEY_MAX][DEVPART_KEY_MAX_SIZE]; /* Key. */ uint8_t __attribute__((aligned(16))) keys[DEVPART_KEY_MAX][DEVPART_KEY_MAX_SIZE]; /* Key. */
uint8_t __attribute__((aligned(16))) iv[DEVPART_IV_MAX_SIZE]; /* IV. */ uint8_t __attribute__((aligned(16))) iv[DEVPART_IV_MAX_SIZE]; /* IV. */
bool initialized; bool initialized;
char *emu_file_path; /* Emulated device file path. */ char *emu_file_path; /* Emulated device file path. */
bool emu_use_file; bool emu_use_file;
} device_partition_t; } device_partition_t;

View File

@@ -31,7 +31,8 @@
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u) #define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u) #define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
#define EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS (1 << 4u) #define EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS (1 << 4u)
#define EXOSPHERE_FLAGS_DEFAULT (EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV) #define EXOSPHERE_FLAG_BLANK_PRODINFO (1 << 5u)
#define EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC (1 << 6u)
typedef struct { typedef struct {
uint32_t magic; uint32_t magic;
@@ -50,5 +51,18 @@ _Static_assert(sizeof(exosphere_config_t) == 0x20 + sizeof(exo_emummc_config_t),
#define EXOSPHERE_DEBUGMODE_USER_KEY "debugmode_user" #define EXOSPHERE_DEBUGMODE_USER_KEY "debugmode_user"
#define EXOSPHERE_DISABLE_USERMODE_EXCEPTION_HANDLERS_KEY "disable_user_exception_handlers" #define EXOSPHERE_DISABLE_USERMODE_EXCEPTION_HANDLERS_KEY "disable_user_exception_handlers"
#define EXOSPHERE_ENABLE_USERMODE_PMU_ACCESS_KEY "enable_user_pmu_access" #define EXOSPHERE_ENABLE_USERMODE_PMU_ACCESS_KEY "enable_user_pmu_access"
#define EXOSPHERE_BLANK_PRODINFO_SYSMMC_KEY "blank_prodinfo_sysmmc"
#define EXOSPHERE_BLANK_PRODINFO_EMUMMC_KEY "blank_prodinfo_emummc"
#define EXOSPHERE_ALLOW_WRITING_TO_CAL_SYSMMC_KEY "allow_writing_to_cal_sysmmc"
#endif typedef struct {
int debugmode;
int debugmode_user;
int disable_user_exception_handlers;
int enable_user_pmu_access;
int blank_prodinfo_sysmmc;
int blank_prodinfo_emummc;
int allow_writing_to_cal_sysmmc;
} exosphere_parse_cfg_t;
#endif

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
@@ -121,7 +121,7 @@ int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool
fsdev_device_t *device = fsdev_find_device(name); fsdev_device_t *device = fsdev_find_device(name);
FRESULT rc; FRESULT rc;
char drname[40]; char drname[40];
if (device != NULL) { if (device != NULL) {
errno = EEXIST; /* Device already exists */ errno = EEXIST; /* Device already exists */
return -1; return -1;
@@ -170,7 +170,7 @@ int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool
VolumeStr[device - g_fsdev_devices] = FKNAM; VolumeStr[device - g_fsdev_devices] = FKNAM;
return fsdev_convert_rc(NULL, rc); return fsdev_convert_rc(NULL, rc);
} }
device->setup = true; device->setup = true;
device->registered = false; device->registered = false;
@@ -289,6 +289,20 @@ int fsdev_unmount_device(const char *name) {
return ret; return ret;
} }
int fsdev_register_keys(const char *name, unsigned int target_firmware, BisPartition part) {
fsdev_device_t *device = fsdev_find_device(name);
if (device == NULL) {
errno = ENOENT;
return -1;
}
derive_bis_key(device->devpart.keys, part, target_firmware);
return 0;
}
int fsdev_unmount_all(void) { int fsdev_unmount_all(void) {
for (size_t i = 0; i < FF_VOLUMES; i++) { for (size_t i = 0; i < FF_VOLUMES; i++) {
int ret = fsdev_unmount_device(g_fsdev_devices[i].name); int ret = fsdev_unmount_device(g_fsdev_devices[i].name);
@@ -403,7 +417,7 @@ static void fsdev_filinfo_to_st(struct stat *st, const FILINFO *info) {
date.tm_sec = (info->ftime << 1) & 63; date.tm_sec = (info->ftime << 1) & 63;
date.tm_min = (info->ftime >> 5) & 63; date.tm_min = (info->ftime >> 5) & 63;
date.tm_hour = (info->ftime >> 11) & 31; date.tm_hour = (info->ftime >> 11) & 31;
date.tm_isdst = 0; date.tm_isdst = 0;
st->st_atime = st->st_mtime = st->st_ctime = mktime(&date); st->st_atime = st->st_mtime = st->st_ctime = mktime(&date);

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef FUSEE_FS_DEV_H #ifndef FUSEE_FS_DEV_H
#define FUSEE_FS_DEV_H #define FUSEE_FS_DEV_H
@@ -21,12 +21,15 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "device_partition.h" #include "device_partition.h"
#include "key_derivation.h"
int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool initialize_immediately); int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool initialize_immediately);
int fsdev_register_device(const char *name); int fsdev_register_device(const char *name);
int fsdev_unregister_device(const char *name); int fsdev_unregister_device(const char *name);
int fsdev_unmount_device(const char *name); /* also unregisters. */ int fsdev_unmount_device(const char *name); /* also unregisters. */
int fsdev_register_keys(const char *name, unsigned int target_firmware, BisPartition part);
int fsdev_set_attr(const char *file, int attr, int mask); /* Non-standard function to set file DOS attributes. */ int fsdev_set_attr(const char *file, int attr, int mask); /* Non-standard function to set file DOS attributes. */
int fsdev_get_attr(const char *file); /* Non-standard function to get file DOS attributes. */ int fsdev_get_attr(const char *file); /* Non-standard function to get file DOS attributes. */

View File

@@ -13,10 +13,12 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdio.h> #include <stdio.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "lib/fatfs/ff.h"
#include "fs_utils.h" #include "fs_utils.h"
#include "fs_dev.h"
size_t get_file_size(const char *filename) { size_t get_file_size(const char *filename) {
struct stat st; struct stat st;
@@ -54,7 +56,7 @@ bool is_valid_folder(const char *path) {
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) { if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
return true; return true;
} }
return false; return false;
} }
@@ -63,6 +65,29 @@ bool is_valid_file(const char *path) {
if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
return true; return true;
} }
return false; return false;
} }
bool is_valid_concatenation_file(const char *path) {
if (is_valid_file(path)) {
return true;
} else if (is_valid_folder(path)) {
/* Check if the archive bit is set. */
int rc = fsdev_get_attr(path);
/* Failed to get file DOS attributes. */
if (rc == -1) {
return false;
}
/* Check if our path is not a directory (it should be if we're in this code, though...). */
if (!(rc & AM_DIR)) {
return false;
}
return (rc & AM_ARC) != 0;
} else {
return false;
}
}

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef FUSEE_FS_UTILS_H #ifndef FUSEE_FS_UTILS_H
#define FUSEE_FS_UTILS_H #define FUSEE_FS_UTILS_H
@@ -25,4 +25,6 @@ size_t dump_to_file(const void *src, size_t src_size, const char *filename);
bool is_valid_folder(const char *path); bool is_valid_folder(const char *path);
bool is_valid_file(const char *path); bool is_valid_file(const char *path);
bool is_valid_concatenation_file(const char *path);
#endif #endif

View File

@@ -206,7 +206,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1)); uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1));
/* Firmware from versions 1.0.0 to 3.0.2. */ /* Firmware from versions 1.0.0 to 3.0.2. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs(); volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
if (hardware_type >= 1) { if (hardware_type >= 1) {
return (hardware_type > 2) ? 3 : hardware_type - 1; return (hardware_type > 2) ? 3 : hardware_type - 1;
@@ -215,7 +215,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
} else { } else {
return 3; return 3;
} }
} else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) { /* Firmware versions from 4.0.0 to 6.2.0. */ } else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */
static const uint32_t types[] = {0,1,4,3}; static const uint32_t types[] = {0,1,4,3};
hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C); hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C);
hardware_type--; hardware_type--;
@@ -261,3 +261,12 @@ void fuse_get_hardware_info(void *dst) {
memcpy(dst, hw_info, 0x10); memcpy(dst, hw_info, 0x10);
} }
/* Get the Key Generation value. */
uint32_t fuse_get_5x_key_generation(void) {
if ((fuse_get_reserved_odm(4) & 0x800) && (fuse_get_reserved_odm(0) == 0x8E61ECAE) && (fuse_get_reserved_odm(1) == 0xF2BA3BB2)) {
return (fuse_get_reserved_odm(2) & 0x1F);
} else {
return 0;
}
}

View File

@@ -219,6 +219,7 @@ uint32_t fuse_get_dram_id(void);
uint32_t fuse_get_hardware_type(uint32_t target_firmware); uint32_t fuse_get_hardware_type(uint32_t target_firmware);
uint32_t fuse_get_retail_type(void); uint32_t fuse_get_retail_type(void);
void fuse_get_hardware_info(void *dst); void fuse_get_hardware_info(void *dst);
uint32_t fuse_get_5x_key_generation(void);
uint32_t fuse_hw_read(uint32_t addr); uint32_t fuse_hw_read(uint32_t addr);
void fuse_hw_write(uint32_t value, uint32_t addr); void fuse_hw_write(uint32_t value, uint32_t addr);

View File

@@ -15,6 +15,7 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include "lib/log.h"
#include "key_derivation.h" #include "key_derivation.h"
#include "masterkey.h" #include "masterkey.h"
#include "se.h" #include "se.h"
@@ -143,29 +144,16 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
} }
/* Do 6.2.0+ keygen. */ /* Do 6.2.0+ keygen. */
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_620) { if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
uint32_t desired_keyblob; uint32_t desired_keyblob;
switch (target_firmware) {
case ATMOSPHERE_TARGET_FIRMWARE_620: if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) {
desired_keyblob = MASTERKEY_REVISION_620; /* NOTE: We load in the current key for all >= 8.1.0 firmwares to reduce sept binaries. */
break; desired_keyblob = MASTERKEY_REVISION_910_CURRENT;
case ATMOSPHERE_TARGET_FIRMWARE_700: } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
case ATMOSPHERE_TARGET_FIRMWARE_800: desired_keyblob = MASTERKEY_REVISION_700_800;
desired_keyblob = MASTERKEY_REVISION_700_800; } else {
break; desired_keyblob = MASTERKEY_REVISION_620;
case ATMOSPHERE_TARGET_FIRMWARE_810:
desired_keyblob = MASTERKEY_REVISION_810;
/* Fallthrough */
case ATMOSPHERE_TARGET_FIRMWARE_900:
desired_keyblob = MASTERKEY_REVISION_900;
/* Fallthrough */
case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
desired_keyblob = MASTERKEY_REVISION_910_CURRENT;
break;
default:
fatal_error("Unknown target firmware: %02x!", target_firmware);
break;
} }
/* Try emulation result. */ /* Try emulation result. */
@@ -213,31 +201,31 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
set_aes_keyslot(0xC, g_dec_keyblobs[available_revision].master_kek, 0x10); set_aes_keyslot(0xC, g_dec_keyblobs[available_revision].master_kek, 0x10);
/* Also set the Package1 key for the revision that is stored on the eMMC boot0 partition. */ /* Also set the Package1 key for the revision that is stored on the eMMC boot0 partition. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_620) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
load_package1_key(available_revision); load_package1_key(available_revision);
} }
/* Derive keys for Exosphere, lock critical keyslots. */ /* Derive keys for Exosphere, lock critical keyslots. */
switch (target_firmware) { switch (target_firmware) {
case ATMOSPHERE_TARGET_FIRMWARE_100: case ATMOSPHERE_TARGET_FIRMWARE_1_0_0:
case ATMOSPHERE_TARGET_FIRMWARE_200: case ATMOSPHERE_TARGET_FIRMWARE_2_0_0:
case ATMOSPHERE_TARGET_FIRMWARE_300: case ATMOSPHERE_TARGET_FIRMWARE_3_0_0:
decrypt_data_into_keyslot(0xD, 0xF, devicekey_seed, 0x10); decrypt_data_into_keyslot(0xD, 0xF, devicekey_seed, 0x10);
decrypt_data_into_keyslot(0xC, 0xC, masterkey_seed, 0x10); decrypt_data_into_keyslot(0xC, 0xC, masterkey_seed, 0x10);
break; break;
case ATMOSPHERE_TARGET_FIRMWARE_400: case ATMOSPHERE_TARGET_FIRMWARE_4_0_0:
decrypt_data_into_keyslot(0xD, 0xF, devicekey_4x_seed, 0x10); decrypt_data_into_keyslot(0xD, 0xF, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10); decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10); decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xC, 0xC, masterkey_seed, 0x10); decrypt_data_into_keyslot(0xC, 0xC, masterkey_seed, 0x10);
break; break;
case ATMOSPHERE_TARGET_FIRMWARE_500: case ATMOSPHERE_TARGET_FIRMWARE_5_0_0:
case ATMOSPHERE_TARGET_FIRMWARE_600: case ATMOSPHERE_TARGET_FIRMWARE_6_0_0:
case ATMOSPHERE_TARGET_FIRMWARE_620: case ATMOSPHERE_TARGET_FIRMWARE_6_2_0:
case ATMOSPHERE_TARGET_FIRMWARE_700: case ATMOSPHERE_TARGET_FIRMWARE_7_0_0:
case ATMOSPHERE_TARGET_FIRMWARE_800: case ATMOSPHERE_TARGET_FIRMWARE_8_0_0:
case ATMOSPHERE_TARGET_FIRMWARE_810: case ATMOSPHERE_TARGET_FIRMWARE_8_1_0:
case ATMOSPHERE_TARGET_FIRMWARE_900: case ATMOSPHERE_TARGET_FIRMWARE_9_0_0:
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10); decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10); decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10); decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
@@ -254,11 +242,13 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
/* Sets final keyslot flags, for handover to TZ/Exosphere. Setting these will prevent the BPMP from using the device key or master key. */ /* Sets final keyslot flags, for handover to TZ/Exosphere. Setting these will prevent the BPMP from using the device key or master key. */
void finalize_nx_keydata(uint32_t target_firmware) { void finalize_nx_keydata(uint32_t target_firmware) {
set_aes_keyslot_flags(0xC, 0xFF); set_aes_keyslot_flags(0xC, 0xFF);
set_aes_keyslot_flags((target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_400) ? (KEYSLOT_SWITCH_4XOLDDEVICEKEY) : (KEYSLOT_SWITCH_DEVICEKEY), 0xFF); set_aes_keyslot_flags((target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) ? (KEYSLOT_SWITCH_4XOLDDEVICEKEY) : (KEYSLOT_SWITCH_DEVICEKEY), 0xFF);
} }
static void generate_specific_aes_key(void *dst, const void *wrapped_key, bool should_mask, uint32_t target_firmware) { static void generate_specific_aes_key(void *dst, const void *wrapped_key, bool should_mask, uint32_t target_firmware, uint32_t generation) {
unsigned int keyslot = (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_400) ? (KEYSLOT_SWITCH_4XOLDDEVICEKEY) : (KEYSLOT_SWITCH_DEVICEKEY); unsigned int keyslot = (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) ? (devkey_get_keyslot(generation)) : (KEYSLOT_SWITCH_DEVICEKEY);
if (fuse_get_bootrom_patch_version() < 0x7F) { if (fuse_get_bootrom_patch_version() < 0x7F) {
/* On dev units, use a fixed "all-zeroes" seed. */ /* On dev units, use a fixed "all-zeroes" seed. */
/* Yes, this data really is all-zero in actual TrustZone .rodata. */ /* Yes, this data really is all-zero in actual TrustZone .rodata. */
@@ -281,7 +271,7 @@ static void generate_specific_aes_key(void *dst, const void *wrapped_key, bool s
} }
} }
static void generate_personalized_aes_key_for_bis(void *dst, const void *wrapped_kek, const void *wrapped_key, uint32_t target_firmware) { static void generate_personalized_aes_key_for_bis(void *dst, const void *wrapped_kek, const void *wrapped_key, uint32_t target_firmware, uint32_t generation) {
static const uint8_t AL16 kek_source[0x10] = { static const uint8_t AL16 kek_source[0x10] = {
0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9
}; };
@@ -289,7 +279,7 @@ static void generate_personalized_aes_key_for_bis(void *dst, const void *wrapped
0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8
}; };
unsigned int keyslot = (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_400) ? (KEYSLOT_SWITCH_4XOLDDEVICEKEY) : (KEYSLOT_SWITCH_DEVICEKEY); unsigned int keyslot = (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) ? (devkey_get_keyslot(generation)) : (KEYSLOT_SWITCH_DEVICEKEY);
/* Derive kek. */ /* Derive kek. */
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, keyslot, kek_source, 0x10); decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, keyslot, kek_source, 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, KEYSLOT_SWITCH_TEMPKEY, wrapped_kek, 0x10); decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, KEYSLOT_SWITCH_TEMPKEY, wrapped_kek, 0x10);
@@ -314,16 +304,18 @@ void derive_bis_key(void *dst, BisPartition partition_id, uint32_t target_firmwa
} }
}; };
const uint32_t bis_key_generation = fuse_get_5x_key_generation();
static const uint8_t AL16 bis_kek_source[0x10] = {0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; static const uint8_t AL16 bis_kek_source[0x10] = {0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F};
switch (partition_id) { switch (partition_id) {
case BisPartition_Calibration: case BisPartition_Calibration:
generate_specific_aes_key(dst, key_source_for_bis[partition_id][0], false, target_firmware); generate_specific_aes_key(dst, key_source_for_bis[partition_id][0], false, target_firmware, bis_key_generation);
generate_specific_aes_key(dst + 0x10, key_source_for_bis[partition_id][1], false, target_firmware); generate_specific_aes_key(dst + 0x10, key_source_for_bis[partition_id][1], false, target_firmware, bis_key_generation);
break; break;
case BisPartition_Safe: case BisPartition_Safe:
case BisPartition_UserSystem: case BisPartition_UserSystem:
generate_personalized_aes_key_for_bis(dst, bis_kek_source, key_source_for_bis[partition_id][0], target_firmware); generate_personalized_aes_key_for_bis(dst, bis_kek_source, key_source_for_bis[partition_id][0], target_firmware, bis_key_generation);
generate_personalized_aes_key_for_bis(dst + 0x10, bis_kek_source, key_source_for_bis[partition_id][1], target_firmware); generate_personalized_aes_key_for_bis(dst + 0x10, bis_kek_source, key_source_for_bis[partition_id][1], target_firmware, bis_key_generation);
break; break;
default: default:
generic_panic(); generic_panic();

View File

@@ -70,7 +70,10 @@ static char* find_chars_or_comment(const char* s, const char* chars)
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ /* Version of strncpy that ensures dest (size bytes) is null-terminated. */
static char* strncpy0(char* dest, const char* src, size_t size) static char* strncpy0(char* dest, const char* src, size_t size)
{ {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
strncpy(dest, src, size - 1); strncpy(dest, src, size - 1);
#pragma GCC diagnostic pop
dest[size - 1] = '\0'; dest[size - 1] = '\0';
return dest; return dest;
} }

View File

@@ -91,7 +91,7 @@ static void add_prefix(ScreenLogLevel screen_log_level, const char *fmt, char *b
/** /**
* print - logs a message and prints it to screen based on its screen_log_level * print - logs a message and prints it to screen based on its screen_log_level
* *
* If the level is below g_screen_log_level it will not be shown but logged to UART * If the level is below g_screen_log_level it will not be shown but logged to UART
* Use SCREEN_LOG_LEVEL_NO_PREFIX if you don't want a prefix to be added * Use SCREEN_LOG_LEVEL_NO_PREFIX if you don't want a prefix to be added
* UART is TODO * UART is TODO

View File

@@ -17,6 +17,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <vapours/ams/ams_target_firmware.h>
#include "utils.h" #include "utils.h"
#include "masterkey.h" #include "masterkey.h"
@@ -26,6 +27,7 @@ static unsigned int g_mkey_revision = 0;
static bool g_determined_mkey_revision = false; static bool g_determined_mkey_revision = false;
static uint8_t g_old_masterkeys[MASTERKEY_REVISION_MAX][0x10]; static uint8_t g_old_masterkeys[MASTERKEY_REVISION_MAX][0x10];
static uint8_t g_old_devicekeys[MASTERKEY_NUM_NEW_DEVICE_KEYS - 1][0x10];
/* TODO: Extend with new vectors, as needed. */ /* TODO: Extend with new vectors, as needed. */
/* Dev unit keys. */ /* Dev unit keys. */
@@ -59,6 +61,39 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
{0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */ {0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */
}; };
static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
{0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */
{0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */
{0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */
{0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 New Device Key Source. */
};
static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
{0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */
{0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */
{0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */
{0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. */
};
static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
{0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34}, /* 4.x New Device Keygen Source. */
{0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.x New Device Keygen Source. */
{0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.x New Device Keygen Source. */
{0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 New Device Keygen Source. */
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 New Device Keygen Source. */
{0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87}, /* 8.1.0 New Device Keygen Source. */
{0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. */
};
static bool check_mkey_revision(unsigned int revision, bool is_retail) { static bool check_mkey_revision(unsigned int revision, bool is_retail) {
uint8_t final_vector[0x10]; uint8_t final_vector[0x10];
@@ -127,3 +162,50 @@ unsigned int mkey_get_keyslot(unsigned int revision) {
return KEYSLOT_SWITCH_TEMPKEY; return KEYSLOT_SWITCH_TEMPKEY;
} }
} }
void derive_new_device_keys(bool is_retail, unsigned int keygen_keyslot, unsigned int target_firmware) {
uint8_t work_buffer[0x10];
for (unsigned int revision = 0; revision < MASTERKEY_NUM_NEW_DEVICE_KEYS; revision++) {
const unsigned int relative_revision = revision + MASTERKEY_REVISION_400_410;
se_aes_ecb_decrypt_block(keygen_keyslot, work_buffer, 0x10, new_device_key_sources[revision], 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, mkey_get_keyslot(0), is_retail ? new_device_keygen_sources[revision] : new_device_keygen_sources_dev[revision], 0x10);
if (relative_revision > mkey_get_revision()) {
break;
} else if (relative_revision == mkey_get_revision()) {
/* On 7.0.0, sept will have derived this key for us already. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
}
} else {
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10);
set_old_devkey(relative_revision, work_buffer);
}
}
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
clear_aes_keyslot(keygen_keyslot);
}
void set_old_devkey(unsigned int revision, const uint8_t *key) {
if (revision < MASTERKEY_REVISION_400_410 || MASTERKEY_REVISION_MAX <= revision) {
generic_panic();
}
memcpy(g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], key, 0x10);
}
unsigned int devkey_get_keyslot(unsigned int revision) {
if (!g_determined_mkey_revision || revision > g_mkey_revision) {
generic_panic();
}
if (revision < MASTERKEY_REVISION_400_410) {
return KEYSLOT_SWITCH_4XOLDDEVICEKEY;
} else if (revision < g_mkey_revision) {
/* Load into a temp keyslot. */
set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], 0x10);
return KEYSLOT_SWITCH_TEMPKEY;
} else {
return KEYSLOT_SWITCH_DEVICEKEY;
}
}

View File

@@ -41,7 +41,11 @@ int mkey_detect_revision(bool is_retail);
unsigned int mkey_get_revision(void); unsigned int mkey_get_revision(void);
unsigned int mkey_get_keyslot(unsigned int revision); unsigned int mkey_get_keyslot(unsigned int revision);
void derive_new_device_keys(bool is_retail, unsigned int keygen_keyslot, unsigned int target_firmware);
void set_old_devkey(unsigned int revision, const uint8_t *key); void set_old_devkey(unsigned int revision, const uint8_t *key);
unsigned int devkey_get_keyslot(unsigned int revision); unsigned int devkey_get_keyslot(unsigned int revision);
#endif #endif

View File

@@ -119,10 +119,16 @@ static int emummc_ini_handler(void *user, const char *section, const char *name,
} else if (strcmp(name, EMUMMC_ID_KEY) == 0) { } else if (strcmp(name, EMUMMC_ID_KEY) == 0) {
sscanf(value, "%lx", &emummc_cfg->id); sscanf(value, "%lx", &emummc_cfg->id);
} else if (strcmp(name, EMUMMC_PATH_KEY) == 0) { } else if (strcmp(name, EMUMMC_PATH_KEY) == 0) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
strncpy(emummc_cfg->path, value, sizeof(emummc_cfg->path) - 1); strncpy(emummc_cfg->path, value, sizeof(emummc_cfg->path) - 1);
#pragma GCC diagnostic pop
emummc_cfg->path[sizeof(emummc_cfg->path) - 1] = '\0'; emummc_cfg->path[sizeof(emummc_cfg->path) - 1] = '\0';
} else if (strcmp(name, EMUMMC_NINTENDO_PATH_KEY) == 0) { } else if (strcmp(name, EMUMMC_NINTENDO_PATH_KEY) == 0) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
strncpy(emummc_cfg->nintendo_path, value, sizeof(emummc_cfg->nintendo_path) - 1); strncpy(emummc_cfg->nintendo_path, value, sizeof(emummc_cfg->nintendo_path) - 1);
#pragma GCC diagnostic pop
emummc_cfg->nintendo_path[sizeof(emummc_cfg->nintendo_path) - 1] = '\0'; emummc_cfg->nintendo_path[sizeof(emummc_cfg->nintendo_path) - 1] = '\0';
} else { } else {
return 0; return 0;
@@ -134,38 +140,57 @@ static int emummc_ini_handler(void *user, const char *section, const char *name,
} }
static int exosphere_ini_handler(void *user, const char *section, const char *name, const char *value) { static int exosphere_ini_handler(void *user, const char *section, const char *name, const char *value) {
exosphere_config_t *exo_cfg = (exosphere_config_t *)user; exosphere_parse_cfg_t *parse_cfg = (exosphere_parse_cfg_t *)user;
int tmp = 0; int tmp = 0;
if (strcmp(section, "exosphere") == 0) { if (strcmp(section, "exosphere") == 0) {
if (strcmp(name, EXOSPHERE_TARGETFW_KEY) == 0) { if (strcmp(name, EXOSPHERE_DEBUGMODE_PRIV_KEY) == 0) {
sscanf(value, "%ld", &exo_cfg->target_firmware);
} else if (strcmp(name, EXOSPHERE_DEBUGMODE_PRIV_KEY) == 0) {
sscanf(value, "%d", &tmp); sscanf(value, "%d", &tmp);
if (tmp) { if (tmp == 1) {
exo_cfg->flags |= EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV; parse_cfg->debugmode = 1;
} else { } else if (tmp == 0) {
exo_cfg->flags &= ~(EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV); parse_cfg->debugmode = 0;
} }
} else if (strcmp(name, EXOSPHERE_DEBUGMODE_USER_KEY) == 0) { } else if (strcmp(name, EXOSPHERE_DEBUGMODE_USER_KEY) == 0) {
sscanf(value, "%d", &tmp); sscanf(value, "%d", &tmp);
if (tmp) { if (tmp == 1) {
exo_cfg->flags |= EXOSPHERE_FLAG_IS_DEBUGMODE_USER; parse_cfg->debugmode_user = 1;
} else { } else if (tmp == 0) {
exo_cfg->flags &= ~(EXOSPHERE_FLAG_IS_DEBUGMODE_USER); parse_cfg->debugmode_user = 0;
} }
} else if (strcmp(name, EXOSPHERE_DISABLE_USERMODE_EXCEPTION_HANDLERS_KEY) == 0) { } else if (strcmp(name, EXOSPHERE_DISABLE_USERMODE_EXCEPTION_HANDLERS_KEY) == 0) {
sscanf(value, "%d", &tmp); sscanf(value, "%d", &tmp);
if (tmp) { if (tmp == 1) {
exo_cfg->flags |= EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS; parse_cfg->disable_user_exception_handlers = 1;
} else { } else if (tmp == 0) {
exo_cfg->flags &= ~(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS); parse_cfg->disable_user_exception_handlers = 0;
} }
} else if (strcmp(name, EXOSPHERE_ENABLE_USERMODE_PMU_ACCESS_KEY) == 0) { } else if (strcmp(name, EXOSPHERE_ENABLE_USERMODE_PMU_ACCESS_KEY) == 0) {
sscanf(value, "%d", &tmp); sscanf(value, "%d", &tmp);
if (tmp) { if (tmp == 1) {
exo_cfg->flags |= EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS; parse_cfg->enable_user_pmu_access = 1;
} else { } else if (tmp == 0) {
exo_cfg->flags &= ~(EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS); parse_cfg->enable_user_pmu_access = 0;
}
} else if (strcmp(name, EXOSPHERE_BLANK_PRODINFO_SYSMMC_KEY) == 0) {
sscanf(value, "%d", &tmp);
if (tmp == 1) {
parse_cfg->blank_prodinfo_sysmmc = 1;
} else if (tmp == 0) {
parse_cfg->blank_prodinfo_sysmmc = 0;
}
} else if (strcmp(name, EXOSPHERE_BLANK_PRODINFO_EMUMMC_KEY) == 0) {
sscanf(value, "%d", &tmp);
if (tmp == 1) {
parse_cfg->blank_prodinfo_emummc = 1;
} else if (tmp == 0) {
parse_cfg->blank_prodinfo_emummc = 0;
}
} else if (strcmp(name, EXOSPHERE_ALLOW_WRITING_TO_CAL_SYSMMC_KEY) == 0) {
sscanf(value, "%d", &tmp);
if (tmp == 1) {
parse_cfg->allow_writing_to_cal_sysmmc = 1;
} else if (tmp == 0) {
parse_cfg->allow_writing_to_cal_sysmmc = 0;
} }
} else { } else {
return 0; return 0;
@@ -199,41 +224,110 @@ static int stratosphere_ini_handler(void *user, const char *section, const char
return 1; return 1;
} }
static bool is_nca_present(const char *nca_name) {
char path[0x100];
snprintf(path, sizeof(path), "system:/contents/registered/%s.nca", nca_name);
return is_valid_concatenation_file(path);
}
static uint32_t nxboot_get_specific_target_firmware(uint32_t target_firmware){
#define CHECK_NCA(NCA_ID, VERSION) do { if (is_nca_present(NCA_ID)) { return ATMOSPHERE_TARGET_FIRMWARE_##VERSION; } } while(0)
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0) {
CHECK_NCA("e951bc9dedcd54f65ffd83d4d050f9e0", 10_0_2);
CHECK_NCA("36ab1acf0c10a2beb9f7d472685f9a89", 10_0_1);
CHECK_NCA("5625cdc21d5f1ca52f6c36ba261505b9", 10_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_9_1_0) {
CHECK_NCA("09ef4d92bb47b33861e695ba524a2c17", 9_2_0);
CHECK_NCA("c5fbb49f2e3648c8cfca758020c53ecb", 9_1_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_9_0_0) {
CHECK_NCA("fd1ffb82dc1da76346343de22edbc97c", 9_0_1);
CHECK_NCA("a6af05b33f8f903aab90c8b0fcbcc6a4", 9_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) {
CHECK_NCA("724d9b432929ea43e787ad81bf09ae65", 8_1_1); /* 8.1.1-100 from Lite */
CHECK_NCA("e9bb0602e939270a9348bddd9b78827b", 8_1_1); /* 8.1.1-12 from chinese gamecard */
CHECK_NCA("7eedb7006ad855ec567114be601b2a9d", 8_1_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_0_0) {
CHECK_NCA("6c5426d27c40288302ad616307867eba", 8_0_1);
CHECK_NCA("4fe7b4abcea4a0bcc50975c1a926efcb", 8_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
CHECK_NCA("e6b22c40bb4fa66a151f1dc8db5a7b5c", 7_0_1);
CHECK_NCA("c613bd9660478de69bc8d0e2e7ea9949", 7_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
CHECK_NCA("6dfaaf1a3cebda6307aa770d9303d9b6", 6_2_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
CHECK_NCA("1d21680af5a034d626693674faf81b02", 6_1_0);
CHECK_NCA("663e74e45ffc86fbbaeb98045feea315", 6_0_1);
CHECK_NCA("258c1786b0f6844250f34d9c6f66095b", 6_0_0); /* Release 6.0.0-5.0 */
CHECK_NCA("286e30bafd7e4197df6551ad802dd815", 6_0_0); /* Pre-Release 6.0.0-4.0 */
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
CHECK_NCA("fce3b0ea366f9c95fe6498b69274b0e7", 5_1_0);
CHECK_NCA("c5758b0cb8c6512e8967e38842d35016", 5_0_2);
CHECK_NCA("53eb605d4620e8fd50064b24fd57783a", 5_0_1);
CHECK_NCA("09a2f9c16ce1c121ae6d231b35d17515", 5_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
CHECK_NCA("77e1ae7661ad8a718b9b13b70304aeea", 4_1_0);
CHECK_NCA("d0e5d20e3260f3083bcc067483b71274", 4_0_1);
CHECK_NCA("483a24ee3fd7149f9112d1931166a678", 4_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
CHECK_NCA("704129fc89e1fcb85c37b3112e51b0fc", 3_0_2);
CHECK_NCA("1fb00543307337d523ccefa9923e0c50", 3_0_1);
CHECK_NCA("6ebd3447473bade18badbeb5032af87d", 3_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
CHECK_NCA("d1c991c53a8a9038f8c3157a553d876d", 2_3_0);
CHECK_NCA("7f90353dff2d7ce69e19e07ebc0d5489", 2_2_0);
CHECK_NCA("e9b3e75fce00e52fe646156634d229b4", 2_1_0);
CHECK_NCA("7a1f79f8184d4b9bae1755090278f52c", 2_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_1_0_0) {
CHECK_NCA("a1b287e07f8455e8192f13d0e45a2aaf", 1_0_0); /* 1.0.0 from Factory */
CHECK_NCA("117f7b9c7da3e8cef02340596af206b3", 1_0_0); /* 1.0.0 from Gamecard */
} else {
fatal_error("[NXBOOT] Unknown Target Firmware!");
}
#undef CHECK_NCA
/* If we didn't find a more specific firmware, return our package1 approximation. */
return target_firmware;
}
static uint32_t nxboot_get_target_firmware(const void *package1loader) { static uint32_t nxboot_get_target_firmware(const void *package1loader) {
const package1loader_header_t *package1loader_header = (const package1loader_header_t *)package1loader; const package1loader_header_t *package1loader_header = (const package1loader_header_t *)package1loader;
switch (package1loader_header->version) { switch (package1loader_header->version) {
case 0x01: /* 1.0.0 */ case 0x01: /* 1.0.0 */
return ATMOSPHERE_TARGET_FIRMWARE_100; return ATMOSPHERE_TARGET_FIRMWARE_1_0_0;
case 0x02: /* 2.0.0 - 2.3.0 */ case 0x02: /* 2.0.0 - 2.3.0 */
return ATMOSPHERE_TARGET_FIRMWARE_200; return ATMOSPHERE_TARGET_FIRMWARE_2_0_0;
case 0x04: /* 3.0.0 and 3.0.1 - 3.0.2 */ case 0x04: /* 3.0.0 and 3.0.1 - 3.0.2 */
return ATMOSPHERE_TARGET_FIRMWARE_300; return ATMOSPHERE_TARGET_FIRMWARE_3_0_0;
case 0x07: /* 4.0.0 - 4.1.0 */ case 0x07: /* 4.0.0 - 4.1.0 */
return ATMOSPHERE_TARGET_FIRMWARE_400; return ATMOSPHERE_TARGET_FIRMWARE_4_0_0;
case 0x0B: /* 5.0.0 - 5.1.0 */ case 0x0B: /* 5.0.0 - 5.1.0 */
return ATMOSPHERE_TARGET_FIRMWARE_500; return ATMOSPHERE_TARGET_FIRMWARE_5_0_0;
case 0x0E: { /* 6.0.0 - 6.2.0 */ case 0x0E: { /* 6.0.0 - 6.2.0 */
if (memcmp(package1loader_header->build_timestamp, "20180802", 8) == 0) { if (memcmp(package1loader_header->build_timestamp, "20180802", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_600; return ATMOSPHERE_TARGET_FIRMWARE_6_0_0;
} else if (memcmp(package1loader_header->build_timestamp, "20181107", 8) == 0) { } else if (memcmp(package1loader_header->build_timestamp, "20181107", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_620; return ATMOSPHERE_TARGET_FIRMWARE_6_2_0;
} else { } else {
fatal_error("[NXBOOT] Unable to identify package1!\n"); fatal_error("[NXBOOT] Unable to identify package1!\n");
} }
} }
case 0x0F: /* 7.0.0 - 7.0.1 */ case 0x0F: /* 7.0.0 - 7.0.1 */
return ATMOSPHERE_TARGET_FIRMWARE_700; return ATMOSPHERE_TARGET_FIRMWARE_7_0_0;
case 0x10: { /* 8.0.0 - 9.0.0 */ case 0x10: { /* 8.0.0 - 9.0.0 */
if (memcmp(package1loader_header->build_timestamp, "20190314", 8) == 0) { if (memcmp(package1loader_header->build_timestamp, "20190314", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_800; return ATMOSPHERE_TARGET_FIRMWARE_8_0_0;
} else if (memcmp(package1loader_header->build_timestamp, "20190531", 8) == 0) { } else if (memcmp(package1loader_header->build_timestamp, "20190531", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_810; return ATMOSPHERE_TARGET_FIRMWARE_8_1_0;
} else if (memcmp(package1loader_header->build_timestamp, "20190809", 8) == 0) { } else if (memcmp(package1loader_header->build_timestamp, "20190809", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_900; return ATMOSPHERE_TARGET_FIRMWARE_9_0_0;
} else if (memcmp(package1loader_header->build_timestamp, "20191021", 8) == 0) { } else if (memcmp(package1loader_header->build_timestamp, "20191021", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_910; return ATMOSPHERE_TARGET_FIRMWARE_9_1_0;
} else if (memcmp(package1loader_header->build_timestamp, "20200303", 8) == 0) { } else if (memcmp(package1loader_header->build_timestamp, "20200303", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_1000; return ATMOSPHERE_TARGET_FIRMWARE_10_0_0;
} else { } else {
fatal_error("[NXBOOT] Unable to identify package1!\n"); fatal_error("[NXBOOT] Unable to identify package1!\n");
} }
@@ -268,7 +362,10 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
/* Initialize values from emummc config. */ /* Initialize values from emummc config. */
exo_emummc_config->base_cfg.id = emummc_cfg.id; exo_emummc_config->base_cfg.id = emummc_cfg.id;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
strncpy(exo_emummc_config->emu_dir_path, emummc_cfg.nintendo_path, sizeof(exo_emummc_config->emu_dir_path)); strncpy(exo_emummc_config->emu_dir_path, emummc_cfg.nintendo_path, sizeof(exo_emummc_config->emu_dir_path));
#pragma GCC diagnostic pop
exo_emummc_config->emu_dir_path[sizeof(exo_emummc_config->emu_dir_path) - 1] = '\0'; exo_emummc_config->emu_dir_path[sizeof(exo_emummc_config->emu_dir_path) - 1] = '\0';
if (emummc_cfg.enabled) { if (emummc_cfg.enabled) {
@@ -282,7 +379,10 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
} }
} else if (is_valid_folder(emummc_cfg.path)) { } else if (is_valid_folder(emummc_cfg.path)) {
exo_emummc_config->base_cfg.type = EMUMMC_TYPE_FILES; exo_emummc_config->base_cfg.type = EMUMMC_TYPE_FILES;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
strncpy(exo_emummc_config->file_cfg.path, emummc_cfg.path, sizeof(exo_emummc_config->file_cfg.path)); strncpy(exo_emummc_config->file_cfg.path, emummc_cfg.path, sizeof(exo_emummc_config->file_cfg.path));
#pragma GCC diagnostic pop
exo_emummc_config->file_cfg.path[sizeof(exo_emummc_config->file_cfg.path) - 1] = '\0'; exo_emummc_config->file_cfg.path[sizeof(exo_emummc_config->file_cfg.path) - 1] = '\0';
int num_parts = 0; int num_parts = 0;
@@ -348,15 +448,42 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke
exo_cfg.target_firmware = target_firmware; exo_cfg.target_firmware = target_firmware;
memcpy(&exo_cfg.emummc_cfg, exo_emummc_cfg, sizeof(*exo_emummc_cfg)); memcpy(&exo_cfg.emummc_cfg, exo_emummc_cfg, sizeof(*exo_emummc_cfg));
const bool is_emummc = exo_emummc_cfg->base_cfg.magic == MAGIC_EMUMMC_CONFIG && exo_emummc_cfg->base_cfg.type != EMUMMC_TYPE_NONE;
if (keygen_type) { if (keygen_type) {
exo_cfg.flags = EXOSPHERE_FLAGS_DEFAULT | EXOSPHERE_FLAG_PERFORM_620_KEYGEN; exo_cfg.flags = EXOSPHERE_FLAG_PERFORM_620_KEYGEN;
} else { } else {
exo_cfg.flags = EXOSPHERE_FLAGS_DEFAULT; exo_cfg.flags = 0;
} }
if (ini_parse_string(get_loader_ctx()->bct0, exosphere_ini_handler, &exo_cfg) < 0) { /* Setup exosphere parse configuration with defaults. */
fatal_error("[NXBOOT] Failed to parse BCT.ini!\n"); exosphere_parse_cfg_t parse_cfg = {
.debugmode = 1,
.debugmode_user = 0,
.disable_user_exception_handlers = 0,
.enable_user_pmu_access = 0,
.blank_prodinfo_sysmmc = 0,
.blank_prodinfo_emummc = 0,
.allow_writing_to_cal_sysmmc = 0,
};
/* If we have an ini to read, parse it. */
char *exosphere_ini = calloc(1, 0x10000);
if (read_from_file(exosphere_ini, 0xFFFF, "exosphere.ini")) {
if (ini_parse_string(exosphere_ini, exosphere_ini_handler, &parse_cfg) < 0) {
fatal_error("[NXBOOT] Failed to parse exosphere.ini!\n");
}
} }
free(exosphere_ini);
/* Apply parse config. */
if (parse_cfg.debugmode) exo_cfg.flags |= EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV;
if (parse_cfg.debugmode_user) exo_cfg.flags |= EXOSPHERE_FLAG_IS_DEBUGMODE_USER;
if (parse_cfg.disable_user_exception_handlers) exo_cfg.flags |= EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS;
if (parse_cfg.enable_user_pmu_access) exo_cfg.flags |= EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS;
if (parse_cfg.blank_prodinfo_sysmmc && !is_emummc) exo_cfg.flags |= EXOSPHERE_FLAG_BLANK_PRODINFO;
if (parse_cfg.blank_prodinfo_emummc && is_emummc) exo_cfg.flags |= EXOSPHERE_FLAG_BLANK_PRODINFO;
if (parse_cfg.allow_writing_to_cal_sysmmc) exo_cfg.flags |= EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC;
if ((exo_cfg.target_firmware < ATMOSPHERE_TARGET_FIRMWARE_MIN) || (exo_cfg.target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX)) { if ((exo_cfg.target_firmware < ATMOSPHERE_TARGET_FIRMWARE_MIN) || (exo_cfg.target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX)) {
fatal_error("[NXBOOT] Invalid Exosphere target firmware!\n"); fatal_error("[NXBOOT] Invalid Exosphere target firmware!\n");
@@ -378,11 +505,11 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
} }
} else { } else {
/* Check if fuses are < 4.0.0, but firmware is >= 4.0.0 */ /* Check if fuses are < 4.0.0, but firmware is >= 4.0.0 */
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_400 && !(fuse_get_reserved_odm(7) & ~0x0000000F)) { if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0 && !(fuse_get_reserved_odm(7) & ~0x0000000F)) {
kip_patches_set_enable_nogc(); kip_patches_set_enable_nogc();
} }
/* Check if the fuses are < 9.0.0, but firmware is >= 9.0.0 */ /* Check if the fuses are < 9.0.0, but firmware is >= 9.0.0 */
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_900 && !(fuse_get_reserved_odm(7) & ~0x000003FF)) { if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_9_0_0 && !(fuse_get_reserved_odm(7) & ~0x000003FF)) {
kip_patches_set_enable_nogc(); kip_patches_set_enable_nogc();
} }
} }
@@ -470,8 +597,8 @@ static void nxboot_move_bootconfig() {
fclose(bcfile); fclose(bcfile);
/* Select the actual BootConfig size and destination address. */ /* Select the actual BootConfig size and destination address. */
bootconfig_addr = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_600) ? 0x4003D000 : 0x4003F800; bootconfig_addr = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_6_0_0) ? 0x4003D000 : 0x4003F800;
bootconfig_size = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) ? 0x3000 : 0x1000; bootconfig_size = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) ? 0x3000 : 0x1000;
/* Copy the BootConfig into IRAM. */ /* Copy the BootConfig into IRAM. */
memset((void *)bootconfig_addr, 0, bootconfig_size); memset((void *)bootconfig_addr, 0, bootconfig_size);
@@ -592,6 +719,7 @@ uint32_t nxboot_main(void) {
/* Find the system's target firmware. */ /* Find the system's target firmware. */
uint32_t target_firmware = nxboot_get_target_firmware(package1loader); uint32_t target_firmware = nxboot_get_target_firmware(package1loader);
if (!target_firmware) if (!target_firmware)
fatal_error("[NXBOOT] Failed to detect target firmware!\n"); fatal_error("[NXBOOT] Failed to detect target firmware!\n");
else else
@@ -639,7 +767,7 @@ uint32_t nxboot_main(void) {
if (!package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size)) { if (!package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size)) {
fatal_error("[NXBOOT] Failed to read the TSEC firmware from Package1loader!\n"); fatal_error("[NXBOOT] Failed to read the TSEC firmware from Package1loader!\n");
} }
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_810) { if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) {
if (fuse_get_retail_type() != 0) { if (fuse_get_retail_type() != 0) {
sept_secondary_enc = sept_secondary_01_enc; sept_secondary_enc = sept_secondary_01_enc;
sept_secondary_enc_size = sept_secondary_01_enc_size; sept_secondary_enc_size = sept_secondary_01_enc_size;
@@ -648,7 +776,7 @@ uint32_t nxboot_main(void) {
sept_secondary_enc_size = sept_secondary_dev_01_enc_size; sept_secondary_enc_size = sept_secondary_dev_01_enc_size;
} }
tsec_fw_size = 0x3300; tsec_fw_size = 0x3300;
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) { } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
if (fuse_get_retail_type() != 0) { if (fuse_get_retail_type() != 0) {
sept_secondary_enc = sept_secondary_00_enc; sept_secondary_enc = sept_secondary_00_enc;
sept_secondary_enc_size = sept_secondary_00_enc_size; sept_secondary_enc_size = sept_secondary_00_enc_size;
@@ -657,7 +785,7 @@ uint32_t nxboot_main(void) {
sept_secondary_enc_size = sept_secondary_dev_00_enc_size; sept_secondary_enc_size = sept_secondary_dev_00_enc_size;
} }
tsec_fw_size = 0x3000; tsec_fw_size = 0x3000;
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) { } else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
tsec_fw_size = 0x2900; tsec_fw_size = 0x2900;
} else { } else {
tsec_fw_size = 0xF00; tsec_fw_size = 0xF00;
@@ -669,7 +797,7 @@ uint32_t nxboot_main(void) {
/* Get the TSEC keys. */ /* Get the TSEC keys. */
uint8_t tsec_key[0x10] = {0}; uint8_t tsec_key[0x10] = {0};
uint8_t tsec_root_keys[0x20][0x10] = {0}; uint8_t tsec_root_keys[0x20][0x10] = {0};
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) { if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
/* Detect whether we need to run sept-secondary in order to derive keys. */ /* Detect whether we need to run sept-secondary in order to derive keys. */
if (!get_and_clear_has_run_sept()) { if (!get_and_clear_has_run_sept()) {
reboot_to_sept(tsec_fw, tsec_fw_size, sept_secondary_enc, sept_secondary_enc_size); reboot_to_sept(tsec_fw, tsec_fw_size, sept_secondary_enc, sept_secondary_enc_size);
@@ -679,7 +807,7 @@ uint32_t nxboot_main(void) {
} }
} }
get_and_clear_has_run_sept(); get_and_clear_has_run_sept();
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) { } else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
uint8_t tsec_keys[0x20] = {0}; uint8_t tsec_keys[0x20] = {0};
/* Emulate the TSEC payload on 6.2.0+. */ /* Emulate the TSEC payload on 6.2.0+. */
@@ -700,17 +828,46 @@ uint32_t nxboot_main(void) {
/* Derive keydata. If on 7.0.0+, sept has already derived keys for us. */ /* Derive keydata. If on 7.0.0+, sept has already derived keys for us. */
unsigned int keygen_type = 0; unsigned int keygen_type = 0;
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
if (derive_nx_keydata(target_firmware, g_keyblobs, available_revision, tsec_key, tsec_root_keys, &keygen_type) != 0) { if (derive_nx_keydata(target_firmware, g_keyblobs, available_revision, tsec_key, tsec_root_keys, &keygen_type) != 0) {
fatal_error("[NXBOOT] Key derivation failed!\n"); fatal_error("[NXBOOT] Key derivation failed!\n");
} }
} }
/* Derive new device keys. */
{
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
derive_new_device_keys(fuse_get_retail_type() != 0, KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY, target_firmware);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
derive_new_device_keys(fuse_get_retail_type() != 0, KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY, target_firmware);
} else {
/* No new keys to derive */
}
}
/* Set the system partition's keys. */
if (fsdev_register_keys("system", target_firmware, BisPartition_UserSystem) != 0) {
fatal_error("[NXBOOT] Failed to set SYSTEM partition keys!\n");
}
/* Mount the system partition. */
if (fsdev_register_device("system") != 0) {
fatal_error("[NXBOOT] Failed to register SYSTEM partition!\n");
}
/* Lightly validate the system partition. */
if (!is_valid_folder("system:/Contents")) {
fatal_error("[NXBOOT] SYSTEM partition seems corrupted!\n");
}
/* Make the target firmware more specific. */
target_firmware = nxboot_get_specific_target_firmware(target_firmware);
/* Setup boot configuration for Exosphère. */ /* Setup boot configuration for Exosphère. */
nxboot_configure_exosphere(target_firmware, keygen_type, &exo_emummc_cfg); nxboot_configure_exosphere(target_firmware, keygen_type, &exo_emummc_cfg);
/* Initialize Boot Reason on older firmware versions. */ /* Initialize Boot Reason on older firmware versions. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Initializing Boot Reason...\n"); print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Initializing Boot Reason...\n");
nxboot_set_bootreason((void *)MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE(target_firmware)); nxboot_set_bootreason((void *)MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE(target_firmware));
} }
@@ -761,11 +918,11 @@ uint32_t nxboot_main(void) {
} }
/* Select the right address for the warmboot firmware. */ /* Select the right address for the warmboot firmware. */
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
warmboot_memaddr = (void *)0x8000D000; warmboot_memaddr = (void *)0x8000D000;
} else if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_600) { } else if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
warmboot_memaddr = (void *)0x4003B000; warmboot_memaddr = (void *)0x4003B000;
} else if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) { } else if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
warmboot_memaddr = (void *)0x4003D800; warmboot_memaddr = (void *)0x4003D800;
} else { } else {
warmboot_memaddr = (void *)0x4003E000; warmboot_memaddr = (void *)0x4003E000;
@@ -776,7 +933,7 @@ uint32_t nxboot_main(void) {
/* Copy the warmboot firmware and set the address in PMC if necessary. */ /* Copy the warmboot firmware and set the address in PMC if necessary. */
if (warmboot_fw && (warmboot_fw_size > 0)) { if (warmboot_fw && (warmboot_fw_size > 0)) {
memcpy(warmboot_memaddr, warmboot_fw, warmboot_fw_size); memcpy(warmboot_memaddr, warmboot_fw, warmboot_fw_size);
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0)
pmc->scratch1 = (uint32_t)warmboot_memaddr; pmc->scratch1 = (uint32_t)warmboot_memaddr;
} }
@@ -796,7 +953,7 @@ uint32_t nxboot_main(void) {
print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT] Reading Exosphère...\n"); print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT] Reading Exosphère...\n");
/* Select the right address for Exosphère. */ /* Select the right address for Exosphère. */
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
exosphere_memaddr = (void *)0x4002D000; exosphere_memaddr = (void *)0x4002D000;
} else { } else {
exosphere_memaddr = (void *)0x4002B000; exosphere_memaddr = (void *)0x4002B000;
@@ -824,7 +981,7 @@ uint32_t nxboot_main(void) {
nxboot_move_bootconfig(); nxboot_move_bootconfig();
/* Set 3.0.0/3.0.1/3.0.2 warmboot security check. */ /* Set 3.0.0/3.0.1/3.0.2 warmboot security check. */
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware == ATMOSPHERE_TARGET_FIRMWARE_300) { if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware == ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
const package1loader_header_t *package1loader_header = (const package1loader_header_t *)package1loader; const package1loader_header_t *package1loader_header = (const package1loader_header_t *)package1loader;
if (!strcmp(package1loader_header->build_timestamp, "20170519101410")) if (!strcmp(package1loader_header->build_timestamp, "20170519101410"))
pmc->secure_scratch32 = 0xE3; /* Warmboot 3.0.0 security check.*/ pmc->secure_scratch32 = 0xE3; /* Warmboot 3.0.0 security check.*/

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef FUSEE_NX_BOOT_H #ifndef FUSEE_NX_BOOT_H
#define FUSEE_NX_BOOT_H #define FUSEE_NX_BOOT_H
@@ -35,7 +35,7 @@ typedef struct {
#define MAILBOX_NX_BOOTLOADER_BASE_100_620 0x40002E00 #define MAILBOX_NX_BOOTLOADER_BASE_100_620 0x40002E00
#define MAILBOX_NX_BOOTLOADER_BASE_700 0x40000000 #define MAILBOX_NX_BOOTLOADER_BASE_700 0x40000000
#define MAILBOX_NX_BOOTLOADER_BASE(targetfw) ((targetfw >= ATMOSPHERE_TARGET_FIRMWARE_700) ? (MAILBOX_NX_BOOTLOADER_BASE_700) : (MAILBOX_NX_BOOTLOADER_BASE_100_620)) #define MAILBOX_NX_BOOTLOADER_BASE(targetfw) ((targetfw >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) ? (MAILBOX_NX_BOOTLOADER_BASE_700) : (MAILBOX_NX_BOOTLOADER_BASE_100_620))
#define MAKE_MAILBOX_NX_BOOTLOADER_REG(targetfw, n) MAKE_REG32(MAILBOX_NX_BOOTLOADER_BASE(targetfw) + n) #define MAKE_MAILBOX_NX_BOOTLOADER_REG(targetfw, n) MAKE_REG32(MAILBOX_NX_BOOTLOADER_BASE(targetfw) + n)
#define MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE(targetfw) (MAILBOX_NX_BOOTLOADER_BASE(targetfw) + 0x10) #define MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE(targetfw) (MAILBOX_NX_BOOTLOADER_BASE(targetfw) + 0x10)

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h> #include <string.h>
#include "cluster.h" #include "cluster.h"
@@ -30,40 +30,40 @@
void nxboot_finish(uint32_t boot_memaddr) { void nxboot_finish(uint32_t boot_memaddr) {
uint32_t target_firmware = MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware; uint32_t target_firmware = MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware;
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
/* Clear used keyslots. */ /* Clear used keyslots. */
clear_aes_keyslot(KEYSLOT_SWITCH_PACKAGE2KEY); clear_aes_keyslot(KEYSLOT_SWITCH_PACKAGE2KEY);
clear_aes_keyslot(KEYSLOT_SWITCH_RNGKEY); clear_aes_keyslot(KEYSLOT_SWITCH_RNGKEY);
/* Lock keyslots. */ /* Lock keyslots. */
set_aes_keyslot_flags(KEYSLOT_SWITCH_MASTERKEY, 0xFF); set_aes_keyslot_flags(KEYSLOT_SWITCH_MASTERKEY, 0xFF);
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF); set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
} else { } else {
set_aes_keyslot_flags(KEYSLOT_SWITCH_4XOLDDEVICEKEY, 0xFF); set_aes_keyslot_flags(KEYSLOT_SWITCH_4XOLDDEVICEKEY, 0xFF);
} }
/* Finalize the GPU UCODE carveout. */ /* Finalize the GPU UCODE carveout. */
/* NOTE: [4.0.0+] This is now done in the Secure Monitor. */ /* NOTE: [4.0.0+] This is now done in the Secure Monitor. */
/* mc_config_carveout_finalize(); */ /* mc_config_carveout_finalize(); */
/* Lock AES keyslots. */ /* Lock AES keyslots. */
for (uint32_t i = 0; i < 16; i++) for (uint32_t i = 0; i < 16; i++)
set_aes_keyslot_flags(i, 0x15); set_aes_keyslot_flags(i, 0x15);
/* Lock RSA keyslots. */ /* Lock RSA keyslots. */
for (uint32_t i = 0; i < 2; i++) for (uint32_t i = 0; i < 2; i++)
set_rsa_keyslot_flags(i, 1); set_rsa_keyslot_flags(i, 1);
/* Lock the Security Engine. */ /* Lock the Security Engine. */
se->SE_TZRAM_SECURITY = 0; se->SE_TZRAM_SECURITY = 0;
se->SE_CRYPTO_SECURITY_PERKEY = 0; se->SE_CRYPTO_SECURITY_PERKEY = 0;
se->SE_RSA_SECURITY_PERKEY = 0; se->SE_RSA_SECURITY_PERKEY = 0;
se->SE_SE_SECURITY &= 0xFFFFFFFB; se->SE_SE_SECURITY &= 0xFFFFFFFB;
/* Boot up Exosphère. */ /* Boot up Exosphère. */
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(target_firmware) = 0; MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(target_firmware) = 0;
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_LOADED_PACKAGE2; MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_LOADED_PACKAGE2;
} else { } else {
MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X; MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X;
@@ -71,30 +71,30 @@ void nxboot_finish(uint32_t boot_memaddr) {
/* Terminate the display. */ /* Terminate the display. */
display_end(); display_end();
/* Check if SMMU emulation has been used. */ /* Check if SMMU emulation has been used. */
uint32_t smmu_magic = *(uint32_t *)(SMMU_AARCH64_PAYLOAD_ADDR + 0xFC); uint32_t smmu_magic = *(uint32_t *)(SMMU_AARCH64_PAYLOAD_ADDR + 0xFC);
if (smmu_magic == 0xDEADC0DE) { if (smmu_magic == 0xDEADC0DE) {
/* Clear the magic. */ /* Clear the magic. */
*(uint32_t *)(SMMU_AARCH64_PAYLOAD_ADDR + 0xFC) = 0; *(uint32_t *)(SMMU_AARCH64_PAYLOAD_ADDR + 0xFC) = 0;
/* Pass the boot address to the already running payload. */ /* Pass the boot address to the already running payload. */
*(uint32_t *)(SMMU_AARCH64_PAYLOAD_ADDR + 0xF0) = boot_memaddr; *(uint32_t *)(SMMU_AARCH64_PAYLOAD_ADDR + 0xF0) = boot_memaddr;
/* Wait a while. */ /* Wait a while. */
mdelay(500); mdelay(500);
} else { } else {
/* Boot CPU0. */ /* Boot CPU0. */
cluster_boot_cpu0(boot_memaddr); cluster_boot_cpu0(boot_memaddr);
} }
/* Wait for Exosphère to wake up. */ /* Wait for Exosphère to wake up. */
while (MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(target_firmware) == 0) { while (MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(target_firmware) == 0) {
udelay(1); udelay(1);
} }
/* Signal Exosphère. */ /* Signal Exosphère. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_FINISHED; MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_FINISHED;
} else { } else {
MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_FINISHED_4X; MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_FINISHED_4X;

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <malloc.h> #include <malloc.h>
@@ -24,8 +24,10 @@
#include "gpt.h" #include "gpt.h"
#include "se.h" #include "se.h"
#include "utils.h" #include "utils.h"
#include "fs_utils.h"
#include "sdmmc/sdmmc.h" #include "sdmmc/sdmmc.h"
#include "lib/log.h"
#include "lib/fatfs/ff.h" #include "lib/fatfs/ff.h"
static bool g_ahb_redirect_enabled = false; static bool g_ahb_redirect_enabled = false;
@@ -59,7 +61,7 @@ SdmmcPartitionNum g_current_emmc_partition = SDMMC_PARTITION_INVALID;
static int mmc_partition_initialize(device_partition_t *devpart) { static int mmc_partition_initialize(device_partition_t *devpart) {
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct; mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
/* Allocate the crypto work buffer. */ /* Allocate the crypto work buffer. */
if ((devpart->read_cipher != NULL) || (devpart->write_cipher != NULL)) { if ((devpart->read_cipher != NULL) || (devpart->write_cipher != NULL)) {
devpart->crypto_work_buffer = memalign(16, devpart->sector_size * 16); devpart->crypto_work_buffer = memalign(16, devpart->sector_size * 16);
@@ -105,7 +107,7 @@ static int mmc_partition_initialize(device_partition_t *devpart) {
static void mmc_partition_finalize(device_partition_t *devpart) { static void mmc_partition_finalize(device_partition_t *devpart) {
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct; mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
/* Finalize hardware. */ /* Finalize hardware. */
if (mmcpart->device == &g_sd_device) { if (mmcpart->device == &g_sd_device) {
if (g_is_emummc) { if (g_is_emummc) {
@@ -123,13 +125,13 @@ static void mmc_partition_finalize(device_partition_t *devpart) {
} }
devpart->initialized = false; devpart->initialized = false;
} }
/* Disable AHB redirection if necessary. */ /* Disable AHB redirection if necessary. */
if (g_ahb_redirect_enabled) { if (g_ahb_redirect_enabled) {
mc_disable_ahb_redirect(); mc_disable_ahb_redirect();
g_ahb_redirect_enabled = false; g_ahb_redirect_enabled = false;
} }
/* Free the crypto work buffer. */ /* Free the crypto work buffer. */
if (devpart->crypto_work_buffer != NULL) { if (devpart->crypto_work_buffer != NULL) {
free(devpart->crypto_work_buffer); free(devpart->crypto_work_buffer);
@@ -138,19 +140,19 @@ static void mmc_partition_finalize(device_partition_t *devpart) {
static int mmc_partition_read(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors) { static int mmc_partition_read(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors) {
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct; mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
if ((mmcpart->device == &g_emmc_device) && (g_current_emmc_partition != mmcpart->partition)) { if ((mmcpart->device == &g_emmc_device) && (g_current_emmc_partition != mmcpart->partition)) {
if (!sdmmc_mmc_select_partition(mmcpart->device, mmcpart->partition)) if (!sdmmc_mmc_select_partition(mmcpart->device, mmcpart->partition))
return EIO; return EIO;
g_current_emmc_partition = mmcpart->partition; g_current_emmc_partition = mmcpart->partition;
} }
return sdmmc_device_read(mmcpart->device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, dst) ? 0 : EIO; return sdmmc_device_read(mmcpart->device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, dst) ? 0 : EIO;
} }
static int mmc_partition_write(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) { static int mmc_partition_write(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) {
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct; mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
if ((mmcpart->device == &g_emmc_device) && (g_current_emmc_partition != mmcpart->partition)) { if ((mmcpart->device == &g_emmc_device) && (g_current_emmc_partition != mmcpart->partition)) {
if (!sdmmc_mmc_select_partition(mmcpart->device, mmcpart->partition)) if (!sdmmc_mmc_select_partition(mmcpart->device, mmcpart->partition))
return EIO; return EIO;
@@ -174,11 +176,11 @@ static int emummc_partition_initialize(device_partition_t *devpart) {
devpart->crypto_work_buffer_num_sectors = 0; devpart->crypto_work_buffer_num_sectors = 0;
} }
devpart->initialized = true; devpart->initialized = true;
return 0; return 0;
} }
static void emummc_partition_finalize(device_partition_t *devpart) { static void emummc_partition_finalize(device_partition_t *devpart) {
/* Free the crypto work buffer. */ /* Free the crypto work buffer. */
if (devpart->crypto_work_buffer != NULL) { if (devpart->crypto_work_buffer != NULL) {
free(devpart->crypto_work_buffer); free(devpart->crypto_work_buffer);
@@ -194,10 +196,10 @@ static int emummc_partition_read(device_partition_t *devpart, void *dst, uint64_
rc = (fread(dst, devpart->sector_size, num_sectors, emummc_file) > 0) ? 0 : -1; rc = (fread(dst, devpart->sector_size, num_sectors, emummc_file) > 0) ? 0 : -1;
fclose(emummc_file); fclose(emummc_file);
return rc; return rc;
} else { } else {
/* Read partition data directly from the SD card device. */ /* Read partition data directly from the SD card device. */
return sdmmc_device_read(&g_sd_device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, dst) ? 0 : EIO; return sdmmc_device_read(&g_sd_device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, dst) ? 0 : EIO;
} }
} }
static int emummc_partition_write(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) { static int emummc_partition_write(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) {
@@ -212,7 +214,7 @@ static int emummc_partition_write(device_partition_t *devpart, const void *src,
} else { } else {
/* Write partition data directly to the SD card device. */ /* Write partition data directly to the SD card device. */
return sdmmc_device_write(&g_sd_device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, (void *)src) ? 0 : EIO; return sdmmc_device_write(&g_sd_device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, (void *)src) ? 0 : EIO;
} }
} }
static int nxfs_bis_crypto_decrypt(device_partition_t *devpart, uint64_t sector, uint64_t num_sectors) { static int nxfs_bis_crypto_decrypt(device_partition_t *devpart, uint64_t sector, uint64_t num_sectors) {
@@ -227,7 +229,7 @@ static int nxfs_bis_crypto_decrypt(device_partition_t *devpart, uint64_t sector,
case DevicePartitionCryptoMode_Xts: case DevicePartitionCryptoMode_Xts:
set_aes_keyslot(keyslot_a, devpart->keys[0], 0x10); set_aes_keyslot(keyslot_a, devpart->keys[0], 0x10);
set_aes_keyslot(keyslot_b, devpart->keys[1], 0x10); set_aes_keyslot(keyslot_b, devpart->keys[1], 0x10);
se_aes_128_xts_nintendo_decrypt(keyslot_a, keyslot_b, sector, devpart->crypto_work_buffer, devpart->crypto_work_buffer, size, devpart->sector_size); se_aes_128_xts_nintendo_decrypt(keyslot_a, keyslot_b, sector, devpart->crypto_work_buffer, devpart->crypto_work_buffer, size, devpart->sector_size, devpart->crypto_sector_size);
return 0; return 0;
case DevicePartitionCryptoMode_None: case DevicePartitionCryptoMode_None:
default: default:
@@ -247,7 +249,7 @@ static int nxfs_bis_crypto_encrypt(device_partition_t *devpart, uint64_t sector,
case DevicePartitionCryptoMode_Xts: case DevicePartitionCryptoMode_Xts:
set_aes_keyslot(keyslot_a, devpart->keys[0], 0x10); set_aes_keyslot(keyslot_a, devpart->keys[0], 0x10);
set_aes_keyslot(keyslot_b, devpart->keys[1], 0x10); set_aes_keyslot(keyslot_b, devpart->keys[1], 0x10);
se_aes_128_xts_nintendo_encrypt(keyslot_a, keyslot_b, sector, devpart->crypto_work_buffer, devpart->crypto_work_buffer, size, devpart->sector_size); se_aes_128_xts_nintendo_encrypt(keyslot_a, keyslot_b, sector, devpart->crypto_work_buffer, devpart->crypto_work_buffer, size, devpart->sector_size, devpart->crypto_sector_size);
return 0; return 0;
case DevicePartitionCryptoMode_None: case DevicePartitionCryptoMode_None:
default: default:
@@ -256,6 +258,7 @@ static int nxfs_bis_crypto_encrypt(device_partition_t *devpart, uint64_t sector,
} }
static const device_partition_t g_mmc_devpart_template = { static const device_partition_t g_mmc_devpart_template = {
.crypto_sector_size = 0x4000,
.sector_size = 512, .sector_size = 512,
.initializer = mmc_partition_initialize, .initializer = mmc_partition_initialize,
.finalizer = mmc_partition_finalize, .finalizer = mmc_partition_finalize,
@@ -264,6 +267,7 @@ static const device_partition_t g_mmc_devpart_template = {
}; };
static const device_partition_t g_emummc_devpart_template = { static const device_partition_t g_emummc_devpart_template = {
.crypto_sector_size = 0x4000,
.sector_size = 512, .sector_size = 512,
.initializer = emummc_partition_initialize, .initializer = emummc_partition_initialize,
.finalizer = emummc_partition_finalize, .finalizer = emummc_partition_finalize,
@@ -378,7 +382,7 @@ static int nxfs_mount_emu_partition_gpt_callback(const efi_entry_t *entry, void
{"BCPKG2-5-Repair-Main", "bcpkg25", false, false, false}, {"BCPKG2-5-Repair-Main", "bcpkg25", false, false, false},
{"BCPKG2-6-Repair-Sub", "bcpkg26", false, false, false}, {"BCPKG2-6-Repair-Sub", "bcpkg26", false, false, false},
{"SAFE", "safe", true, true, false}, {"SAFE", "safe", true, true, false},
{"SYSTEM", "system", true, true, false}, {"SYSTEM", "system", true, true, true},
{"USER", "user", true, true, false}, {"USER", "user", true, true, false},
}; };
@@ -442,26 +446,26 @@ int nxfs_mount_sd() {
model.device_struct = &g_sd_mmcpart; model.device_struct = &g_sd_mmcpart;
model.start_sector = 0; model.start_sector = 0;
model.num_sectors = 1u << 30; /* arbitrary numbers of sectors. TODO: find the size of the SD in sectors. */ model.num_sectors = 1u << 30; /* arbitrary numbers of sectors. TODO: find the size of the SD in sectors. */
/* Mount the SD card device. */ /* Mount the SD card device. */
rc = fsdev_mount_device("sdmc", &model, true); rc = fsdev_mount_device("sdmc", &model, true);
if (rc == -1) { if (rc == -1) {
return -1; return -1;
} }
/* Register the SD card device. */ /* Register the SD card device. */
rc = fsdev_register_device("sdmc"); rc = fsdev_register_device("sdmc");
if (rc == -1) { if (rc == -1) {
return -1; return -1;
} }
/* All fs devices are ready. */ /* All fs devices are ready. */
if (rc == 0) { if (rc == 0) {
g_fsdev_ready = true; g_fsdev_ready = true;
} }
return rc; return rc;
} }
@@ -469,36 +473,36 @@ int nxfs_mount_emmc() {
device_partition_t model; device_partition_t model;
int rc; int rc;
FILE *rawnand; FILE *rawnand;
/* Setup a template for boot0. */ /* Setup a template for boot0. */
model = g_mmc_devpart_template; model = g_mmc_devpart_template;
model.device_struct = &g_emmc_boot0_mmcpart; model.device_struct = &g_emmc_boot0_mmcpart;
model.start_sector = 0; model.start_sector = 0;
model.num_sectors = 0x184000 / model.sector_size; model.num_sectors = 0x184000 / model.sector_size;
/* Mount boot0 device. */ /* Mount boot0 device. */
rc = rawdev_mount_device("boot0", &model, true); rc = rawdev_mount_device("boot0", &model, true);
if (rc == -1) { if (rc == -1) {
return -1; return -1;
} }
/* Register boot0 device. */ /* Register boot0 device. */
rc = rawdev_register_device("boot0"); rc = rawdev_register_device("boot0");
if (rc == -1) { if (rc == -1) {
return -1; return -1;
} }
/* Setup a template for boot1. */ /* Setup a template for boot1. */
model = g_mmc_devpart_template; model = g_mmc_devpart_template;
model.device_struct = &g_emmc_boot1_mmcpart; model.device_struct = &g_emmc_boot1_mmcpart;
model.start_sector = 0; model.start_sector = 0;
model.num_sectors = 0x80000 / model.sector_size; model.num_sectors = 0x80000 / model.sector_size;
/* Mount boot1 device. */ /* Mount boot1 device. */
rc = rawdev_mount_device("boot1", &model, false); rc = rawdev_mount_device("boot1", &model, false);
if (rc == -1) { if (rc == -1) {
return -1; return -1;
} }
@@ -510,38 +514,38 @@ int nxfs_mount_emmc() {
model.device_struct = &g_emmc_user_mmcpart; model.device_struct = &g_emmc_user_mmcpart;
model.start_sector = 0; model.start_sector = 0;
model.num_sectors = (256ull << 30) / model.sector_size; model.num_sectors = (256ull << 30) / model.sector_size;
/* Mount raw NAND device. */ /* Mount raw NAND device. */
rc = rawdev_mount_device("rawnand", &model, false); rc = rawdev_mount_device("rawnand", &model, false);
if (rc == -1) { if (rc == -1) {
return -1; return -1;
} }
/* Register raw NAND device. */ /* Register raw NAND device. */
rc = rawdev_register_device("rawnand"); rc = rawdev_register_device("rawnand");
if (rc == -1) { if (rc == -1) {
return -1; return -1;
} }
/* Open raw NAND device. */ /* Open raw NAND device. */
rawnand = fopen("rawnand:/", "rb"); rawnand = fopen("rawnand:/", "rb");
if (rawnand == NULL) { if (rawnand == NULL) {
return -1; return -1;
} }
/* Iterate the GPT and mount each raw NAND partition. */ /* Iterate the GPT and mount each raw NAND partition. */
rc = gpt_iterate_through_entries(rawnand, model.sector_size, nxfs_mount_partition_gpt_callback, &model); rc = gpt_iterate_through_entries(rawnand, model.sector_size, nxfs_mount_partition_gpt_callback, &model);
/* Close raw NAND device. */ /* Close raw NAND device. */
fclose(rawnand); fclose(rawnand);
/* All raw devices are ready. */ /* All raw devices are ready. */
if (rc == 0) { if (rc == 0) {
g_rawdev_ready = true; g_rawdev_ready = true;
} }
return rc; return rc;
} }
@@ -549,7 +553,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
device_partition_t model; device_partition_t model;
int rc; int rc;
FILE *rawnand; FILE *rawnand;
/* Setup an emulation template for boot0. */ /* Setup an emulation template for boot0. */
model = g_emummc_devpart_template; model = g_emummc_devpart_template;
model.start_sector = emummc_start_sector + (0x400000 * 0 / model.sector_size); model.start_sector = emummc_start_sector + (0x400000 * 0 / model.sector_size);
@@ -558,20 +562,20 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
/* Mount emulated boot0 device. */ /* Mount emulated boot0 device. */
rc = emudev_mount_device("boot0", &model, NULL, 0, 0); rc = emudev_mount_device("boot0", &model, NULL, 0, 0);
/* Failed to mount boot0 device. */ /* Failed to mount boot0 device. */
if (rc == -1) { if (rc == -1) {
return -1; return -1;
} }
/* Register emulated boot0 device. */ /* Register emulated boot0 device. */
rc = emudev_register_device("boot0"); rc = emudev_register_device("boot0");
/* Failed to register boot0 device. */ /* Failed to register boot0 device. */
if (rc == -1) { if (rc == -1) {
return -2; return -2;
} }
/* Setup an emulation template for boot1. */ /* Setup an emulation template for boot1. */
model = g_emummc_devpart_template; model = g_emummc_devpart_template;
model.start_sector = emummc_start_sector + (0x400000 * 1 / model.sector_size); model.start_sector = emummc_start_sector + (0x400000 * 1 / model.sector_size);
@@ -580,7 +584,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
/* Mount emulated boot1 device. */ /* Mount emulated boot1 device. */
rc = emudev_mount_device("boot1", &model, NULL, 0, 0); rc = emudev_mount_device("boot1", &model, NULL, 0, 0);
/* Failed to mount boot1. */ /* Failed to mount boot1. */
if (rc == -1) { if (rc == -1) {
return -3; return -3;
@@ -593,43 +597,43 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
model.start_sector = emummc_start_sector + (0x400000 * 2 / model.sector_size); model.start_sector = emummc_start_sector + (0x400000 * 2 / model.sector_size);
model.num_sectors = (256ull << 30) / model.sector_size; model.num_sectors = (256ull << 30) / model.sector_size;
model.emu_use_file = false; model.emu_use_file = false;
/* Mount emulated raw NAND device. */ /* Mount emulated raw NAND device. */
rc = emudev_mount_device("rawnand", &model, NULL, 0, 0); rc = emudev_mount_device("rawnand", &model, NULL, 0, 0);
/* Failed to mount raw NAND. */ /* Failed to mount raw NAND. */
if (rc == -1) { if (rc == -1) {
return -4; return -4;
} }
/* Register emulated raw NAND device. */ /* Register emulated raw NAND device. */
rc = emudev_register_device("rawnand"); rc = emudev_register_device("rawnand");
/* Failed to register raw NAND device. */ /* Failed to register raw NAND device. */
if (rc == -1) { if (rc == -1) {
return -5; return -5;
} }
/* Open emulated raw NAND device. */ /* Open emulated raw NAND device. */
rawnand = fopen("rawnand:/", "rb"); rawnand = fopen("rawnand:/", "rb");
/* Failed to open emulated raw NAND device. */ /* Failed to open emulated raw NAND device. */
if (rawnand == NULL) { if (rawnand == NULL) {
return -6; return -6;
} }
/* Iterate the GPT and mount each emulated raw NAND partition. */ /* Iterate the GPT and mount each emulated raw NAND partition. */
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, NULL, 0, 0); rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, NULL, 0, 0);
/* Close emulated raw NAND device. */ /* Close emulated raw NAND device. */
fclose(rawnand); fclose(rawnand);
/* All emulated devices are ready. */ /* All emulated devices are ready. */
if (rc == 0) { if (rc == 0) {
g_emudev_ready = true; g_emudev_ready = true;
g_is_emummc = true; g_is_emummc = true;
} }
return rc; return rc;
} }
@@ -640,85 +644,85 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
bool is_exfat; bool is_exfat;
char emummc_boot0_path[0x300 + 1] = {0}; char emummc_boot0_path[0x300 + 1] = {0};
char emummc_boot1_path[0x300 + 1] = {0}; char emummc_boot1_path[0x300 + 1] = {0};
/* Check if the SD card is EXFAT formatted. */ /* Check if the SD card is EXFAT formatted. */
rc = fsdev_is_exfat("sdmc"); rc = fsdev_is_exfat("sdmc");
/* Failed to detect file system type. */ /* Failed to detect file system type. */
if (rc == -1) { if (rc == -1) {
return -1; return -1;
} }
/* Set EXFAT status. */ /* Set EXFAT status. */
is_exfat = (rc == 1); is_exfat = (rc == 1);
/* Reject single part in FAT32. */ /* Reject single part in FAT32. */
/* NOTE: This check has no effect in the current design. */ /* NOTE: This check has no effect in the current design. */
if (!is_exfat && (num_parts < 1)) { if (!is_exfat && (num_parts < 1)) {
return -2; return -2;
} }
/* We want a folder with the archive bit set. */ /* We want a folder with the archive bit set. */
rc = fsdev_get_attr(emummc_path); rc = fsdev_get_attr(emummc_path);
/* Failed to get file DOS attributes. */ /* Failed to get file DOS attributes. */
if (rc == -1) { if (rc == -1) {
return -3; return -3;
} }
/* Our path is not a directory. */ /* Our path is not a directory. */
if (!(rc & AM_DIR)) { if (!(rc & AM_DIR)) {
return -4; return -4;
} }
/* Check if the archive bit is not set. */ /* Check if the archive bit is not set. */
if (!(rc & AM_ARC)) { if (!(rc & AM_ARC)) {
/* Try to set the archive bit. */ /* Try to set the archive bit. */
rc = fsdev_set_attr(emummc_path, AM_ARC, AM_ARC); rc = fsdev_set_attr(emummc_path, AM_ARC, AM_ARC);
/* Failed to set file DOS attributes. */ /* Failed to set file DOS attributes. */
if (rc == -1) { if (rc == -1) {
return -5; return -5;
} }
} }
/* Setup an emulation template for boot0. */ /* Setup an emulation template for boot0. */
model = g_emummc_devpart_template; model = g_emummc_devpart_template;
model.start_sector = 0; model.start_sector = 0;
model.num_sectors = 0x400000 / model.sector_size; model.num_sectors = 0x400000 / model.sector_size;
model.emu_use_file = true; model.emu_use_file = true;
/* Prepare boot0 file path. */ /* Prepare boot0 file path. */
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0"); snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
/* Mount emulated boot0 device. */ /* Mount emulated boot0 device. */
rc = emudev_mount_device("boot0", &model, emummc_boot0_path, 0, 0); rc = emudev_mount_device("boot0", &model, emummc_boot0_path, 0, 0);
/* Failed to mount boot0 device. */ /* Failed to mount boot0 device. */
if (rc == -1) { if (rc == -1) {
return -6; return -6;
} }
/* Register emulated boot0 device. */ /* Register emulated boot0 device. */
rc = emudev_register_device("boot0"); rc = emudev_register_device("boot0");
/* Failed to register boot0 device. */ /* Failed to register boot0 device. */
if (rc == -1) { if (rc == -1) {
return -7; return -7;
} }
/* Setup an emulation template for boot1. */ /* Setup an emulation template for boot1. */
model = g_emummc_devpart_template; model = g_emummc_devpart_template;
model.start_sector = 0; model.start_sector = 0;
model.num_sectors = 0x400000 / model.sector_size; model.num_sectors = 0x400000 / model.sector_size;
model.emu_use_file = true; model.emu_use_file = true;
/* Prepare boot1 file path. */ /* Prepare boot1 file path. */
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1"); snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
/* Mount emulated boot1 device. */ /* Mount emulated boot1 device. */
rc = emudev_mount_device("boot1", &model, emummc_boot1_path, 0, 0); rc = emudev_mount_device("boot1", &model, emummc_boot1_path, 0, 0);
/* Failed to mount boot1. */ /* Failed to mount boot1. */
if (rc == -1) { if (rc == -1) {
return -8; return -8;
@@ -726,7 +730,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
/* Register emulated boot1 device. */ /* Register emulated boot1 device. */
rc = emudev_register_device("boot1"); rc = emudev_register_device("boot1");
/* Failed to register boot1 device. */ /* Failed to register boot1 device. */
if (rc == -1) { if (rc == -1) {
return -9; return -9;
@@ -737,93 +741,93 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
model.start_sector = 0; model.start_sector = 0;
model.num_sectors = (256ull << 30) / model.sector_size; model.num_sectors = (256ull << 30) / model.sector_size;
model.emu_use_file = true; model.emu_use_file = true;
/* Mount emulated raw NAND device from single or multiple parts. */ /* Mount emulated raw NAND device from single or multiple parts. */
rc = emudev_mount_device("rawnand", &model, emummc_path, num_parts, part_limit); rc = emudev_mount_device("rawnand", &model, emummc_path, num_parts, part_limit);
/* Failed to mount raw NAND. */ /* Failed to mount raw NAND. */
if (rc == -1) { if (rc == -1) {
return -10; return -10;
} }
/* Register emulated raw NAND device. */ /* Register emulated raw NAND device. */
rc = emudev_register_device("rawnand"); rc = emudev_register_device("rawnand");
/* Failed to register raw NAND device. */ /* Failed to register raw NAND device. */
if (rc == -1) { if (rc == -1) {
return -11; return -11;
} }
/* Open emulated raw NAND device. */ /* Open emulated raw NAND device. */
rawnand = fopen("rawnand:/", "rb"); rawnand = fopen("rawnand:/", "rb");
/* Failed to open emulated raw NAND device. */ /* Failed to open emulated raw NAND device. */
if (rawnand == NULL) { if (rawnand == NULL) {
return -12; return -12;
} }
/* Iterate the GPT and mount each emulated raw NAND partition. */ /* Iterate the GPT and mount each emulated raw NAND partition. */
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emummc_path, num_parts, part_limit); rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emummc_path, num_parts, part_limit);
/* Close emulated raw NAND device. */ /* Close emulated raw NAND device. */
fclose(rawnand); fclose(rawnand);
/* All emulated devices are ready. */ /* All emulated devices are ready. */
if (rc == 0) { if (rc == 0) {
g_emudev_ready = true; g_emudev_ready = true;
g_is_emummc = true; g_is_emummc = true;
} }
return rc; return rc;
} }
int nxfs_unmount_sd() { int nxfs_unmount_sd() {
int rc = 0; int rc = 0;
/* Unmount all fs devices. */ /* Unmount all fs devices. */
if (g_fsdev_ready) { if (g_fsdev_ready) {
rc = fsdev_unmount_all(); rc = fsdev_unmount_all();
g_fsdev_ready = false; g_fsdev_ready = false;
} }
return rc; return rc;
} }
int nxfs_unmount_emmc() { int nxfs_unmount_emmc() {
int rc = 0; int rc = 0;
/* Unmount all raw devices. */ /* Unmount all raw devices. */
if (g_rawdev_ready) { if (g_rawdev_ready) {
rc = rawdev_unmount_all(); rc = rawdev_unmount_all();
g_rawdev_ready = false; g_rawdev_ready = false;
} }
return rc; return rc;
} }
int nxfs_unmount_emummc() { int nxfs_unmount_emummc() {
int rc = 0; int rc = 0;
/* Unmount all emulated devices. */ /* Unmount all emulated devices. */
if (g_emudev_ready) { if (g_emudev_ready) {
rc = emudev_unmount_all(); rc = emudev_unmount_all();
g_emudev_ready = false; g_emudev_ready = false;
} }
return rc; return rc;
} }
int nxfs_init() { int nxfs_init() {
int rc; int rc;
/* Mount and register the SD card. */ /* Mount and register the SD card. */
rc = nxfs_mount_sd(); rc = nxfs_mount_sd();
/* Set the SD card as the default file system device. */ /* Set the SD card as the default file system device. */
if (rc == 0) { if (rc == 0) {
rc = fsdev_set_default_device("sdmc"); rc = fsdev_set_default_device("sdmc");
} }
return rc; return rc;
} }

View File

@@ -90,13 +90,13 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
package2_patch_kernel(kernel, &kernel_size, is_sd_kernel, (void *)&orig_ini1, target_firmware); package2_patch_kernel(kernel, &kernel_size, is_sd_kernel, (void *)&orig_ini1, target_firmware);
/* Ensure we know where embedded INI is if present, and we don't if not. */ /* 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) || if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_8_0_0 && orig_ini1 != NULL) ||
(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 == NULL)) { (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_0_0 && orig_ini1 == NULL)) {
fatal_error("Error: inappropriate kernel embedded ini context"); fatal_error("Error: inappropriate kernel embedded ini context");
} }
print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilding the INI1 section...\n"); print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilding the INI1 section...\n");
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_8_0_0) {
package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1); package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1);
} else { } else {
/* On 8.0.0, place INI1 right after kernelldr for our sanity. */ /* On 8.0.0, place INI1 right after kernelldr for our sanity. */

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h> #include <string.h>
#include "utils.h" #include "utils.h"
@@ -60,7 +60,7 @@ void se_verify_flags_cleared(void) {
/* Set the flags for an AES keyslot. */ /* Set the flags for an AES keyslot. */
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) { void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) { if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic(); generic_panic();
} }
@@ -79,7 +79,7 @@ void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
/* Set the flags for an RSA keyslot. */ /* Set the flags for an RSA keyslot. */
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) { void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX) { if (keyslot >= KEYSLOT_RSA_MAX) {
generic_panic(); generic_panic();
} }
@@ -98,7 +98,7 @@ void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
void clear_aes_keyslot(unsigned int keyslot) { void clear_aes_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) { if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic(); generic_panic();
} }
@@ -112,7 +112,7 @@ void clear_aes_keyslot(unsigned int keyslot) {
void clear_rsa_keyslot(unsigned int keyslot) { void clear_rsa_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX) { if (keyslot >= KEYSLOT_RSA_MAX) {
generic_panic(); generic_panic();
} }
@@ -132,7 +132,7 @@ void clear_rsa_keyslot(unsigned int keyslot) {
void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) { void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) { if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) {
generic_panic(); generic_panic();
} }
@@ -145,7 +145,7 @@ void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size) { void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) { if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) {
generic_panic(); generic_panic();
} }
@@ -166,7 +166,7 @@ void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_
void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) { void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) { if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) {
generic_panic(); generic_panic();
} }
@@ -179,7 +179,7 @@ void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
void clear_aes_keyslot_iv(unsigned int keyslot) { void clear_aes_keyslot_iv(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) { if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic(); generic_panic();
} }
@@ -198,7 +198,7 @@ void set_se_ctr(const void *ctr) {
void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size) { void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSLOT_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) { if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSLOT_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
generic_panic(); generic_panic();
} }
@@ -235,7 +235,7 @@ void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, co
void se_get_exp_mod_output(void *buf, size_t size) { void se_get_exp_mod_output(void *buf, size_t size) {
size_t num_dwords = (size >> 2); size_t num_dwords = (size >> 2);
if (num_dwords < 1) { if (num_dwords < 1) {
return; return;
} }
@@ -351,7 +351,7 @@ void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src,
void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) { void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) { if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) {
generic_panic(); generic_panic();
} }
@@ -382,7 +382,7 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config_high) { void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config_high) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) { if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
generic_panic(); generic_panic();
} }
@@ -403,7 +403,7 @@ void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_si
void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) { void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) { if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
generic_panic(); generic_panic();
} }
@@ -444,14 +444,24 @@ void aes_128_xts_nintendo_get_tweak(uint8_t *tweak, size_t sector) {
} }
} }
void aes_128_xts_nintendo_xor_with_tweak(unsigned int keyslot, size_t sector, uint8_t *dst, const uint8_t *src, size_t size) { void aes_128_xts_nintendo_xor_with_tweak(unsigned int keyslot, size_t sector, uint8_t *dst, const uint8_t *src, size_t size, size_t crypto_sector_size) {
if ((size & 0xF) || size == 0) { if ((size & 0xF) || size == 0) {
generic_panic(); generic_panic();
} }
unsigned int sector_scale = crypto_sector_size / size;
unsigned int real_sector = sector / sector_scale;
uint8_t tweak[0x10]; uint8_t tweak[0x10];
aes_128_xts_nintendo_get_tweak(tweak, sector); aes_128_xts_nintendo_get_tweak(tweak, real_sector);
se_aes_128_ecb_encrypt_block(keyslot, tweak, sizeof(tweak), tweak, sizeof(tweak)); se_aes_128_ecb_encrypt_block(keyslot, tweak, sizeof(tweak), tweak, sizeof(tweak));
unsigned int num_pre_blocks = ((sector % sector_scale) * size) / 0x10;
for (unsigned int pre = 0; pre < num_pre_blocks; pre++) {
shift_left_xor_rb_le(tweak);
}
for (unsigned int block = 0; block < (size >> 4); block++) { for (unsigned int block = 0; block < (size >> 4); block++) {
for (unsigned int i = 0; i < 0x10; i++) { for (unsigned int i = 0; i < 0x10; i++) {
dst[(block << 4) | i] = src[(block << 4) | i] ^ tweak[i]; dst[(block << 4) | i] = src[(block << 4) | i] ^ tweak[i];
@@ -460,16 +470,16 @@ void aes_128_xts_nintendo_xor_with_tweak(unsigned int keyslot, size_t sector, ui
} }
} }
void aes_128_xts_nintendo_crypt_sector(unsigned int keyslot_1, unsigned int keyslot_2, size_t sector, bool encrypt, void *dst, const void *src, size_t size) { void aes_128_xts_nintendo_crypt_sector(unsigned int keyslot_1, unsigned int keyslot_2, size_t sector, bool encrypt, void *dst, const void *src, size_t size, size_t crypto_sector_size) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if ((size & 0xF) || size == 0) { if ((size & 0xF) || size == 0 || crypto_sector_size < size || (crypto_sector_size % size) != 0) {
generic_panic(); generic_panic();
} }
/* XOR. */ /* XOR. */
aes_128_xts_nintendo_xor_with_tweak(keyslot_2, sector, dst, src, size); aes_128_xts_nintendo_xor_with_tweak(keyslot_2, sector, dst, src, size, crypto_sector_size);
/* Encrypt/Decrypt. */ /* Encrypt/Decrypt. */
if (encrypt) { if (encrypt) {
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY); se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY);
@@ -480,38 +490,39 @@ void aes_128_xts_nintendo_crypt_sector(unsigned int keyslot_1, unsigned int keys
} }
se->SE_CRYPTO_LAST_BLOCK = (size >> 4) - 1; se->SE_CRYPTO_LAST_BLOCK = (size >> 4) - 1;
trigger_se_blocking_op(OP_START, dst, size, src, size); trigger_se_blocking_op(OP_START, dst, size, src, size);
/* XOR. */ /* XOR. */
aes_128_xts_nintendo_xor_with_tweak(keyslot_2, sector, dst, dst, size); aes_128_xts_nintendo_xor_with_tweak(keyslot_2, sector, dst, dst, size, crypto_sector_size);
} }
/* Encrypt with AES-XTS (Nintendo's custom tweak). */ /* Encrypt with AES-XTS (Nintendo's custom tweak). */
void se_aes_128_xts_nintendo_encrypt(unsigned int keyslot_1, unsigned int keyslot_2, size_t base_sector, void *dst, const void *src, size_t size, unsigned int sector_size) { void se_aes_128_xts_nintendo_encrypt(unsigned int keyslot_1, unsigned int keyslot_2, size_t base_sector, void *dst, const void *src, size_t size, unsigned int sector_size, unsigned int crypto_sector_size) {
if ((size & 0xF) || size == 0) { if ((size & 0xF) || size == 0 || crypto_sector_size < sector_size || (crypto_sector_size % sector_size) != 0) {
generic_panic(); generic_panic();
} }
size_t sector = base_sector; size_t sector = base_sector;
for (size_t ofs = 0; ofs < size; ofs += sector_size) { for (size_t ofs = 0; ofs < size; ofs += sector_size) {
aes_128_xts_nintendo_crypt_sector(keyslot_1, keyslot_2, sector, true, dst + ofs, src + ofs, sector_size); aes_128_xts_nintendo_crypt_sector(keyslot_1, keyslot_2, sector, true, dst + ofs, src + ofs, sector_size, crypto_sector_size);
sector++; sector++;
} }
} }
/* Decrypt with AES-XTS (Nintendo's custom tweak). */ /* Decrypt with AES-XTS (Nintendo's custom tweak). */
void se_aes_128_xts_nintendo_decrypt(unsigned int keyslot_1, unsigned int keyslot_2, size_t base_sector, void *dst, const void *src, size_t size, unsigned int sector_size) { void se_aes_128_xts_nintendo_decrypt(unsigned int keyslot_1, unsigned int keyslot_2, size_t base_sector, void *dst, const void *src, size_t size, unsigned int sector_size, unsigned int crypto_sector_size) {
if ((size & 0xF) || size == 0) { if ((size & 0xF) || size == 0 || crypto_sector_size < sector_size || (crypto_sector_size % sector_size) != 0) {
generic_panic(); generic_panic();
} }
size_t sector = base_sector; size_t sector = base_sector;
for (size_t ofs = 0; ofs < size; ofs += sector_size) { for (size_t ofs = 0; ofs < size; ofs += sector_size) {
aes_128_xts_nintendo_crypt_sector(keyslot_1, keyslot_2, sector, false, dst + ofs, src + ofs, sector_size); aes_128_xts_nintendo_crypt_sector(keyslot_1, keyslot_2, sector, false, dst + ofs, src + ofs, sector_size, crypto_sector_size);
sector++; sector++;
} }
} }
void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size, unsigned int config_high) { void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size, unsigned int config_high) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) { if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic(); generic_panic();
} }
@@ -568,7 +579,7 @@ void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size,
void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv) { void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) { if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
generic_panic(); generic_panic();
} }
@@ -583,7 +594,7 @@ void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, co
/* SHA256 Implementation. */ /* SHA256 Implementation. */
void se_calculate_sha256(void *dst, const void *src, size_t src_size) { void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
/* Setup config for SHA256, size = BITS(src_size) */ /* Setup config for SHA256, size = BITS(src_size) */
se->SE_CONFIG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG); se->SE_CONFIG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
se->SE_SHA_CONFIG = 1; se->SE_SHA_CONFIG = 1;
@@ -608,7 +619,7 @@ void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
/* RNG API */ /* RNG API */
void se_initialize_rng(unsigned int keyslot) { void se_initialize_rng(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) { if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic(); generic_panic();
} }
@@ -628,7 +639,7 @@ void se_initialize_rng(unsigned int keyslot) {
void se_generate_random(unsigned int keyslot, void *dst, size_t size) { void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) { if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic(); generic_panic();
} }

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef FUSEE_SE_H #ifndef FUSEE_SE_H
#define FUSEE_SE_H #define FUSEE_SE_H
@@ -182,8 +182,8 @@ void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size);
void set_se_ctr(const void *ctr); void set_se_ctr(const void *ctr);
/* Secure AES API */ /* Secure AES API */
void se_aes_128_xts_nintendo_decrypt(unsigned int keyslot_1, unsigned int keyslot_2, unsigned int base_sector, void *dst, const void *src, size_t size, unsigned int sector_size); void se_aes_128_xts_nintendo_decrypt(unsigned int keyslot_1, unsigned int keyslot_2, unsigned int base_sector, void *dst, const void *src, size_t size, unsigned int sector_size, unsigned int crypto_sector_size);
void se_aes_128_xts_nintendo_encrypt(unsigned int keyslot_1, unsigned int keyslot_2, unsigned int base_sector, void *dst, const void *src, size_t size, unsigned int sector_size); void se_aes_128_xts_nintendo_encrypt(unsigned int keyslot_1, unsigned int keyslot_2, unsigned int base_sector, void *dst, const void *src, size_t size, unsigned int sector_size, unsigned int crypto_sector_size);
void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size); void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size);
void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size); void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size);
void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);

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