Compare commits
89 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bc0250cea | ||
|
|
524da78b0e | ||
|
|
7458879555 | ||
|
|
1d40a08ef9 | ||
|
|
be07035954 | ||
|
|
b7c4dae899 | ||
|
|
94d0d06660 | ||
|
|
2e4e59dbda | ||
|
|
0fb528836c | ||
|
|
4a01ae8b9d | ||
|
|
5bec9395b1 | ||
|
|
3bc2d79384 | ||
|
|
6ac1ff6f24 | ||
|
|
93e0c9194d | ||
|
|
6ad0f0e7f2 | ||
|
|
4f50f57bb7 | ||
|
|
97cba5e881 | ||
|
|
6eb77e69c4 | ||
|
|
90d754f920 | ||
|
|
b39b6f0d5b | ||
|
|
dcfb3bc9b5 | ||
|
|
b4d003b4b9 | ||
|
|
bc1d3ccc91 | ||
|
|
152a945561 | ||
|
|
3da0cda4ae | ||
|
|
d77fe98203 | ||
|
|
94ec9ae41b | ||
|
|
332dbdd497 | ||
|
|
98cc051387 | ||
|
|
f2944d36ba | ||
|
|
46d79387e8 | ||
|
|
0bb2c0a04f | ||
|
|
eca2b453ae | ||
|
|
e14dc18bd3 | ||
|
|
c7743c6098 | ||
|
|
d81a3bdc36 | ||
|
|
32e5283ac2 | ||
|
|
1d9a4f47fd | ||
|
|
3f5f9b60ea | ||
|
|
08e1b4d116 | ||
|
|
683580861f | ||
|
|
7d30460214 | ||
|
|
d7ba3291ed | ||
|
|
c07f54f370 | ||
|
|
6fe8ada37a | ||
|
|
94b10b5779 | ||
|
|
9b677c81a5 | ||
|
|
a25be61e94 | ||
|
|
116e00c21c | ||
|
|
122b0775f1 | ||
|
|
11f840b1e3 | ||
|
|
36039ddbb7 | ||
|
|
5347f0d583 | ||
|
|
408dde533f | ||
|
|
b15b46a68e | ||
|
|
ba6f298618 | ||
|
|
c6424921a6 | ||
|
|
8547802904 | ||
|
|
353e27b9e2 | ||
|
|
4a38a36036 | ||
|
|
200d2df785 | ||
|
|
73552c86c3 | ||
|
|
dd80e1f463 | ||
|
|
15c929a0e4 | ||
|
|
aa4c79cd9c | ||
|
|
6719abec65 | ||
|
|
79b9e07ee9 | ||
|
|
eca5ac01b8 | ||
|
|
50ea19e7a2 | ||
|
|
823a1f3ea3 | ||
|
|
b73895df0a | ||
|
|
5062329979 | ||
|
|
065485b971 | ||
|
|
6193283f03 | ||
|
|
eb48e7cc59 | ||
|
|
d98490d339 | ||
|
|
b2e86f5a1b | ||
|
|
0e9974e7b3 | ||
|
|
496be5ecd4 | ||
|
|
50a91b1d6e | ||
|
|
f872be67eb | ||
|
|
e04679f05a | ||
|
|
8d1ada2a1b | ||
|
|
a50d6a2696 | ||
|
|
76d72fa946 | ||
|
|
8b19fdfd51 | ||
|
|
612d846132 | ||
|
|
816ce605d3 | ||
|
|
07c95662b1 |
6
Makefile
6
Makefile
@@ -58,10 +58,12 @@ dist-no-debug: all
|
||||
mkdir atmosphere-$(AMSVER)/switch
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000008
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000000D
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000002B
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000003C
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/config_templates
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/config
|
||||
@@ -82,10 +84,12 @@ dist-no-debug: all
|
||||
cp -r config_templates/hbl_html atmosphere-$(AMSVER)/atmosphere/hbl_html
|
||||
cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000008/exefs.nsp
|
||||
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/atmosphere/contents/010000000000000D/exefs.nsp
|
||||
cp stratosphere/erpt/erpt.nsp atmosphere-$(AMSVER)/atmosphere/contents/010000000000002B/exefs.nsp
|
||||
cp stratosphere/eclct.stub/eclct.stub.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/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/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
|
||||
touch atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/flags/boot2.flag
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/flags
|
||||
@@ -133,6 +137,8 @@ dist: dist-no-debug
|
||||
cp stratosphere/ro/ro.elf atmosphere-$(AMSVER)-debug/ro.elf
|
||||
cp stratosphere/sm/sm.elf atmosphere-$(AMSVER)-debug/sm.elf
|
||||
cp stratosphere/spl/spl.elf atmosphere-$(AMSVER)-debug/spl.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 ../;
|
||||
rm -r atmosphere-$(AMSVER)-debug
|
||||
mv atmosphere-$(AMSVER)-debug.zip out/atmosphere-$(AMSVER)-debug.zip
|
||||
|
||||
@@ -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).
|
||||
|
||||
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.
|
||||
|
||||
Credits
|
||||
|
||||
@@ -5,16 +5,6 @@ stage2_mtc_path = atmosphere/fusee-mtc.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
|
||||
; 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]
|
||||
; To force-enable nogc, add nogc = 1
|
||||
; To force-disable nogc, add nogc = 0
|
||||
|
||||
45
config_templates/exosphere.ini
Normal file
45
config_templates/exosphere.ini
Normal 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
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
# Building Atmosphère
|
||||
The process for building Atmosphère is similar to building Fusée Gelée payloads and other Switch apps.
|
||||
|
||||
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
|
||||
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 switch-libjpeg-turbo devkitARM devkitarm-rules
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -1,4 +1,82 @@
|
||||
# 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
|
||||
+ 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.
|
||||
+ However, exosphere did not set cpuactlr_el1. This meant that the register held the reset value going into boot.
|
||||
+ 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.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 0.11.0
|
||||
+ Support was added for 10.0.0.
|
||||
+ Exosphere has been updated to reflect the new key import semantics in 10.0.0.
|
||||
+ kernel_ldr now implements physical ASLR for the kernel's backing pages.
|
||||
+ Loader, NCM, and PM have been updated to reflect the changes Nintendo made in 10.0.0.
|
||||
+ Creport was updated to use the new `pgl` service to terminate processes instead of `ns:dev`.
|
||||
+ A reimplementation of the `erpt` (error reports) system module was added.
|
||||
+ In previous versions of Atmosphere, a majority of error reports were prevented via a combination of custom creport, fatal, and stubbed eclct.
|
||||
+ However, error reports were still generated via some system actions.
|
||||
+ Most notably, any time the error applet appeared, an error report was generated.
|
||||
+ By default, atmosphere disabled the *uploading* of error reports, but going online in OFW after an error report occurred in Atmosphere could lead to undesirable telemetry.
|
||||
+ Atmosphere's `erpt` reimplementation allows the system to interact with existing error reports as expected.
|
||||
+ However, all new error reports are instead saved to the sd card (`/atmosphere/erpt_reports`), and are not committed to the system savegame.
|
||||
+ Users curious about what kind of telemetry is being prevented can view the reports as they're generated in there.
|
||||
+ Reports are saved as msgpack (as this is what Nintendo uses).
|
||||
+ Please note, not all telemetry is disabled. Play reports and System reports will continue to function unmodified.
|
||||
+ With atmosphere's `erpt` implementation, homebrew can now use the native error applet to display errors without worrying about generating undesirable telemetry.
|
||||
+ libstratosphere and libvapours received a number of improvements.
|
||||
+ With thanks to @Adubbz for his work, the NCM namespace now has client code.
|
||||
+ This lays the groundwork for first-class system update/downgrade homebrew support in the near future.
|
||||
+ 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.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 0.10.5
|
||||
+ 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.
|
||||
|
||||
21
docs/licensing_exemptions/MIT_LICENSE
Normal file
21
docs/licensing_exemptions/MIT_LICENSE
Normal 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.
|
||||
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/m4xw/emuMMC
|
||||
branch = develop
|
||||
commit = d12dd5464422029a1e5601916517ec3f1c81d8d0
|
||||
parent = 259a1a7513236a1de4d373bc6cb99032ede2c626
|
||||
commit = b168ddf5fbb31013ff529a4859110c82b11eb361
|
||||
parent = c07f54f3709a4710e0aead6c91139fa0893b5e5c
|
||||
method = rebase
|
||||
cmdver = 0.4.1
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
|
||||
|
||||
### Supported Horizon Versions
|
||||
**1.0.0 - 9.1.0**
|
||||
**1.0.0 - 10.0.0**
|
||||
|
||||
## Features
|
||||
* Arbitrary SDMMC backend selection
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
#include "offsets/900_exfat.h"
|
||||
#include "offsets/910.h"
|
||||
#include "offsets/910_exfat.h"
|
||||
#include "offsets/1000.h"
|
||||
#include "offsets/1000_exfat.h"
|
||||
#include "../utils/fatal.h"
|
||||
|
||||
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
||||
@@ -100,6 +102,8 @@ DEFINE_OFFSET_STRUCT(_900);
|
||||
DEFINE_OFFSET_STRUCT(_900_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_910);
|
||||
DEFINE_OFFSET_STRUCT(_910_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_1000);
|
||||
DEFINE_OFFSET_STRUCT(_1000_EXFAT);
|
||||
|
||||
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
switch (version) {
|
||||
@@ -161,6 +165,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
return &(GET_OFFSET_STRUCT_NAME(_910));
|
||||
case FS_VER_9_1_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_910_EXFAT));
|
||||
case FS_VER_10_0_0:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1000));
|
||||
case FS_VER_10_0_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1000_EXFAT));
|
||||
default:
|
||||
fatal_abort(Fatal_UnknownVersion);
|
||||
}
|
||||
|
||||
@@ -65,6 +65,9 @@ enum FS_VER
|
||||
FS_VER_9_1_0,
|
||||
FS_VER_9_1_0_EXFAT,
|
||||
|
||||
FS_VER_10_0_0,
|
||||
FS_VER_10_0_0_EXFAT,
|
||||
|
||||
FS_VER_MAX,
|
||||
};
|
||||
|
||||
|
||||
58
emummc/source/FS/offsets/1000.h
Normal file
58
emummc/source/FS/offsets/1000.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||
* Copyright (c) 2019 Atmosphere-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __FS_1000_H__
|
||||
#define __FS_1000_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_1000_SDMMC_ACCESSOR_GC 0x14DC90
|
||||
#define FS_OFFSET_1000_SDMMC_ACCESSOR_SD 0x14BDA0
|
||||
#define FS_OFFSET_1000_SDMMC_ACCESSOR_NAND 0x146C20
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_1000_SDMMC_WRAPPER_READ 0x142380
|
||||
#define FS_OFFSET_1000_SDMMC_WRAPPER_WRITE 0x142460
|
||||
#define FS_OFFSET_1000_RTLD 0x634
|
||||
#define FS_OFFSET_1000_RTLD_DESTINATION 0x9C
|
||||
|
||||
#define FS_OFFSET_1000_CLKRST_SET_MIN_V_CLK_RATE 0x1415A0
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_1000_LOCK_MUTEX 0x28910
|
||||
#define FS_OFFSET_1000_UNLOCK_MUTEX 0x28960
|
||||
|
||||
#define FS_OFFSET_1000_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1422E0
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_1000_SD_MUTEX 0xE273E8
|
||||
#define FS_OFFSET_1000_NAND_MUTEX 0xE22DA0
|
||||
#define FS_OFFSET_1000_ACTIVE_PARTITION 0xE22DE0
|
||||
#define FS_OFFSET_1000_SDMMC_DAS_HANDLE 0xE0AB90
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_1000_SD_DAS_INIT 0x151CEC
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_1000_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0006BBA4, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00078520, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007ED0C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0009115C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_1000_H__
|
||||
58
emummc/source/FS/offsets/1000_exfat.h
Normal file
58
emummc/source/FS/offsets/1000_exfat.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||
* Copyright (c) 2019 Atmosphere-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __FS_1000_EXFAT_H__
|
||||
#define __FS_1000_EXFAT_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_1000_EXFAT_SDMMC_ACCESSOR_GC 0x14DC90
|
||||
#define FS_OFFSET_1000_EXFAT_SDMMC_ACCESSOR_SD 0x14BDA0
|
||||
#define FS_OFFSET_1000_EXFAT_SDMMC_ACCESSOR_NAND 0x146C20
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_1000_EXFAT_SDMMC_WRAPPER_READ 0x142380
|
||||
#define FS_OFFSET_1000_EXFAT_SDMMC_WRAPPER_WRITE 0x142460
|
||||
#define FS_OFFSET_1000_EXFAT_RTLD 0x634
|
||||
#define FS_OFFSET_1000_EXFAT_RTLD_DESTINATION 0x9C
|
||||
|
||||
#define FS_OFFSET_1000_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1415A0
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_1000_EXFAT_LOCK_MUTEX 0x28910
|
||||
#define FS_OFFSET_1000_EXFAT_UNLOCK_MUTEX 0x28960
|
||||
|
||||
#define FS_OFFSET_1000_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1422E0
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_1000_EXFAT_SD_MUTEX 0xE353E8
|
||||
#define FS_OFFSET_1000_EXFAT_NAND_MUTEX 0xE30DA0
|
||||
#define FS_OFFSET_1000_EXFAT_ACTIVE_PARTITION 0xE30DE0
|
||||
#define FS_OFFSET_1000_EXFAT_SDMMC_DAS_HANDLE 0xE18B90
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_1000_EXFAT_SD_DAS_INIT 0x151CEC
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_1000_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0006BBA4, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00078520, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007ED0C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0009115C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_1000_EXFAT_H__
|
||||
@@ -36,7 +36,6 @@ sdmmc_storage_t sd_storage;
|
||||
|
||||
// init vars
|
||||
bool custom_driver = true;
|
||||
extern const volatile emuMMC_ctx_t emuMMC_ctx;
|
||||
|
||||
// FS funcs
|
||||
_sdmmc_accessor_gc sdmmc_accessor_gc;
|
||||
@@ -344,7 +343,7 @@ uint64_t sdmmc_wrapper_controller_close(int mmc_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (mmc_id == FS_SDMMC_EMMC)
|
||||
{
|
||||
// Close file handles and unmount
|
||||
|
||||
@@ -50,8 +50,18 @@ extern "C" {
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x55.
|
||||
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
|
||||
* @warning Only exists on [10.0.0+]. For older versions use \ref svcLegacyQueryIoMapping.
|
||||
*/
|
||||
Result svcQueryIoMapping(u64* virtaddr, u64 physaddr, u64 size);
|
||||
Result svcQueryIoMapping(u64* virtaddr, u64* out_size, u64 physaddr, u64 size);
|
||||
|
||||
/**
|
||||
* @brief Returns a virtual address mapped to a given IO range.
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x55.
|
||||
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
|
||||
* @warning Only exists on [1.0.0-9.2.0]. For newer versions use \ref svcQueryIoMapping.
|
||||
*/
|
||||
Result svcLegacyQueryIoMapping(u64* virtaddr, u64 physaddr, u64 size);
|
||||
|
||||
/**
|
||||
* @brief Attaches a device address space to a device.
|
||||
|
||||
@@ -17,6 +17,15 @@
|
||||
.endm
|
||||
|
||||
SVC_BEGIN svcQueryIoMapping
|
||||
STP X0, X1, [SP, #-16]!
|
||||
SVC 0x55
|
||||
LDP X3, X4, [SP], #16
|
||||
STR X1, [X3]
|
||||
STR X2, [X4]
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcLegacyQueryIoMapping
|
||||
STR X0, [SP, #-16]!
|
||||
SVC 0x55
|
||||
LDR X2, [SP], #16
|
||||
|
||||
@@ -25,11 +25,12 @@ enum FatalReason
|
||||
Fatal_InvalidAccessor,
|
||||
Fatal_ReadNoAccessor,
|
||||
Fatal_WriteNoAccessor,
|
||||
Fatal_IoMapping,
|
||||
Fatal_IoMappingLegacy,
|
||||
Fatal_UnknownVersion,
|
||||
Fatal_BadResult,
|
||||
Fatal_GetConfig,
|
||||
Fatal_CloseAccessor,
|
||||
Fatal_IoMapping,
|
||||
Fatal_Max
|
||||
};
|
||||
|
||||
|
||||
@@ -38,8 +38,15 @@ static inline uintptr_t _GetIoMapping(u64 io_addr, u64 io_size)
|
||||
u64 vaddr;
|
||||
u64 aligned_addr = (io_addr & ~0xFFFul);
|
||||
u64 aligned_size = io_size + (io_addr - aligned_addr);
|
||||
if (svcQueryIoMapping(&vaddr, aligned_addr, aligned_size) != 0) {
|
||||
fatal_abort(Fatal_IoMapping);
|
||||
if (emuMMC_ctx.fs_ver >= FS_VER_10_0_0) {
|
||||
u64 out_size;
|
||||
if (svcQueryIoMapping(&vaddr, &out_size, aligned_addr, aligned_size) != 0) {
|
||||
fatal_abort(Fatal_IoMapping);
|
||||
}
|
||||
} else {
|
||||
if (svcLegacyQueryIoMapping(&vaddr, aligned_addr, aligned_size) != 0) {
|
||||
fatal_abort(Fatal_IoMappingLegacy);
|
||||
}
|
||||
}
|
||||
return (uintptr_t)(vaddr + (io_addr - aligned_addr));
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define _UTIL_H_
|
||||
|
||||
#include "types.h"
|
||||
#include "../emuMMC/emummc_ctx.h"
|
||||
|
||||
intptr_t QueryIoMapping(u64 addr, u64 size);
|
||||
#define byte_swap_32(num) ((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
|
||||
@@ -37,4 +38,6 @@ void usleep(u64 ticks);
|
||||
void msleep(u64 milliseconds);
|
||||
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
|
||||
|
||||
extern volatile emuMMC_ctx_t emuMMC_ctx;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -290,7 +290,15 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
|
||||
break;
|
||||
case CONFIGITEM_HAS_RCM_BUG_PATCH:
|
||||
/* 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;
|
||||
default:
|
||||
result = 2;
|
||||
|
||||
@@ -45,6 +45,8 @@ typedef enum {
|
||||
CONFIGITEM_NEEDS_SHUTDOWN = 65002,
|
||||
CONFIGITEM_EXOSPHERE_VERHASH = 65003,
|
||||
CONFIGITEM_HAS_RCM_BUG_PATCH = 65004,
|
||||
CONFIGITEM_SHOULD_BLANK_PRODINFO = 65005,
|
||||
CONFIGITEM_ALLOW_CAL_WRITES = 65006,
|
||||
} ConfigItem;
|
||||
|
||||
#define REBOOT_KIND_NO_REBOOT 0
|
||||
|
||||
@@ -27,6 +27,9 @@ static bool g_has_loaded_config = false;
|
||||
|
||||
#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. */
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!g_has_loaded_config) {
|
||||
generic_panic();
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
|
||||
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
|
||||
#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)
|
||||
|
||||
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_disable_usermode_exception_handlers(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);
|
||||
|
||||
|
||||
@@ -263,19 +263,20 @@ uint32_t fuse_get_5x_key_generation(void) {
|
||||
/* Returns the fuse version expected for the firmware. */
|
||||
uint32_t fuse_get_expected_fuse_version(uint32_t target_firmware) {
|
||||
static const uint8_t expected_versions[ATMOSPHERE_TARGET_FIRMWARE_COUNT+1] = {
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_100] = 1,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_200] = 2,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_300] = 3,
|
||||
/* [ATMOSPHERE_TARGET_FIRMWARE_302] = 4, */
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_400] = 5,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_500] = 6,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_600] = 7,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_620] = 8,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_700] = 9,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_800] = 9,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_810] = 10,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_900] = 11,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_910] = 12,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_100] = 1,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_200] = 2,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_300] = 3,
|
||||
/* [ATMOSPHERE_TARGET_FIRMWARE_302] = 4, */
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_400] = 5,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_500] = 6,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_600] = 7,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_620] = 8,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_700] = 9,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_800] = 9,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_810] = 10,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_900] = 11,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_910] = 12,
|
||||
[ATMOSPHERE_TARGET_FIRMWARE_1000] = 13,
|
||||
};
|
||||
|
||||
if (target_firmware > ATMOSPHERE_TARGET_FIRMWARE_COUNT) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.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) */
|
||||
se_aes_128_ecb_encrypt_block(KEYSLOT_SWITCH_TEMPKEY, h, 0x10, x, 0x10);
|
||||
|
||||
|
||||
size_t total_size = data_size;
|
||||
|
||||
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) {
|
||||
gf128_mul(x, x, h);
|
||||
}
|
||||
|
||||
|
||||
uint64_t xor_size = total_size << 3;
|
||||
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 {
|
||||
p_x[1] ^= xor_size;
|
||||
}
|
||||
|
||||
|
||||
gf128_mul(x, x, h);
|
||||
|
||||
|
||||
/* If final output block, XOR with encrypted J block. */
|
||||
if (encrypt) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t intermediate_buf[0x400] = {0};
|
||||
|
||||
|
||||
/* Unwrap the key */
|
||||
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 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);
|
||||
|
||||
|
||||
if (!is_personalized) {
|
||||
/* Devkit non-personalized keys have no further authentication. */
|
||||
memcpy(dst, intermediate_buf, src_size - 0x10);
|
||||
memset(intermediate_buf, 0, sizeof(intermediate_buf));
|
||||
return src_size - 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
/* J = GHASH(CTR); */
|
||||
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. */
|
||||
uint8_t calc_mac[0x10];
|
||||
ghash(calc_mac, intermediate_buf, src_size - 0x20, j_block, true);
|
||||
|
||||
|
||||
/* Const-time memcmp. */
|
||||
const uint8_t *src_bytes = src;
|
||||
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) {
|
||||
*out_deviceid_high = intermediate_buf[src_size - 0x28];
|
||||
}
|
||||
|
||||
|
||||
memcpy(dst, intermediate_buf, src_size - 0x30);
|
||||
memset(intermediate_buf, 0, sizeof(intermediate_buf));
|
||||
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);
|
||||
flush_dcache_range(intermediate_buf, intermediate_buf + 0x10);
|
||||
|
||||
/* Copy in the src. */
|
||||
memcpy(intermediate_buf + 0x10, src, src_size);
|
||||
|
||||
/* Write Device ID. */
|
||||
write64be(intermediate_buf, src_size + 0x18, fuse_get_device_id() | (deviceid_high << 56));
|
||||
|
||||
|
||||
/* J = GHASH(CTR); */
|
||||
uint8_t j_block[0x10];
|
||||
ghash(j_block, intermediate_buf, 0x10, NULL, false);
|
||||
|
||||
32
exosphere/src/mc0.h
Normal file
32
exosphere/src/mc0.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EXOSPHERE_MC0_H
|
||||
#define EXOSPHERE_MC0_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "memory_map.h"
|
||||
|
||||
/* Exosphere driver for the Tegra X1 MC0. */
|
||||
|
||||
static inline uintptr_t get_mc0_base(void) {
|
||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC0);
|
||||
}
|
||||
|
||||
#define MC0_BASE (get_mc0_base())
|
||||
#define MAKE_MC0_REG(n) MAKE_REG32(MC0_BASE + n)
|
||||
|
||||
#endif
|
||||
32
exosphere/src/mc1.h
Normal file
32
exosphere/src/mc1.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EXOSPHERE_MC0_H
|
||||
#define EXOSPHERE_MC0_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "memory_map.h"
|
||||
|
||||
/* Exosphere driver for the Tegra X1 MC1. */
|
||||
|
||||
static inline uintptr_t get_mc1_base(void) {
|
||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC1);
|
||||
}
|
||||
|
||||
#define MC1_BASE (get_mc1_base())
|
||||
#define MAKE_MC1_REG(n) MAKE_REG32(MC1_BASE + n)
|
||||
|
||||
#endif
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef EXOSPHERE_MEMORY_MAP_H
|
||||
#define EXOSPHERE_MEMORY_MAP_H
|
||||
|
||||
@@ -48,9 +48,11 @@
|
||||
#define _MMAPDEV15 ( 0x6000D000ull, 0x1000ull, true ) /* GPIO-1 - GPIO-8 */
|
||||
#define _MMAPDEV16 ( 0x7000C000ull, 0x1000ull, true ) /* I2C-I2C4 */
|
||||
#define _MMAPDEV17 ( 0x6000F000ull, 0x1000ull, true ) /* Exception vectors */
|
||||
#define _MMAPDEV18 ( 0x00000000ull, 0x1000ull, true ) /* AMS irampage, NOT mapped at startup */
|
||||
#define _MMAPDEV19 ( 0x00000000ull, 0x1000ull, true ) /* AMS userpage, NOT mapped at startup */
|
||||
#define _MMAPDEV20 ( 0x40038000ull, 0x5000ull, true ) /* DEBUG: IRAM */
|
||||
#define _MMAPDEV18 ( 0x7001C000ull, 0x1000ull, true ) /* MC0 */
|
||||
#define _MMAPDEV19 ( 0x7001D000ull, 0x1000ull, true ) /* MC1 */
|
||||
#define _MMAPDEV20 ( 0x00000000ull, 0x1000ull, true ) /* AMS irampage, NOT mapped at startup */
|
||||
#define _MMAPDEV21 ( 0x00000000ull, 0x1000ull, true ) /* AMS userpage, NOT mapped at startup */
|
||||
#define _MMAPDEV22 ( 0x40038000ull, 0x1000ull, true ) /* DEBUG: IRAM */
|
||||
|
||||
/* MMIO 7.0.0+. (addr). */
|
||||
#define _MMAPDEV7X0 ( 0x50041000ull ) /* ARM Interrupt Distributor */
|
||||
@@ -71,9 +73,11 @@
|
||||
#define _MMAPDEV7X15 ( 0x6000D000ull ) /* GPIO-1 - GPIO-8 */
|
||||
#define _MMAPDEV7X16 ( 0x7000C000ull ) /* I2C-I2C4 */
|
||||
#define _MMAPDEV7X17 ( 0x6000F000ull ) /* Exception vectors */
|
||||
#define _MMAPDEV7X18 ( 0x00000000ull ) /* AMS irampage, NOT mapped at startup */
|
||||
#define _MMAPDEV7X19 ( 0x00000000ull ) /* AMS userpage, NOT mapped at startup */
|
||||
#define _MMAPDEV7X20 ( 0x40038000ull ) /* DEBUG: IRAM */
|
||||
#define _MMAPDEV7X18 ( 0x7001C000ull ) /* MC0 */
|
||||
#define _MMAPDEV7X19 ( 0x7001D000ull ) /* MC1 */
|
||||
#define _MMAPDEV7X20 ( 0x00000000ull ) /* AMS irampage, NOT mapped at startup */
|
||||
#define _MMAPDEV7X21 ( 0x00000000ull ) /* AMS userpage, NOT mapped at startup */
|
||||
#define _MMAPDEV7X22 ( 0x40038000ull ) /* DEBUG: IRAM */
|
||||
|
||||
/* LP0 entry ram segments (addr, size, additional attributes) */
|
||||
#define _MMAPLP0ES0 ( 0x40020000ull, 0x10000ull, MMU_PTE_BLOCK_NS | ATTRIB_MEMTYPE_DEVICE ) /* Encrypted TZRAM */
|
||||
@@ -133,10 +137,12 @@
|
||||
#define MMIO_DEVID_GPIO 15
|
||||
#define MMIO_DEVID_DTV_I2C234 16
|
||||
#define MMIO_DEVID_EXCEPTION_VECTORS 17
|
||||
#define MMIO_DEVID_AMS_IRAM_PAGE 18
|
||||
#define MMIO_DEVID_AMS_USER_PAGE 19
|
||||
#define MMIO_DEVID_DEBUG_IRAM 20
|
||||
#define MMIO_DEVID_MAX 21
|
||||
#define MMIO_DEVID_MC0 18
|
||||
#define MMIO_DEVID_MC1 19
|
||||
#define MMIO_DEVID_AMS_IRAM_PAGE 20
|
||||
#define MMIO_DEVID_AMS_USER_PAGE 21
|
||||
#define MMIO_DEVID_DEBUG_IRAM 22
|
||||
#define MMIO_DEVID_MAX 23
|
||||
|
||||
#define LP0_ENTRY_RAM_SEGMENT_ID_ENCRYPTED_TZRAM 0
|
||||
#define LP0_ENTRY_RAM_SEGMENT_ID_LP0_ENTRY_CODE 1
|
||||
|
||||
@@ -149,6 +149,7 @@ static void setup_se(void) {
|
||||
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);
|
||||
break;
|
||||
}
|
||||
@@ -338,7 +339,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
|
||||
|
||||
/* Perform version checks. */
|
||||
/* We will be compatible with all package2s released before current, but not newer ones. */
|
||||
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_910_CURRENT) {
|
||||
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_1000_CURRENT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -466,6 +467,7 @@ static void copy_warmboot_bin_to_dram() {
|
||||
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;
|
||||
break;
|
||||
}
|
||||
@@ -551,6 +553,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
||||
MAKE_REG32(PMC_BASE + 0x360) = 0x18C;
|
||||
break;
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_1000:
|
||||
MAKE_REG32(PMC_BASE + 0x360) = 0x1AD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
|
||||
#define PACKAGE2_MAXVER_700_800 0xA
|
||||
#define PACKAGE2_MAXVER_810 0xB
|
||||
#define PACKAGE2_MAXVER_900 0xC
|
||||
#define PACKAGE2_MAXVER_910_CURRENT 0xD
|
||||
#define PACKAGE2_MAXVER_910_920 0xD
|
||||
#define PACKAGE2_MAXVER_1000_CURRENT 0xE
|
||||
|
||||
#define PACKAGE2_MINVER_100 0x3
|
||||
#define PACKAGE2_MINVER_200 0x4
|
||||
@@ -86,7 +87,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
|
||||
#define PACKAGE2_MINVER_700_800 0xB
|
||||
#define PACKAGE2_MINVER_810 0xC
|
||||
#define PACKAGE2_MINVER_900 0xD
|
||||
#define PACKAGE2_MINVER_910_CURRENT 0xE
|
||||
#define PACKAGE2_MINVER_910_920 0xE
|
||||
#define PACKAGE2_MINVER_1000_CURRENT 0xF
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
|
||||
20
exosphere/src/rsa_common.c
Normal file
20
exosphere/src/rsa_common.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "rsa_common.h"
|
||||
|
||||
/* Instantiate the shared RSA data inside a single translation unit. */
|
||||
rsa_shared_data_t g_rsa_shared_data = {};
|
||||
36
exosphere/src/rsa_common.h
Normal file
36
exosphere/src/rsa_common.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EXOSPHERE_RSA_COMMON_H
|
||||
#define EXOSPHERE_RSA_COMMON_H
|
||||
#include <stdint.h>
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t user_data[0x100];
|
||||
} storage_exp_mod;
|
||||
struct {
|
||||
uint32_t master_key_rev;
|
||||
uint32_t type;
|
||||
uint64_t expected_label_hash[4];
|
||||
} unwrap_titlekey;
|
||||
} rsa_shared_data_t __attribute__((aligned(4)));
|
||||
|
||||
_Static_assert(sizeof(rsa_shared_data_t) == 0x100);
|
||||
|
||||
extern rsa_shared_data_t g_rsa_shared_data;
|
||||
|
||||
#endif
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "utils.h"
|
||||
@@ -47,24 +47,25 @@ void ll_init(volatile se_ll_t *ll, void *buffer, size_t size) {
|
||||
ll->addr_info.address = 0;
|
||||
ll->addr_info.size = 0;
|
||||
}
|
||||
|
||||
|
||||
flush_dcache_range((uint8_t *)ll, (uint8_t *)ll + sizeof(*ll));
|
||||
}
|
||||
|
||||
void set_security_engine_callback(unsigned int (*callback)(void)) {
|
||||
if (callback == NULL || g_se_callback != NULL) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Set the callback. */
|
||||
g_se_callback = callback;
|
||||
|
||||
/* Enable SE Interrupt firing for async op. */
|
||||
se_get_regs()->SE_INT_ENABLE = 0x10;
|
||||
}
|
||||
|
||||
/* Fires on Security Engine operation completion. */
|
||||
void se_operation_completed(void) {
|
||||
se_get_regs()->SE_INT_ENABLE = 0;
|
||||
if (g_se_callback != NULL) {
|
||||
g_se_callback();
|
||||
unsigned int (*callback)(void) = g_se_callback;
|
||||
if (callback != NULL) {
|
||||
g_se_callback = NULL;
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +104,7 @@ void se_validate_stored_vector(void) {
|
||||
|
||||
uint8_t calc_vector[0x10];
|
||||
se_generate_test_vector(calc_vector);
|
||||
|
||||
|
||||
/* Ensure nobody's messed with the security engine while we slept. */
|
||||
if (memcmp(calc_vector, g_se_stored_test_vector, 0x10) != 0) {
|
||||
generic_panic();
|
||||
@@ -122,7 +123,7 @@ void se_generate_stored_vector(void) {
|
||||
/* Set the flags for an AES keyslot. */
|
||||
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -141,7 +142,7 @@ void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
||||
/* Set the flags for an RSA keyslot. */
|
||||
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_RSA_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -160,7 +161,7 @@ void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
||||
|
||||
void clear_aes_keyslot(unsigned int keyslot) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -174,7 +175,7 @@ void clear_aes_keyslot(unsigned int keyslot) {
|
||||
|
||||
void clear_rsa_keyslot(unsigned int keyslot) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_RSA_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -194,7 +195,7 @@ void clear_rsa_keyslot(unsigned int keyslot) {
|
||||
|
||||
void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -207,7 +208,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) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -228,7 +229,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) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -241,7 +242,7 @@ void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
|
||||
|
||||
void clear_aes_keyslot_iv(unsigned int keyslot) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -260,7 +261,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) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSIZE_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -276,7 +277,7 @@ void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_sr
|
||||
|
||||
void se_aes_crypt_insecure_internal(unsigned int keyslot, uint32_t out_ll_paddr, uint32_t in_ll_paddr, size_t size, unsigned int crypt_config, bool encrypt, unsigned int (*callback)(void)) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -304,9 +305,6 @@ void se_aes_crypt_insecure_internal(unsigned int keyslot, uint32_t out_ll_paddr,
|
||||
/* Set the callback, for after the async operation. */
|
||||
set_security_engine_callback(callback);
|
||||
|
||||
/* Enable SE Interrupt firing for async op. */
|
||||
se->SE_INT_ENABLE = 0x10;
|
||||
|
||||
/* Setup Input/Output lists */
|
||||
se->SE_IN_LL_ADDR = in_ll_paddr;
|
||||
se->SE_OUT_LL_ADDR = out_ll_paddr;
|
||||
@@ -338,7 +336,7 @@ void se_aes_cbc_decrypt_insecure(unsigned int keyslot, uint32_t out_ll_paddr, ui
|
||||
se_aes_crypt_insecure_internal(keyslot, out_ll_paddr, in_ll_paddr, size, 0x66, false, callback);
|
||||
}
|
||||
|
||||
void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*callback)(void)) {
|
||||
void se_exp_mod(unsigned int keyslot, const void *buf, size_t size, unsigned int (*callback)(void)) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
uint8_t stack_buf[KEYSIZE_RSA_MAX];
|
||||
|
||||
@@ -348,7 +346,7 @@ void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*cal
|
||||
|
||||
/* Endian swap the input. */
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
stack_buf[i] = *((uint8_t *)buf + size - i - 1);
|
||||
stack_buf[i] = *((const uint8_t *)buf + size - i - 1);
|
||||
}
|
||||
|
||||
se->SE_CONFIG = (ALG_RSA | DST_RSAREG);
|
||||
@@ -358,9 +356,6 @@ void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*cal
|
||||
|
||||
set_security_engine_callback(callback);
|
||||
|
||||
/* Enable SE interrupt firing for async op. */
|
||||
se->SE_INT_ENABLE = 0x10;
|
||||
|
||||
flush_dcache_range(stack_buf, stack_buf + KEYSIZE_RSA_MAX);
|
||||
trigger_se_rsa_op(stack_buf, size);
|
||||
|
||||
@@ -468,7 +463,7 @@ bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const v
|
||||
void trigger_se_rsa_op(void *buf, size_t size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
se_ll_t in_ll;
|
||||
|
||||
|
||||
ll_init(&in_ll, (void *)buf, size);
|
||||
|
||||
/* Set the input LL. */
|
||||
@@ -491,19 +486,19 @@ void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const v
|
||||
|
||||
ll_init(&in_ll, (void *)src, src_size);
|
||||
ll_init(&out_ll, dst, dst_size);
|
||||
|
||||
|
||||
__dsb_sy();
|
||||
|
||||
/* Set the LLs. */
|
||||
se->SE_IN_LL_ADDR = (uint32_t) get_physical_address(&in_ll);
|
||||
se->SE_OUT_LL_ADDR = (uint32_t) get_physical_address(&out_ll);
|
||||
|
||||
|
||||
/* Set registers for operation. */
|
||||
se->SE_ERR_STATUS = se->SE_ERR_STATUS;
|
||||
se->SE_INT_STATUS = se->SE_INT_STATUS;
|
||||
se->SE_OPERATION = op;
|
||||
(void)(se->SE_OPERATION);
|
||||
|
||||
|
||||
__dsb_ish();
|
||||
|
||||
while (!(se->SE_INT_STATUS & 0x10)) { /* Wait a while */ }
|
||||
@@ -538,7 +533,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) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -548,7 +543,7 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
|
||||
}
|
||||
if (dst_size) {
|
||||
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int num_blocks = src_size >> 4;
|
||||
|
||||
@@ -576,12 +571,12 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
|
||||
|
||||
if (dst_size) {
|
||||
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -606,7 +601,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) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -632,15 +627,15 @@ void shift_left_xor_rb(uint8_t *key) {
|
||||
|
||||
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();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
||||
if (data_size) {
|
||||
flush_dcache_range((uint8_t *)data, (uint8_t *)data + data_size);
|
||||
}
|
||||
|
||||
|
||||
/* Generate the derived key, to be XOR'd with final output block. */
|
||||
uint8_t derived_key[0x10] = {0};
|
||||
se_aes_ecb_encrypt_block(keyslot, derived_key, sizeof(derived_key), derived_key, sizeof(derived_key), config_high);
|
||||
@@ -652,7 +647,7 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
|
||||
se->SE_CONFIG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16);
|
||||
se->SE_CRYPTO_CONFIG = (keyslot << 24) | (0x145);
|
||||
clear_aes_keyslot_iv(keyslot);
|
||||
|
||||
|
||||
unsigned int num_blocks = (data_size + 0xF) >> 4;
|
||||
/* Handle aligned blocks. */
|
||||
if (num_blocks > 1) {
|
||||
@@ -660,7 +655,7 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, data, data_size);
|
||||
se->SE_CRYPTO_CONFIG |= 0x80;
|
||||
}
|
||||
|
||||
|
||||
/* Create final block. */
|
||||
uint8_t last_block[0x10] = {0};
|
||||
if (data_size & 0xF) {
|
||||
@@ -669,11 +664,11 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
|
||||
} else if (data_size >= 0x10) {
|
||||
memcpy(last_block, data + data_size - 0x10, 0x10);
|
||||
}
|
||||
|
||||
|
||||
for (unsigned int i = 0; i < 0x10; i++) {
|
||||
last_block[i] ^= derived_key[i];
|
||||
}
|
||||
|
||||
|
||||
/* Perform last operation. */
|
||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||
flush_dcache_range(last_block, last_block + sizeof(last_block));
|
||||
@@ -694,11 +689,11 @@ 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) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
||||
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16);
|
||||
se->SE_CRYPTO_CONFIG = (keyslot << 24) | 0x144;
|
||||
set_aes_keyslot_iv(keyslot, iv, 0x10);
|
||||
@@ -709,7 +704,7 @@ void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, co
|
||||
/* SHA256 Implementation. */
|
||||
void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
/* Setup config for SHA256, size = BITS(src_size) */
|
||||
se->SE_CONFIG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
|
||||
se->SE_SHA_CONFIG = 1;
|
||||
@@ -721,7 +716,7 @@ void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
|
||||
se->SE_SHA_MSG_LEFT[1] = 0;
|
||||
se->SE_SHA_MSG_LEFT[2] = 0;
|
||||
se->SE_SHA_MSG_LEFT[3] = 0;
|
||||
|
||||
|
||||
/* Trigger the operation. */
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, src, src_size);
|
||||
|
||||
@@ -734,7 +729,7 @@ void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
|
||||
/* RNG API */
|
||||
void se_initialize_rng(unsigned int keyslot) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -754,7 +749,7 @@ void se_initialize_rng(unsigned int keyslot) {
|
||||
|
||||
void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -777,7 +772,7 @@ void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
|
||||
/* SE context save API. */
|
||||
void se_set_in_context_save_mode(bool is_context_save_mode) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
uint32_t val = se->SE_SE_SECURITY;
|
||||
if (is_context_save_mode) {
|
||||
val |= 0x10000;
|
||||
@@ -791,7 +786,7 @@ void se_set_in_context_save_mode(bool is_context_save_mode) {
|
||||
|
||||
void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
if (dst_keyslot >= KEYSLOT_AES_MAX || rng_keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
@@ -801,7 +796,7 @@ void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot)
|
||||
se->SE_CRYPTO_CONFIG = (rng_keyslot << 24) | 0x108;
|
||||
se->SE_RNG_CONFIG = 4;
|
||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||
|
||||
|
||||
/* Generate low part of key. */
|
||||
se->SE_CRYPTO_KEYTABLE_DST = (dst_keyslot << 8);
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
||||
@@ -812,7 +807,7 @@ void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot)
|
||||
|
||||
void se_generate_srk(unsigned int srkgen_keyslot) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
|
||||
se->SE_CONFIG = (ALG_RNG | DST_SRK);
|
||||
se->SE_CRYPTO_CONFIG = (srkgen_keyslot << 24) | 0x108;
|
||||
se->SE_RNG_CONFIG = 6;
|
||||
@@ -847,24 +842,24 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void
|
||||
/* Generate the SRK (context save encryption key). */
|
||||
se_generate_random_key(srkgen_keyslot, rng_keyslot);
|
||||
se_generate_srk(srkgen_keyslot);
|
||||
|
||||
|
||||
flush_dcache_range(work_buf, work_buf + 0x10);
|
||||
se_generate_random(rng_keyslot, work_buf, 0x10);
|
||||
flush_dcache_range(work_buf, work_buf + 0x10);
|
||||
|
||||
|
||||
/* Save random initial block. */
|
||||
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY);
|
||||
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_MEM);
|
||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||
se_encrypt_with_srk(dst, 0x10, work_buf, 0x10);
|
||||
|
||||
|
||||
/* Save Sticky Bits. */
|
||||
for (unsigned int i = 0; i < 0x2; i++) {
|
||||
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_STICKY_BITS) | (i << CTX_SAVE_STICKY_BIT_INDEX_SHIFT);
|
||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||
se_encrypt_with_srk(dst + 0x10 + (i * 0x10), 0x10, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Save AES Key Table. */
|
||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
||||
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
|
||||
@@ -874,21 +869,21 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void
|
||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||
se_encrypt_with_srk(dst + 0x40 + (i * 0x20), 0x10, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Save AES Original IVs. */
|
||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
||||
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_ORIGINAL_IV);
|
||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||
se_encrypt_with_srk(dst + 0x230 + (i * 0x10), 0x10, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Save AES Updated IVs */
|
||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
||||
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_UPDATED_IV);
|
||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||
se_encrypt_with_srk(dst + 0x330 + (i * 0x10), 0x10, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Save RSA Keytable. */
|
||||
uint8_t *rsa_ctx_out = (uint8_t *)dst + 0x430;
|
||||
for (unsigned int rsa_key = 0; rsa_key < KEYSLOT_RSA_MAX; rsa_key++) {
|
||||
@@ -901,13 +896,13 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Save "Known Pattern. " */
|
||||
static const uint8_t context_save_known_pattern[0x10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
|
||||
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_MEM);
|
||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||
se_encrypt_with_srk(dst + 0x830, 0x10, context_save_known_pattern, 0x10);
|
||||
|
||||
|
||||
/* Save SRK into PMC registers. */
|
||||
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_SRK);
|
||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef EXOSPHERE_SE_H
|
||||
#define EXOSPHERE_SE_H
|
||||
|
||||
@@ -213,7 +213,7 @@ void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, co
|
||||
void se_calculate_sha256(void *dst, const void *src, size_t src_size);
|
||||
|
||||
/* RSA API */
|
||||
void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*callback)(void));
|
||||
void se_exp_mod(unsigned int keyslot, const void *buf, size_t size, unsigned int (*callback)(void));
|
||||
void se_get_exp_mod_output(void *buf, size_t size);
|
||||
void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size);
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "synchronization.h"
|
||||
#include "masterkey.h"
|
||||
#include "mc.h"
|
||||
#include "mc0.h"
|
||||
#include "mc1.h"
|
||||
#include "memory_map.h"
|
||||
#include "pmc.h"
|
||||
#include "randomcache.h"
|
||||
@@ -188,6 +190,7 @@ void set_version_specific_smcs(void) {
|
||||
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;
|
||||
@@ -433,19 +436,18 @@ uint32_t smc_get_result(smc_args_t *args) {
|
||||
}
|
||||
|
||||
uint32_t smc_exp_mod_get_result(void *buf, uint64_t size) {
|
||||
if (get_exp_mod_done() != 1) {
|
||||
return 3;
|
||||
uint32_t res = get_exp_mod_result();
|
||||
if (res == 0) {
|
||||
if (size == 0x100) {
|
||||
se_get_exp_mod_output(buf, 0x100);
|
||||
/* smc_exp_mod is done now. */
|
||||
clear_user_smc_in_progress();
|
||||
res = 0;
|
||||
} else {
|
||||
res = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (size != 0x100) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
se_get_exp_mod_output(buf, 0x100);
|
||||
|
||||
/* smc_exp_mod is done now. */
|
||||
clear_user_smc_in_progress();
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t smc_exp_mod(smc_args_t *args) {
|
||||
@@ -508,30 +510,31 @@ uint32_t smc_unwrap_rsa_oaep_wrapped_titlekey_get_result(void *buf, uint64_t siz
|
||||
uint8_t aes_wrapped_titlekey[0x10];
|
||||
uint8_t titlekey[0x10];
|
||||
uint64_t sealed_titlekey[2];
|
||||
if (get_exp_mod_done() != 1) {
|
||||
return 3;
|
||||
uint32_t res = get_exp_mod_result();
|
||||
if (res == 0) {
|
||||
if (size == 0x10) {
|
||||
se_get_exp_mod_output(rsa_wrapped_titlekey, 0x100);
|
||||
if (tkey_rsa_oaep_unwrap(aes_wrapped_titlekey, 0x10, rsa_wrapped_titlekey, 0x100) == 0x10) {
|
||||
tkey_aes_unwrap(titlekey, 0x10, aes_wrapped_titlekey, 0x10);
|
||||
seal_titlekey(sealed_titlekey, 0x10, titlekey, 0x10);
|
||||
|
||||
p_sealed_key[0] = sealed_titlekey[0];
|
||||
p_sealed_key[1] = sealed_titlekey[1];
|
||||
|
||||
res = 0;
|
||||
} else {
|
||||
/* Failed to extract RSA OAEP wrapped key. */
|
||||
res = 2;
|
||||
}
|
||||
|
||||
/* smc_unwrap_rsa_oaep_wrapped_titlekey is done now. */
|
||||
clear_user_smc_in_progress();
|
||||
} else {
|
||||
res = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (size != 0x10) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
se_get_exp_mod_output(rsa_wrapped_titlekey, 0x100);
|
||||
if (tkey_rsa_oaep_unwrap(aes_wrapped_titlekey, 0x10, rsa_wrapped_titlekey, 0x100) != 0x10) {
|
||||
/* Failed to extract RSA OAEP wrapped key. */
|
||||
clear_user_smc_in_progress();
|
||||
return 2;
|
||||
}
|
||||
|
||||
tkey_aes_unwrap(titlekey, 0x10, aes_wrapped_titlekey, 0x10);
|
||||
seal_titlekey(sealed_titlekey, 0x10, titlekey, 0x10);
|
||||
|
||||
p_sealed_key[0] = sealed_titlekey[0];
|
||||
p_sealed_key[1] = sealed_titlekey[1];
|
||||
|
||||
/* smc_unwrap_rsa_oaep_wrapped_titlekey is done now. */
|
||||
clear_user_smc_in_progress();
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t smc_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
|
||||
@@ -616,7 +619,7 @@ uint32_t smc_read_write_register(smc_args_t *args) {
|
||||
}
|
||||
/* Check for PMC registers. */
|
||||
if (0x7000E400 <= address && address <= 0x7000EFFF) {
|
||||
const uint8_t pmc_whitelist[0x28] = {
|
||||
static const uint8_t pmc_whitelist[0x28] = {
|
||||
0xB9, 0xF9, 0x07, 0x00, 0x00, 0x00, 0x80, 0x03,
|
||||
0x00, 0x00, 0x00, 0x17, 0x00, 0xC4, 0x07, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x00,
|
||||
@@ -632,39 +635,83 @@ uint32_t smc_read_write_register(smc_args_t *args) {
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
} else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400 && MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) <= address &&
|
||||
address < MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) + MMIO_GET_DEVICE_SIZE(MMIO_DEVID_MC)) {
|
||||
/* Memory Controller RW supported only on 4.0.0+ */
|
||||
const uint8_t mc_whitelist[0x68] = {
|
||||
0x9F, 0x31, 0x30, 0x00, 0xF0, 0xFF, 0xF7, 0x01,
|
||||
0xCD, 0xFE, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x40, 0x73, 0x3E, 0x2F, 0x00, 0x00, 0x6E,
|
||||
0x30, 0x05, 0x06, 0xB0, 0x71, 0xC8, 0x43, 0x04,
|
||||
0x80, 0x1F, 0x08, 0x80, 0x03, 0x00, 0x0E, 0x00,
|
||||
0x08, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x30, 0xF0, 0x03, 0x03, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x31, 0x00, 0x40, 0x00, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xFE, 0x0F,
|
||||
0x01, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00
|
||||
};
|
||||
uint32_t offset = (uint32_t)(address - 0x70019000);
|
||||
uint32_t wl_ind = (offset >> 5);
|
||||
/* If address is whitelisted, allow write. */
|
||||
if (wl_ind < sizeof(mc_whitelist) && (mc_whitelist[wl_ind] & (1 << ((offset >> 2) & 0x7)))) {
|
||||
p_mmio = (volatile uint32_t *)(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC) + offset);
|
||||
} else {
|
||||
/* These addresses are not allowed by the whitelist. */
|
||||
/* 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. */
|
||||
/* This is "probably" to fuck with hackers who got access to smcReadWriteRegister and are trying to get */
|
||||
/* control of the BPMP for jamais vu etc., since there's no other reason to return 0 despite failure. */
|
||||
if (address == 0x7001923C || address == 0x70019298) {
|
||||
return 0;
|
||||
} else {
|
||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) {
|
||||
static const uint8_t mc_whitelist_5x[0xD00/(sizeof(uint32_t) * 8)] = {
|
||||
0x9F, 0x31, 0x30, 0x00, 0xF0, 0xFF, 0xF7, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x40, 0x73, 0x3E, 0x2F, 0x00, 0x00, 0x6E,
|
||||
0x30, 0x05, 0x06, 0xB0, 0x71, 0xC8, 0x43, 0x04,
|
||||
0x80, 0xFF, 0x08, 0x80, 0x03, 0x38, 0x8E, 0x1F,
|
||||
0xC8, 0xFF, 0xFF, 0x00, 0x0E, 0x00, 0x00, 0x00,
|
||||
0xF0, 0x1F, 0x00, 0x30, 0xF0, 0x03, 0x03, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x31, 0x00, 0x40, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x0F,
|
||||
0x01, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00
|
||||
};
|
||||
static const uint8_t mc01_whitelist_5x[0xC00/(sizeof(uint32_t) * 8)] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xCD, 0xFE, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00,
|
||||
};
|
||||
static const struct {
|
||||
uint32_t phys_addr;
|
||||
uint32_t size;
|
||||
uint64_t virt_addr;
|
||||
const uint8_t *whitelist;
|
||||
} register_whitelists[3] = {
|
||||
{ MMIO_GET_DEVICE_PA(MMIO_DEVID_MC), sizeof(mc_whitelist_5x) * (sizeof(uint32_t) * 8), MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC), mc_whitelist_5x },
|
||||
{ MMIO_GET_DEVICE_PA(MMIO_DEVID_MC0), sizeof(mc01_whitelist_5x) * (sizeof(uint32_t) * 8), MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC0), mc01_whitelist_5x },
|
||||
{ MMIO_GET_DEVICE_PA(MMIO_DEVID_MC1), sizeof(mc01_whitelist_5x) * (sizeof(uint32_t) * 8), MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC1), mc01_whitelist_5x },
|
||||
};
|
||||
for (unsigned int which = 0; which < 3; which++) {
|
||||
if (register_whitelists[which].phys_addr <= address && address < register_whitelists[which].phys_addr + register_whitelists[which].size) {
|
||||
uint32_t offset = (uint32_t)(address - register_whitelists[which].phys_addr);
|
||||
uint32_t wl_ind = (offset >> 5);
|
||||
/* If address is whitelisted, allow write. */
|
||||
if (register_whitelists[which].whitelist[wl_ind] & (1 << ((offset >> 2) & 0x7))) {
|
||||
p_mmio = (volatile uint32_t *)(register_whitelists[which].virt_addr + offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
|
||||
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+ */
|
||||
static const uint8_t mc_whitelist[0x68] = {
|
||||
0x9F, 0x31, 0x30, 0x00, 0xF0, 0xFF, 0xF7, 0x01,
|
||||
0xCD, 0xFE, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x40, 0x73, 0x3E, 0x2F, 0x00, 0x00, 0x6E,
|
||||
0x30, 0x05, 0x06, 0xB0, 0x71, 0xC8, 0x43, 0x04,
|
||||
0x80, 0x1F, 0x08, 0x80, 0x03, 0x00, 0x0E, 0x00,
|
||||
0x08, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x30, 0xF0, 0x03, 0x03, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x31, 0x00, 0x40, 0x00, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xFE, 0x0F,
|
||||
0x01, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00
|
||||
};
|
||||
uint32_t offset = (uint32_t)(address - MMIO_GET_DEVICE_PA(MMIO_DEVID_MC));
|
||||
uint32_t wl_ind = (offset >> 5);
|
||||
/* If address is whitelisted, allow write. */
|
||||
if (mc_whitelist[wl_ind] & (1 << ((offset >> 2) & 0x7))) {
|
||||
p_mmio = (volatile uint32_t *)(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC) + offset);
|
||||
}
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,9 +730,16 @@ uint32_t smc_read_write_register(smc_args_t *args) {
|
||||
/* Return old value. */
|
||||
args->X[1] = old_value;
|
||||
return 0;
|
||||
} else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400 && (address == 0x7001923C || address == 0x70019298)) {
|
||||
/* These addresses are not allowed by the whitelist. */
|
||||
/* 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. */
|
||||
/* This is "probably" to fuck with hackers who got access to smcReadWriteRegister and are trying to get */
|
||||
/* control of the BPMP for jamais vu etc., since there's no other reason to return 0 despite failure. */
|
||||
return 0;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -34,12 +34,93 @@
|
||||
|
||||
/* Globals. */
|
||||
static bool g_crypt_aes_done = false;
|
||||
static bool g_exp_mod_done = false;
|
||||
static uint32_t g_exp_mod_result = 0;
|
||||
|
||||
static uint8_t g_imported_exponents[4][0x100];
|
||||
static __attribute__((aligned(4))) uint8_t g_imported_exponents[4][0x100];
|
||||
static __attribute__((aligned(4))) uint8_t g_imported_moduli[4][0x100];
|
||||
static bool g_is_modulus_verified[4];
|
||||
|
||||
static __attribute__((aligned(4))) const uint8_t g_rsa_public_key[4] = { 0x00, 0x01, 0x00, 0x01 };
|
||||
|
||||
static __attribute__((aligned(4))) const uint8_t g_rsa_test_vector[0x100] = {
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
|
||||
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D'
|
||||
};
|
||||
|
||||
static uint32_t g_test_exp_mod_keyslot = 0;
|
||||
static uint32_t g_test_exp_mod_usecase = 0;
|
||||
static bool g_test_exp_mod_in_progress = false;
|
||||
|
||||
static uint8_t g_rsausecase_to_cryptousecase[5] = {1, 2, 3, 5, 6};
|
||||
|
||||
static void import_rsa_exponent(unsigned int which, const uint8_t *exponent, uint64_t size) {
|
||||
g_is_modulus_verified[which] = false;
|
||||
for (unsigned int i = 0; i < 0x100; i++) {
|
||||
g_imported_exponents[which][i] = exponent[i];
|
||||
g_imported_moduli[which][i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void import_rsa_modulus(unsigned int which, const uint8_t *modulus, uint64_t size) {
|
||||
uint64_t clamped_size = 0x100;
|
||||
if (size <= 0x100) {
|
||||
clamped_size = size;
|
||||
}
|
||||
if (clamped_size != 0) {
|
||||
/* The official secure monitor implements this via bit-fiddling, */
|
||||
/* and to prevent accidental inaccuracy we will too. */
|
||||
/* It's probably done to prevent errors on negative sizes. */
|
||||
uint64_t remaining = 0x100;
|
||||
if (size != 0x100 && (~size >= ~0xFFFFFFFFFFFFFEFFULL)) {
|
||||
remaining = size;
|
||||
}
|
||||
memcpy(&g_imported_moduli[which][0], modulus, remaining);
|
||||
}
|
||||
}
|
||||
|
||||
static bool load_imported_rsa_keypair(unsigned int keyslot, unsigned int which) {
|
||||
if (!g_is_modulus_verified[which]) {
|
||||
return false;
|
||||
}
|
||||
set_rsa_keyslot(keyslot, g_imported_moduli[which], 0x100, g_imported_exponents[which], 0x100);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void test_rsa_modulus_public(unsigned int which, unsigned int keyslot, const uint8_t *modulus, uint64_t modulus_size, unsigned int (*callback)(void)) {
|
||||
import_rsa_modulus(which, modulus, modulus_size);
|
||||
set_rsa_keyslot(keyslot, modulus, modulus_size, g_rsa_public_key, 0x4);
|
||||
se_exp_mod(keyslot, g_rsa_test_vector, 0x100, callback);
|
||||
}
|
||||
|
||||
static void test_rsa_modulus_private(unsigned int which, unsigned int keyslot, unsigned int (*callback)(void)) {
|
||||
uint8_t exponentiated_data[0x100];
|
||||
se_get_exp_mod_output(exponentiated_data, sizeof(exponentiated_data));
|
||||
set_rsa_keyslot(keyslot, g_imported_moduli[which], 0x100, g_imported_exponents[which], 0x100);
|
||||
se_exp_mod(keyslot, exponentiated_data, 0x100, callback);
|
||||
}
|
||||
|
||||
static void validate_rsa_result(unsigned int which) {
|
||||
char result[0x100];
|
||||
se_get_exp_mod_output(result, sizeof(result));
|
||||
if (memcmp(result, g_rsa_test_vector, sizeof(result)) == 0) {
|
||||
g_is_modulus_verified[which] = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_user_keyslot_valid(unsigned int keyslot) {
|
||||
switch (exosphere_get_target_firmware()) {
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_100:
|
||||
@@ -55,27 +136,45 @@ static bool is_user_keyslot_valid(unsigned int keyslot) {
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_900:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_1000:
|
||||
default:
|
||||
return keyslot <= 5;
|
||||
}
|
||||
}
|
||||
|
||||
void set_exp_mod_done(bool done) {
|
||||
g_exp_mod_done = done;
|
||||
void set_exp_mod_result(uint32_t result) {
|
||||
g_exp_mod_result = result;
|
||||
}
|
||||
|
||||
bool get_exp_mod_done(void) {
|
||||
return g_exp_mod_done;
|
||||
uint32_t get_exp_mod_result(void) {
|
||||
return g_exp_mod_result;
|
||||
}
|
||||
|
||||
uint32_t exp_mod_done_handler(void) {
|
||||
set_exp_mod_done(true);
|
||||
set_exp_mod_result(0);
|
||||
|
||||
se_trigger_interrupt();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t test_exp_mod_done_handler(void) {
|
||||
if (g_test_exp_mod_in_progress) {
|
||||
g_test_exp_mod_in_progress = false;
|
||||
test_rsa_modulus_private(g_test_exp_mod_usecase, g_test_exp_mod_keyslot, test_exp_mod_done_handler);
|
||||
} else {
|
||||
validate_rsa_result(g_test_exp_mod_usecase);
|
||||
if (load_imported_rsa_keypair(g_test_exp_mod_keyslot, g_test_exp_mod_usecase)) {
|
||||
se_exp_mod(g_test_exp_mod_keyslot, g_rsa_shared_data.storage_exp_mod.user_data, 0x100, exp_mod_done_handler);
|
||||
} else {
|
||||
set_exp_mod_result(2);
|
||||
se_trigger_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t user_exp_mod(smc_args_t *args) {
|
||||
uint8_t modulus[0x100];
|
||||
uint8_t exponent[0x100];
|
||||
@@ -108,7 +207,8 @@ uint32_t user_exp_mod(smc_args_t *args) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
set_exp_mod_done(false);
|
||||
set_exp_mod_result(3);
|
||||
|
||||
/* Hardcode RSA keyslot 0. */
|
||||
set_rsa_keyslot(0, modulus, 0x100, exponent, exponent_size);
|
||||
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
|
||||
@@ -650,10 +750,21 @@ uint32_t user_secure_exp_mod(smc_args_t *args) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
set_exp_mod_done(false);
|
||||
set_exp_mod_result(3);
|
||||
|
||||
/* Hardcode RSA keyslot 0. */
|
||||
set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[exponent_id], 0x100);
|
||||
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
|
||||
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_1000) {
|
||||
set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[exponent_id], 0x100);
|
||||
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
|
||||
} else if (load_imported_rsa_keypair(0, exponent_id)) {
|
||||
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
|
||||
} else {
|
||||
memcpy(g_rsa_shared_data.storage_exp_mod.user_data, input, 0x100);
|
||||
g_test_exp_mod_keyslot = 0;
|
||||
g_test_exp_mod_usecase = exponent_id;
|
||||
g_test_exp_mod_in_progress = true;
|
||||
test_rsa_modulus_public(exponent_id, 0, modulus, 0x100, test_exp_mod_done_handler);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -700,7 +811,7 @@ uint32_t user_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
set_exp_mod_done(false);
|
||||
set_exp_mod_result(3);
|
||||
|
||||
/* Expected label_hash occupies args->X[3] to args->X[6]. */
|
||||
tkey_set_expected_label_hash(&args->X[3]);
|
||||
@@ -879,6 +990,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
|
||||
}
|
||||
|
||||
unsigned int exponent_id;
|
||||
bool import_modulus;
|
||||
|
||||
switch (usecase) {
|
||||
case 0:
|
||||
@@ -888,22 +1000,33 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
|
||||
return 0;
|
||||
case 1:
|
||||
exponent_id = 1;
|
||||
import_modulus = false;
|
||||
break;
|
||||
case 2:
|
||||
exponent_id = 0;
|
||||
import_modulus = true;
|
||||
break;
|
||||
case 3:
|
||||
exponent_id = 2;
|
||||
import_modulus = false;
|
||||
break;
|
||||
case 4:
|
||||
exponent_id = 3;
|
||||
import_modulus = true;
|
||||
break;
|
||||
default:
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Copy key to global. */
|
||||
memcpy(g_imported_exponents[exponent_id], user_data, 0x100);
|
||||
/* Modulus import isn't implemented on < 10.0.0. */
|
||||
import_modulus &= (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_1000);
|
||||
|
||||
/* Import the key. */
|
||||
import_rsa_exponent(exponent_id, user_data, 0x100);
|
||||
if (import_modulus) {
|
||||
import_rsa_modulus(exponent_id, user_data + 0x100, 0x100);
|
||||
g_is_modulus_verified[exponent_id] = true;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef EXOSPHERE_SMC_USER_H
|
||||
#define EXOSPHERE_SMC_USER_H
|
||||
|
||||
@@ -41,7 +41,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args);
|
||||
void set_crypt_aes_done(bool done);
|
||||
bool get_crypt_aes_done(void);
|
||||
|
||||
void set_exp_mod_done(bool done);
|
||||
bool get_exp_mod_done(void);
|
||||
void set_exp_mod_result(uint32_t result);
|
||||
uint32_t get_exp_mod_result(void);
|
||||
|
||||
#endif
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -25,14 +25,10 @@
|
||||
#include "masterkey.h"
|
||||
#include "se.h"
|
||||
|
||||
static uint64_t g_tkey_expected_label_hash[4];
|
||||
static unsigned int g_tkey_master_key_rev = MASTERKEY_REVISION_MAX;
|
||||
static unsigned int g_tkey_type = 0;
|
||||
|
||||
/* Set the expected db prefix. */
|
||||
void tkey_set_expected_label_hash(uint64_t *label_hash) {
|
||||
for (unsigned int i = 0; i < 4; i++) {
|
||||
g_tkey_expected_label_hash[i] = label_hash[i];
|
||||
g_rsa_shared_data.unwrap_titlekey.expected_label_hash[i] = label_hash[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +36,7 @@ void tkey_set_master_key_rev(unsigned int master_key_rev) {
|
||||
if (master_key_rev >= MASTERKEY_REVISION_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
g_tkey_master_key_rev = master_key_rev;
|
||||
g_rsa_shared_data.unwrap_titlekey.master_key_rev = master_key_rev;
|
||||
}
|
||||
|
||||
static void tkey_validate_type(unsigned int type) {
|
||||
@@ -51,7 +47,7 @@ static void tkey_validate_type(unsigned int type) {
|
||||
|
||||
void tkey_set_type(unsigned int type) {
|
||||
tkey_validate_type(type);
|
||||
g_tkey_type = type;
|
||||
g_rsa_shared_data.unwrap_titlekey.type = type;
|
||||
}
|
||||
|
||||
/* Reference for MGF1 can be found here: https://en.wikipedia.org/wiki/Mask_generation_function#MGF1 */
|
||||
@@ -116,7 +112,7 @@ size_t tkey_rsa_oaep_unwrap(void *dst, size_t dst_size, void *src, size_t src_si
|
||||
uint8_t *db = message + 0x21;
|
||||
|
||||
/* This will be passed to smc_unwrap_rsa_oaep_wrapped_titlekey. */
|
||||
uint8_t *expected_label_hash = (uint8_t *)(&g_tkey_expected_label_hash[0]);
|
||||
uint8_t *expected_label_hash = (uint8_t *)(&g_rsa_shared_data.unwrap_titlekey.expected_label_hash[0]);
|
||||
|
||||
/* Unmask the salt. */
|
||||
calculate_mgf1_and_xor(salt, 0x20, db, 0xDF);
|
||||
@@ -171,13 +167,13 @@ static const uint8_t titlekek_sources[TITLEKEY_TYPE_MAX+1][0x10] = {
|
||||
};
|
||||
|
||||
void tkey_aes_unwrap(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
if (g_tkey_master_key_rev >= MASTERKEY_REVISION_MAX || dst_size != 0x10 || src_size != 0x10) {
|
||||
if (g_rsa_shared_data.unwrap_titlekey.master_key_rev >= MASTERKEY_REVISION_MAX || dst_size != 0x10 || src_size != 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
||||
/* Generate the appropriate titlekek into keyslot 9. */
|
||||
unsigned int master_keyslot = mkey_get_keyslot(g_tkey_master_key_rev);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, master_keyslot, titlekek_sources[g_tkey_type], 0x10);
|
||||
unsigned int master_keyslot = mkey_get_keyslot(g_rsa_shared_data.unwrap_titlekey.master_key_rev);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, master_keyslot, titlekek_sources[g_rsa_shared_data.unwrap_titlekey.type], 0x10);
|
||||
|
||||
/* Unwrap the titlekey using the titlekek. */
|
||||
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, dst, 0x10, src, 0x10);
|
||||
|
||||
@@ -13,11 +13,12 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef EXOSPHERE_TITLEKEY_H
|
||||
#define EXOSPHERE_TITLEKEY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rsa_common.h"
|
||||
|
||||
#define TITLEKEY_TYPE_MAX 0x1
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "utils.h"
|
||||
#include "memory_map.h"
|
||||
#include "mc.h"
|
||||
@@ -65,7 +65,7 @@ void init_dma_controllers(unsigned int target_firmware) {
|
||||
MAKE_REG32(0x6000C038) = 0x0;
|
||||
|
||||
/* MSELECT_CONFIG_0 |= WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */
|
||||
MAKE_REG32(0x50060000) |= 0x38000000;
|
||||
MAKE_REG32(0x50060000) = (MAKE_REG32(0x50060000) & 0xC4FFFFFF) | 0x38000000;
|
||||
|
||||
/* AHB_ARBITRATION_DISABLE_0 - Disables USB, USB2, and AHB-DMA from arbitration */
|
||||
MAKE_REG32(0x6000C004) = 0x40060;
|
||||
@@ -99,7 +99,7 @@ void init_dma_controllers(unsigned int target_firmware) {
|
||||
MAKE_REG32(0x60020038) = 0;
|
||||
|
||||
/* MSELECT_CONFIG_0 |= WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */
|
||||
MAKE_REG32(0x50060000) |= 0x38000000;
|
||||
MAKE_REG32(0x50060000) |= (MAKE_REG32(0x50060000) & 0xC4FFFFFF) | 0x38000000;
|
||||
|
||||
/* AHB_ARBITRATION_PRIORITY_CTRL_0 - Select high prio group with prio 7 */
|
||||
MAKE_REG32(0x6000C008) = 0xE0000001;
|
||||
@@ -111,6 +111,14 @@ void init_dma_controllers(unsigned int target_firmware) {
|
||||
|
||||
void _set_memory_registers_enable_mmu(const uintptr_t ttbr0) {
|
||||
static const uintptr_t vbar = TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800;
|
||||
/*
|
||||
- Non-cacheable load forwarding enabled
|
||||
- Disable load-pass DMB.
|
||||
- NOTE: This and this alone is done via inline asm, due to register argument limits.
|
||||
*/
|
||||
|
||||
static const uint64_t cpuactlr = 0x800000001000000ull;
|
||||
__asm__ __volatile__("msr s3_1_c15_c2_0, %0" :: "r"(cpuactlr) : "memory", "cc");
|
||||
|
||||
/*
|
||||
- Disable table walk descriptor access prefetch.
|
||||
@@ -197,12 +205,12 @@ void warmboot_init(void) {
|
||||
*/
|
||||
flush_dcache_all();
|
||||
invalidate_icache_all();
|
||||
|
||||
|
||||
/* On warmboot (not cpu_on) only */
|
||||
if (VIRT_MC_SECURITY_CFG3 == 0) {
|
||||
init_dma_controllers(g_exosphere_target_firmware_for_init);
|
||||
}
|
||||
|
||||
|
||||
/*identity_remap_tzram();*/
|
||||
/* 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) {
|
||||
|
||||
@@ -82,6 +82,9 @@ typedef enum {
|
||||
FS_VER_9_1_0,
|
||||
FS_VER_9_1_0_EXFAT,
|
||||
|
||||
FS_VER_10_0_0,
|
||||
FS_VER_10_0_0_EXFAT,
|
||||
|
||||
FS_VER_MAX,
|
||||
} emummc_fs_ver_t;
|
||||
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
|
||||
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
|
||||
#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 {
|
||||
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_DISABLE_USERMODE_EXCEPTION_HANDLERS_KEY "disable_user_exception_handlers"
|
||||
#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
|
||||
|
||||
@@ -417,6 +417,9 @@ static const uint8_t g_fs_hashes[FS_VER_MAX][0x8] = {
|
||||
|
||||
"\xB5\xE7\xA6\x4C\x6F\x5C\x4F\xE3", /* FS_VER_9_1_0 */
|
||||
"\xF1\x96\xD1\x44\xD0\x44\x45\xB6", /* FS_VER_9_1_0_EXFAT */
|
||||
|
||||
"\x3E\xEB\xD9\xB7\xBC\xD1\xB5\xE0", /* FS_VER_10_0_0 */
|
||||
"\x81\x7E\xA2\xB0\xB7\x02\xC1\xF3", /* FS_VER_10_0_0_EXFAT */
|
||||
};
|
||||
|
||||
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver) {
|
||||
|
||||
@@ -486,20 +486,77 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(900, proc_id_send)[] = {0xA9BF
|
||||
static const uint8_t MAKE_KERNEL_PATTERN_NAME(900, proc_id_recv)[] = {0x68, 0x03, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0xE0, 0x03, 0x1B, 0xAA, 0x00, 0x01, 0x3F, 0xD6, 0xE8, 0x03, 0x17, 0x2A, 0xF7, 0x0A, 0x00, 0x11, 0x08, 0xF5, 0x7E, 0xD3};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, proc_id_recv)[] = {0xA9BF2FEA, 0xF9404BEB, 0x2A1703EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
|
||||
|
||||
/*
|
||||
stp x10, x11, [sp, #-0x10]!
|
||||
ldr x11, [sp, #0xC0]
|
||||
mov w10, w22
|
||||
lsl x10, x10, #2
|
||||
ldr x10, [x11, x10]
|
||||
mov x9, #0x0000ffffffffffff
|
||||
and x8, x10, x9
|
||||
mov x9, #0xffff000000000000
|
||||
and x10, x10, x9
|
||||
mov x9, #0xfffe000000000000
|
||||
cmp x10, x9
|
||||
beq #0x20
|
||||
|
||||
stp x8, x9, [sp, #-0x10]!
|
||||
ldr x8, [x23]
|
||||
ldr x8, [x8, #0x38]
|
||||
mov x0, x23
|
||||
blr x8
|
||||
ldp x8, x9, [sp],#0x10
|
||||
mov x8, x0
|
||||
|
||||
ldp x10, x11, [sp],#0x10
|
||||
mov x0, x8
|
||||
*/
|
||||
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1000, proc_id_send)[] = {0xE8, 0x02, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0xE0, 0x03, 0x17, 0xAA, 0x00, 0x01, 0x3F, 0xD6, 0x08, 0x4B, 0x36, 0x8B, 0x09, 0xFC, 0x60, 0xD3, 0x00, 0x25, 0x00, 0x29};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, proc_id_send)[] = {0xA9BF2FEA, 0xF94063EB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002E8, 0xF9401D08, 0xAA1703E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
|
||||
/*
|
||||
stp x10, x11, [sp, #-0x10]!
|
||||
ldr x11, [sp, #0xC8]
|
||||
mov w10, w26
|
||||
lsl x10, x10, #2
|
||||
ldr x10, [x11, x10]
|
||||
mov x9, #0x0000ffffffffffff
|
||||
and x8, x10, x9
|
||||
mov x9, #0xffff000000000000
|
||||
and x10, x10, x9
|
||||
mov x9, #0xfffe000000000000
|
||||
cmp x10, x9
|
||||
beq #0x20
|
||||
|
||||
stp x8, x9, [sp, #-0x10]!
|
||||
ldr x8, [x28]
|
||||
ldr x8, [x8, #0x38]
|
||||
mov x0, x28
|
||||
blr x8
|
||||
ldp x8, x9, [sp],#0x10
|
||||
mov x8, x0
|
||||
|
||||
ldp x10, x11, [sp],#0x10
|
||||
mov x0, x8
|
||||
*/
|
||||
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1000, proc_id_recv)[] = {0x88, 0x03, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0xE0, 0x03, 0x1C, 0xAA, 0x00, 0x01, 0x3F, 0xD6, 0xE8, 0x87, 0x40, 0xF9, 0x08, 0x49, 0x3A, 0x8B, 0x09, 0xFC, 0x60, 0xD3};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, proc_id_recv)[] = {0xA9BF2FEA, 0xF94067EB, 0x2A1A03EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400388, 0xF9401D08, 0xAA1C03E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
|
||||
|
||||
|
||||
/* svcControlCodeMemory Patches */
|
||||
/* b.eq -> nop */
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(600, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(700, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(600, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(700, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, svc_control_codememory)[] = {MAKE_NOP};
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, svc_control_codememory)[] = {MAKE_NOP};
|
||||
|
||||
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, system_memory_increase)[] = {0x52A3C008}; /* MOV W8, #0x1E000000 */
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(600, system_memory_increase)[] = {0x52A3B008}; /* MOV W8, #0x1D800000 */
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(700, system_memory_increase)[] = {0x52A3B008}; /* MOV W8, #0x1D800000 */
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, system_memory_increase)[] = {0x52A3C008}; /* MOV W8, #0x1E000000 */
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(600, system_memory_increase)[] = {0x52A3B008}; /* MOV W8, #0x1D800000 */
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(700, system_memory_increase)[] = {0x52A3B008}; /* MOV W8, #0x1D800000 */
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
|
||||
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
|
||||
|
||||
/* Hook Definitions. */
|
||||
static const kernel_patch_t g_kernel_patches_100[] = {
|
||||
@@ -735,6 +792,35 @@ static const kernel_patch_t g_kernel_patches_900[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const kernel_patch_t g_kernel_patches_1000[] = {
|
||||
{ /* Send Message Process ID Patch. */
|
||||
.pattern_size = 0x1C,
|
||||
.pattern = MAKE_KERNEL_PATTERN_NAME(1000, proc_id_send),
|
||||
.pattern_hook_offset = 0x0,
|
||||
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1000, proc_id_send))/sizeof(instruction_t),
|
||||
.branch_back_offset = 0x10,
|
||||
.payload = MAKE_KERNEL_PATCH_NAME(1000, proc_id_send)
|
||||
},
|
||||
{ /* Receive Message Process ID Patch. */
|
||||
.pattern_size = 0x1C,
|
||||
.pattern = MAKE_KERNEL_PATTERN_NAME(1000, proc_id_recv),
|
||||
.pattern_hook_offset = 0x0,
|
||||
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1000, proc_id_recv))/sizeof(instruction_t),
|
||||
.branch_back_offset = 0x10,
|
||||
.payload = MAKE_KERNEL_PATCH_NAME(1000, proc_id_recv)
|
||||
},
|
||||
{ /* svcControlCodeMemory Patch. */
|
||||
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1000, svc_control_codememory))/sizeof(instruction_t),
|
||||
.payload = MAKE_KERNEL_PATCH_NAME(1000, svc_control_codememory),
|
||||
.patch_offset = 0x45DAC,
|
||||
},
|
||||
{ /* System Memory Increase Patch. */
|
||||
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1000, system_memory_increase))/sizeof(instruction_t),
|
||||
.payload = MAKE_KERNEL_PATCH_NAME(1000, system_memory_increase),
|
||||
.patch_offset = 0x66950,
|
||||
}
|
||||
};
|
||||
|
||||
#define KERNEL_PATCHES(vers) .num_patches = sizeof(g_kernel_patches_##vers)/sizeof(kernel_patch_t), .patches = g_kernel_patches_##vers,
|
||||
|
||||
/* Kernel Infos. */
|
||||
@@ -811,6 +897,15 @@ static const kernel_info_t g_kernel_infos[] = {
|
||||
.embedded_ini_ptr = 0x180,
|
||||
.free_code_space_offset = 0x65780,
|
||||
KERNEL_PATCHES(900)
|
||||
},
|
||||
{ /* 10.0.0. */
|
||||
.hash = {0x59, 0x31, 0xE6, 0x46, 0xF7, 0xAA, 0x15, 0x59, 0x78, 0xC7, 0xB3, 0xA5, 0xFA, 0x80, 0xE2, 0xC0, 0xCA, 0x6F, 0x31, 0x97, 0x3D, 0x86, 0x8A, 0x69, 0xF3, 0xBF, 0xE6, 0xE5, 0x61, 0xA7, 0x1B, 0x5B, },
|
||||
.hash_offset = 0x1B8,
|
||||
.hash_size = 0x93000 - 0x1B8,
|
||||
.embedded_ini_offset = 0x93000,
|
||||
.embedded_ini_ptr = 0x178,
|
||||
.free_code_space_offset = 0x67790,
|
||||
KERNEL_PATCHES(1000)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -855,7 +950,7 @@ const kernel_info_t *get_kernel_info(void *kernel, size_t size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void package2_patch_kernel(void *_kernel, size_t *kernel_size, bool is_sd_kernel, void **out_ini1) {
|
||||
void package2_patch_kernel(void *_kernel, size_t *kernel_size, bool is_sd_kernel, void **out_ini1, uint32_t target_firmware) {
|
||||
const kernel_info_t *kernel_info = get_kernel_info(_kernel, *kernel_size);
|
||||
*out_ini1 = NULL;
|
||||
|
||||
@@ -876,6 +971,12 @@ void package2_patch_kernel(void *_kernel, size_t *kernel_size, bool is_sd_kernel
|
||||
const uint32_t kernel_ldr_offset = *((volatile uint64_t *)((uintptr_t)_kernel + kernel_info->embedded_ini_ptr + 8));
|
||||
memcpy((void *)((uintptr_t)_kernel + kernel_ldr_offset), kernel_ldr_bin, kernel_ldr_bin_size);
|
||||
|
||||
/* Set target firmware for our kernel loader. */
|
||||
uint32_t *kldr_u32 = (uint32_t *)((uintptr_t)_kernel + kernel_ldr_offset);
|
||||
if (kldr_u32[1] == 0x30444C4D) {
|
||||
kldr_u32[2] = target_firmware;
|
||||
}
|
||||
|
||||
/* Update size. */
|
||||
*kernel_size = kernel_ldr_offset + kernel_ldr_bin_size;
|
||||
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
void package2_patch_kernel(void *kernel, size_t *kernel_size, bool is_sd_kernel, void **out_ini1);
|
||||
void package2_patch_kernel(void *kernel, size_t *kernel_size, bool is_sd_kernel, void **out_ini1, uint32_t target_firmware);
|
||||
|
||||
#endif
|
||||
@@ -160,6 +160,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||
desired_keyblob = MASTERKEY_REVISION_900;
|
||||
/* Fallthrough */
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_1000:
|
||||
desired_keyblob = MASTERKEY_REVISION_910_CURRENT;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -134,38 +134,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) {
|
||||
exosphere_config_t *exo_cfg = (exosphere_config_t *)user;
|
||||
exosphere_parse_cfg_t *parse_cfg = (exosphere_parse_cfg_t *)user;
|
||||
int tmp = 0;
|
||||
if (strcmp(section, "exosphere") == 0) {
|
||||
if (strcmp(name, EXOSPHERE_TARGETFW_KEY) == 0) {
|
||||
sscanf(value, "%ld", &exo_cfg->target_firmware);
|
||||
} else if (strcmp(name, EXOSPHERE_DEBUGMODE_PRIV_KEY) == 0) {
|
||||
if (strcmp(name, EXOSPHERE_DEBUGMODE_PRIV_KEY) == 0) {
|
||||
sscanf(value, "%d", &tmp);
|
||||
if (tmp) {
|
||||
exo_cfg->flags |= EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV;
|
||||
} else {
|
||||
exo_cfg->flags &= ~(EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV);
|
||||
if (tmp == 1) {
|
||||
parse_cfg->debugmode = 1;
|
||||
} else if (tmp == 0) {
|
||||
parse_cfg->debugmode = 0;
|
||||
}
|
||||
} else if (strcmp(name, EXOSPHERE_DEBUGMODE_USER_KEY) == 0) {
|
||||
sscanf(value, "%d", &tmp);
|
||||
if (tmp) {
|
||||
exo_cfg->flags |= EXOSPHERE_FLAG_IS_DEBUGMODE_USER;
|
||||
} else {
|
||||
exo_cfg->flags &= ~(EXOSPHERE_FLAG_IS_DEBUGMODE_USER);
|
||||
if (tmp == 1) {
|
||||
parse_cfg->debugmode_user = 1;
|
||||
} else if (tmp == 0) {
|
||||
parse_cfg->debugmode_user = 0;
|
||||
}
|
||||
} else if (strcmp(name, EXOSPHERE_DISABLE_USERMODE_EXCEPTION_HANDLERS_KEY) == 0) {
|
||||
sscanf(value, "%d", &tmp);
|
||||
if (tmp) {
|
||||
exo_cfg->flags |= EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS;
|
||||
} else {
|
||||
exo_cfg->flags &= ~(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
|
||||
if (tmp == 1) {
|
||||
parse_cfg->disable_user_exception_handlers = 1;
|
||||
} else if (tmp == 0) {
|
||||
parse_cfg->disable_user_exception_handlers = 0;
|
||||
}
|
||||
} else if (strcmp(name, EXOSPHERE_ENABLE_USERMODE_PMU_ACCESS_KEY) == 0) {
|
||||
sscanf(value, "%d", &tmp);
|
||||
if (tmp) {
|
||||
exo_cfg->flags |= EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS;
|
||||
} else {
|
||||
exo_cfg->flags &= ~(EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS);
|
||||
if (tmp == 1) {
|
||||
parse_cfg->enable_user_pmu_access = 1;
|
||||
} else if (tmp == 0) {
|
||||
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 {
|
||||
return 0;
|
||||
@@ -232,6 +251,8 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
|
||||
return ATMOSPHERE_TARGET_FIRMWARE_900;
|
||||
} else if (memcmp(package1loader_header->build_timestamp, "20191021", 8) == 0) {
|
||||
return ATMOSPHERE_TARGET_FIRMWARE_910;
|
||||
} else if (memcmp(package1loader_header->build_timestamp, "20200303", 8) == 0) {
|
||||
return ATMOSPHERE_TARGET_FIRMWARE_1000;
|
||||
} else {
|
||||
fatal_error("[NXBOOT] Unable to identify package1!\n");
|
||||
}
|
||||
@@ -346,15 +367,42 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke
|
||||
exo_cfg.target_firmware = target_firmware;
|
||||
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) {
|
||||
exo_cfg.flags = EXOSPHERE_FLAGS_DEFAULT | EXOSPHERE_FLAG_PERFORM_620_KEYGEN;
|
||||
exo_cfg.flags = EXOSPHERE_FLAG_PERFORM_620_KEYGEN;
|
||||
} 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) {
|
||||
fatal_error("[NXBOOT] Failed to parse BCT.ini!\n");
|
||||
/* Setup exosphere parse configuration with defaults. */
|
||||
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)) {
|
||||
fatal_error("[NXBOOT] Invalid Exosphere target firmware!\n");
|
||||
|
||||
@@ -87,7 +87,7 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
|
||||
}
|
||||
|
||||
/* Perform any patches we want to the NX kernel. */
|
||||
package2_patch_kernel(kernel, &kernel_size, is_sd_kernel, (void *)&orig_ini1);
|
||||
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. */
|
||||
if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) ||
|
||||
@@ -232,7 +232,7 @@ static bool package2_validate_metadata(package2_meta_t *metadata, uint8_t data[]
|
||||
|
||||
/* Perform version checks. */
|
||||
/* We will be compatible with all package2s released before current, but not newer ones. */
|
||||
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_910_CURRENT) {
|
||||
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_1000_CURRENT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
#define PACKAGE2_MAXVER_700_800 0xA
|
||||
#define PACKAGE2_MAXVER_810 0xB
|
||||
#define PACKAGE2_MAXVER_900 0xC
|
||||
#define PACKAGE2_MAXVER_910_CURRENT 0xD
|
||||
#define PACKAGE2_MAXVER_910_920 0xD
|
||||
#define PACKAGE2_MAXVER_1000_CURRENT 0xE
|
||||
|
||||
#define PACKAGE2_MINVER_100 0x3
|
||||
#define PACKAGE2_MINVER_200 0x4
|
||||
@@ -52,7 +53,8 @@
|
||||
#define PACKAGE2_MINVER_700_800 0xB
|
||||
#define PACKAGE2_MINVER_810 0xC
|
||||
#define PACKAGE2_MINVER_900 0xD
|
||||
#define PACKAGE2_MINVER_910_CURRENT 0xE
|
||||
#define PACKAGE2_MINVER_910_920 0xE
|
||||
#define PACKAGE2_MINVER_1000_CURRENT 0xF
|
||||
|
||||
#define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull))
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
||||
branch = master
|
||||
commit = de221b5d73fe688ebd93fc3a180ab3cec2ec2c34
|
||||
parent = 0b52596087a9195f22cc2f6e6dc0ee35cee80357
|
||||
commit = bb40dae329450407a24db2c3c4edd4ed1fd46532
|
||||
parent = 745887955507cf42361f37aacfe5ca5477b8e5d5
|
||||
method = merge
|
||||
cmdver = 0.4.1
|
||||
|
||||
@@ -10,7 +10,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).
|
||||
|
||||
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 atmosphere-libs 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 atmosphere-libs 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 atmosphere-libs project under the Zero-Clause BSD license.
|
||||
|
||||
Credits
|
||||
|
||||
@@ -5,7 +5,7 @@ endif
|
||||
include $(DEVKITPRO)/devkitA64/base_rules
|
||||
|
||||
export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM64
|
||||
export ATMOSPHERE_SETTINGS += -march=armv8-a -mtp=soft
|
||||
export ATMOSPHERE_SETTINGS += -march=armv8-a+crc+crypto -mtp=soft
|
||||
export ATMOSPHERE_CFLAGS +=
|
||||
export ATMOSPHERE_CXXFLAGS +=
|
||||
export ATMOSPHERE_ASFLAGS +=
|
||||
|
||||
@@ -6,7 +6,8 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
PRECOMPILED_HEADERS := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/include/mesosphere.hpp
|
||||
#PRECOMPILED_HEADERS := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/include/mesosphere.hpp
|
||||
PRECOMPILED_HEADERS :=
|
||||
|
||||
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE
|
||||
SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -mgeneral-regs-only -ffixed-x18 -Werror -fno-non-call-exceptions
|
||||
|
||||
@@ -10,7 +10,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).
|
||||
|
||||
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 libmesosphere 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 libmesosphere 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 libmesosphere project under the Zero-Clause BSD license.
|
||||
|
||||
Credits
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <mesosphere/kern_k_typed_address.hpp>
|
||||
#include <mesosphere/kern_select_cpu.hpp>
|
||||
#include <mesosphere/arch/arm64/kern_k_page_table_entry.hpp>
|
||||
#include <mesosphere/kern_select_system_control.hpp>
|
||||
|
||||
namespace ams::kern::arch::arm64::init {
|
||||
|
||||
@@ -64,6 +65,220 @@ namespace ams::kern::arch::arm64::init {
|
||||
/* The MMU is necessarily not yet turned on, if we are creating an initial page table. */
|
||||
std::memset(reinterpret_cast<void *>(GetInteger(address)), 0, PageSize);
|
||||
}
|
||||
private:
|
||||
size_t NOINLINE GetBlockCount(KVirtualAddress virt_addr, size_t size, size_t block_size) {
|
||||
const KVirtualAddress end_virt_addr = virt_addr + size;
|
||||
size_t count = 0;
|
||||
while (virt_addr < end_virt_addr) {
|
||||
L1PageTableEntry *l1_entry = GetL1Entry(this->l1_table, virt_addr);
|
||||
|
||||
/* If an L1 block is mapped or we're empty, advance by L1BlockSize. */
|
||||
if (l1_entry->IsBlock() || l1_entry->IsEmpty()) {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L1BlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= L1BlockSize);
|
||||
virt_addr += L1BlockSize;
|
||||
if (l1_entry->IsBlock() && block_size == L1BlockSize) {
|
||||
count++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Non empty and non-block must be table. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsTable());
|
||||
|
||||
/* Table, so check if we're mapped in L2. */
|
||||
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
|
||||
|
||||
if (l2_entry->IsBlock() || l2_entry->IsEmpty()) {
|
||||
const size_t advance_size = (l2_entry->IsBlock() && l2_entry->IsContiguous()) ? L2ContiguousBlockSize : L2BlockSize;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size);
|
||||
virt_addr += advance_size;
|
||||
if (l2_entry->IsBlock() && block_size == advance_size) {
|
||||
count++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Non empty and non-block must be table. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsTable());
|
||||
|
||||
/* Table, so check if we're mapped in L3. */
|
||||
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
|
||||
|
||||
/* L3 must be block or empty. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsBlock() || l3_entry->IsEmpty());
|
||||
|
||||
const size_t advance_size = (l3_entry->IsBlock() && l3_entry->IsContiguous()) ? L3ContiguousBlockSize : L3BlockSize;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size);
|
||||
virt_addr += advance_size;
|
||||
if (l3_entry->IsBlock() && block_size == advance_size) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
KVirtualAddress NOINLINE GetBlockByIndex(KVirtualAddress virt_addr, size_t size, size_t block_size, size_t index) {
|
||||
const KVirtualAddress end_virt_addr = virt_addr + size;
|
||||
size_t count = 0;
|
||||
while (virt_addr < end_virt_addr) {
|
||||
L1PageTableEntry *l1_entry = GetL1Entry(this->l1_table, virt_addr);
|
||||
|
||||
/* If an L1 block is mapped or we're empty, advance by L1BlockSize. */
|
||||
if (l1_entry->IsBlock() || l1_entry->IsEmpty()) {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L1BlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= L1BlockSize);
|
||||
if (l1_entry->IsBlock() && block_size == L1BlockSize) {
|
||||
if ((count++) == index) {
|
||||
return virt_addr;
|
||||
}
|
||||
}
|
||||
virt_addr += L1BlockSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Non empty and non-block must be table. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsTable());
|
||||
|
||||
/* Table, so check if we're mapped in L2. */
|
||||
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
|
||||
|
||||
if (l2_entry->IsBlock() || l2_entry->IsEmpty()) {
|
||||
const size_t advance_size = (l2_entry->IsBlock() && l2_entry->IsContiguous()) ? L2ContiguousBlockSize : L2BlockSize;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size);
|
||||
if (l2_entry->IsBlock() && block_size == advance_size) {
|
||||
if ((count++) == index) {
|
||||
return virt_addr;
|
||||
}
|
||||
}
|
||||
virt_addr += advance_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Non empty and non-block must be table. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsTable());
|
||||
|
||||
/* Table, so check if we're mapped in L3. */
|
||||
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
|
||||
|
||||
/* L3 must be block or empty. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsBlock() || l3_entry->IsEmpty());
|
||||
|
||||
const size_t advance_size = (l3_entry->IsBlock() && l3_entry->IsContiguous()) ? L3ContiguousBlockSize : L3BlockSize;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size);
|
||||
if (l3_entry->IsBlock() && block_size == advance_size) {
|
||||
if ((count++) == index) {
|
||||
return virt_addr;
|
||||
}
|
||||
}
|
||||
virt_addr += advance_size;
|
||||
}
|
||||
return Null<KVirtualAddress>;
|
||||
}
|
||||
|
||||
PageTableEntry *GetMappingEntry(KVirtualAddress virt_addr, size_t block_size) {
|
||||
L1PageTableEntry *l1_entry = GetL1Entry(this->l1_table, virt_addr);
|
||||
|
||||
if (l1_entry->IsBlock()) {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(block_size == L1BlockSize);
|
||||
return l1_entry;
|
||||
}
|
||||
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsTable());
|
||||
|
||||
/* Table, so check if we're mapped in L2. */
|
||||
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
|
||||
|
||||
if (l2_entry->IsBlock()) {
|
||||
const size_t real_size = (l2_entry->IsContiguous()) ? L2ContiguousBlockSize : L2BlockSize;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(real_size == block_size);
|
||||
return l2_entry;
|
||||
}
|
||||
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsTable());
|
||||
|
||||
/* Table, so check if we're mapped in L3. */
|
||||
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
|
||||
|
||||
/* L3 must be block. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsBlock());
|
||||
|
||||
const size_t real_size = (l3_entry->IsContiguous()) ? L3ContiguousBlockSize : L3BlockSize;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(real_size == block_size);
|
||||
return l3_entry;
|
||||
}
|
||||
|
||||
void NOINLINE SwapBlocks(KVirtualAddress src_virt_addr, KVirtualAddress dst_virt_addr, size_t block_size, bool do_copy) {
|
||||
static_assert(L2ContiguousBlockSize / L2BlockSize == L3ContiguousBlockSize / L3BlockSize);
|
||||
const bool contig = (block_size == L2ContiguousBlockSize || block_size == L3ContiguousBlockSize);
|
||||
const size_t num_mappings = contig ? L2ContiguousBlockSize / L2BlockSize : 1;
|
||||
|
||||
/* Unmap the source. */
|
||||
PageTableEntry *src_entry = this->GetMappingEntry(src_virt_addr, block_size);
|
||||
const auto src_saved = *src_entry;
|
||||
for (size_t i = 0; i < num_mappings; i++) {
|
||||
src_entry[i] = InvalidPageTableEntry;
|
||||
}
|
||||
|
||||
/* Unmap the target. */
|
||||
PageTableEntry *dst_entry = this->GetMappingEntry(dst_virt_addr, block_size);
|
||||
const auto dst_saved = *dst_entry;
|
||||
for (size_t i = 0; i < num_mappings; i++) {
|
||||
dst_entry[i] = InvalidPageTableEntry;
|
||||
}
|
||||
|
||||
/* Invalidate the entire tlb. */
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
cpu::InvalidateEntireTlb();
|
||||
|
||||
/* Copy data, if we should. */
|
||||
const u64 negative_block_size_for_mask = static_cast<u64>(-static_cast<s64>(block_size));
|
||||
const u64 offset_mask = negative_block_size_for_mask & ((1ul << 48) - 1);
|
||||
const KVirtualAddress copy_src_addr = KVirtualAddress(src_saved.GetRawAttributesUnsafeForSwap() & offset_mask);
|
||||
const KVirtualAddress copy_dst_addr = KVirtualAddress(dst_saved.GetRawAttributesUnsafeForSwap() & offset_mask);
|
||||
if (block_size && do_copy) {
|
||||
u8 tmp[0x100];
|
||||
for (size_t ofs = 0; ofs < block_size; ofs += sizeof(tmp)) {
|
||||
std::memcpy(tmp, GetVoidPointer(copy_src_addr + ofs), sizeof(tmp));
|
||||
std::memcpy(GetVoidPointer(copy_src_addr + ofs), GetVoidPointer(copy_dst_addr + ofs), sizeof(tmp));
|
||||
std::memcpy(GetVoidPointer(copy_dst_addr + ofs), tmp, sizeof(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
/* Swap the mappings. */
|
||||
const u64 attr_preserve_mask = (negative_block_size_for_mask | 0xFFFF000000000000ul) ^ ((1ul << 48) - 1);
|
||||
const size_t shift_for_contig = contig ? 4 : 0;
|
||||
size_t advanced_size = 0;
|
||||
const u64 src_attr_val = src_saved.GetRawAttributesUnsafeForSwap() & attr_preserve_mask;
|
||||
const u64 dst_attr_val = dst_saved.GetRawAttributesUnsafeForSwap() & attr_preserve_mask;
|
||||
for (size_t i = 0; i < num_mappings; i++) {
|
||||
reinterpret_cast<u64 *>(src_entry)[i] = GetInteger(copy_dst_addr + (advanced_size >> shift_for_contig)) | src_attr_val;
|
||||
reinterpret_cast<u64 *>(dst_entry)[i] = GetInteger(copy_src_addr + (advanced_size >> shift_for_contig)) | dst_attr_val;
|
||||
advanced_size += block_size;
|
||||
}
|
||||
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
void NOINLINE PhysicallyRandomize(KVirtualAddress virt_addr, size_t size, size_t block_size, bool do_copy) {
|
||||
const size_t block_count = this->GetBlockCount(virt_addr, size, block_size);
|
||||
if (block_count > 1) {
|
||||
for (size_t cur_block = 0; cur_block < block_count; cur_block++) {
|
||||
const size_t target_block = KSystemControl::Init::GenerateRandomRange(cur_block, block_count - 1);
|
||||
if (cur_block != target_block) {
|
||||
const KVirtualAddress cur_virt_addr = this->GetBlockByIndex(virt_addr, size, block_size, cur_block);
|
||||
const KVirtualAddress target_virt_addr = this->GetBlockByIndex(virt_addr, size, block_size, target_block);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(cur_virt_addr != Null<KVirtualAddress>);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(target_virt_addr != Null<KVirtualAddress>);
|
||||
this->SwapBlocks(cur_virt_addr, target_virt_addr, block_size, do_copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, IPageAllocator &allocator) {
|
||||
/* Ensure that addresses and sizes are page aligned. */
|
||||
@@ -76,8 +291,8 @@ namespace ams::kern::arch::arm64::init {
|
||||
L1PageTableEntry *l1_entry = GetL1Entry(this->l1_table, virt_addr);
|
||||
|
||||
/* Can we make an L1 block? */
|
||||
if (util::IsAligned(GetInteger(virt_addr), L1BlockSize) && util::IsAligned(GetInteger(phys_addr), L1BlockSize) && util::IsAligned(size, L1BlockSize)) {
|
||||
*l1_entry = L1PageTableEntry(phys_addr, attr, false);
|
||||
if (util::IsAligned(GetInteger(virt_addr), L1BlockSize) && util::IsAligned(GetInteger(phys_addr), L1BlockSize) && size >= L1BlockSize) {
|
||||
*l1_entry = L1PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, false);
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
virt_addr += L1BlockSize;
|
||||
@@ -90,16 +305,16 @@ namespace ams::kern::arch::arm64::init {
|
||||
if (!l1_entry->IsTable()) {
|
||||
KPhysicalAddress new_table = allocator.Allocate();
|
||||
ClearNewPageTable(new_table);
|
||||
*l1_entry = L1PageTableEntry(new_table, attr.IsPrivilegedExecuteNever());
|
||||
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
|
||||
|
||||
/* Can we make a contiguous L2 block? */
|
||||
if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && util::IsAligned(size, L2ContiguousBlockSize)) {
|
||||
if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && size >= L2ContiguousBlockSize) {
|
||||
for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
|
||||
l2_entry[i] = L2PageTableEntry(phys_addr, attr, true);
|
||||
l2_entry[i] = L2PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, true);
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
virt_addr += L2BlockSize;
|
||||
@@ -110,8 +325,8 @@ namespace ams::kern::arch::arm64::init {
|
||||
}
|
||||
|
||||
/* Can we make an L2 block? */
|
||||
if (util::IsAligned(GetInteger(virt_addr), L2BlockSize) && util::IsAligned(GetInteger(phys_addr), L2BlockSize) && util::IsAligned(size, L2BlockSize)) {
|
||||
*l2_entry = L2PageTableEntry(phys_addr, attr, false);
|
||||
if (util::IsAligned(GetInteger(virt_addr), L2BlockSize) && util::IsAligned(GetInteger(phys_addr), L2BlockSize) && size >= L2BlockSize) {
|
||||
*l2_entry = L2PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, false);
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
virt_addr += L2BlockSize;
|
||||
@@ -124,16 +339,16 @@ namespace ams::kern::arch::arm64::init {
|
||||
if (!l2_entry->IsTable()) {
|
||||
KPhysicalAddress new_table = allocator.Allocate();
|
||||
ClearNewPageTable(new_table);
|
||||
*l2_entry = L2PageTableEntry(new_table, attr.IsPrivilegedExecuteNever());
|
||||
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
|
||||
|
||||
/* Can we make a contiguous L3 block? */
|
||||
if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && util::IsAligned(size, L3ContiguousBlockSize)) {
|
||||
if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && size >= L3ContiguousBlockSize) {
|
||||
for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) {
|
||||
l3_entry[i] = L3PageTableEntry(phys_addr, attr, true);
|
||||
l3_entry[i] = L3PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, true);
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
virt_addr += L3BlockSize;
|
||||
@@ -144,7 +359,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
}
|
||||
|
||||
/* Make an L3 block. */
|
||||
*l3_entry = L3PageTableEntry(phys_addr, attr, false);
|
||||
*l3_entry = L3PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, false);
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
virt_addr += L3BlockSize;
|
||||
phys_addr += L3BlockSize;
|
||||
@@ -179,6 +394,77 @@ namespace ams::kern::arch::arm64::init {
|
||||
return l3_entry->GetBlock() + (GetInteger(virt_addr) & (L3BlockSize - 1));
|
||||
}
|
||||
|
||||
KPhysicalAddress GetPhysicalAddressOfRandomizedRange(KVirtualAddress virt_addr, size_t size) const {
|
||||
/* Define tracking variables for ourselves to use. */
|
||||
KPhysicalAddress min_phys_addr = Null<KPhysicalAddress>;
|
||||
KPhysicalAddress max_phys_addr = Null<KPhysicalAddress>;
|
||||
|
||||
/* Ensure the range we're querying is valid. */
|
||||
const KVirtualAddress end_virt_addr = virt_addr + size;
|
||||
if (virt_addr > end_virt_addr) {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(size == 0);
|
||||
return min_phys_addr;
|
||||
}
|
||||
|
||||
auto UpdateExtents = [&](const KPhysicalAddress block, size_t block_size) ALWAYS_INLINE_LAMBDA {
|
||||
/* Ensure that we are allowed to have the block here. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), block_size));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(block_size <= GetInteger(end_virt_addr) - GetInteger(virt_addr));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(block), block_size));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(size >= block_size);
|
||||
|
||||
const KPhysicalAddress block_end = block + block_size;
|
||||
|
||||
/* We want to update min phys addr when it's 0 or > block. */
|
||||
/* This is equivalent in two's complement to (n - 1) >= block. */
|
||||
if ((GetInteger(min_phys_addr) - 1) >= GetInteger(block)) {
|
||||
min_phys_addr = block;
|
||||
}
|
||||
|
||||
/* Update max phys addr when it's 0 or < block_end. */
|
||||
if (GetInteger(max_phys_addr) < GetInteger(block_end) || GetInteger(max_phys_addr) == 0) {
|
||||
max_phys_addr = block_end;
|
||||
}
|
||||
|
||||
/* Traverse onwards. */
|
||||
virt_addr += block_size;
|
||||
};
|
||||
|
||||
while (virt_addr < end_virt_addr) {
|
||||
L1PageTableEntry *l1_entry = GetL1Entry(this->l1_table, virt_addr);
|
||||
|
||||
/* If an L1 block is mapped, update. */
|
||||
if (l1_entry->IsBlock()) {
|
||||
UpdateExtents(l1_entry->GetBlock(), L1BlockSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Not a block, so we must have a table. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsTable());
|
||||
|
||||
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
|
||||
if (l2_entry->IsBlock()) {
|
||||
UpdateExtents(l2_entry->GetBlock(), l2_entry->IsContiguous() ? L2ContiguousBlockSize : L2BlockSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Not a block, so we must have a table. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsTable());
|
||||
|
||||
/* We must have a mapped l3 entry to inspect. */
|
||||
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsBlock());
|
||||
|
||||
UpdateExtents(l3_entry->GetBlock(), l3_entry->IsContiguous() ? L3ContiguousBlockSize : L3BlockSize);
|
||||
}
|
||||
|
||||
/* Ensure we got the right range. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(GetInteger(max_phys_addr) - GetInteger(min_phys_addr) == size);
|
||||
|
||||
/* Write the address that we found. */
|
||||
return min_phys_addr;
|
||||
}
|
||||
|
||||
bool IsFree(KVirtualAddress virt_addr, size_t size) {
|
||||
/* Ensure that addresses and sizes are page aligned. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize));
|
||||
@@ -242,7 +528,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
/* Ensure that we are allowed to have an L1 block here. */
|
||||
const KPhysicalAddress block = l1_entry->GetBlock();
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L1BlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(size, L1BlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(size >= L1BlockSize);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsCompatibleWithAttribute(attr_before, false));
|
||||
|
||||
/* Invalidate the existing L1 block. */
|
||||
@@ -251,7 +537,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
cpu::InvalidateEntireTlb();
|
||||
|
||||
/* Create new L1 block. */
|
||||
*l1_entry = L1PageTableEntry(block, attr_after, false);
|
||||
*l1_entry = L1PageTableEntry(PageTableEntry::BlockTag{}, block, attr_after, false);
|
||||
|
||||
virt_addr += L1BlockSize;
|
||||
size -= L1BlockSize;
|
||||
@@ -269,7 +555,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
/* Ensure that we are allowed to have a contiguous L2 block here. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(block), L2ContiguousBlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(size, L2ContiguousBlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(size >= L2ContiguousBlockSize);
|
||||
|
||||
/* Invalidate the existing contiguous L2 block. */
|
||||
for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
|
||||
@@ -282,7 +568,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
|
||||
/* Create a new contiguous L2 block. */
|
||||
for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
|
||||
l2_entry[i] = L2PageTableEntry(block + L2BlockSize * i, attr_after, true);
|
||||
l2_entry[i] = L2PageTableEntry(PageTableEntry::BlockTag{}, block + L2BlockSize * i, attr_after, true);
|
||||
}
|
||||
|
||||
virt_addr += L2ContiguousBlockSize;
|
||||
@@ -291,7 +577,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
/* Ensure that we are allowed to have an L2 block here. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L2BlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(block), L2BlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(size, L2BlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(size >= L2BlockSize);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsCompatibleWithAttribute(attr_before, false));
|
||||
|
||||
/* Invalidate the existing L2 block. */
|
||||
@@ -300,7 +586,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
cpu::InvalidateEntireTlb();
|
||||
|
||||
/* Create new L2 block. */
|
||||
*l2_entry = L2PageTableEntry(block, attr_after, false);
|
||||
*l2_entry = L2PageTableEntry(PageTableEntry::BlockTag{}, block, attr_after, false);
|
||||
|
||||
virt_addr += L2BlockSize;
|
||||
size -= L2BlockSize;
|
||||
@@ -321,7 +607,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
/* Ensure that we are allowed to have a contiguous L3 block here. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(block), L3ContiguousBlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(size, L3ContiguousBlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(size >= L3ContiguousBlockSize);
|
||||
|
||||
/* Invalidate the existing contiguous L3 block. */
|
||||
for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) {
|
||||
@@ -334,7 +620,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
|
||||
/* Create a new contiguous L3 block. */
|
||||
for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) {
|
||||
l3_entry[i] = L3PageTableEntry(block + L3BlockSize * i, attr_after, true);
|
||||
l3_entry[i] = L3PageTableEntry(PageTableEntry::BlockTag{}, block + L3BlockSize * i, attr_after, true);
|
||||
}
|
||||
|
||||
virt_addr += L3ContiguousBlockSize;
|
||||
@@ -343,7 +629,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
/* Ensure that we are allowed to have an L3 block here. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L3BlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(block), L3BlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(size, L3BlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(size >= L3BlockSize);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsCompatibleWithAttribute(attr_before, false));
|
||||
|
||||
/* Invalidate the existing L3 block. */
|
||||
@@ -352,7 +638,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
cpu::InvalidateEntireTlb();
|
||||
|
||||
/* Create new L3 block. */
|
||||
*l3_entry = L3PageTableEntry(block, attr_after, false);
|
||||
*l3_entry = L3PageTableEntry(PageTableEntry::BlockTag{}, block, attr_after, false);
|
||||
|
||||
virt_addr += L3BlockSize;
|
||||
size -= L3BlockSize;
|
||||
@@ -363,32 +649,62 @@ namespace ams::kern::arch::arm64::init {
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
void PhysicallyRandomize(KVirtualAddress virt_addr, size_t size, bool do_copy) {
|
||||
this->PhysicallyRandomize(virt_addr, size, L1BlockSize, do_copy);
|
||||
this->PhysicallyRandomize(virt_addr, size, L2ContiguousBlockSize, do_copy);
|
||||
this->PhysicallyRandomize(virt_addr, size, L2BlockSize, do_copy);
|
||||
this->PhysicallyRandomize(virt_addr, size, L3ContiguousBlockSize, do_copy);
|
||||
this->PhysicallyRandomize(virt_addr, size, L3BlockSize, do_copy);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class KInitialPageAllocator : public KInitialPageTable::IPageAllocator {
|
||||
private:
|
||||
uintptr_t next_address;
|
||||
public:
|
||||
constexpr ALWAYS_INLINE KInitialPageAllocator() : next_address(Null<uintptr_t>) { /* ... */ }
|
||||
struct State {
|
||||
uintptr_t next_address;
|
||||
uintptr_t free_bitmap;
|
||||
};
|
||||
private:
|
||||
State state;
|
||||
public:
|
||||
constexpr ALWAYS_INLINE KInitialPageAllocator() : state{} { /* ... */ }
|
||||
|
||||
ALWAYS_INLINE void Initialize(uintptr_t address) {
|
||||
this->next_address = address;
|
||||
this->state.next_address = address + BITSIZEOF(this->state.free_bitmap) * PageSize;
|
||||
this->state.free_bitmap = ~uintptr_t();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE uintptr_t GetFinalNextAddress() {
|
||||
const uintptr_t final_address = this->next_address;
|
||||
this->next_address = Null<uintptr_t>;
|
||||
return final_address;
|
||||
ALWAYS_INLINE void InitializeFromState(uintptr_t state_val) {
|
||||
if (kern::GetTargetFirmware() >= kern::TargetFirmware_10_0_0) {
|
||||
this->state = *reinterpret_cast<State *>(state_val);
|
||||
} else {
|
||||
this->state.next_address = state_val;
|
||||
this->state.free_bitmap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE uintptr_t GetFinalState() {
|
||||
return this->GetFinalNextAddress();
|
||||
ALWAYS_INLINE void GetFinalState(State *out) {
|
||||
*out = this->state;
|
||||
this->state = {};
|
||||
}
|
||||
public:
|
||||
virtual KPhysicalAddress Allocate() override {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(this->next_address != Null<uintptr_t>);
|
||||
const uintptr_t allocated = this->next_address;
|
||||
this->next_address += PageSize;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(this->state.next_address != Null<uintptr_t>);
|
||||
uintptr_t allocated = this->state.next_address;
|
||||
if (this->state.free_bitmap != 0) {
|
||||
u64 index;
|
||||
uintptr_t mask;
|
||||
do {
|
||||
index = KSystemControl::Init::GenerateRandomRange(0, BITSIZEOF(this->state.free_bitmap) - 1);
|
||||
mask = (static_cast<uintptr_t>(1) << index);
|
||||
} while ((this->state.free_bitmap & mask) == 0);
|
||||
this->state.free_bitmap &= ~mask;
|
||||
allocated = this->state.next_address - ((BITSIZEOF(this->state.free_bitmap) - index) * PageSize);
|
||||
} else {
|
||||
this->state.next_address += PageSize;
|
||||
}
|
||||
|
||||
std::memset(reinterpret_cast<void *>(allocated), 0, PageSize);
|
||||
return allocated;
|
||||
}
|
||||
|
||||
@@ -156,6 +156,7 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
void ClearPageToZeroImpl(void *);
|
||||
void FlushEntireDataCacheSharedForInit();
|
||||
void FlushEntireDataCacheLocalForInit();
|
||||
void StoreEntireCacheForInit();
|
||||
|
||||
void FlushEntireDataCache();
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace ams::kern::arch::arm64 {
|
||||
private:
|
||||
constexpr PageTableEntry GetEntryTemplate(const KPageProperties properties) const {
|
||||
/* Set basic attributes. */
|
||||
PageTableEntry entry;
|
||||
PageTableEntry entry{PageTableEntry::ExtensionFlag_Valid};
|
||||
entry.SetPrivilegedExecuteNever(true);
|
||||
entry.SetAccessFlag(PageTableEntry::AccessFlag_Accessed);
|
||||
entry.SetShareable(PageTableEntry::Shareable_InnerShareable);
|
||||
@@ -163,6 +163,9 @@ namespace ams::kern::arch::arm64 {
|
||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
/* Set the fault bit based on whether the page is mapped. */
|
||||
entry.SetMapped((properties.perm & KMemoryPermission_NotMapped) == 0);
|
||||
|
||||
return entry;
|
||||
}
|
||||
public:
|
||||
@@ -258,8 +261,6 @@ namespace ams::kern::arch::arm64 {
|
||||
}
|
||||
}
|
||||
|
||||
ClearPageTable(table);
|
||||
|
||||
MESOSPHERE_ASSERT(this->GetPageTableManager().GetRefCount(table) == 0);
|
||||
|
||||
return table;
|
||||
|
||||
@@ -30,6 +30,8 @@ namespace ams::kern::arch::arm64 {
|
||||
class PageTableEntry {
|
||||
public:
|
||||
struct InvalidTag{};
|
||||
struct TableTag{};
|
||||
struct BlockTag{};
|
||||
|
||||
enum Permission : u64 {
|
||||
Permission_KernelRWX = ((0ul << 53) | (1ul << 54) | (0ul << 6)),
|
||||
@@ -62,13 +64,26 @@ namespace ams::kern::arch::arm64 {
|
||||
AccessFlag_Accessed = (1 << 10),
|
||||
};
|
||||
|
||||
enum MappingFlag : u64 {
|
||||
MappingFlag_NotMapped = (0 << 0),
|
||||
MappingFlag_Mapped = (1 << 0),
|
||||
};
|
||||
|
||||
enum ExtensionFlag : u64 {
|
||||
ExtensionFlag_NotContiguous = (1ul << 55),
|
||||
ExtensionFlag_Valid = (1ul << 56),
|
||||
|
||||
ExtensionFlag_ValidAndMapped = (ExtensionFlag_Valid | MappingFlag_Mapped),
|
||||
ExtensionFlag_TestTableMask = (ExtensionFlag_Valid | (1ul << 1)),
|
||||
};
|
||||
|
||||
enum Type : u64 {
|
||||
Type_None = 0x0,
|
||||
Type_L1Block = 0x1,
|
||||
Type_L1Table = 0x3,
|
||||
Type_L2Block = 0x1,
|
||||
Type_L2Table = 0x3,
|
||||
Type_L3Block = 0x3,
|
||||
Type_L1Block = ExtensionFlag_Valid,
|
||||
Type_L1Table = 0x2,
|
||||
Type_L2Block = ExtensionFlag_Valid,
|
||||
Type_L2Table = 0x2,
|
||||
Type_L3Block = ExtensionFlag_TestTableMask,
|
||||
};
|
||||
|
||||
enum ContigType : u64 {
|
||||
@@ -79,17 +94,17 @@ namespace ams::kern::arch::arm64 {
|
||||
u64 attributes;
|
||||
public:
|
||||
/* Take in a raw attribute. */
|
||||
constexpr ALWAYS_INLINE PageTableEntry() : attributes() { /* ... */ }
|
||||
constexpr ALWAYS_INLINE PageTableEntry(u64 attr) : attributes(attr) { /* ... */ }
|
||||
constexpr explicit ALWAYS_INLINE PageTableEntry() : attributes() { /* ... */ }
|
||||
constexpr explicit ALWAYS_INLINE PageTableEntry(u64 attr) : attributes(attr) { /* ... */ }
|
||||
|
||||
constexpr ALWAYS_INLINE PageTableEntry(InvalidTag) : attributes(0) { /* ... */ }
|
||||
constexpr explicit ALWAYS_INLINE PageTableEntry(InvalidTag) : attributes(0) { /* ... */ }
|
||||
|
||||
/* Extend a previous attribute. */
|
||||
constexpr ALWAYS_INLINE PageTableEntry(const PageTableEntry &rhs, u64 new_attr) : attributes(rhs.attributes | new_attr) { /* ... */ }
|
||||
constexpr explicit ALWAYS_INLINE PageTableEntry(const PageTableEntry &rhs, u64 new_attr) : attributes(rhs.attributes | new_attr) { /* ... */ }
|
||||
|
||||
/* Construct a new attribute. */
|
||||
constexpr ALWAYS_INLINE PageTableEntry(Permission perm, PageAttribute p_a, Shareable share)
|
||||
: attributes(static_cast<u64>(perm) | static_cast<u64>(AccessFlag_Accessed) | static_cast<u64>(p_a) | static_cast<u64>(share))
|
||||
constexpr explicit ALWAYS_INLINE PageTableEntry(Permission perm, PageAttribute p_a, Shareable share, MappingFlag m)
|
||||
: attributes(static_cast<u64>(perm) | static_cast<u64>(AccessFlag_Accessed) | static_cast<u64>(p_a) | static_cast<u64>(share) | static_cast<u64>(ExtensionFlag_Valid) | static_cast<u64>(m))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
@@ -123,7 +138,7 @@ namespace ams::kern::arch::arm64 {
|
||||
}
|
||||
}
|
||||
public:
|
||||
constexpr ALWAYS_INLINE bool IsContiguousAllowed() const { return this->GetBits(55, 1) != 0; }
|
||||
constexpr ALWAYS_INLINE bool IsContiguousAllowed() const { return this->GetBits(55, 1) == 0; }
|
||||
constexpr ALWAYS_INLINE bool IsUserExecuteNever() const { return this->GetBits(54, 1) != 0; }
|
||||
constexpr ALWAYS_INLINE bool IsPrivilegedExecuteNever() const { return this->GetBits(53, 1) != 0; }
|
||||
constexpr ALWAYS_INLINE bool IsContiguous() const { return this->GetBits(52, 1) != 0; }
|
||||
@@ -134,8 +149,10 @@ namespace ams::kern::arch::arm64 {
|
||||
constexpr ALWAYS_INLINE bool IsReadOnly() const { return this->GetBits(7, 1) != 0; }
|
||||
constexpr ALWAYS_INLINE bool IsUserAccessible() const { return this->GetBits(6, 1) != 0; }
|
||||
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBits(5, 1) != 0; }
|
||||
constexpr ALWAYS_INLINE bool IsBlock() const { return this->GetBits(0, 2) == 0x1; }
|
||||
constexpr ALWAYS_INLINE bool IsTable() const { return this->GetBits(0, 2) == 0x3; }
|
||||
constexpr ALWAYS_INLINE bool IsBlock() const { return (this->attributes & ExtensionFlag_TestTableMask) == ExtensionFlag_Valid; }
|
||||
constexpr ALWAYS_INLINE bool IsTable() const { return (this->attributes & ExtensionFlag_TestTableMask) == 2; }
|
||||
constexpr ALWAYS_INLINE bool IsEmpty() const { return (this->attributes & ExtensionFlag_TestTableMask) == 0; }
|
||||
constexpr ALWAYS_INLINE bool IsMapped() const { return this->GetBits(0, 1) != 0; }
|
||||
|
||||
constexpr ALWAYS_INLINE decltype(auto) SetContiguousAllowed(bool en) { this->SetBit(55, !en); return *this; }
|
||||
constexpr ALWAYS_INLINE decltype(auto) SetUserExecuteNever(bool en) { this->SetBit(54, en); return *this; }
|
||||
@@ -147,9 +164,10 @@ namespace ams::kern::arch::arm64 {
|
||||
constexpr ALWAYS_INLINE decltype(auto) SetReadOnly(bool en) { this->SetBit(7, en); return *this; }
|
||||
constexpr ALWAYS_INLINE decltype(auto) SetUserAccessible(bool en) { this->SetBit(6, en); return *this; }
|
||||
constexpr ALWAYS_INLINE decltype(auto) SetPageAttribute(PageAttribute a) { this->SetBitsDirect(2, 3, a); return *this; }
|
||||
constexpr ALWAYS_INLINE decltype(auto) SetMapped(bool m) { static_assert(static_cast<u64>(MappingFlag_Mapped == (1 << 0))); this->SetBit(0, m); return *this; }
|
||||
|
||||
constexpr ALWAYS_INLINE u64 GetEntryTemplate() const {
|
||||
constexpr u64 Mask = (0xFFF0000000000FFFul & ~u64(0x3ul | (0x1ul << 52)));
|
||||
constexpr u64 Mask = (0xFFF0000000000FFFul & ~u64((0x1ul << 52) | ExtensionFlag_TestTableMask));
|
||||
return this->attributes & Mask;
|
||||
}
|
||||
|
||||
@@ -157,6 +175,10 @@ namespace ams::kern::arch::arm64 {
|
||||
return this->attributes == attr;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE u64 GetRawAttributesUnsafeForSwap() const {
|
||||
return this->attributes;
|
||||
}
|
||||
|
||||
protected:
|
||||
constexpr ALWAYS_INLINE u64 GetRawAttributes() const {
|
||||
return this->attributes;
|
||||
@@ -171,22 +193,22 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
class L1PageTableEntry : public PageTableEntry {
|
||||
public:
|
||||
constexpr ALWAYS_INLINE L1PageTableEntry(InvalidTag) : PageTableEntry(InvalidTag{}) { /* ... */ }
|
||||
constexpr explicit ALWAYS_INLINE L1PageTableEntry(InvalidTag) : PageTableEntry(InvalidTag{}) { /* ... */ }
|
||||
|
||||
constexpr ALWAYS_INLINE L1PageTableEntry(KPhysicalAddress phys_addr, bool pxn)
|
||||
constexpr explicit ALWAYS_INLINE L1PageTableEntry(TableTag, KPhysicalAddress phys_addr, bool pxn)
|
||||
: PageTableEntry((0x3ul << 60) | (static_cast<u64>(pxn) << 59) | GetInteger(phys_addr) | 0x3)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE L1PageTableEntry(KPhysicalAddress phys_addr, bool is_kernel, bool pxn)
|
||||
constexpr explicit ALWAYS_INLINE L1PageTableEntry(TableTag, KPhysicalAddress phys_addr, bool is_kernel, bool pxn)
|
||||
: PageTableEntry(((is_kernel ? 0x3ul : 0) << 60) | (static_cast<u64>(pxn) << 59) | GetInteger(phys_addr) | 0x3)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE L1PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
||||
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x1)
|
||||
constexpr explicit ALWAYS_INLINE L1PageTableEntry(BlockTag, KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
||||
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | PageTableEntry::ExtensionFlag_Valid)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
@@ -210,28 +232,28 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
constexpr ALWAYS_INLINE bool IsCompatibleWithAttribute(const PageTableEntry &rhs, bool contig) const {
|
||||
/* Check whether this has the same permission/etc as the desired attributes. */
|
||||
return L1PageTableEntry(this->GetBlock(), rhs, contig).GetRawAttributes() == this->GetRawAttributes();
|
||||
return L1PageTableEntry(BlockTag{}, this->GetBlock(), rhs, contig).GetRawAttributes() == this->GetRawAttributes();
|
||||
}
|
||||
};
|
||||
|
||||
class L2PageTableEntry : public PageTableEntry {
|
||||
public:
|
||||
constexpr ALWAYS_INLINE L2PageTableEntry(InvalidTag) : PageTableEntry(InvalidTag{}) { /* ... */ }
|
||||
constexpr explicit ALWAYS_INLINE L2PageTableEntry(InvalidTag) : PageTableEntry(InvalidTag{}) { /* ... */ }
|
||||
|
||||
constexpr ALWAYS_INLINE L2PageTableEntry(KPhysicalAddress phys_addr, bool pxn)
|
||||
constexpr explicit ALWAYS_INLINE L2PageTableEntry(TableTag, KPhysicalAddress phys_addr, bool pxn)
|
||||
: PageTableEntry((0x3ul << 60) | (static_cast<u64>(pxn) << 59) | GetInteger(phys_addr) | 0x3)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE L2PageTableEntry(KPhysicalAddress phys_addr, bool is_kernel, bool pxn)
|
||||
constexpr explicit ALWAYS_INLINE L2PageTableEntry(TableTag, KPhysicalAddress phys_addr, bool is_kernel, bool pxn)
|
||||
: PageTableEntry(((is_kernel ? 0x3ul : 0) << 60) | (static_cast<u64>(pxn) << 59) | GetInteger(phys_addr) | 0x3)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE L2PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
||||
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x1)
|
||||
constexpr explicit ALWAYS_INLINE L2PageTableEntry(BlockTag, KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
||||
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | PageTableEntry::ExtensionFlag_Valid)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
@@ -255,21 +277,21 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
constexpr ALWAYS_INLINE bool IsCompatibleWithAttribute(const PageTableEntry &rhs, bool contig) const {
|
||||
/* Check whether this has the same permission/etc as the desired attributes. */
|
||||
return L2PageTableEntry(this->GetBlock(), rhs, contig).GetRawAttributes() == this->GetRawAttributes();
|
||||
return L2PageTableEntry(BlockTag{}, this->GetBlock(), rhs, contig).GetRawAttributes() == this->GetRawAttributes();
|
||||
}
|
||||
};
|
||||
|
||||
class L3PageTableEntry : public PageTableEntry {
|
||||
public:
|
||||
constexpr ALWAYS_INLINE L3PageTableEntry(InvalidTag) : PageTableEntry(InvalidTag{}) { /* ... */ }
|
||||
constexpr explicit ALWAYS_INLINE L3PageTableEntry(InvalidTag) : PageTableEntry(InvalidTag{}) { /* ... */ }
|
||||
|
||||
constexpr ALWAYS_INLINE L3PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
||||
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x3)
|
||||
constexpr explicit ALWAYS_INLINE L3PageTableEntry(BlockTag, KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
||||
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | static_cast<u64>(ExtensionFlag_TestTableMask))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE bool IsBlock() const { return this->GetBits(0, 2) == 0x3; }
|
||||
constexpr ALWAYS_INLINE bool IsBlock() const { return (GetRawAttributes() & ExtensionFlag_TestTableMask) == ExtensionFlag_TestTableMask; }
|
||||
|
||||
constexpr ALWAYS_INLINE KPhysicalAddress GetBlock() const {
|
||||
return this->SelectBits(12, 36);
|
||||
@@ -277,7 +299,7 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
constexpr ALWAYS_INLINE bool IsCompatibleWithAttribute(const PageTableEntry &rhs, bool contig) const {
|
||||
/* Check whether this has the same permission/etc as the desired attributes. */
|
||||
return L3PageTableEntry(this->GetBlock(), rhs, contig).GetRawAttributes() == this->GetRawAttributes();
|
||||
return L3PageTableEntry(BlockTag{}, this->GetBlock(), rhs, contig).GetRawAttributes() == this->GetRawAttributes();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -26,27 +26,27 @@ namespace ams::kern::arch::arm64 {
|
||||
constexpr KNotAlignedSpinLock() : packed_tickets(0) { /* ... */ }
|
||||
|
||||
void Lock() {
|
||||
u32 tmp0, tmp1;
|
||||
u32 tmp0, tmp1, tmp2;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" prfm pstl1keep, %[packed_tickets]\n"
|
||||
"1:\n"
|
||||
" ldaxr %w[tmp0], %[packed_tickets]\n"
|
||||
" add %w[tmp0], %w[tmp0], #0x10000\n"
|
||||
" stxr %w[tmp1], %w[tmp0], %[packed_tickets]\n"
|
||||
" add %w[tmp2], %w[tmp0], #0x10000\n"
|
||||
" stxr %w[tmp1], %w[tmp2], %[packed_tickets]\n"
|
||||
" cbnz %w[tmp1], 1b\n"
|
||||
" \n"
|
||||
" and %w[tmp1], %w[tmp0], #0xFFFF\n"
|
||||
" cmp %w[tmp1], %w[tmp0], lsr #16\n"
|
||||
" b.eq done"
|
||||
" b.eq 3f\n"
|
||||
" sevl\n"
|
||||
"2:\n"
|
||||
" wfe\n"
|
||||
" ldaxrh %w[tmp1], %[packed_tickets]\n"
|
||||
" cmp %w[tmp1], %w[tmp0], lsr #16\n"
|
||||
" b.ne 2b\n"
|
||||
"done:\n"
|
||||
: [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [packed_tickets]"+Q"(this->packed_tickets)
|
||||
"3:\n"
|
||||
: [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [tmp2]"=&r"(tmp2), [packed_tickets]"+Q"(this->packed_tickets)
|
||||
:
|
||||
: "cc", "memory"
|
||||
);
|
||||
@@ -106,6 +106,6 @@ namespace ams::kern::arch::arm64 {
|
||||
};
|
||||
static_assert(sizeof(KAlignedSpinLock) == 2 * cpu::DataCacheLineSize);
|
||||
|
||||
using KSpinLock = KAlignedSpinLock;
|
||||
using KSpinLock = KNotAlignedSpinLock;
|
||||
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||
/* Randomness. */
|
||||
static void GenerateRandomBytes(void *dst, size_t size);
|
||||
static u64 GenerateRandomRange(u64 min, u64 max);
|
||||
static u64 GenerateRandomU64();
|
||||
|
||||
/* Privileged Access. */
|
||||
static void ReadWriteRegisterPrivileged(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value);
|
||||
|
||||
@@ -20,6 +20,24 @@ namespace ams::kern {
|
||||
|
||||
constexpr size_t PageSize = 4_KB;
|
||||
|
||||
enum TargetFirmware : u32 {
|
||||
TargetFirmware_1_0_0 = ATMOSPHERE_TARGET_FIRMWARE_100,
|
||||
TargetFirmware_2_0_0 = ATMOSPHERE_TARGET_FIRMWARE_200,
|
||||
TargetFirmware_3_0_0 = ATMOSPHERE_TARGET_FIRMWARE_300,
|
||||
TargetFirmware_4_0_0 = ATMOSPHERE_TARGET_FIRMWARE_400,
|
||||
TargetFirmware_5_0_0 = ATMOSPHERE_TARGET_FIRMWARE_500,
|
||||
TargetFirmware_6_0_0 = ATMOSPHERE_TARGET_FIRMWARE_600,
|
||||
TargetFirmware_6_2_0 = ATMOSPHERE_TARGET_FIRMWARE_620,
|
||||
TargetFirmware_7_0_0 = ATMOSPHERE_TARGET_FIRMWARE_700,
|
||||
TargetFirmware_8_0_0 = ATMOSPHERE_TARGET_FIRMWARE_800,
|
||||
TargetFirmware_8_1_0 = ATMOSPHERE_TARGET_FIRMWARE_810,
|
||||
TargetFirmware_9_0_0 = ATMOSPHERE_TARGET_FIRMWARE_900,
|
||||
TargetFirmware_9_1_0 = ATMOSPHERE_TARGET_FIRMWARE_910,
|
||||
TargetFirmware_10_0_0 = ATMOSPHERE_TARGET_FIRMWARE_1000,
|
||||
};
|
||||
|
||||
TargetFirmware GetTargetFirmware();
|
||||
|
||||
}
|
||||
|
||||
#if 1 || defined(AMS_BUILD_FOR_AUDITING)
|
||||
|
||||
@@ -204,9 +204,9 @@ namespace ams::kern {
|
||||
u8 irq_access_flags[IrqFlagCount]{};
|
||||
u64 core_mask{};
|
||||
u64 priority_mask{};
|
||||
util::BitPack32 debug_capabilities;
|
||||
util::BitPack32 debug_capabilities{0};
|
||||
s32 handle_table_size{};
|
||||
util::BitPack32 intended_kernel_version;
|
||||
util::BitPack32 intended_kernel_version{0};
|
||||
u32 program_type{};
|
||||
private:
|
||||
static constexpr ALWAYS_INLINE void SetSvcAllowedImpl(u8 *data, u32 id) {
|
||||
@@ -254,7 +254,7 @@ namespace ams::kern {
|
||||
Result SetCapability(const util::BitPack32 cap, u32 &set_flags, u32 &set_svc, KProcessPageTable *page_table);
|
||||
Result SetCapabilities(const u32 *caps, s32 num_caps, KProcessPageTable *page_table);
|
||||
public:
|
||||
constexpr KCapabilities() : debug_capabilities(0), intended_kernel_version(0) { /* ... */ }
|
||||
constexpr KCapabilities() = default;
|
||||
|
||||
Result Initialize(const u32 *caps, s32 num_caps, KProcessPageTable *page_table);
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <mesosphere/kern_common.hpp>
|
||||
#include <mesosphere/kern_k_spin_lock.hpp>
|
||||
#include <mesosphere/kern_k_slab_heap.hpp>
|
||||
#include <mesosphere/kern_k_page_group.hpp>
|
||||
#include <mesosphere/kern_k_memory_block.hpp>
|
||||
#include <mesosphere/kern_k_page_bitmap.hpp>
|
||||
#include <mesosphere/kern_select_interrupt_manager.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
class KDynamicPageManager {
|
||||
public:
|
||||
class PageBuffer {
|
||||
private:
|
||||
u8 buffer[PageSize];
|
||||
};
|
||||
static_assert(sizeof(PageBuffer) == PageSize);
|
||||
private:
|
||||
KSpinLock lock;
|
||||
KPageBitmap page_bitmap;
|
||||
size_t used;
|
||||
size_t peak;
|
||||
size_t count;
|
||||
KVirtualAddress address;
|
||||
size_t size;
|
||||
public:
|
||||
KDynamicPageManager() : lock(), page_bitmap(), used(), peak(), count(), address(), size() { /* ... */ }
|
||||
|
||||
Result Initialize(KVirtualAddress memory, size_t sz) {
|
||||
/* We need to have positive size. */
|
||||
R_UNLESS(sz > 0, svc::ResultOutOfMemory());
|
||||
|
||||
/* Calculate metadata overhead. */
|
||||
const size_t metadata_size = KPageBitmap::CalculateMetadataOverheadSize(sz / sizeof(PageBuffer));
|
||||
const size_t allocatable_size = sz - metadata_size;
|
||||
|
||||
/* Set tracking fields. */
|
||||
this->address = memory;
|
||||
this->size = util::AlignDown(allocatable_size, sizeof(PageBuffer));
|
||||
this->count = allocatable_size / sizeof(PageBuffer);
|
||||
R_UNLESS(this->count > 0, svc::ResultOutOfMemory());
|
||||
|
||||
/* Clear the metadata region. */
|
||||
u64 *metadata_ptr = GetPointer<u64>(this->address + allocatable_size);
|
||||
std::memset(metadata_ptr, 0, metadata_size);
|
||||
|
||||
/* Initialize the bitmap. */
|
||||
this->page_bitmap.Initialize(metadata_ptr, this->count);
|
||||
|
||||
/* Free the pages to the bitmap. */
|
||||
std::memset(GetPointer<PageBuffer>(this->address), 0, this->count * sizeof(PageBuffer));
|
||||
for (size_t i = 0; i < this->count; i++) {
|
||||
this->page_bitmap.SetBit(i);
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
constexpr KVirtualAddress GetAddress() const { return this->address; }
|
||||
constexpr size_t GetSize() const { return this->size; }
|
||||
constexpr size_t GetUsed() const { return this->used; }
|
||||
constexpr size_t GetPeak() const { return this->peak; }
|
||||
constexpr size_t GetCount() const { return this->count; }
|
||||
|
||||
PageBuffer *Allocate() {
|
||||
/* Take the lock. */
|
||||
KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(this->lock);
|
||||
|
||||
/* Find a random free block. */
|
||||
ssize_t soffset = this->page_bitmap.FindFreeBlock(true);
|
||||
if (AMS_UNLIKELY(soffset < 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const size_t offset = static_cast<size_t>(soffset);
|
||||
|
||||
/* Update our tracking. */
|
||||
this->page_bitmap.ClearBit(offset);
|
||||
this->peak = std::max(this->peak, (++this->used));
|
||||
|
||||
return GetPointer<PageBuffer>(this->address) + offset;
|
||||
}
|
||||
|
||||
void Free(PageBuffer *pb) {
|
||||
/* Take the lock. */
|
||||
KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(this->lock);
|
||||
|
||||
/* Set the bit for the free page. */
|
||||
size_t offset = (reinterpret_cast<uintptr_t>(pb) - GetInteger(this->address)) / sizeof(PageBuffer);
|
||||
this->page_bitmap.SetBit(offset);
|
||||
|
||||
/* Decrement our used count. */
|
||||
--this->used;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -18,29 +18,20 @@
|
||||
#include <mesosphere/kern_k_slab_heap.hpp>
|
||||
#include <mesosphere/kern_k_page_group.hpp>
|
||||
#include <mesosphere/kern_k_memory_block.hpp>
|
||||
#include <mesosphere/kern_k_dynamic_page_manager.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
namespace impl {
|
||||
|
||||
class DynamicSlabHeapPage {
|
||||
private:
|
||||
u8 buffer[PageSize];
|
||||
};
|
||||
static_assert(sizeof(DynamicSlabHeapPage) == PageSize);
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class KDynamicSlabHeap {
|
||||
NON_COPYABLE(KDynamicSlabHeap);
|
||||
NON_MOVEABLE(KDynamicSlabHeap);
|
||||
private:
|
||||
using Impl = impl::KSlabHeapImpl;
|
||||
using PageBuffer = impl::DynamicSlabHeapPage;
|
||||
using PageBuffer = KDynamicPageManager::PageBuffer;
|
||||
private:
|
||||
Impl impl;
|
||||
KDynamicSlabHeap<PageBuffer> *next_allocator;
|
||||
KDynamicPageManager *page_allocator;
|
||||
std::atomic<size_t> used;
|
||||
std::atomic<size_t> peak;
|
||||
std::atomic<size_t> count;
|
||||
@@ -54,7 +45,7 @@ namespace ams::kern {
|
||||
return std::addressof(this->impl);
|
||||
}
|
||||
public:
|
||||
constexpr KDynamicSlabHeap() : impl(), next_allocator(), used(), peak(), count(), address(), size() { /* ... */ }
|
||||
constexpr KDynamicSlabHeap() : impl(), page_allocator(), used(), peak(), count(), address(), size() { /* ... */ }
|
||||
|
||||
constexpr KVirtualAddress GetAddress() const { return this->address; }
|
||||
constexpr size_t GetSize() const { return this->size; }
|
||||
@@ -80,10 +71,27 @@ namespace ams::kern {
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize(KDynamicSlabHeap<PageBuffer> *next) {
|
||||
this->next_allocator = next;
|
||||
this->address = next->GetAddress();
|
||||
this->size = next->GetSize();
|
||||
void Initialize(KDynamicPageManager *page_allocator) {
|
||||
this->page_allocator = page_allocator;
|
||||
this->address = this->page_allocator->GetAddress();
|
||||
this->size = this->page_allocator->GetSize();
|
||||
}
|
||||
|
||||
void Initialize(KDynamicPageManager *page_allocator, size_t num_objects) {
|
||||
MESOSPHERE_ASSERT(page_allocator != nullptr);
|
||||
|
||||
/* Initialize members. */
|
||||
this->Initialize(page_allocator);
|
||||
|
||||
/* Allocate until we have the correct number of objects. */
|
||||
while (this->count < num_objects) {
|
||||
auto *allocated = reinterpret_cast<T *>(this->page_allocator->Allocate());
|
||||
MESOSPHERE_ABORT_UNLESS(allocated != nullptr);
|
||||
for (size_t i = 0; i < sizeof(PageBuffer) / sizeof(T); i++) {
|
||||
this->GetImpl()->Free(allocated + i);
|
||||
}
|
||||
this->count += sizeof(PageBuffer) / sizeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
T *Allocate() {
|
||||
@@ -91,8 +99,8 @@ namespace ams::kern {
|
||||
|
||||
/* If we fail to allocate, try to get a new page from our next allocator. */
|
||||
if (AMS_UNLIKELY(allocated == nullptr)) {
|
||||
if (this->next_allocator != nullptr) {
|
||||
allocated = reinterpret_cast<T *>(this->next_allocator->Allocate());
|
||||
if (this->page_allocator != nullptr) {
|
||||
allocated = reinterpret_cast<T *>(this->page_allocator->Allocate());
|
||||
if (allocated != nullptr) {
|
||||
/* If we succeeded in getting a page, free the rest to our slab. */
|
||||
for (size_t i = 1; i < sizeof(PageBuffer) / sizeof(T); i++) {
|
||||
@@ -126,7 +134,6 @@ namespace ams::kern {
|
||||
}
|
||||
};
|
||||
|
||||
class KDynamicPageManager : public KDynamicSlabHeap<impl::DynamicSlabHeapPage>{};
|
||||
class KBlockInfoManager : public KDynamicSlabHeap<KBlockInfo>{};
|
||||
class KMemoryBlockSlabManager : public KDynamicSlabHeap<KMemoryBlock>{};
|
||||
|
||||
|
||||
@@ -142,6 +142,8 @@ namespace ams::kern {
|
||||
KMemoryPermission_KernelWrite = ams::svc::MemoryPermission_Write << KMemoryPermission_KernelShift,
|
||||
KMemoryPermission_KernelExecute = ams::svc::MemoryPermission_Execute << KMemoryPermission_KernelShift,
|
||||
|
||||
KMemoryPermission_NotMapped = (1 << (2 * KMemoryPermission_KernelShift)),
|
||||
|
||||
KMemoryPermission_KernelReadWrite = KMemoryPermission_KernelRead | KMemoryPermission_KernelWrite,
|
||||
KMemoryPermission_KernelReadExecute = KMemoryPermission_KernelRead | KMemoryPermission_KernelExecute,
|
||||
|
||||
@@ -156,14 +158,13 @@ namespace ams::kern {
|
||||
};
|
||||
|
||||
constexpr KMemoryPermission ConvertToKMemoryPermission(ams::svc::MemoryPermission perm) {
|
||||
return static_cast<KMemoryPermission>((perm & KMemoryPermission_UserMask) | KMemoryPermission_KernelRead | ((perm & KMemoryPermission_UserWrite) << KMemoryPermission_KernelShift));
|
||||
return static_cast<KMemoryPermission>((perm & KMemoryPermission_UserMask) | KMemoryPermission_KernelRead | ((perm & KMemoryPermission_UserWrite) << KMemoryPermission_KernelShift) | (perm == ams::svc::MemoryPermission_None ? KMemoryPermission_NotMapped : KMemoryPermission_None));
|
||||
}
|
||||
|
||||
enum KMemoryAttribute : u8 {
|
||||
KMemoryAttribute_None = 0x00,
|
||||
KMemoryAttribute_Mask = 0x7F,
|
||||
KMemoryAttribute_All = KMemoryAttribute_Mask,
|
||||
KMemoryAttribute_DontCareMask = 0x80,
|
||||
KMemoryAttribute_UserMask = 0x7F,
|
||||
KMemoryAttribute_All = 0xFF,
|
||||
|
||||
KMemoryAttribute_Locked = ams::svc::MemoryAttribute_Locked,
|
||||
KMemoryAttribute_IpcLocked = ams::svc::MemoryAttribute_IpcLocked,
|
||||
@@ -171,9 +172,6 @@ namespace ams::kern {
|
||||
KMemoryAttribute_Uncached = ams::svc::MemoryAttribute_Uncached,
|
||||
};
|
||||
|
||||
static_assert((KMemoryAttribute_Mask & KMemoryAttribute_DontCareMask) == 0);
|
||||
static_assert(static_cast<typename std::underlying_type<KMemoryAttribute>::type>(~(KMemoryAttribute_Mask | KMemoryAttribute_DontCareMask)) == 0);
|
||||
|
||||
struct KMemoryInfo {
|
||||
uintptr_t address;
|
||||
size_t size;
|
||||
@@ -189,7 +187,7 @@ namespace ams::kern {
|
||||
.addr = this->address,
|
||||
.size = this->size,
|
||||
.state = static_cast<ams::svc::MemoryState>(this->state & KMemoryState_Mask),
|
||||
.attr = static_cast<ams::svc::MemoryAttribute>(this->attribute & KMemoryAttribute_Mask),
|
||||
.attr = static_cast<ams::svc::MemoryAttribute>(this->attribute & KMemoryAttribute_UserMask),
|
||||
.perm = static_cast<ams::svc::MemoryPermission>(this->perm & KMemoryPermission_UserMask),
|
||||
.ipc_refcount = this->ipc_lock_count,
|
||||
.device_refcount = this->device_use_count,
|
||||
@@ -297,7 +295,7 @@ namespace ams::kern {
|
||||
|
||||
constexpr bool HasProperties(KMemoryState s, KMemoryPermission p, KMemoryAttribute a) const {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
constexpr auto AttributeIgnoreMask = KMemoryAttribute_DontCareMask | KMemoryAttribute_IpcLocked | KMemoryAttribute_DeviceShared;
|
||||
constexpr auto AttributeIgnoreMask = KMemoryAttribute_IpcLocked | KMemoryAttribute_DeviceShared;
|
||||
return this->memory_state == s && this->perm == p && (this->attribute | AttributeIgnoreMask) == (a | AttributeIgnoreMask);
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ namespace ams::kern {
|
||||
KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const;
|
||||
|
||||
void Update(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr);
|
||||
void UpdateLock(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, void (KMemoryBlock::*lock_func)(KMemoryPermission new_perm), KMemoryPermission perm);
|
||||
|
||||
iterator FindIterator(KProcessAddress address) const {
|
||||
return this->memory_block_tree.find(KMemoryBlock(address, 1, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None));
|
||||
|
||||
@@ -58,11 +58,11 @@ namespace ams::kern {
|
||||
Impl *next;
|
||||
Impl *prev;
|
||||
public:
|
||||
constexpr Impl() : heap(), page_reference_counts(), metadata_region(), pool(), next(), prev() { /* ... */ }
|
||||
Impl() : heap(), page_reference_counts(), metadata_region(), pool(), next(), prev() { /* ... */ }
|
||||
|
||||
size_t Initialize(const KMemoryRegion *region, Pool pool, KVirtualAddress metadata_region, KVirtualAddress metadata_region_end);
|
||||
|
||||
KVirtualAddress AllocateBlock(s32 index) { return this->heap.AllocateBlock(index); }
|
||||
KVirtualAddress AllocateBlock(s32 index, bool random) { return this->heap.AllocateBlock(index, random); }
|
||||
void Free(KVirtualAddress addr, size_t num_pages) { this->heap.Free(addr, num_pages); }
|
||||
|
||||
void TrackAllocationForOptimizedProcess(KVirtualAddress block, size_t num_pages);
|
||||
@@ -149,8 +149,10 @@ namespace ams::kern {
|
||||
return cur->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
Result AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool optimize, bool random);
|
||||
public:
|
||||
constexpr KMemoryManager()
|
||||
KMemoryManager()
|
||||
: pool_locks(), pool_managers_head(), pool_managers_tail(), managers(), num_managers(), optimized_process_ids(), has_optimized_process()
|
||||
{
|
||||
/* ... */
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <mesosphere/kern_common.hpp>
|
||||
#include <mesosphere/kern_select_system_control.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
class KPageBitmap {
|
||||
private:
|
||||
class RandomBitGenerator {
|
||||
private:
|
||||
util::TinyMT rng;
|
||||
u32 entropy;
|
||||
u32 bits_available;
|
||||
private:
|
||||
void RefreshEntropy() {
|
||||
this->entropy = rng.GenerateRandomU32();
|
||||
this->bits_available = BITSIZEOF(this->entropy);
|
||||
}
|
||||
|
||||
bool GenerateRandomBit() {
|
||||
if (this->bits_available == 0) {
|
||||
this->RefreshEntropy();
|
||||
}
|
||||
|
||||
const bool rnd_bit = (this->entropy & 1) != 0;
|
||||
this->entropy >>= 1;
|
||||
--this->bits_available;
|
||||
return rnd_bit;
|
||||
}
|
||||
public:
|
||||
RandomBitGenerator() : rng(), entropy(), bits_available() {
|
||||
this->rng.Initialize(static_cast<u32>(KSystemControl::GenerateRandomU64()));
|
||||
}
|
||||
|
||||
size_t SelectRandomBit(u64 bitmap) {
|
||||
u64 selected = 0;
|
||||
|
||||
u64 cur_num_bits = BITSIZEOF(bitmap) / 2;
|
||||
u64 cur_mask = (1ull << cur_num_bits) - 1;
|
||||
|
||||
while (cur_num_bits) {
|
||||
const u64 low = (bitmap >> 0) & cur_mask;
|
||||
const u64 high = (bitmap >> cur_num_bits) & cur_mask;
|
||||
|
||||
bool choose_low;
|
||||
if (high == 0) {
|
||||
/* If only low val is set, choose low. */
|
||||
choose_low = true;
|
||||
} else if (low == 0) {
|
||||
/* If only high val is set, choose high. */
|
||||
choose_low = false;
|
||||
} else {
|
||||
/* If both are set, choose random. */
|
||||
choose_low = this->GenerateRandomBit();
|
||||
}
|
||||
|
||||
/* If we chose low, proceed with low. */
|
||||
if (choose_low) {
|
||||
bitmap = low;
|
||||
selected += 0;
|
||||
} else {
|
||||
bitmap = high;
|
||||
selected += cur_num_bits;
|
||||
}
|
||||
|
||||
/* Proceed. */
|
||||
cur_num_bits /= 2;
|
||||
cur_mask >>= cur_num_bits;
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
};
|
||||
public:
|
||||
static constexpr size_t MaxDepth = 4;
|
||||
private:
|
||||
u64 *bit_storages[MaxDepth];
|
||||
RandomBitGenerator rng;
|
||||
size_t num_bits;
|
||||
size_t used_depths;
|
||||
public:
|
||||
KPageBitmap() : bit_storages(), rng(), num_bits(), used_depths() { /* ... */ }
|
||||
|
||||
constexpr size_t GetNumBits() const { return this->num_bits; }
|
||||
constexpr s32 GetHighestDepthIndex() const { return static_cast<s32>(this->used_depths) - 1; }
|
||||
|
||||
u64 *Initialize(u64 *storage, size_t size) {
|
||||
/* Initially, everything is un-set. */
|
||||
this->num_bits = 0;
|
||||
|
||||
/* Calculate the needed bitmap depth. */
|
||||
this->used_depths = static_cast<size_t>(GetRequiredDepth(size));
|
||||
MESOSPHERE_ASSERT(this->used_depths <= MaxDepth);
|
||||
|
||||
/* Set the bitmap pointers. */
|
||||
for (s32 depth = this->GetHighestDepthIndex(); depth >= 0; depth--) {
|
||||
this->bit_storages[depth] = storage;
|
||||
size = util::AlignUp(size, BITSIZEOF(u64)) / BITSIZEOF(u64);
|
||||
storage += size;
|
||||
}
|
||||
|
||||
return storage;
|
||||
}
|
||||
|
||||
ssize_t FindFreeBlock(bool random) {
|
||||
uintptr_t offset = 0;
|
||||
s32 depth = 0;
|
||||
|
||||
if (random) {
|
||||
do {
|
||||
const u64 v = this->bit_storages[depth][offset];
|
||||
if (v == 0) {
|
||||
/* If depth is bigger than zero, then a previous level indicated a block was free. */
|
||||
MESOSPHERE_ASSERT(depth == 0);
|
||||
return -1;
|
||||
}
|
||||
offset = offset * BITSIZEOF(u64) + this->rng.SelectRandomBit(v);
|
||||
++depth;
|
||||
} while (depth < static_cast<s32>(this->used_depths));
|
||||
} else {
|
||||
do {
|
||||
const u64 v = this->bit_storages[depth][offset];
|
||||
if (v == 0) {
|
||||
/* If depth is bigger than zero, then a previous level indicated a block was free. */
|
||||
MESOSPHERE_ASSERT(depth == 0);
|
||||
return -1;
|
||||
}
|
||||
offset = offset * BITSIZEOF(u64) + __builtin_ctzll(v);
|
||||
++depth;
|
||||
} while (depth < static_cast<s32>(this->used_depths));
|
||||
}
|
||||
|
||||
return static_cast<ssize_t>(offset);
|
||||
}
|
||||
|
||||
void SetBit(size_t offset) {
|
||||
this->SetBit(this->GetHighestDepthIndex(), offset);
|
||||
this->num_bits++;
|
||||
}
|
||||
|
||||
void ClearBit(size_t offset) {
|
||||
this->ClearBit(this->GetHighestDepthIndex(), offset);
|
||||
this->num_bits--;
|
||||
}
|
||||
|
||||
bool ClearRange(size_t offset, size_t count) {
|
||||
s32 depth = this->GetHighestDepthIndex();
|
||||
u64 *bits = this->bit_storages[depth];
|
||||
size_t bit_ind = offset / BITSIZEOF(u64);
|
||||
if (AMS_LIKELY(count < BITSIZEOF(u64))) {
|
||||
const size_t shift = offset % BITSIZEOF(u64);
|
||||
MESOSPHERE_ASSERT(shift + count <= BITSIZEOF(u64));
|
||||
/* Check that all the bits are set. */
|
||||
const u64 mask = ((u64(1) << count) - 1) << shift;
|
||||
u64 v = bits[bit_ind];
|
||||
if ((v & mask) != mask) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Clear the bits. */
|
||||
v &= ~mask;
|
||||
bits[bit_ind] = v;
|
||||
if (v == 0) {
|
||||
this->ClearBit(depth - 1, bit_ind);
|
||||
}
|
||||
} else {
|
||||
MESOSPHERE_ASSERT(offset % BITSIZEOF(u64) == 0);
|
||||
MESOSPHERE_ASSERT(count % BITSIZEOF(u64) == 0);
|
||||
/* Check that all the bits are set. */
|
||||
size_t remaining = count;
|
||||
size_t i = 0;
|
||||
do {
|
||||
if (bits[bit_ind + i++] != ~u64(0)) {
|
||||
return false;
|
||||
}
|
||||
remaining -= BITSIZEOF(u64);
|
||||
} while (remaining > 0);
|
||||
|
||||
/* Clear the bits. */
|
||||
remaining = count;
|
||||
i = 0;
|
||||
do {
|
||||
bits[bit_ind + i] = 0;
|
||||
this->ClearBit(depth - 1, bit_ind + i);
|
||||
i++;
|
||||
remaining -= BITSIZEOF(u64);
|
||||
} while (remaining > 0);
|
||||
}
|
||||
|
||||
this->num_bits -= count;
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
void SetBit(s32 depth, size_t offset) {
|
||||
while (depth >= 0) {
|
||||
size_t ind = offset / BITSIZEOF(u64);
|
||||
size_t which = offset % BITSIZEOF(u64);
|
||||
const u64 mask = u64(1) << which;
|
||||
|
||||
u64 *bit = std::addressof(this->bit_storages[depth][ind]);
|
||||
u64 v = *bit;
|
||||
MESOSPHERE_ASSERT((v & mask) == 0);
|
||||
*bit = v | mask;
|
||||
if (v) {
|
||||
break;
|
||||
}
|
||||
offset = ind;
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
|
||||
void ClearBit(s32 depth, size_t offset) {
|
||||
while (depth >= 0) {
|
||||
size_t ind = offset / BITSIZEOF(u64);
|
||||
size_t which = offset % BITSIZEOF(u64);
|
||||
const u64 mask = u64(1) << which;
|
||||
|
||||
u64 *bit = std::addressof(this->bit_storages[depth][ind]);
|
||||
u64 v = *bit;
|
||||
MESOSPHERE_ASSERT((v & mask) != 0);
|
||||
v &= ~mask;
|
||||
*bit = v;
|
||||
if (v) {
|
||||
break;
|
||||
}
|
||||
offset = ind;
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
private:
|
||||
static constexpr s32 GetRequiredDepth(size_t region_size) {
|
||||
s32 depth = 0;
|
||||
while (true) {
|
||||
region_size /= BITSIZEOF(u64);
|
||||
depth++;
|
||||
if (region_size == 0) {
|
||||
return depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
static constexpr size_t CalculateMetadataOverheadSize(size_t region_size) {
|
||||
size_t overhead_bits = 0;
|
||||
for (s32 depth = GetRequiredDepth(region_size) - 1; depth >= 0; depth--) {
|
||||
region_size = util::AlignUp(region_size, BITSIZEOF(u64)) / BITSIZEOF(u64);
|
||||
overhead_bits += region_size;
|
||||
}
|
||||
return overhead_bits * sizeof(u64);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include <mesosphere/kern_common.hpp>
|
||||
#include <mesosphere/kern_k_page_bitmap.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
@@ -52,178 +53,13 @@ namespace ams::kern {
|
||||
private:
|
||||
class Block {
|
||||
private:
|
||||
class Bitmap {
|
||||
public:
|
||||
static constexpr size_t MaxDepth = 4;
|
||||
private:
|
||||
u64 *bit_storages[MaxDepth];
|
||||
size_t num_bits;
|
||||
size_t used_depths;
|
||||
public:
|
||||
constexpr Bitmap() : bit_storages(), num_bits(), used_depths() { /* ... */ }
|
||||
|
||||
constexpr size_t GetNumBits() const { return this->num_bits; }
|
||||
constexpr s32 GetHighestDepthIndex() const { return static_cast<s32>(this->used_depths) - 1; }
|
||||
|
||||
u64 *Initialize(u64 *storage, size_t size) {
|
||||
/* Initially, everything is un-set. */
|
||||
this->num_bits = 0;
|
||||
|
||||
/* Calculate the needed bitmap depth. */
|
||||
this->used_depths = static_cast<size_t>(GetRequiredDepth(size));
|
||||
MESOSPHERE_ASSERT(this->used_depths <= MaxDepth);
|
||||
|
||||
/* Set the bitmap pointers. */
|
||||
for (s32 depth = this->GetHighestDepthIndex(); depth >= 0; depth--) {
|
||||
this->bit_storages[depth] = storage;
|
||||
size = util::AlignUp(size, BITSIZEOF(u64)) / BITSIZEOF(u64);
|
||||
storage += size;
|
||||
}
|
||||
|
||||
return storage;
|
||||
}
|
||||
|
||||
ssize_t FindFreeBlock() const {
|
||||
uintptr_t offset = 0;
|
||||
s32 depth = 0;
|
||||
|
||||
do {
|
||||
const u64 v = this->bit_storages[depth][offset];
|
||||
if (v == 0) {
|
||||
/* If depth is bigger than zero, then a previous level indicated a block was free. */
|
||||
MESOSPHERE_ASSERT(depth == 0);
|
||||
return -1;
|
||||
}
|
||||
offset = offset * BITSIZEOF(u64) + __builtin_ctzll(v);
|
||||
++depth;
|
||||
} while (depth < static_cast<s32>(this->used_depths));
|
||||
|
||||
return static_cast<ssize_t>(offset);
|
||||
}
|
||||
|
||||
void SetBit(size_t offset) {
|
||||
this->SetBit(this->GetHighestDepthIndex(), offset);
|
||||
this->num_bits++;
|
||||
}
|
||||
|
||||
void ClearBit(size_t offset) {
|
||||
this->ClearBit(this->GetHighestDepthIndex(), offset);
|
||||
this->num_bits--;
|
||||
}
|
||||
|
||||
bool ClearRange(size_t offset, size_t count) {
|
||||
s32 depth = this->GetHighestDepthIndex();
|
||||
u64 *bits = this->bit_storages[depth];
|
||||
size_t bit_ind = offset / BITSIZEOF(u64);
|
||||
if (AMS_LIKELY(count < BITSIZEOF(u64))) {
|
||||
const size_t shift = offset % BITSIZEOF(u64);
|
||||
MESOSPHERE_ASSERT(shift + count <= BITSIZEOF(u64));
|
||||
/* Check that all the bits are set. */
|
||||
const u64 mask = ((u64(1) << count) - 1) << shift;
|
||||
u64 v = bits[bit_ind];
|
||||
if ((v & mask) != mask) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Clear the bits. */
|
||||
v &= ~mask;
|
||||
bits[bit_ind] = v;
|
||||
if (v == 0) {
|
||||
this->ClearBit(depth - 1, bit_ind);
|
||||
}
|
||||
} else {
|
||||
MESOSPHERE_ASSERT(offset % BITSIZEOF(u64) == 0);
|
||||
MESOSPHERE_ASSERT(count % BITSIZEOF(u64) == 0);
|
||||
/* Check that all the bits are set. */
|
||||
size_t remaining = count;
|
||||
size_t i = 0;
|
||||
do {
|
||||
if (bits[bit_ind + i++] != ~u64(0)) {
|
||||
return false;
|
||||
}
|
||||
remaining -= BITSIZEOF(u64);
|
||||
} while (remaining > 0);
|
||||
|
||||
/* Clear the bits. */
|
||||
remaining = count;
|
||||
i = 0;
|
||||
do {
|
||||
bits[bit_ind + i] = 0;
|
||||
this->ClearBit(depth - 1, bit_ind + i);
|
||||
i++;
|
||||
remaining -= BITSIZEOF(u64);
|
||||
} while (remaining > 0);
|
||||
}
|
||||
|
||||
this->num_bits -= count;
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
void SetBit(s32 depth, size_t offset) {
|
||||
while (depth >= 0) {
|
||||
size_t ind = offset / BITSIZEOF(u64);
|
||||
size_t which = offset % BITSIZEOF(u64);
|
||||
const u64 mask = u64(1) << which;
|
||||
|
||||
u64 *bit = std::addressof(this->bit_storages[depth][ind]);
|
||||
u64 v = *bit;
|
||||
MESOSPHERE_ASSERT((v & mask) == 0);
|
||||
*bit = v | mask;
|
||||
if (v) {
|
||||
break;
|
||||
}
|
||||
offset = ind;
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
|
||||
void ClearBit(s32 depth, size_t offset) {
|
||||
while (depth >= 0) {
|
||||
size_t ind = offset / BITSIZEOF(u64);
|
||||
size_t which = offset % BITSIZEOF(u64);
|
||||
const u64 mask = u64(1) << which;
|
||||
|
||||
u64 *bit = std::addressof(this->bit_storages[depth][ind]);
|
||||
u64 v = *bit;
|
||||
MESOSPHERE_ASSERT((v & mask) != 0);
|
||||
v &= ~mask;
|
||||
*bit = v;
|
||||
if (v) {
|
||||
break;
|
||||
}
|
||||
offset = ind;
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
private:
|
||||
static constexpr s32 GetRequiredDepth(size_t region_size) {
|
||||
s32 depth = 0;
|
||||
while (true) {
|
||||
region_size /= BITSIZEOF(u64);
|
||||
depth++;
|
||||
if (region_size == 0) {
|
||||
return depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
static constexpr size_t CalculateMetadataOverheadSize(size_t region_size) {
|
||||
size_t overhead_bits = 0;
|
||||
for (s32 depth = GetRequiredDepth(region_size) - 1; depth >= 0; depth--) {
|
||||
region_size = util::AlignUp(region_size, BITSIZEOF(u64)) / BITSIZEOF(u64);
|
||||
overhead_bits += region_size;
|
||||
}
|
||||
return overhead_bits * sizeof(u64);
|
||||
}
|
||||
};
|
||||
private:
|
||||
Bitmap bitmap;
|
||||
KPageBitmap bitmap;
|
||||
KVirtualAddress heap_address;
|
||||
uintptr_t end_offset;
|
||||
size_t block_shift;
|
||||
size_t next_block_shift;
|
||||
public:
|
||||
constexpr Block() : bitmap(), heap_address(), end_offset(), block_shift(), next_block_shift() { /* ... */ }
|
||||
Block() : bitmap(), heap_address(), end_offset(), block_shift(), next_block_shift() { /* ... */ }
|
||||
|
||||
constexpr size_t GetShift() const { return this->block_shift; }
|
||||
constexpr size_t GetNextShift() const { return this->next_block_shift; }
|
||||
@@ -266,9 +102,9 @@ namespace ams::kern {
|
||||
return Null<KVirtualAddress>;
|
||||
}
|
||||
|
||||
KVirtualAddress PopBlock() {
|
||||
KVirtualAddress PopBlock(bool random) {
|
||||
/* Find a free block. */
|
||||
ssize_t soffset = this->bitmap.FindFreeBlock();
|
||||
ssize_t soffset = this->bitmap.FindFreeBlock(random);
|
||||
if (soffset < 0) {
|
||||
return Null<KVirtualAddress>;
|
||||
}
|
||||
@@ -283,7 +119,7 @@ namespace ams::kern {
|
||||
const size_t cur_block_size = (u64(1) << cur_block_shift);
|
||||
const size_t next_block_size = (u64(1) << next_block_shift);
|
||||
const size_t align = (next_block_shift != 0) ? next_block_size : cur_block_size;
|
||||
return Bitmap::CalculateMetadataOverheadSize((align * 2 + util::AlignUp(region_size, align)) / cur_block_size);
|
||||
return KPageBitmap::CalculateMetadataOverheadSize((align * 2 + util::AlignUp(region_size, align)) / cur_block_size);
|
||||
}
|
||||
};
|
||||
private:
|
||||
@@ -298,7 +134,7 @@ namespace ams::kern {
|
||||
|
||||
void FreeBlock(KVirtualAddress block, s32 index);
|
||||
public:
|
||||
constexpr KPageHeap() : heap_address(), heap_size(), used_size(), num_blocks(), blocks() { /* ... */ }
|
||||
KPageHeap() : heap_address(), heap_size(), used_size(), num_blocks(), blocks() { /* ... */ }
|
||||
|
||||
constexpr KVirtualAddress GetAddress() const { return this->heap_address; }
|
||||
constexpr size_t GetSize() const { return this->heap_size; }
|
||||
@@ -313,7 +149,7 @@ namespace ams::kern {
|
||||
this->used_size = this->heap_size - (this->GetNumFreePages() * PageSize);
|
||||
}
|
||||
|
||||
KVirtualAddress AllocateBlock(s32 index);
|
||||
KVirtualAddress AllocateBlock(s32 index, bool random);
|
||||
void Free(KVirtualAddress addr, size_t num_pages);
|
||||
private:
|
||||
static size_t CalculateMetadataOverheadSize(size_t region_size, const size_t *block_shifts, size_t num_block_shifts);
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace ams::kern {
|
||||
};
|
||||
static_assert(std::is_trivially_destructible<PageLinkedList>::value);
|
||||
|
||||
static constexpr u32 DefaultMemoryIgnoreAttr = KMemoryAttribute_DontCareMask | KMemoryAttribute_IpcLocked | KMemoryAttribute_DeviceShared;
|
||||
static constexpr u32 DefaultMemoryIgnoreAttr = KMemoryAttribute_IpcLocked | KMemoryAttribute_DeviceShared;
|
||||
|
||||
static constexpr size_t GetAddressSpaceWidth(ams::svc::CreateProcessFlag as_type) {
|
||||
switch (static_cast<ams::svc::CreateProcessFlag>(as_type & ams::svc::CreateProcessFlag_AddressSpaceMask)) {
|
||||
@@ -135,6 +135,7 @@ namespace ams::kern {
|
||||
KProcessAddress code_region_end;
|
||||
size_t max_heap_size;
|
||||
size_t max_physical_memory_size;
|
||||
size_t mapped_unsafe_physical_memory;
|
||||
mutable KLightLock general_lock;
|
||||
mutable KLightLock map_physical_memory_lock;
|
||||
KPageTableImpl impl;
|
||||
@@ -156,9 +157,9 @@ namespace ams::kern {
|
||||
address_space_start(), address_space_end(), heap_region_start(), heap_region_end(), current_heap_end(),
|
||||
alias_region_start(), alias_region_end(), stack_region_start(), stack_region_end(), kernel_map_region_start(),
|
||||
kernel_map_region_end(), alias_code_region_start(), alias_code_region_end(), code_region_start(), code_region_end(),
|
||||
max_heap_size(), max_physical_memory_size(), general_lock(), map_physical_memory_lock(), impl(), memory_block_manager(),
|
||||
allocate_option(), address_space_width(), is_kernel(), enable_aslr(), memory_block_slab_manager(), block_info_manager(),
|
||||
cached_physical_linear_region(), cached_physical_heap_region(), cached_virtual_heap_region(),
|
||||
max_heap_size(), max_physical_memory_size(),mapped_unsafe_physical_memory(), general_lock(), map_physical_memory_lock(),
|
||||
impl(), memory_block_manager(), allocate_option(), address_space_width(), is_kernel(), enable_aslr(), memory_block_slab_manager(),
|
||||
block_info_manager(), cached_physical_linear_region(), cached_physical_heap_region(), cached_virtual_heap_region(),
|
||||
heap_fill_value(), ipc_fill_value(), stack_fill_value()
|
||||
{
|
||||
/* ... */
|
||||
|
||||
@@ -57,13 +57,13 @@ namespace ams::kern {
|
||||
return std::addressof(this->ref_counts[(addr - this->GetAddress()) / PageSize]);
|
||||
}
|
||||
public:
|
||||
void Initialize(KDynamicPageManager *next_allocator, RefCount *rc) {
|
||||
BaseHeap::Initialize(next_allocator);
|
||||
void Initialize(KDynamicPageManager *page_allocator, RefCount *rc) {
|
||||
BaseHeap::Initialize(page_allocator);
|
||||
this->Initialize(rc);
|
||||
}
|
||||
|
||||
void Initialize(KVirtualAddress memory, size_t sz, RefCount *rc) {
|
||||
BaseHeap::Initialize(memory, sz);
|
||||
void Initialize(KDynamicPageManager *page_allocator, size_t object_count, RefCount *rc) {
|
||||
BaseHeap::Initialize(page_allocator, object_count);
|
||||
this->Initialize(rc);
|
||||
}
|
||||
|
||||
@@ -72,6 +72,10 @@ namespace ams::kern {
|
||||
}
|
||||
|
||||
void Free(KVirtualAddress addr) {
|
||||
/* Ensure all pages in the heap are zero. */
|
||||
cpu::ClearPageToZero(GetVoidPointer(addr));
|
||||
|
||||
/* Free the page. */
|
||||
BaseHeap::Free(GetPointer<impl::PageTablePage>(addr));
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ namespace ams::kern {
|
||||
u32 version{};
|
||||
KHandleTable handle_table{};
|
||||
KProcessAddress plr_address{};
|
||||
void *plr_heap_address{};
|
||||
KThread *exception_thread{};
|
||||
ThreadList thread_list{};
|
||||
SharedMemoryInfoList shared_memory_list{};
|
||||
@@ -118,7 +119,7 @@ namespace ams::kern {
|
||||
private:
|
||||
Result Initialize(const ams::svc::CreateProcessParameter ¶ms);
|
||||
public:
|
||||
constexpr KProcess() { /* ... */ }
|
||||
KProcess() { /* ... */ }
|
||||
virtual ~KProcess() { /* ... */ }
|
||||
|
||||
Result Initialize(const ams::svc::CreateProcessParameter ¶ms, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool);
|
||||
|
||||
@@ -333,6 +333,13 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
return PerformCacheOperationBySetWayLocal<true>(FlushDataCacheLineBySetWayImpl);
|
||||
}
|
||||
|
||||
void StoreEntireCacheForInit() {
|
||||
PerformCacheOperationBySetWayLocal<true>(StoreDataCacheLineBySetWayImpl);
|
||||
PerformCacheOperationBySetWayShared<true>(StoreDataCacheLineBySetWayImpl);
|
||||
DataSynchronizationBarrierInnerShareable();
|
||||
InvalidateEntireInstructionCache();
|
||||
}
|
||||
|
||||
void FlushEntireDataCache() {
|
||||
return PerformCacheOperationBySetWayShared<false>(FlushDataCacheLineBySetWayImpl);
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ namespace ams::kern::arch::arm64 {
|
||||
/* Set the entry. */
|
||||
l2_phys = GetPageTablePhysicalAddress(l2_virt);
|
||||
PteDataSynchronizationBarrier();
|
||||
*l1_entry = L1PageTableEntry(l2_phys, this->IsKernel(), true);
|
||||
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, l2_phys, this->IsKernel(), true);
|
||||
PteDataSynchronizationBarrier();
|
||||
l2_allocated = true;
|
||||
} else {
|
||||
@@ -319,7 +319,7 @@ namespace ams::kern::arch::arm64 {
|
||||
/* Set the entry. */
|
||||
l3_phys = GetPageTablePhysicalAddress(l3_virt);
|
||||
PteDataSynchronizationBarrier();
|
||||
*l2_entry = L2PageTableEntry(l3_phys, this->IsKernel(), true);
|
||||
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, l3_phys, this->IsKernel(), true);
|
||||
PteDataSynchronizationBarrier();
|
||||
l2_open_count++;
|
||||
} else {
|
||||
@@ -329,7 +329,7 @@ namespace ams::kern::arch::arm64 {
|
||||
MESOSPHERE_ASSERT(l3_virt != Null<KVirtualAddress>);
|
||||
|
||||
/* Map the page. */
|
||||
*impl.GetL3EntryFromTable(l3_virt, virt_addr) = L3PageTableEntry(phys_addr, entry_template, false);
|
||||
*impl.GetL3EntryFromTable(l3_virt, virt_addr) = L3PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, PageTableEntry(entry_template), false);
|
||||
l3_open_count++;
|
||||
virt_addr += PageSize;
|
||||
phys_addr += PageSize;
|
||||
@@ -706,6 +706,8 @@ namespace ams::kern::arch::arm64 {
|
||||
/* If there's no L1 table, don't bother. */
|
||||
L1PageTableEntry *l1_entry = impl.GetL1Entry(virt_addr);
|
||||
if (!l1_entry->IsTable()) {
|
||||
/* Ensure the table is not corrupted. */
|
||||
MESOSPHERE_ABORT_UNLESS(l1_entry->IsBlock() || l1_entry->IsEmpty());
|
||||
return merged;
|
||||
}
|
||||
|
||||
@@ -726,7 +728,7 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
/* Validate that we can merge. */
|
||||
for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) {
|
||||
if (!impl.GetL3Entry(l2_entry, virt_addr + L3BlockSize * i)->Is(entry_template | GetInteger(phys_addr + PageSize * i) | PageTableEntry::Type_L3Block)) {
|
||||
if (!impl.GetL3Entry(l2_entry, virt_addr + L3BlockSize * i)->Is(entry_template | GetInteger(phys_addr + L3BlockSize * i) | PageTableEntry::Type_L3Block)) {
|
||||
return merged;
|
||||
}
|
||||
}
|
||||
@@ -748,14 +750,14 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
/* Validate that we can merge. */
|
||||
for (size_t i = 0; i < L2BlockSize / L3ContiguousBlockSize; i++) {
|
||||
if (!impl.GetL3Entry(l2_entry, virt_addr + L3BlockSize * i)->Is(entry_template | GetInteger(phys_addr + L3ContiguousBlockSize * i) | PageTableEntry::ContigType_Contiguous)) {
|
||||
if (!impl.GetL3Entry(l2_entry, virt_addr + L3ContiguousBlockSize * i)->Is(entry_template | GetInteger(phys_addr + L3ContiguousBlockSize * i) | PageTableEntry::ContigType_Contiguous | PageTableEntry::Type_L3Block)) {
|
||||
return merged;
|
||||
}
|
||||
}
|
||||
|
||||
/* Merge! */
|
||||
PteDataSynchronizationBarrier();
|
||||
*l2_entry = L2PageTableEntry(phys_addr, entry_template, false);
|
||||
*l2_entry = L2PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, PageTableEntry(entry_template), false);
|
||||
|
||||
/* Note that we updated. */
|
||||
this->NoteUpdated();
|
||||
@@ -765,61 +767,67 @@ namespace ams::kern::arch::arm64 {
|
||||
KVirtualAddress l3_table = util::AlignDown(reinterpret_cast<uintptr_t>(l3_entry), PageSize);
|
||||
if (this->GetPageTableManager().IsInPageTableHeap(l3_table)) {
|
||||
this->GetPageTableManager().Close(l3_table, L2BlockSize / L3BlockSize);
|
||||
ClearPageTable(l3_table);
|
||||
this->FreePageTable(page_list, l3_table);
|
||||
}
|
||||
}
|
||||
if (l2_entry->IsBlock()) {
|
||||
/* If it's not contiguous, try to make it so. */
|
||||
if (!l2_entry->IsContiguous()) {
|
||||
virt_addr = util::AlignDown(GetInteger(virt_addr), L2ContiguousBlockSize);
|
||||
KPhysicalAddress phys_addr = util::AlignDown(GetInteger(l2_entry->GetBlock()), L2ContiguousBlockSize);
|
||||
const u64 entry_template = l2_entry->GetEntryTemplate();
|
||||
|
||||
/* Validate that we can merge. */
|
||||
for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
|
||||
if (!impl.GetL2Entry(l1_entry, virt_addr + L2BlockSize * i)->Is(entry_template | GetInteger(phys_addr + PageSize * i) | PageTableEntry::Type_L2Block)) {
|
||||
return merged;
|
||||
}
|
||||
}
|
||||
/* If the l2 entry is not a block or we can't make it contiguous, we're done. */
|
||||
if (!l2_entry->IsBlock() || !l2_entry->IsContiguousAllowed()) {
|
||||
return merged;
|
||||
}
|
||||
|
||||
/* Merge! */
|
||||
for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
|
||||
impl.GetL2Entry(l1_entry, virt_addr + L2BlockSize * i)->SetContiguous(true);
|
||||
}
|
||||
|
||||
/* Note that we updated. */
|
||||
this->NoteUpdated();
|
||||
merged = true;
|
||||
}
|
||||
|
||||
/* We might be able to upgrade a contiguous set of L2 entries into an L1 block. */
|
||||
virt_addr = util::AlignDown(GetInteger(virt_addr), L1BlockSize);
|
||||
KPhysicalAddress phys_addr = util::AlignDown(GetInteger(l2_entry->GetBlock()), L1BlockSize);
|
||||
/* If it's not contiguous, try to make it so. */
|
||||
if (!l2_entry->IsContiguous()) {
|
||||
virt_addr = util::AlignDown(GetInteger(virt_addr), L2ContiguousBlockSize);
|
||||
KPhysicalAddress phys_addr = util::AlignDown(GetInteger(l2_entry->GetBlock()), L2ContiguousBlockSize);
|
||||
const u64 entry_template = l2_entry->GetEntryTemplate();
|
||||
|
||||
/* Validate that we can merge. */
|
||||
for (size_t i = 0; i < L1BlockSize / L2ContiguousBlockSize; i++) {
|
||||
if (!impl.GetL2Entry(l1_entry, virt_addr + L3BlockSize * i)->Is(entry_template | GetInteger(phys_addr + L2ContiguousBlockSize * i) | PageTableEntry::ContigType_Contiguous)) {
|
||||
for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
|
||||
if (!impl.GetL2Entry(l1_entry, virt_addr + L2BlockSize * i)->Is(entry_template | GetInteger(phys_addr + L2BlockSize * i) | PageTableEntry::Type_L2Block)) {
|
||||
return merged;
|
||||
}
|
||||
}
|
||||
|
||||
/* Merge! */
|
||||
PteDataSynchronizationBarrier();
|
||||
*l1_entry = L1PageTableEntry(phys_addr, entry_template, false);
|
||||
for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
|
||||
impl.GetL2Entry(l1_entry, virt_addr + L2BlockSize * i)->SetContiguous(true);
|
||||
}
|
||||
|
||||
/* Note that we updated. */
|
||||
this->NoteUpdated();
|
||||
merged = true;
|
||||
}
|
||||
|
||||
/* Free the L2 table. */
|
||||
KVirtualAddress l2_table = util::AlignDown(reinterpret_cast<uintptr_t>(l2_entry), PageSize);
|
||||
if (this->GetPageTableManager().IsInPageTableHeap(l2_table)) {
|
||||
this->GetPageTableManager().Close(l2_table, L1BlockSize / L2BlockSize);
|
||||
this->FreePageTable(page_list, l2_table);
|
||||
/* We might be able to upgrade a contiguous set of L2 entries into an L1 block. */
|
||||
virt_addr = util::AlignDown(GetInteger(virt_addr), L1BlockSize);
|
||||
KPhysicalAddress phys_addr = util::AlignDown(GetInteger(l2_entry->GetBlock()), L1BlockSize);
|
||||
const u64 entry_template = l2_entry->GetEntryTemplate();
|
||||
|
||||
/* Validate that we can merge. */
|
||||
for (size_t i = 0; i < L1BlockSize / L2ContiguousBlockSize; i++) {
|
||||
if (!impl.GetL2Entry(l1_entry, virt_addr + L2ContiguousBlockSize * i)->Is(entry_template | GetInteger(phys_addr + L2ContiguousBlockSize * i) | PageTableEntry::ContigType_Contiguous | PageTableEntry::Type_L2Block)) {
|
||||
return merged;
|
||||
}
|
||||
}
|
||||
|
||||
/* Merge! */
|
||||
PteDataSynchronizationBarrier();
|
||||
*l1_entry = L1PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, PageTableEntry(entry_template), false);
|
||||
|
||||
/* Note that we updated. */
|
||||
this->NoteUpdated();
|
||||
merged = true;
|
||||
|
||||
/* Free the L2 table. */
|
||||
KVirtualAddress l2_table = util::AlignDown(reinterpret_cast<uintptr_t>(l2_entry), PageSize);
|
||||
if (this->GetPageTableManager().IsInPageTableHeap(l2_table)) {
|
||||
this->GetPageTableManager().Close(l2_table, L1BlockSize / L2BlockSize);
|
||||
ClearPageTable(l2_table);
|
||||
this->FreePageTable(page_list, l2_table);
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
@@ -846,7 +854,7 @@ namespace ams::kern::arch::arm64 {
|
||||
/* Set the entries in the L2 table. */
|
||||
const u64 entry_template = l1_entry->GetEntryTemplate();
|
||||
for (size_t i = 0; i < L1BlockSize / L2BlockSize; i++) {
|
||||
*(impl.GetL2EntryFromTable(l2_table, block_virt_addr + L2BlockSize * i)) = L2PageTableEntry(block_phys_addr + L2BlockSize * i, entry_template, true);
|
||||
*(impl.GetL2EntryFromTable(l2_table, block_virt_addr + L2BlockSize * i)) = L2PageTableEntry(PageTableEntry::BlockTag{}, block_phys_addr + L2BlockSize * i, PageTableEntry(entry_template), true);
|
||||
}
|
||||
|
||||
/* Open references to the L2 table. */
|
||||
@@ -854,11 +862,12 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
/* Replace the L1 entry with one to the new table. */
|
||||
PteDataSynchronizationBarrier();
|
||||
*l1_entry = L1PageTableEntry(l2_phys, this->IsKernel(), true);
|
||||
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, l2_phys, this->IsKernel(), true);
|
||||
this->NoteUpdated();
|
||||
}
|
||||
|
||||
/* If we don't have an l1 table, we're done. */
|
||||
MESOSPHERE_ABORT_UNLESS(l1_entry->IsTable() || l1_entry->IsEmpty());
|
||||
R_SUCCEED_IF(!l1_entry->IsTable());
|
||||
|
||||
/* We want to separate L2 contiguous blocks into L2 blocks, so check that our size permits that. */
|
||||
@@ -892,7 +901,7 @@ namespace ams::kern::arch::arm64 {
|
||||
/* Set the entries in the L3 table. */
|
||||
const u64 entry_template = l2_entry->GetEntryTemplate();
|
||||
for (size_t i = 0; i < L2BlockSize / L3BlockSize; i++) {
|
||||
*(impl.GetL3EntryFromTable(l3_table, block_virt_addr + L3BlockSize * i)) = L3PageTableEntry(block_phys_addr + L3BlockSize * i, entry_template, true);
|
||||
*(impl.GetL3EntryFromTable(l3_table, block_virt_addr + L3BlockSize * i)) = L3PageTableEntry(PageTableEntry::BlockTag{}, block_phys_addr + L3BlockSize * i, PageTableEntry(entry_template), true);
|
||||
}
|
||||
|
||||
/* Open references to the L3 table. */
|
||||
@@ -900,11 +909,12 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
/* Replace the L2 entry with one to the new table. */
|
||||
PteDataSynchronizationBarrier();
|
||||
*l2_entry = L2PageTableEntry(l3_phys, this->IsKernel(), true);
|
||||
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, l3_phys, this->IsKernel(), true);
|
||||
this->NoteUpdated();
|
||||
}
|
||||
|
||||
/* If we don't have an L3 table, we're done. */
|
||||
MESOSPHERE_ABORT_UNLESS(l2_entry->IsTable() || l2_entry->IsEmpty());
|
||||
R_SUCCEED_IF(!l2_entry->IsTable());
|
||||
|
||||
/* We want to separate L3 contiguous blocks into L2 blocks, so check that our size permits that. */
|
||||
@@ -940,8 +950,6 @@ namespace ams::kern::arch::arm64 {
|
||||
Result KPageTable::ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, bool refresh_mapping, PageLinkedList *page_list, bool reuse_ll) {
|
||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
auto &impl = this->GetImpl();
|
||||
|
||||
/* Separate pages before we change permissions. */
|
||||
const size_t size = num_pages * PageSize;
|
||||
R_TRY(this->SeparatePages(virt_addr, std::min(GetInteger(virt_addr) & -GetInteger(virt_addr), size), page_list, reuse_ll));
|
||||
@@ -954,117 +962,163 @@ namespace ams::kern::arch::arm64 {
|
||||
merge_guard.Cancel();
|
||||
}
|
||||
|
||||
/* Cache initial addresses for use on cleanup. */
|
||||
const KProcessAddress orig_virt_addr = virt_addr;
|
||||
size_t remaining_pages = num_pages;
|
||||
/* ===================================================== */
|
||||
|
||||
/* Begin traversal. */
|
||||
TraversalContext context;
|
||||
TraversalEntry next_entry;
|
||||
MESOSPHERE_ABORT_UNLESS(impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), virt_addr));
|
||||
/* Define a helper function which will apply our template to entries. */
|
||||
|
||||
/* Continue changing properties until we've changed them for all pages. */
|
||||
while (remaining_pages > 0) {
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(next_entry.phys_addr), next_entry.block_size));
|
||||
MESOSPHERE_ABORT_UNLESS(next_entry.block_size <= remaining_pages * PageSize);
|
||||
enum ApplyOption : u32 {
|
||||
ApplyOption_None = 0,
|
||||
ApplyOption_FlushDataCache = (1u << 0),
|
||||
ApplyOption_MergeMappings = (1u << 1),
|
||||
};
|
||||
|
||||
L1PageTableEntry *l1_entry = impl.GetL1Entry(virt_addr);
|
||||
switch (next_entry.block_size) {
|
||||
case L1BlockSize:
|
||||
{
|
||||
/* Clear the entry, if we should. */
|
||||
if (refresh_mapping) {
|
||||
*l1_entry = InvalidL1PageTableEntry;
|
||||
this->NoteUpdated();
|
||||
if (IsHeapPhysicalAddress(next_entry.phys_addr)) {
|
||||
cpu::FlushDataCache(GetVoidPointer(GetHeapVirtualAddress(next_entry.phys_addr)), L1BlockSize);
|
||||
}
|
||||
}
|
||||
auto ApplyEntryTemplate = [this, virt_addr, num_pages, page_list](PageTableEntry entry_template, u32 apply_option) -> void {
|
||||
/* Create work variables for us to use. */
|
||||
KProcessAddress cur_virt_addr = virt_addr;
|
||||
size_t remaining_pages = num_pages;
|
||||
|
||||
/* Write the updated entry. */
|
||||
*l1_entry = L1PageTableEntry(next_entry.phys_addr, entry_template, false);
|
||||
auto &impl = this->GetImpl();
|
||||
|
||||
/* Begin traversal. */
|
||||
TraversalContext context;
|
||||
TraversalEntry next_entry;
|
||||
MESOSPHERE_ABORT_UNLESS(impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), cur_virt_addr));
|
||||
|
||||
/* Continue changing properties until we've changed them for all pages. */
|
||||
while (remaining_pages > 0) {
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(next_entry.phys_addr), next_entry.block_size));
|
||||
MESOSPHERE_ABORT_UNLESS(next_entry.block_size <= remaining_pages * PageSize);
|
||||
|
||||
/* If we should flush entries, do so. */
|
||||
if ((apply_option & ApplyOption_FlushDataCache) != 0) {
|
||||
if (IsHeapPhysicalAddress(next_entry.phys_addr)) {
|
||||
cpu::FlushDataCache(GetVoidPointer(GetHeapVirtualAddress(next_entry.phys_addr)), next_entry.block_size);
|
||||
}
|
||||
break;
|
||||
case L2ContiguousBlockSize:
|
||||
case L2BlockSize:
|
||||
{
|
||||
/* Get the number of L2 blocks. */
|
||||
const size_t num_l2_blocks = next_entry.block_size / L2BlockSize;
|
||||
}
|
||||
|
||||
/* Get the L2 entry. */
|
||||
KPhysicalAddress l2_phys = Null<KPhysicalAddress>;
|
||||
MESOSPHERE_ABORT_UNLESS(l1_entry->GetTable(l2_phys));
|
||||
const KVirtualAddress l2_virt = GetPageTableVirtualAddress(l2_phys);
|
||||
/* Apply the entry template. */
|
||||
L1PageTableEntry *l1_entry = impl.GetL1Entry(cur_virt_addr);
|
||||
switch (next_entry.block_size) {
|
||||
case L1BlockSize:
|
||||
{
|
||||
/* Write the updated entry. */
|
||||
*l1_entry = L1PageTableEntry(PageTableEntry::BlockTag{}, next_entry.phys_addr, entry_template, false);
|
||||
}
|
||||
break;
|
||||
case L2ContiguousBlockSize:
|
||||
case L2BlockSize:
|
||||
{
|
||||
/* Get the number of L2 blocks. */
|
||||
const size_t num_l2_blocks = next_entry.block_size / L2BlockSize;
|
||||
|
||||
/* Clear the entry, if we should. */
|
||||
if (refresh_mapping) {
|
||||
/* Get the L2 entry. */
|
||||
KPhysicalAddress l2_phys = Null<KPhysicalAddress>;
|
||||
MESOSPHERE_ABORT_UNLESS(l1_entry->GetTable(l2_phys));
|
||||
const KVirtualAddress l2_virt = GetPageTableVirtualAddress(l2_phys);
|
||||
|
||||
/* Write the updated entry. */
|
||||
const bool contig = next_entry.block_size == L2ContiguousBlockSize;
|
||||
for (size_t i = 0; i < num_l2_blocks; i++) {
|
||||
*impl.GetL2EntryFromTable(l2_virt, virt_addr + L2BlockSize * i) = InvalidL2PageTableEntry;
|
||||
}
|
||||
this->NoteUpdated();
|
||||
if (IsHeapPhysicalAddress(next_entry.phys_addr)) {
|
||||
cpu::FlushDataCache(GetVoidPointer(GetHeapVirtualAddress(next_entry.phys_addr)), next_entry.block_size);
|
||||
*impl.GetL2EntryFromTable(l2_virt, cur_virt_addr + L2BlockSize * i) = L2PageTableEntry(PageTableEntry::BlockTag{}, next_entry.phys_addr + L2BlockSize * i, entry_template, contig);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case L3ContiguousBlockSize:
|
||||
case L3BlockSize:
|
||||
{
|
||||
/* Get the number of L3 blocks. */
|
||||
const size_t num_l3_blocks = next_entry.block_size / L3BlockSize;
|
||||
|
||||
/* Write the updated entry. */
|
||||
const bool contig = next_entry.block_size == L2ContiguousBlockSize;
|
||||
for (size_t i = 0; i < num_l2_blocks; i++) {
|
||||
*impl.GetL2EntryFromTable(l2_virt, virt_addr + L2BlockSize * i) = L2PageTableEntry(next_entry.phys_addr + L2BlockSize * i, entry_template, contig);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case L3ContiguousBlockSize:
|
||||
case L3BlockSize:
|
||||
{
|
||||
/* Get the number of L3 blocks. */
|
||||
const size_t num_l3_blocks = next_entry.block_size / L3BlockSize;
|
||||
/* Get the L2 entry. */
|
||||
KPhysicalAddress l2_phys = Null<KPhysicalAddress>;
|
||||
MESOSPHERE_ABORT_UNLESS(l1_entry->GetTable(l2_phys));
|
||||
const KVirtualAddress l2_virt = GetPageTableVirtualAddress(l2_phys);
|
||||
L2PageTableEntry *l2_entry = impl.GetL2EntryFromTable(l2_virt, cur_virt_addr);
|
||||
|
||||
/* Get the L2 entry. */
|
||||
KPhysicalAddress l2_phys = Null<KPhysicalAddress>;
|
||||
MESOSPHERE_ABORT_UNLESS(l1_entry->GetTable(l2_phys));
|
||||
const KVirtualAddress l2_virt = GetPageTableVirtualAddress(l2_phys);
|
||||
L2PageTableEntry *l2_entry = impl.GetL2EntryFromTable(l2_virt, virt_addr);
|
||||
/* Get the L3 entry. */
|
||||
KPhysicalAddress l3_phys = Null<KPhysicalAddress>;
|
||||
MESOSPHERE_ABORT_UNLESS(l2_entry->GetTable(l3_phys));
|
||||
const KVirtualAddress l3_virt = GetPageTableVirtualAddress(l3_phys);
|
||||
|
||||
/* Get the L3 entry. */
|
||||
KPhysicalAddress l3_phys = Null<KPhysicalAddress>;
|
||||
MESOSPHERE_ABORT_UNLESS(l2_entry->GetTable(l3_phys));
|
||||
const KVirtualAddress l3_virt = GetPageTableVirtualAddress(l3_phys);
|
||||
|
||||
/* Clear the entry, if we should. */
|
||||
if (refresh_mapping) {
|
||||
/* Write the updated entry. */
|
||||
const bool contig = next_entry.block_size == L3ContiguousBlockSize;
|
||||
for (size_t i = 0; i < num_l3_blocks; i++) {
|
||||
*impl.GetL3EntryFromTable(l3_virt, virt_addr + L3BlockSize * i) = InvalidL3PageTableEntry;
|
||||
}
|
||||
this->NoteUpdated();
|
||||
if (IsHeapPhysicalAddress(next_entry.phys_addr)) {
|
||||
cpu::FlushDataCache(GetVoidPointer(GetHeapVirtualAddress(next_entry.phys_addr)), next_entry.block_size);
|
||||
*impl.GetL3EntryFromTable(l3_virt, cur_virt_addr + L3BlockSize * i) = L3PageTableEntry(PageTableEntry::BlockTag{}, next_entry.phys_addr + L3BlockSize * i, entry_template, contig);
|
||||
}
|
||||
}
|
||||
break;
|
||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
/* Write the updated entry. */
|
||||
const bool contig = next_entry.block_size == L3ContiguousBlockSize;
|
||||
for (size_t i = 0; i < num_l3_blocks; i++) {
|
||||
*impl.GetL3EntryFromTable(l3_virt, virt_addr + L3BlockSize * i) = L3PageTableEntry(next_entry.phys_addr + L3BlockSize * i, entry_template, contig);
|
||||
/* If our option asks us to, try to merge mappings. */
|
||||
bool merge = ((apply_option & ApplyOption_MergeMappings) != 0) && next_entry.block_size < L1BlockSize;
|
||||
if (merge) {
|
||||
const size_t larger_align = GetLargerAlignment(next_entry.block_size);
|
||||
if (util::IsAligned(GetInteger(cur_virt_addr) + next_entry.block_size, larger_align)) {
|
||||
const uintptr_t aligned_start = util::AlignDown(GetInteger(cur_virt_addr), larger_align);
|
||||
if (virt_addr <= aligned_start && aligned_start + larger_align - 1 < GetInteger(virt_addr) + (num_pages * PageSize) - 1) {
|
||||
merge = this->MergePages(cur_virt_addr, page_list);
|
||||
} else {
|
||||
merge = false;
|
||||
}
|
||||
} else {
|
||||
merge = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we merged, correct the traversal to a sane state. */
|
||||
if (merge) {
|
||||
/* NOTE: Nintendo does not verify the result of this BeginTraversal call. */
|
||||
MESOSPHERE_ABORT_UNLESS(impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), cur_virt_addr));
|
||||
|
||||
/* The actual size needs to not take into account the portion of the block before our virtual address. */
|
||||
const size_t actual_size = next_entry.block_size - (GetInteger(next_entry.phys_addr) & (next_entry.block_size - 1));
|
||||
remaining_pages -= std::min(remaining_pages, actual_size / PageSize);
|
||||
cur_virt_addr += actual_size;
|
||||
} else {
|
||||
/* If we didn't merge, just advance. */
|
||||
remaining_pages -= next_entry.block_size / PageSize;
|
||||
cur_virt_addr += next_entry.block_size;
|
||||
}
|
||||
|
||||
/* Continue our traversal. */
|
||||
if (remaining_pages == 0) {
|
||||
break;
|
||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
MESOSPHERE_ABORT_UNLESS(impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* ===================================================== */
|
||||
|
||||
/* If we don't need to refresh the pages, we can just apply the mappings. */
|
||||
if (!refresh_mapping) {
|
||||
ApplyEntryTemplate(entry_template, ApplyOption_None);
|
||||
this->NoteUpdated();
|
||||
} else {
|
||||
/* We need to refresh the mappings. */
|
||||
/* First, apply the changes without the mapped bit. This will cause all entries to page fault if accessed. */
|
||||
{
|
||||
PageTableEntry unmapped_template = entry_template;
|
||||
unmapped_template.SetMapped(false);
|
||||
ApplyEntryTemplate(unmapped_template, ApplyOption_MergeMappings);
|
||||
this->NoteUpdated();
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
virt_addr += next_entry.block_size;
|
||||
remaining_pages -= next_entry.block_size / PageSize;
|
||||
if (remaining_pages == 0) {
|
||||
break;
|
||||
/* Next, take and immediately release the scheduler lock. This will force a reschedule. */
|
||||
{
|
||||
KScopedSchedulerLock sl;
|
||||
}
|
||||
MESOSPHERE_ABORT_UNLESS(impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)));
|
||||
|
||||
/* Finally, apply the changes as directed, flushing the mappings before they're applied. */
|
||||
ApplyEntryTemplate(entry_template, ApplyOption_FlushDataCache);
|
||||
}
|
||||
|
||||
/* We've succeeded, now perform what coalescing we can. */
|
||||
this->MergePages(orig_virt_addr, page_list);
|
||||
this->MergePages(virt_addr, page_list);
|
||||
if (num_pages > 1) {
|
||||
this->MergePages(orig_virt_addr + (num_pages - 1) * PageSize, page_list);
|
||||
this->MergePages(virt_addr + (num_pages - 1) * PageSize, page_list);
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
|
||||
@@ -81,6 +81,15 @@ namespace ams::kern::board::nintendo::nx {
|
||||
return value;
|
||||
}
|
||||
|
||||
void EnsureRandomGeneratorInitialized() {
|
||||
if (AMS_UNLIKELY(!g_initialized_random_generator)) {
|
||||
u64 seed;
|
||||
smc::GenerateRandomBytes(&seed, sizeof(seed));
|
||||
g_random_generator.Initialize(reinterpret_cast<u32*>(&seed), sizeof(seed) / sizeof(u32));
|
||||
g_initialized_random_generator = true;
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u64 GenerateRandomU64FromGenerator() {
|
||||
return g_random_generator.GenerateRandomU64();
|
||||
}
|
||||
@@ -304,16 +313,20 @@ namespace ams::kern::board::nintendo::nx {
|
||||
KScopedInterruptDisable intr_disable;
|
||||
KScopedSpinLock lk(g_random_lock);
|
||||
|
||||
if (AMS_UNLIKELY(!g_initialized_random_generator)) {
|
||||
u64 seed;
|
||||
GenerateRandomBytes(&seed, sizeof(seed));
|
||||
g_random_generator.Initialize(reinterpret_cast<u32*>(&seed), sizeof(seed) / sizeof(u32));
|
||||
g_initialized_random_generator = true;
|
||||
}
|
||||
EnsureRandomGeneratorInitialized();
|
||||
|
||||
return GenerateUniformRange(min, max, GenerateRandomU64FromGenerator);
|
||||
}
|
||||
|
||||
u64 KSystemControl::GenerateRandomU64() {
|
||||
KScopedInterruptDisable intr_disable;
|
||||
KScopedSpinLock lk(g_random_lock);
|
||||
|
||||
EnsureRandomGeneratorInitialized();
|
||||
|
||||
return GenerateRandomU64FromGenerator();
|
||||
}
|
||||
|
||||
void KSystemControl::SleepSystem() {
|
||||
MESOSPHERE_LOG("SleepSystem() was called\n");
|
||||
KSleepManager::SleepSystem();
|
||||
|
||||
@@ -197,6 +197,7 @@ namespace ams::kern {
|
||||
cur_address += cur_info.GetSize();
|
||||
remaining_pages -= cur_info.GetNumPages();
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
/* Find the iterator now that we've updated. */
|
||||
@@ -227,6 +228,86 @@ namespace ams::kern {
|
||||
}
|
||||
}
|
||||
|
||||
void KMemoryBlockManager::UpdateLock(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, void (KMemoryBlock::*lock_func)(KMemoryPermission new_perm), KMemoryPermission perm) {
|
||||
/* Ensure for auditing that we never end up with an invalid tree. */
|
||||
KScopedMemoryBlockManagerAuditor auditor(this);
|
||||
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(address), PageSize));
|
||||
|
||||
KProcessAddress cur_address = address;
|
||||
size_t remaining_pages = num_pages;
|
||||
iterator it = this->FindIterator(address);
|
||||
iterator prev = it, next = it;
|
||||
bool check_coalesce_prev = false, check_coalesce_next = false;
|
||||
|
||||
while (remaining_pages > 0) {
|
||||
const size_t remaining_size = remaining_pages * PageSize;
|
||||
KMemoryInfo cur_info = it->GetMemoryInfo();
|
||||
|
||||
/* If we need to, create a new block before and insert it. */
|
||||
if (cur_info.address != GetInteger(cur_address)) {
|
||||
KMemoryBlock *new_block = allocator->Allocate();
|
||||
|
||||
it->Split(new_block, cur_address);
|
||||
it = this->memory_block_tree.insert(*new_block);
|
||||
it++;
|
||||
|
||||
cur_info = it->GetMemoryInfo();
|
||||
cur_address = cur_info.GetAddress();
|
||||
} else if (cur_address == address && cur_address != this->start_address) {
|
||||
/* If there's a previous, we should check for coalescing. */
|
||||
check_coalesce_prev = true;
|
||||
prev--;
|
||||
} else if (cur_info.GetSize() > remaining_size) {
|
||||
/* If we need to, create a new block after and insert it. */
|
||||
KMemoryBlock *new_block = allocator->Allocate();
|
||||
|
||||
it->Split(new_block, cur_address + remaining_size);
|
||||
it = this->memory_block_tree.insert(*new_block);
|
||||
|
||||
cur_info = it->GetMemoryInfo();
|
||||
} else if (cur_info.GetSize() == remaining_size) {
|
||||
/* Otherwise if we can map precisely, we may need to check for coalescing against next block. */
|
||||
next = it;
|
||||
++next;
|
||||
if (next != this->memory_block_tree.end()) {
|
||||
check_coalesce_next = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the locked update function. */
|
||||
(std::addressof(*it)->*lock_func)(perm);
|
||||
cur_address += cur_info.GetSize();
|
||||
remaining_pages -= cur_info.GetNumPages();
|
||||
it++;
|
||||
}
|
||||
|
||||
/* If we should try to coalesce prev, do so. */
|
||||
if (check_coalesce_prev) {
|
||||
it = prev;
|
||||
it++;
|
||||
if (prev->HasSameProperties(*it)) {
|
||||
KMemoryBlock *block = std::addressof(*it);
|
||||
const size_t pages = it->GetNumPages();
|
||||
this->memory_block_tree.erase(it);
|
||||
allocator->Free(block);
|
||||
prev->Add(pages);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we should try to coalesce next, do so. */
|
||||
if (check_coalesce_next) {
|
||||
it = next;
|
||||
it--;
|
||||
if (it->HasSameProperties(*next)) {
|
||||
KMemoryBlock *block = std::addressof(*next);
|
||||
const size_t pages = next->GetNumPages();
|
||||
this->memory_block_tree.erase(next);
|
||||
allocator->Free(block);
|
||||
it->Add(pages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Debug. */
|
||||
bool KMemoryBlockManager::CheckState() const {
|
||||
/* If we fail, we should dump blocks. */
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace ams::kern {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr PageTableEntry KernelRwDataAttribute(PageTableEntry::Permission_KernelRW, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable);
|
||||
constexpr PageTableEntry KernelRwDataAttribute(PageTableEntry::Permission_KernelRW, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped);
|
||||
|
||||
constexpr size_t CarveoutAlignment = 0x20000;
|
||||
constexpr size_t CarveoutSizeMax = 512_MB - CarveoutAlignment;
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace ams::kern {
|
||||
Impl *chosen_manager = nullptr;
|
||||
KVirtualAddress allocated_block = Null<KVirtualAddress>;
|
||||
for (chosen_manager = this->GetFirstManager(pool, dir); chosen_manager != nullptr; chosen_manager = this->GetNextManager(chosen_manager, dir)) {
|
||||
allocated_block = chosen_manager->AllocateBlock(heap_index);
|
||||
allocated_block = chosen_manager->AllocateBlock(heap_index, true);
|
||||
if (allocated_block != Null<KVirtualAddress>) {
|
||||
break;
|
||||
}
|
||||
@@ -129,19 +129,7 @@ namespace ams::kern {
|
||||
return allocated_block;
|
||||
}
|
||||
|
||||
Result KMemoryManager::Allocate(KPageGroup *out, size_t num_pages, u32 option) {
|
||||
MESOSPHERE_ASSERT(out != nullptr);
|
||||
MESOSPHERE_ASSERT(out->GetNumPages() == 0);
|
||||
|
||||
/* Early return if we're allocating no pages. */
|
||||
if (num_pages == 0) {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* Lock the pool that we're allocating from. */
|
||||
const auto [pool, dir] = DecodeOption(option);
|
||||
KScopedLightLock lk(this->pool_locks[pool]);
|
||||
|
||||
Result KMemoryManager::AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool optimize, bool random) {
|
||||
/* Choose a heap based on our page size request. */
|
||||
const s32 heap_index = KPageHeap::GetBlockIndex(num_pages);
|
||||
R_UNLESS(0 <= heap_index, svc::ResultOutOfMemory());
|
||||
@@ -162,7 +150,7 @@ namespace ams::kern {
|
||||
for (Impl *cur_manager = this->GetFirstManager(pool, dir); cur_manager != nullptr; cur_manager = this->GetNextManager(cur_manager, dir)) {
|
||||
while (num_pages >= pages_per_alloc) {
|
||||
/* Allocate a block. */
|
||||
KVirtualAddress allocated_block = cur_manager->AllocateBlock(index);
|
||||
KVirtualAddress allocated_block = cur_manager->AllocateBlock(index, random);
|
||||
if (allocated_block == Null<KVirtualAddress>) {
|
||||
break;
|
||||
}
|
||||
@@ -175,7 +163,7 @@ namespace ams::kern {
|
||||
}
|
||||
|
||||
/* Maintain the optimized memory bitmap, if we should. */
|
||||
if (this->has_optimized_process[pool]) {
|
||||
if (optimize) {
|
||||
cur_manager->TrackAllocationForOptimizedProcess(allocated_block, pages_per_alloc);
|
||||
}
|
||||
|
||||
@@ -193,6 +181,21 @@ namespace ams::kern {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result KMemoryManager::Allocate(KPageGroup *out, size_t num_pages, u32 option) {
|
||||
MESOSPHERE_ASSERT(out != nullptr);
|
||||
MESOSPHERE_ASSERT(out->GetNumPages() == 0);
|
||||
|
||||
/* Early return if we're allocating no pages. */
|
||||
R_SUCCEED_IF(num_pages == 0);
|
||||
|
||||
/* Lock the pool that we're allocating from. */
|
||||
const auto [pool, dir] = DecodeOption(option);
|
||||
KScopedLightLock lk(this->pool_locks[pool]);
|
||||
|
||||
/* Allocate the page group. */
|
||||
return this->AllocatePageGroupImpl(out, num_pages, pool, dir, this->has_optimized_process[pool], true);
|
||||
}
|
||||
|
||||
size_t KMemoryManager::Impl::Initialize(const KMemoryRegion *region, Pool p, KVirtualAddress metadata, KVirtualAddress metadata_end) {
|
||||
/* Calculate metadata sizes. */
|
||||
const size_t ref_count_size = (region->GetSize() / PageSize) * sizeof(u16);
|
||||
|
||||
@@ -51,11 +51,11 @@ namespace ams::kern {
|
||||
return num_free;
|
||||
}
|
||||
|
||||
KVirtualAddress KPageHeap::AllocateBlock(s32 index) {
|
||||
KVirtualAddress KPageHeap::AllocateBlock(s32 index, bool random) {
|
||||
const size_t needed_size = this->blocks[index].GetSize();
|
||||
|
||||
for (s32 i = index; i < static_cast<s32>(this->num_blocks); i++) {
|
||||
if (const KVirtualAddress addr = this->blocks[i].PopBlock(); addr != Null<KVirtualAddress>) {
|
||||
if (const KVirtualAddress addr = this->blocks[i].PopBlock(random); addr != Null<KVirtualAddress>) {
|
||||
if (const size_t allocated_size = this->blocks[i].GetSize(); allocated_size > needed_size) {
|
||||
this->Free(addr + needed_size, (allocated_size - needed_size) / PageSize);
|
||||
}
|
||||
|
||||
@@ -20,35 +20,36 @@ namespace ams::kern {
|
||||
|
||||
Result KPageTableBase::InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end) {
|
||||
/* Initialize our members. */
|
||||
this->address_space_width = (is_64_bit) ? BITSIZEOF(u64) : BITSIZEOF(u32);
|
||||
this->address_space_start = KProcessAddress(GetInteger(start));
|
||||
this->address_space_end = KProcessAddress(GetInteger(end));
|
||||
this->is_kernel = true;
|
||||
this->enable_aslr = true;
|
||||
this->address_space_width = (is_64_bit) ? BITSIZEOF(u64) : BITSIZEOF(u32);
|
||||
this->address_space_start = KProcessAddress(GetInteger(start));
|
||||
this->address_space_end = KProcessAddress(GetInteger(end));
|
||||
this->is_kernel = true;
|
||||
this->enable_aslr = true;
|
||||
|
||||
this->heap_region_start = 0;
|
||||
this->heap_region_end = 0;
|
||||
this->current_heap_end = 0;
|
||||
this->alias_region_start = 0;
|
||||
this->alias_region_end = 0;
|
||||
this->stack_region_start = 0;
|
||||
this->stack_region_end = 0;
|
||||
this->kernel_map_region_start = 0;
|
||||
this->kernel_map_region_end = 0;
|
||||
this->alias_code_region_start = 0;
|
||||
this->alias_code_region_end = 0;
|
||||
this->code_region_start = 0;
|
||||
this->code_region_end = 0;
|
||||
this->max_heap_size = 0;
|
||||
this->max_physical_memory_size = 0;
|
||||
this->heap_region_start = 0;
|
||||
this->heap_region_end = 0;
|
||||
this->current_heap_end = 0;
|
||||
this->alias_region_start = 0;
|
||||
this->alias_region_end = 0;
|
||||
this->stack_region_start = 0;
|
||||
this->stack_region_end = 0;
|
||||
this->kernel_map_region_start = 0;
|
||||
this->kernel_map_region_end = 0;
|
||||
this->alias_code_region_start = 0;
|
||||
this->alias_code_region_end = 0;
|
||||
this->code_region_start = 0;
|
||||
this->code_region_end = 0;
|
||||
this->max_heap_size = 0;
|
||||
this->max_physical_memory_size = 0;
|
||||
this->mapped_unsafe_physical_memory = 0;
|
||||
|
||||
this->memory_block_slab_manager = std::addressof(Kernel::GetSystemMemoryBlockManager());
|
||||
this->block_info_manager = std::addressof(Kernel::GetBlockInfoManager());
|
||||
this->memory_block_slab_manager = std::addressof(Kernel::GetSystemMemoryBlockManager());
|
||||
this->block_info_manager = std::addressof(Kernel::GetBlockInfoManager());
|
||||
|
||||
this->allocate_option = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
|
||||
this->heap_fill_value = MemoryFillValue_Zero;
|
||||
this->ipc_fill_value = MemoryFillValue_Zero;
|
||||
this->stack_fill_value = MemoryFillValue_Zero;
|
||||
this->allocate_option = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
|
||||
this->heap_fill_value = MemoryFillValue_Zero;
|
||||
this->ipc_fill_value = MemoryFillValue_Zero;
|
||||
this->stack_fill_value = MemoryFillValue_Zero;
|
||||
|
||||
this->cached_physical_linear_region = nullptr;
|
||||
this->cached_physical_heap_region = nullptr;
|
||||
@@ -222,9 +223,10 @@ namespace ams::kern {
|
||||
}
|
||||
|
||||
/* Set heap and fill members. */
|
||||
this->current_heap_end = this->heap_region_start;
|
||||
this->max_heap_size = 0;
|
||||
this->max_physical_memory_size = 0;
|
||||
this->current_heap_end = this->heap_region_start;
|
||||
this->max_heap_size = 0;
|
||||
this->max_physical_memory_size = 0;
|
||||
this->mapped_unsafe_physical_memory = 0;
|
||||
|
||||
const bool fill_memory = KTargetSystem::IsDebugMemoryFillEnabled();
|
||||
this->heap_fill_value = fill_memory ? MemoryFillValue_Heap : MemoryFillValue_Zero;
|
||||
|
||||
@@ -35,7 +35,8 @@ namespace ams::kern {
|
||||
|
||||
/* Create and clear the process local region. */
|
||||
R_TRY(this->CreateThreadLocalRegion(std::addressof(this->plr_address)));
|
||||
std::memset(this->GetThreadLocalRegionPointer(this->plr_address), 0, ams::svc::ThreadLocalRegionSize);
|
||||
this->plr_heap_address = this->GetThreadLocalRegionPointer(this->plr_address);
|
||||
std::memset(this->plr_heap_address, 0, ams::svc::ThreadLocalRegionSize);
|
||||
|
||||
/* Copy in the name from parameters. */
|
||||
static_assert(sizeof(params.name) < sizeof(this->name));
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace ams::kern {
|
||||
|
||||
namespace {
|
||||
|
||||
KDynamicPageManager g_resource_manager_page_manager;
|
||||
|
||||
template<typename T>
|
||||
ALWAYS_INLINE void PrintMemoryRegion(const char *prefix, const T &extents) {
|
||||
static_assert(std::is_same<decltype(extents.GetAddress()), uintptr_t>::value);
|
||||
@@ -88,24 +90,29 @@ namespace ams::kern {
|
||||
|
||||
void Kernel::InitializeResourceManagers(KVirtualAddress address, size_t size) {
|
||||
/* Ensure that the buffer is suitable for our use. */
|
||||
const size_t app_size = ApplicationMemoryBlockSlabHeapSize * sizeof(KMemoryBlock);
|
||||
const size_t sys_size = SystemMemoryBlockSlabHeapSize * sizeof(KMemoryBlock);
|
||||
const size_t info_size = BlockInfoSlabHeapSize * sizeof(KBlockInfo);
|
||||
const size_t fixed_size = util::AlignUp(app_size + sys_size + info_size, PageSize);
|
||||
//const size_t app_size = ApplicationMemoryBlockSlabHeapSize * sizeof(KMemoryBlock);
|
||||
//const size_t sys_size = SystemMemoryBlockSlabHeapSize * sizeof(KMemoryBlock);
|
||||
//const size_t info_size = BlockInfoSlabHeapSize * sizeof(KBlockInfo);
|
||||
//const size_t fixed_size = util::AlignUp(app_size + sys_size + info_size, PageSize);
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(address), PageSize));
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, PageSize));
|
||||
MESOSPHERE_ABORT_UNLESS(fixed_size < size);
|
||||
|
||||
size_t pt_size = size - fixed_size;
|
||||
const size_t rc_size = util::AlignUp(KPageTableManager::CalculateReferenceCountSize(pt_size), PageSize);
|
||||
MESOSPHERE_ABORT_UNLESS(rc_size < pt_size);
|
||||
pt_size -= rc_size;
|
||||
/* Ensure that we have space for our reference counts. */
|
||||
const size_t rc_size = util::AlignUp(KPageTableManager::CalculateReferenceCountSize(size), PageSize);
|
||||
MESOSPHERE_ABORT_UNLESS(rc_size < size);
|
||||
size -= rc_size;
|
||||
|
||||
/* Initialize the slabheaps. */
|
||||
s_app_memory_block_manager.Initialize(address + pt_size, app_size);
|
||||
s_sys_memory_block_manager.Initialize(address + pt_size + app_size, sys_size);
|
||||
s_block_info_manager.Initialize(address + pt_size + app_size + sys_size, info_size);
|
||||
s_page_table_manager.Initialize(address, pt_size, GetPointer<KPageTableManager::RefCount>(address + pt_size + fixed_size));
|
||||
/* Initialize the resource managers' shared page manager. */
|
||||
g_resource_manager_page_manager.Initialize(address, size);
|
||||
|
||||
/* Initialize the fixed-size slabheaps. */
|
||||
s_app_memory_block_manager.Initialize(std::addressof(g_resource_manager_page_manager), ApplicationMemoryBlockSlabHeapSize);
|
||||
s_sys_memory_block_manager.Initialize(std::addressof(g_resource_manager_page_manager), SystemMemoryBlockSlabHeapSize);
|
||||
s_block_info_manager.Initialize(std::addressof(g_resource_manager_page_manager), BlockInfoSlabHeapSize);
|
||||
|
||||
/* Reserve all remaining pages for the page table manager. */
|
||||
const size_t num_pt_pages = g_resource_manager_page_manager.GetCount() - g_resource_manager_page_manager.GetUsed();
|
||||
s_page_table_manager.Initialize(std::addressof(g_resource_manager_page_manager), num_pt_pages, GetPointer<KPageTableManager::RefCount>(address + size));
|
||||
}
|
||||
|
||||
void Kernel::PrintLayout() {
|
||||
|
||||
@@ -14,7 +14,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).
|
||||
|
||||
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 libstratosphere 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 libstratosphere 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 libstratosphere project under the Zero-Clause BSD license.
|
||||
|
||||
Credits
|
||||
|
||||
@@ -19,47 +19,55 @@
|
||||
/* libvapours (pulls in util, svc, results). */
|
||||
#include <vapours.hpp>
|
||||
|
||||
/* Libstratosphere definitions. */
|
||||
#include <stratosphere/ams/impl/ams_system_thread_definitions.hpp>
|
||||
|
||||
/* Libstratosphere-only utility. */
|
||||
#include "stratosphere/util.hpp"
|
||||
#include <stratosphere/util.hpp>
|
||||
|
||||
/* Sadly required shims. */
|
||||
#include "stratosphere/svc/svc_stratosphere_shims.hpp"
|
||||
#include <stratosphere/svc/svc_stratosphere_shims.hpp>
|
||||
|
||||
/* Critical modules with no dependencies. */
|
||||
#include "stratosphere/ams.hpp"
|
||||
#include "stratosphere/os.hpp"
|
||||
#include "stratosphere/dd.hpp"
|
||||
#include "stratosphere/lmem.hpp"
|
||||
#include "stratosphere/mem.hpp"
|
||||
#include <stratosphere/ams.hpp>
|
||||
#include <stratosphere/os.hpp>
|
||||
#include <stratosphere/dd.hpp>
|
||||
#include <stratosphere/lmem.hpp>
|
||||
#include <stratosphere/mem.hpp>
|
||||
|
||||
/* Pull in all ID definitions from NCM. */
|
||||
#include "stratosphere/ncm/ncm_ids.hpp"
|
||||
#include <stratosphere/ncm/ncm_ids.hpp>
|
||||
|
||||
/* At this point, just include the rest alphabetically. */
|
||||
/* TODO: Figure out optimal order. */
|
||||
#include "stratosphere/boot2.hpp"
|
||||
#include "stratosphere/cfg.hpp"
|
||||
#include "stratosphere/dmnt.hpp"
|
||||
#include "stratosphere/fatal.hpp"
|
||||
#include "stratosphere/hid.hpp"
|
||||
#include "stratosphere/hos.hpp"
|
||||
#include "stratosphere/kvdb.hpp"
|
||||
#include "stratosphere/ldr.hpp"
|
||||
#include "stratosphere/lr.hpp"
|
||||
#include "stratosphere/map.hpp"
|
||||
#include "stratosphere/ncm.hpp"
|
||||
#include "stratosphere/patcher.hpp"
|
||||
#include "stratosphere/pm.hpp"
|
||||
#include "stratosphere/reg.hpp"
|
||||
#include "stratosphere/ro.hpp"
|
||||
#include "stratosphere/settings.hpp"
|
||||
#include "stratosphere/sf.hpp"
|
||||
#include "stratosphere/sm.hpp"
|
||||
#include "stratosphere/spl.hpp"
|
||||
#include "stratosphere/updater.hpp"
|
||||
|
||||
#include <stratosphere/boot2.hpp>
|
||||
#include <stratosphere/capsrv.hpp>
|
||||
#include <stratosphere/cfg.hpp>
|
||||
#include <stratosphere/dmnt.hpp>
|
||||
#include <stratosphere/erpt.hpp>
|
||||
#include <stratosphere/fatal.hpp>
|
||||
#include <stratosphere/hid.hpp>
|
||||
#include <stratosphere/hos.hpp>
|
||||
#include <stratosphere/kvdb.hpp>
|
||||
#include <stratosphere/ldr.hpp>
|
||||
#include <stratosphere/lr.hpp>
|
||||
#include <stratosphere/map.hpp>
|
||||
#include <stratosphere/ncm.hpp>
|
||||
#include <stratosphere/nim.hpp>
|
||||
#include <stratosphere/patcher.hpp>
|
||||
#include <stratosphere/pgl.hpp>
|
||||
#include <stratosphere/psc.hpp>
|
||||
#include <stratosphere/pm.hpp>
|
||||
#include <stratosphere/reg.hpp>
|
||||
#include <stratosphere/ro.hpp>
|
||||
#include <stratosphere/settings.hpp>
|
||||
#include <stratosphere/sf.hpp>
|
||||
#include <stratosphere/sm.hpp>
|
||||
#include <stratosphere/spl.hpp>
|
||||
#include <stratosphere/time.hpp>
|
||||
#include <stratosphere/updater.hpp>
|
||||
|
||||
/* Include FS last. */
|
||||
#include "stratosphere/fs.hpp"
|
||||
#include "stratosphere/fssrv.hpp"
|
||||
#include "stratosphere/fssystem.hpp"
|
||||
#include <stratosphere/fs.hpp>
|
||||
#include <stratosphere/fssrv.hpp>
|
||||
#include <stratosphere/fssystem.hpp>
|
||||
@@ -22,4 +22,8 @@ namespace ams {
|
||||
/* Will be called by libstratosphere on crash. */
|
||||
void CrashHandler(ThreadExceptionDump *ctx);
|
||||
|
||||
/* API for boot sysmodule. */
|
||||
void InitializeForBoot();
|
||||
void SetInitialRebootPayload(const void *src, size_t src_size);
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,11 @@ namespace ams::exosphere {
|
||||
|
||||
bool IsRcmBugPatched();
|
||||
|
||||
bool ShouldBlankProdInfo();
|
||||
bool ShouldAllowWritesToProdInfo();
|
||||
|
||||
u64 GetDeviceId();
|
||||
|
||||
void CopyToIram(uintptr_t iram_dst, const void *dram_src, size_t size);
|
||||
void CopyFromIram(void *dram_dst, uintptr_t iram_src, size_t size);
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace ams::exosphere {
|
||||
AMS_DEFINE_TARGET_FIRMWARE_ENUM(810),
|
||||
AMS_DEFINE_TARGET_FIRMWARE_ENUM(900),
|
||||
AMS_DEFINE_TARGET_FIRMWARE_ENUM(910),
|
||||
AMS_DEFINE_TARGET_FIRMWARE_ENUM(1000),
|
||||
};
|
||||
#undef AMS_DEFINE_TARGET_FIRMWARE_ENUM
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::impl {
|
||||
|
||||
struct SystemThreadDefinition {
|
||||
s32 priority;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#define AMS_DEFINE_SYSTEM_THREAD(__AMS_THREAD_PRIORITY__, __AMS_MODULE__, __AMS_THREAD_NAME__) \
|
||||
constexpr inline const ::ams::impl::SystemThreadDefinition SystemThreadDefinition##__AMS_MODULE__##__AMS_THREAD_NAME__ = { __AMS_THREAD_PRIORITY__, "ams." # __AMS_MODULE__ "." #__AMS_THREAD_NAME__ }
|
||||
|
||||
/* sm. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(-1, sm, Main);
|
||||
|
||||
/* spl. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(-1, spl, Main);
|
||||
|
||||
/* Loader. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, ldr, Main);
|
||||
|
||||
/* Process Manager. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, pm, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, pm, ProcessTrack);
|
||||
|
||||
/* NCM. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, ncm, MainWaitThreads);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, ncm, ContentManagerServerIpcSession);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, ncm, LocationResolverServerIpcSession);
|
||||
|
||||
/* FS. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(16, fs, WorkerThreadPool);
|
||||
AMS_DEFINE_SYSTEM_THREAD(17, fs, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(17, fs, WorkerRealTimeAccess);
|
||||
AMS_DEFINE_SYSTEM_THREAD(18, fs, WorkerNormalPriorityAccess);
|
||||
AMS_DEFINE_SYSTEM_THREAD(19, fs, WorkerLowPriorityAccess);
|
||||
AMS_DEFINE_SYSTEM_THREAD(30, fs, WorkerBackgroundAccess);
|
||||
AMS_DEFINE_SYSTEM_THREAD(30, fs, PatrolReader);
|
||||
|
||||
/* Boot. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(-1, boot, Main);
|
||||
|
||||
/* Mitm. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(-7, mitm, InitializeThread);
|
||||
AMS_DEFINE_SYSTEM_THREAD(-1, mitm_sf, QueryServerProcessThread);
|
||||
AMS_DEFINE_SYSTEM_THREAD(16, mitm_fs, RomFileSystemInitializeThread);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, mitm, DebugThrowThread);
|
||||
|
||||
/* boot2. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(20, boot2, Main);
|
||||
|
||||
/* dmnt. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(-3, dmnt, MultiCoreEventManager);
|
||||
AMS_DEFINE_SYSTEM_THREAD(-1, dmnt, CheatDebugEvents);
|
||||
AMS_DEFINE_SYSTEM_THREAD(-1, dmnt, MultiCoreBP);
|
||||
AMS_DEFINE_SYSTEM_THREAD(11, dmnt, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(11, dmnt, Ipc);
|
||||
AMS_DEFINE_SYSTEM_THREAD(11, dmnt, CheatDetect);
|
||||
AMS_DEFINE_SYSTEM_THREAD(20, dmnt, CheatVirtualMachine);
|
||||
|
||||
/* fatal */
|
||||
AMS_DEFINE_SYSTEM_THREAD(-13, fatal, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(-13, fatalsrv, FatalTaskThread);
|
||||
AMS_DEFINE_SYSTEM_THREAD( 9, fatalsrv, IpcDispatcher);
|
||||
|
||||
/* creport. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(16, creport, Main);
|
||||
|
||||
/* ro. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(16, ro, Main);
|
||||
|
||||
/* bpc. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(4, bpc, IpcServer);
|
||||
|
||||
/* hid. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(-10, hid, IpcServer);
|
||||
|
||||
/* ns.*/
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, ns, ApplicationManagerIpcSession);
|
||||
|
||||
/* settings. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, settings, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, settings, IpcServer);
|
||||
|
||||
/* erpt. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, erpt, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, erpt, IpcServer);
|
||||
|
||||
/* jpegdec. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, jpegdec, Main);
|
||||
|
||||
/* pgl. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, pgl, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, pgl, ProcessControlTask);
|
||||
|
||||
#undef AMS_DEFINE_SYSTEM_THREAD
|
||||
|
||||
}
|
||||
|
||||
#define AMS_GET_SYSTEM_THREAD_PRIORITY(__AMS_MODULE__, __AMS_THREAD_NAME__) ::ams::impl::SystemThreadDefinition##__AMS_MODULE__##__AMS_THREAD_NAME__.priority
|
||||
#define AMS_GET_SYSTEM_THREAD_NAME(__AMS_MODULE__, __AMS_THREAD_NAME__) ::ams::impl::SystemThreadDefinition##__AMS_MODULE__##__AMS_THREAD_NAME__.name
|
||||
22
libraries/libstratosphere/include/stratosphere/capsrv.hpp
Normal file
22
libraries/libstratosphere/include/stratosphere/capsrv.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stratosphere/capsrv/capsrv_screen_shot_decode_option.hpp>
|
||||
#include <stratosphere/capsrv/server/capsrv_server_config.hpp>
|
||||
#include <stratosphere/capsrv/server/capsrv_server_decoder_api.hpp>
|
||||
#include <stratosphere/capsrv/capsrv_screen_shot_control_api.hpp>
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/vi/vi_layer_stack.hpp>
|
||||
|
||||
namespace ams::capsrv {
|
||||
|
||||
constexpr inline s32 DefaultCaptureTimeoutMilliSeconds = 100;
|
||||
|
||||
Result InitializeScreenShotControl();
|
||||
void FinalizeScreenShotControl();
|
||||
|
||||
Result CaptureJpegScreenshot(u64 *out_size, void *dst, size_t dst_size, vi::LayerStack layer_stack, TimeSpan timeout);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::capsrv {
|
||||
|
||||
enum ScreenShotDecoderFlag : u64 {
|
||||
ScreenShotDecoderFlag_None = (0 << 0),
|
||||
ScreenShotDecoderFlag_EnableFancyUpsampling = (1 << 0),
|
||||
ScreenShotDecoderFlag_EnableBlockSmoothing = (1 << 1),
|
||||
};
|
||||
|
||||
using ScreenShotJpegDecoderFlagType = typename std::underlying_type<ScreenShotDecoderFlag>::type;
|
||||
|
||||
struct ScreenShotDecodeOption {
|
||||
ScreenShotJpegDecoderFlagType flags;
|
||||
u8 reserved[0x20 - sizeof(ScreenShotJpegDecoderFlagType)];
|
||||
|
||||
static constexpr ScreenShotDecodeOption GetDefaultOption() {
|
||||
return ScreenShotDecodeOption{};
|
||||
}
|
||||
|
||||
constexpr bool HasJpegDecoderFlag(ScreenShotJpegDecoderFlagType flag) const {
|
||||
return (this->flags & flag) != 0;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(ScreenShotDecodeOption) == 0x20);
|
||||
static_assert(sizeof(ScreenShotDecodeOption) == sizeof(::CapsScreenShotDecodeOption));
|
||||
static_assert(std::is_pod<ScreenShotDecodeOption>::value);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::capsrv::server {
|
||||
|
||||
constexpr inline int ScreenShotWidth = 1280;
|
||||
constexpr inline int ScreenShotHeight = 720;
|
||||
|
||||
constexpr inline int MovieWidth = 1280;
|
||||
constexpr inline int MovieHeight = 720;
|
||||
|
||||
constexpr inline size_t SoftwareJpegDecoderWorkMemorySize = 16_KB;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::capsrv::server {
|
||||
|
||||
Result InitializeForDecoderServer();
|
||||
void FinalizeForDecoderServer();
|
||||
|
||||
void DecoderControlServerThreadFunction(void *);
|
||||
|
||||
}
|
||||
25
libraries/libstratosphere/include/stratosphere/erpt.hpp
Normal file
25
libraries/libstratosphere/include/stratosphere/erpt.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stratosphere/erpt/erpt_ids.autogen.hpp>
|
||||
#include <stratosphere/erpt/erpt_types.hpp>
|
||||
#include <stratosphere/erpt/erpt_multiple_category_context.hpp>
|
||||
#include <stratosphere/erpt/sf/erpt_sf_i_context.hpp>
|
||||
#include <stratosphere/erpt/sf/erpt_sf_i_session.hpp>
|
||||
#include <stratosphere/erpt/srv/erpt_srv_types.hpp>
|
||||
#include <stratosphere/erpt/srv/erpt_srv_api.hpp>
|
||||
@@ -0,0 +1,780 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
/* NOTE: This file is auto-generated. */
|
||||
/* Do not make edits to this file by hand. */
|
||||
|
||||
#define AMS_ERPT_FOREACH_FIELD_TYPE(HANDLER) \
|
||||
HANDLER(FieldType_NumericU64, 0 ) \
|
||||
HANDLER(FieldType_NumericU32, 1 ) \
|
||||
HANDLER(FieldType_NumericI64, 2 ) \
|
||||
HANDLER(FieldType_NumericI32, 3 ) \
|
||||
HANDLER(FieldType_String, 4 ) \
|
||||
HANDLER(FieldType_U8Array, 5 ) \
|
||||
HANDLER(FieldType_U32Array, 6 ) \
|
||||
HANDLER(FieldType_U64Array, 7 ) \
|
||||
HANDLER(FieldType_I32Array, 8 ) \
|
||||
HANDLER(FieldType_I64Array, 9 ) \
|
||||
HANDLER(FieldType_Bool, 10) \
|
||||
HANDLER(FieldType_NumericU16, 11) \
|
||||
HANDLER(FieldType_NumericU8, 12) \
|
||||
HANDLER(FieldType_NumericI16, 13) \
|
||||
HANDLER(FieldType_NumericI8, 14) \
|
||||
HANDLER(FieldType_I8Array, 15) \
|
||||
|
||||
#define AMS_ERPT_FOREACH_CATEGORY(HANDLER) \
|
||||
HANDLER(Test, 0 ) \
|
||||
HANDLER(ErrorInfo, 1 ) \
|
||||
HANDLER(ConnectionStatusInfo, 2 ) \
|
||||
HANDLER(NetworkInfo, 3 ) \
|
||||
HANDLER(NXMacAddressInfo, 4 ) \
|
||||
HANDLER(StealthNetworkInfo, 5 ) \
|
||||
HANDLER(LimitHighCapacityInfo, 6 ) \
|
||||
HANDLER(NATTypeInfo, 7 ) \
|
||||
HANDLER(WirelessAPMacAddressInfo, 8 ) \
|
||||
HANDLER(GlobalIPAddressInfo, 9 ) \
|
||||
HANDLER(EnableWirelessInterfaceInfo, 10 ) \
|
||||
HANDLER(EnableWifiInfo, 11 ) \
|
||||
HANDLER(EnableBluetoothInfo, 12 ) \
|
||||
HANDLER(EnableNFCInfo, 13 ) \
|
||||
HANDLER(NintendoZoneSSIDListVersionInfo, 14 ) \
|
||||
HANDLER(LANAdapterMacAddressInfo, 15 ) \
|
||||
HANDLER(ApplicationInfo, 16 ) \
|
||||
HANDLER(OccurrenceInfo, 17 ) \
|
||||
HANDLER(ProductModelInfo, 18 ) \
|
||||
HANDLER(CurrentLanguageInfo, 19 ) \
|
||||
HANDLER(UseNetworkTimeProtocolInfo, 20 ) \
|
||||
HANDLER(TimeZoneInfo, 21 ) \
|
||||
HANDLER(ControllerFirmwareInfo, 22 ) \
|
||||
HANDLER(VideoOutputInfo, 23 ) \
|
||||
HANDLER(NANDFreeSpaceInfo, 24 ) \
|
||||
HANDLER(SDCardFreeSpaceInfo, 25 ) \
|
||||
HANDLER(ScreenBrightnessInfo, 26 ) \
|
||||
HANDLER(AudioFormatInfo, 27 ) \
|
||||
HANDLER(MuteOnHeadsetUnpluggedInfo, 28 ) \
|
||||
HANDLER(NumUserRegisteredInfo, 29 ) \
|
||||
HANDLER(DataDeletionInfo, 30 ) \
|
||||
HANDLER(ControllerVibrationInfo, 31 ) \
|
||||
HANDLER(LockScreenInfo, 32 ) \
|
||||
HANDLER(InternalBatteryLotNumberInfo, 33 ) \
|
||||
HANDLER(LeftControllerSerialNumberInfo, 34 ) \
|
||||
HANDLER(RightControllerSerialNumberInfo, 35 ) \
|
||||
HANDLER(NotificationInfo, 36 ) \
|
||||
HANDLER(TVInfo, 37 ) \
|
||||
HANDLER(SleepInfo, 38 ) \
|
||||
HANDLER(ConnectionInfo, 39 ) \
|
||||
HANDLER(NetworkErrorInfo, 40 ) \
|
||||
HANDLER(FileAccessPathInfo, 41 ) \
|
||||
HANDLER(GameCardCIDInfo, 42 ) \
|
||||
HANDLER(NANDCIDInfo, 43 ) \
|
||||
HANDLER(MicroSDCIDInfo, 44 ) \
|
||||
HANDLER(NANDSpeedModeInfo, 45 ) \
|
||||
HANDLER(MicroSDSpeedModeInfo, 46 ) \
|
||||
HANDLER(GameCardSpeedModeInfo, 47 ) \
|
||||
HANDLER(UserAccountInternalIDInfo, 48 ) \
|
||||
HANDLER(NetworkServiceAccountInternalIDInfo, 49 ) \
|
||||
HANDLER(NintendoAccountInternalIDInfo, 50 ) \
|
||||
HANDLER(USB3AvailableInfo, 51 ) \
|
||||
HANDLER(CallStackInfo, 52 ) \
|
||||
HANDLER(SystemStartupLogInfo, 53 ) \
|
||||
HANDLER(RegionSettingInfo, 54 ) \
|
||||
HANDLER(NintendoZoneConnectedInfo, 55 ) \
|
||||
HANDLER(ForceSleepInfo, 56 ) \
|
||||
HANDLER(ChargerInfo, 57 ) \
|
||||
HANDLER(RadioStrengthInfo, 58 ) \
|
||||
HANDLER(ErrorInfoAuto, 59 ) \
|
||||
HANDLER(AccessPointInfo, 60 ) \
|
||||
HANDLER(ErrorInfoDefaults, 61 ) \
|
||||
HANDLER(SystemPowerStateInfo, 62 ) \
|
||||
HANDLER(PerformanceInfo, 63 ) \
|
||||
HANDLER(ThrottlingInfo, 64 ) \
|
||||
HANDLER(GameCardErrorInfo, 65 ) \
|
||||
HANDLER(EdidInfo, 66 ) \
|
||||
HANDLER(ThermalInfo, 67 ) \
|
||||
HANDLER(CradleFirmwareInfo, 68 ) \
|
||||
HANDLER(RunningApplicationInfo, 69 ) \
|
||||
HANDLER(RunningAppletInfo, 70 ) \
|
||||
HANDLER(FocusedAppletHistoryInfo, 71 ) \
|
||||
HANDLER(CompositorInfo, 72 ) \
|
||||
HANDLER(BatteryChargeInfo, 73 ) \
|
||||
HANDLER(NANDExtendedCsd, 74 ) \
|
||||
HANDLER(NANDPatrolInfo, 75 ) \
|
||||
HANDLER(NANDErrorInfo, 76 ) \
|
||||
HANDLER(NANDDriverLog, 77 ) \
|
||||
HANDLER(SdCardSizeSpec, 78 ) \
|
||||
HANDLER(SdCardErrorInfo, 79 ) \
|
||||
HANDLER(SdCardDriverLog , 80 ) \
|
||||
HANDLER(FsProxyErrorInfo, 81 ) \
|
||||
HANDLER(SystemAppletSceneInfo, 82 ) \
|
||||
HANDLER(VideoInfo, 83 ) \
|
||||
HANDLER(GpuErrorInfo, 84 ) \
|
||||
HANDLER(PowerClockInfo, 85 ) \
|
||||
HANDLER(AdspErrorInfo, 86 ) \
|
||||
HANDLER(NvDispDeviceInfo, 87 ) \
|
||||
HANDLER(NvDispDcWindowInfo, 88 ) \
|
||||
HANDLER(NvDispDpModeInfo, 89 ) \
|
||||
HANDLER(NvDispDpLinkSpec, 90 ) \
|
||||
HANDLER(NvDispDpLinkStatus, 91 ) \
|
||||
HANDLER(NvDispDpHdcpInfo, 92 ) \
|
||||
HANDLER(NvDispDpAuxCecInfo, 93 ) \
|
||||
HANDLER(NvDispDcInfo, 94 ) \
|
||||
HANDLER(NvDispDsiInfo, 95 ) \
|
||||
HANDLER(NvDispErrIDInfo, 96 ) \
|
||||
HANDLER(SdCardMountInfo, 97 ) \
|
||||
HANDLER(RetailInteractiveDisplayInfo, 98 ) \
|
||||
HANDLER(CompositorStateInfo, 99 ) \
|
||||
HANDLER(CompositorLayerInfo, 100) \
|
||||
HANDLER(CompositorDisplayInfo, 101) \
|
||||
HANDLER(CompositorHWCInfo, 102) \
|
||||
HANDLER(MonitorCapability, 103) \
|
||||
HANDLER(ErrorReportSharePermissionInfo, 104) \
|
||||
HANDLER(MultimediaInfo, 105) \
|
||||
HANDLER(ConnectedControllerInfo, 106) \
|
||||
HANDLER(FsMemoryInfo, 107) \
|
||||
HANDLER(UserClockContextInfo, 108) \
|
||||
HANDLER(NetworkClockContextInfo, 109) \
|
||||
HANDLER(AcpGeneralSettingsInfo, 110) \
|
||||
HANDLER(AcpPlayLogSettingsInfo, 111) \
|
||||
HANDLER(AcpAocSettingsInfo, 112) \
|
||||
HANDLER(AcpBcatSettingsInfo, 113) \
|
||||
HANDLER(AcpStorageSettingsInfo, 114) \
|
||||
HANDLER(AcpRatingSettingsInfo, 115) \
|
||||
HANDLER(MonitorSettings, 116) \
|
||||
HANDLER(RebootlessSystemUpdateVersionInfo, 117) \
|
||||
HANDLER(NifmConnectionTestInfo, 118) \
|
||||
HANDLER(PcieLoggedStateInfo, 119) \
|
||||
HANDLER(NetworkSecurityCertificateInfo, 120) \
|
||||
HANDLER(AcpNeighborDetectionInfo, 121) \
|
||||
HANDLER(GpuCrashInfo, 122) \
|
||||
HANDLER(UsbStateInfo, 123) \
|
||||
HANDLER(NvHostErrInfo, 124) \
|
||||
HANDLER(RunningUlaInfo, 125) \
|
||||
|
||||
#define AMS_ERPT_FOREACH_FIELD(HANDLER) \
|
||||
HANDLER(TestU64, 0, Test, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(TestU32, 1, Test, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(TestI64, 2, Test, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(TestI32, 3, Test, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(TestString, 4, Test, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(TestU8Array, 5, Test, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(TestU32Array, 6, Test, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(TestU64Array, 7, Test, FieldType_U64Array, FieldFlag_None ) \
|
||||
HANDLER(TestI32Array, 8, Test, FieldType_I32Array, FieldFlag_None ) \
|
||||
HANDLER(TestI64Array, 9, Test, FieldType_I64Array, FieldFlag_None ) \
|
||||
HANDLER(ErrorCode, 10, ErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ErrorDescription, 11, ErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(OccurrenceTimestamp, 12, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(ReportIdentifier, 13, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ConnectionStatus, 14, ConnectionStatusInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(AccessPointSSID, 15, AccessPointInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(AccessPointSecurityType, 16, AccessPointInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RadioStrength, 17, RadioStrengthInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NXMacAddress, 18, NXMacAddressInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(IPAddressAcquisitionMethod, 19, NetworkInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(CurrentIPAddress, 20, NetworkInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(SubnetMask, 21, NetworkInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(GatewayIPAddress, 22, NetworkInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(DNSType, 23, NetworkInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(PriorityDNSIPAddress, 24, NetworkInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(AlternateDNSIPAddress, 25, NetworkInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(UseProxyFlag, 26, NetworkInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(ProxyIPAddress, 27, NetworkInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ProxyPort, 28, NetworkInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(ProxyAutoAuthenticateFlag, 29, NetworkInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(MTU, 30, NetworkInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(ConnectAutomaticallyFlag, 31, NetworkInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(UseStealthNetworkFlag, 32, StealthNetworkInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(LimitHighCapacityFlag, 33, LimitHighCapacityInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NATType, 34, NATTypeInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(WirelessAPMacAddress, 35, WirelessAPMacAddressInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(GlobalIPAddress, 36, GlobalIPAddressInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(EnableWirelessInterfaceFlag, 37, EnableWirelessInterfaceInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(EnableWifiFlag, 38, EnableWifiInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(EnableBluetoothFlag, 39, EnableBluetoothInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(EnableNFCFlag, 40, EnableNFCInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NintendoZoneSSIDListVersion, 41, NintendoZoneSSIDListVersionInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(LANAdapterMacAddress, 42, LANAdapterMacAddressInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ApplicationID, 43, ApplicationInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ApplicationTitle, 44, ApplicationInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ApplicationVersion, 45, ApplicationInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ApplicationStorageLocation, 46, ApplicationInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(DownloadContentType, 47, OccurrenceInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(InstallContentType, 48, OccurrenceInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ConsoleStartingUpFlag, 49, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(SystemStartingUpFlag, 50, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(ConsoleFirstInitFlag, 51, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(HomeMenuScreenDisplayedFlag, 52, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(DataManagementScreenDisplayedFlag, 53, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(ConnectionTestingFlag, 54, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(ApplicationRunningFlag, 55, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(DataCorruptionDetectedFlag, 56, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(ProductModel, 57, ProductModelInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(CurrentLanguage, 58, CurrentLanguageInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(UseNetworkTimeProtocolFlag, 59, UseNetworkTimeProtocolInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(TimeZone, 60, TimeZoneInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ControllerFirmware, 61, ControllerFirmwareInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(VideoOutputSetting, 62, VideoOutputInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(NANDFreeSpace, 63, NANDFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(SDCardFreeSpace, 64, SDCardFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(SerialNumber, 65, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(OsVersion, 66, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ScreenBrightnessAutoAdjustFlag, 67, ScreenBrightnessInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(HdmiAudioOutputMode, 68, AudioFormatInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(SpeakerAudioOutputMode, 69, AudioFormatInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(HeadphoneAudioOutputMode, 70, AudioFormatInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(MuteOnHeadsetUnpluggedFlag, 71, MuteOnHeadsetUnpluggedInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NumUserRegistered, 72, NumUserRegisteredInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(StorageAutoOrganizeFlag, 73, DataDeletionInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(ControllerVibrationVolume, 74, ControllerVibrationInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(LockScreenFlag, 75, LockScreenInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(InternalBatteryLotNumber, 76, InternalBatteryLotNumberInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(LeftControllerSerialNumber, 77, LeftControllerSerialNumberInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RightControllerSerialNumber, 78, RightControllerSerialNumberInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(NotifyInGameDownloadCompletionFlag, 79, NotificationInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NotificationSoundFlag, 80, NotificationInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(TVResolutionSetting, 81, TVInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RGBRangeSetting, 82, TVInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ReduceScreenBurnFlag, 83, TVInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(TVAllowsCecFlag, 84, TVInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(HandheldModeTimeToScreenSleep, 85, SleepInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ConsoleModeTimeToScreenSleep, 86, SleepInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(StopAutoSleepDuringContentPlayFlag, 87, SleepInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(LastConnectionTestDownloadSpeed, 88, ConnectionInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(LastConnectionTestUploadSpeed, 89, ConnectionInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(DEPRECATED_ServerFQDN, 90, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(HTTPRequestContents, 91, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(HTTPRequestResponseContents, 92, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(EdgeServerIPAddress, 93, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(CDNContentPath, 94, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(FileAccessPath, 95, FileAccessPathInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(GameCardCID, 96, GameCardCIDInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(NANDCID, 97, NANDCIDInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(MicroSDCID, 98, MicroSDCIDInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(NANDSpeedMode, 99, NANDSpeedModeInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(MicroSDSpeedMode, 100, MicroSDSpeedModeInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(GameCardSpeedMode, 101, GameCardSpeedModeInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(UserAccountInternalID, 102, UserAccountInternalIDInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(NetworkServiceAccountInternalID, 103, NetworkServiceAccountInternalIDInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(NintendoAccountInternalID, 104, NintendoAccountInternalIDInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(USB3AvailableFlag, 105, USB3AvailableInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(CallStack, 106, CallStackInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(SystemStartupLog, 107, SystemStartupLogInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RegionSetting, 108, RegionSettingInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(NintendoZoneConnectedFlag, 109, NintendoZoneConnectedInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(ForcedSleepHighTemperatureReading, 110, ForceSleepInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(ForcedSleepFanSpeedReading, 111, ForceSleepInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(ForcedSleepHWInfo, 112, ForceSleepInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(AbnormalPowerStateInfo, 113, ChargerInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(ScreenBrightnessLevel, 114, ScreenBrightnessInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ProgramId, 115, ErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(AbortFlag, 116, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(ReportVisibilityFlag, 117, ErrorInfoAuto, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(FatalFlag, 118, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(OccurrenceTimestampNet, 119, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(ResultBacktrace, 120, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(GeneralRegisterAarch32, 121, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(StackBacktrace32, 122, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(ExceptionInfoAarch32, 123, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(GeneralRegisterAarch64, 124, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \
|
||||
HANDLER(ExceptionInfoAarch64, 125, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \
|
||||
HANDLER(StackBacktrace64, 126, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \
|
||||
HANDLER(RegisterSetFlag32, 127, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(RegisterSetFlag64, 128, ErrorInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(ProgramMappedAddr32, 129, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(ProgramMappedAddr64, 130, ErrorInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(AbortType, 131, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(PrivateOsVersion, 132, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(CurrentSystemPowerState, 133, SystemPowerStateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(PreviousSystemPowerState, 134, SystemPowerStateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(DestinationSystemPowerState, 135, SystemPowerStateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(PscTransitionCurrentState, 136, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(PscTransitionPreviousState, 137, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(PscInitializedList, 138, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(PscCurrentPmStateList, 139, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(PscNextPmStateList, 140, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(PerformanceMode, 141, PerformanceInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(PerformanceConfiguration, 142, PerformanceInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(Throttled, 143, ThrottlingInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(ThrottlingDuration, 144, ThrottlingInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(ThrottlingTimestamp, 145, ThrottlingInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(GameCardCrcErrorCount, 146, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GameCardAsicCrcErrorCount, 147, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GameCardRefreshCount, 148, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GameCardReadRetryCount, 149, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(EdidBlock, 150, EdidInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(EdidExtensionBlock, 151, EdidInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(CreateProcessFailureFlag, 152, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(TemperaturePcb, 153, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(TemperatureSoc, 154, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(CurrentFanDuty, 155, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(LastDvfsThresholdTripped, 156, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(CradlePdcHFwVersion, 157, CradleFirmwareInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(CradlePdcAFwVersion, 158, CradleFirmwareInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(CradleMcuFwVersion, 159, CradleFirmwareInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(CradleDp2HdmiFwVersion, 160, CradleFirmwareInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(RunningApplicationId, 161, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RunningApplicationTitle, 162, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RunningApplicationVersion, 163, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RunningApplicationStorageLocation, 164, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RunningAppletList, 165, RunningAppletInfo, FieldType_U64Array, FieldFlag_None ) \
|
||||
HANDLER(FocusedAppletHistory, 166, FocusedAppletHistoryInfo, FieldType_U64Array, FieldFlag_None ) \
|
||||
HANDLER(CompositorState, 167, CompositorStateInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(CompositorLayerState, 168, CompositorLayerInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(CompositorDisplayState, 169, CompositorDisplayInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(CompositorHWCState, 170, CompositorHWCInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(InputCurrentLimit, 171, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(BoostModeCurrentLimit, 172, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(FastChargeCurrentLimit, 173, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(ChargeVoltageLimit, 174, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(ChargeConfiguration, 175, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(HizMode, 176, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(ChargeEnabled, 177, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(PowerSupplyPath, 178, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(BatteryTemperature, 179, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(BatteryChargePercent, 180, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(BatteryChargeVoltage, 181, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(BatteryAge, 182, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(PowerRole, 183, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(PowerSupplyType, 184, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(PowerSupplyVoltage, 185, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(PowerSupplyCurrent, 186, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(FastBatteryChargingEnabled, 187, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(ControllerPowerSupplyAcquired, 188, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(OtgRequested, 189, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NANDPreEolInfo, 190, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NANDDeviceLifeTimeEstTypA, 191, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NANDDeviceLifeTimeEstTypB, 192, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NANDPatrolCount, 193, NANDPatrolInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NANDNumActivationFailures, 194, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NANDNumActivationErrorCorrections, 195, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NANDNumReadWriteFailures, 196, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NANDNumReadWriteErrorCorrections, 197, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NANDErrorLog, 198, NANDDriverLog, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(SdCardUserAreaSize, 199, SdCardSizeSpec, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(SdCardProtectedAreaSize, 200, SdCardSizeSpec, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(SdCardNumActivationFailures, 201, SdCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(SdCardNumActivationErrorCorrections, 202, SdCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(SdCardNumReadWriteFailures, 203, SdCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(SdCardNumReadWriteErrorCorrections, 204, SdCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(SdCardErrorLog, 205, SdCardDriverLog , FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(EncryptionKey, 206, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(EncryptedExceptionInfo, 207, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(GameCardTimeoutRetryErrorCount, 208, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(FsRemountForDataCorruptCount, 209, FsProxyErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(FsRemountForDataCorruptRetryOutCount, 210, FsProxyErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GameCardInsertionCount, 211, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GameCardRemovalCount, 212, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GameCardAsicInitializeCount, 213, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(TestU16, 214, Test, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(TestU8, 215, Test, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(TestI16, 216, Test, FieldType_NumericI16, FieldFlag_None ) \
|
||||
HANDLER(TestI8, 217, Test, FieldType_NumericI8, FieldFlag_None ) \
|
||||
HANDLER(SystemAppletScene, 218, SystemAppletSceneInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(CodecType, 219, VideoInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(DecodeBuffers, 220, VideoInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(FrameWidth, 221, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(FrameHeight, 222, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(ColorPrimaries, 223, VideoInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(TransferCharacteristics, 224, VideoInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(MatrixCoefficients, 225, VideoInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(DisplayWidth, 226, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(DisplayHeight, 227, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(DARWidth, 228, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(DARHeight, 229, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(ColorFormat, 230, VideoInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(ColorSpace, 231, VideoInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(SurfaceLayout, 232, VideoInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(BitStream, 233, VideoInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(VideoDecState, 234, VideoInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorChannelId, 235, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorAruId, 236, GpuErrorInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorType, 237, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorFaultInfo, 238, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorWriteAccess, 239, GpuErrorInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorFaultAddress, 240, GpuErrorInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorFaultUnit, 241, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorFaultType, 242, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorHwContextPointer, 243, GpuErrorInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorContextStatus, 244, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorPbdmaIntr, 245, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorPbdmaErrorType, 246, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorPbdmaHeaderShadow, 247, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorPbdmaHeader, 248, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorPbdmaGpShadow0, 249, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GpuErrorPbdmaGpShadow1, 250, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(AccessPointChannel, 251, AccessPointInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(ThreadName, 252, ErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(AdspExceptionRegisters, 253, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(AdspExceptionSpsr, 254, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(AdspExceptionProgramCounter, 255, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(AdspExceptionLinkRegister, 256, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(AdspExceptionStackPointer, 257, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(AdspExceptionArmModeRegisters, 258, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(AdspExceptionStackAddress, 259, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(AdspExceptionStackDump, 260, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(AdspExceptionReason, 261, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(OscillatorClock, 262, PowerClockInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(CpuDvfsTableClocks, 263, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(CpuDvfsTableVoltages, 264, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \
|
||||
HANDLER(GpuDvfsTableClocks, 265, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(GpuDvfsTableVoltages, 266, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \
|
||||
HANDLER(EmcDvfsTableClocks, 267, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(EmcDvfsTableVoltages, 268, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \
|
||||
HANDLER(ModuleClockFrequencies, 269, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(ModuleClockEnableFlags, 270, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(ModulePowerEnableFlags, 271, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(ModuleResetAssertFlags, 272, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(ModuleMinimumVoltageClockRates, 273, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(PowerDomainEnableFlags, 274, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(PowerDomainVoltages, 275, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \
|
||||
HANDLER(AccessPointRssi, 276, RadioStrengthInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(FuseInfo, 277, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(VideoLog, 278, VideoInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(GameCardDeviceId, 279, GameCardCIDInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(GameCardAsicReinitializeCount, 280, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(GameCardAsicReinitializeFailureCount, 281, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(GameCardAsicReinitializeFailureDetail, 282, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(GameCardRefreshSuccessCount, 283, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(GameCardAwakenCount, 284, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GameCardAwakenFailureCount, 285, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(GameCardReadCountFromInsert, 286, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GameCardReadCountFromAwaken, 287, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GameCardLastReadErrorPageAddress, 288, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GameCardLastReadErrorPageCount, 289, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(AppletManagerContextTrace, 290, ErrorInfo, FieldType_I32Array, FieldFlag_None ) \
|
||||
HANDLER(NvDispIsRegistered, 291, NvDispDeviceInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispIsSuspend, 292, NvDispDeviceInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDC0SurfaceNum, 293, NvDispDeviceInfo, FieldType_I32Array, FieldFlag_None ) \
|
||||
HANDLER(NvDispDC1SurfaceNum, 294, NvDispDeviceInfo, FieldType_I32Array, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowSrcRectX, 295, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowSrcRectY, 296, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowSrcRectWidth, 297, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowSrcRectHeight, 298, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowDstRectX, 299, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowDstRectY, 300, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowDstRectWidth, 301, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowDstRectHeight, 302, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowIndex, 303, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowBlendOperation, 304, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowAlphaOperation, 305, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowDepth, 306, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowAlpha, 307, NvDispDcWindowInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowHFilter, 308, NvDispDcWindowInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowVFilter, 309, NvDispDcWindowInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowOptions, 310, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispWindowSyncPointId, 311, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPSorPower, 312, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPClkType, 313, NvDispDpModeInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPEnable, 314, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPState, 315, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPEdid, 316, NvDispDpModeInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPEdidSize, 317, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPEdidExtSize, 318, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPFakeMode, 319, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPModeNumber, 320, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPPlugInOut, 321, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPAuxIntHandler, 322, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPForceMaxLinkBW, 323, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPIsConnected, 324, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkValid, 325, NvDispDpLinkSpec, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkMaxBW, 326, NvDispDpLinkSpec, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkMaxLaneCount, 327, NvDispDpLinkSpec, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkDownSpread, 328, NvDispDpLinkSpec, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkSupportEnhancedFraming, 329, NvDispDpLinkSpec, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkBpp, 330, NvDispDpLinkSpec, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkScaramberCap, 331, NvDispDpLinkSpec, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkBW, 332, NvDispDpLinkStatus, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkLaneCount, 333, NvDispDpLinkStatus, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkEnhancedFraming, 334, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkScrambleEnable, 335, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkActivePolarity, 336, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkActiveCount, 337, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkTUSize, 338, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkActiveFrac, 339, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkWatermark, 340, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkHBlank, 341, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkVBlank, 342, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkOnlyEnhancedFraming, 343, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkOnlyEdpCap, 344, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkSupportFastLT, 345, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkLTDataValid, 346, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkTsp3Support, 347, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDPLinkAuxInterval, 348, NvDispDpLinkStatus, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispHdcpCreated, 349, NvDispDpHdcpInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispHdcpUserRequest, 350, NvDispDpHdcpInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispHdcpPlugged, 351, NvDispDpHdcpInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispHdcpState, 352, NvDispDpHdcpInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispHdcpFailCount, 353, NvDispDpHdcpInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(NvDispHdcpHdcp22, 354, NvDispDpHdcpInfo, FieldType_NumericI8, FieldFlag_None ) \
|
||||
HANDLER(NvDispHdcpMaxRetry, 355, NvDispDpHdcpInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispHdcpHpd, 356, NvDispDpHdcpInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispHdcpRepeater, 357, NvDispDpHdcpInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispCecRxBuf, 358, NvDispDpAuxCecInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(NvDispCecRxLength, 359, NvDispDpAuxCecInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(NvDispCecTxBuf, 360, NvDispDpAuxCecInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(NvDispCecTxLength, 361, NvDispDpAuxCecInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(NvDispCecTxRet, 362, NvDispDpAuxCecInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(NvDispCecState, 363, NvDispDpAuxCecInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispCecTxInfo, 364, NvDispDpAuxCecInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispCecRxInfo, 365, NvDispDpAuxCecInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCIndex, 366, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCInitialize, 367, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCClock, 368, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCFrequency, 369, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCFailed, 370, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCModeWidth, 371, NvDispDcInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCModeHeight, 372, NvDispDcInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCModeBpp, 373, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCPanelFrequency, 374, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCWinDirty, 375, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCWinEnable, 376, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCVrr, 377, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDCPanelInitialize, 378, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDsiDataFormat, 379, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDsiVideoMode, 380, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDsiRefreshRate, 381, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDsiLpCmdModeFrequency, 382, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDsiHsCmdModeFrequency, 383, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDsiPanelResetTimeout, 384, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDsiPhyFrequency, 385, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDsiFrequency, 386, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDsiInstance, 387, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDcDsiHostCtrlEnable, 388, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDcDsiInit, 389, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDcDsiEnable, 390, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDcDsiHsMode, 391, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDcDsiVendorId, 392, NvDispDsiInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(NvDispDcDsiLcdVendorNum, 393, NvDispDsiInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(NvDispDcDsiHsClockControl, 394, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDcDsiEnableHsClockInLpMode, 395, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDcDsiTeFrameUpdate, 396, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispDcDsiGangedType, 397, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispDcDsiHbpInPktSeq, 398, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NvDispErrID, 399, NvDispErrIDInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispErrData0, 400, NvDispErrIDInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvDispErrData1, 401, NvDispErrIDInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(SdCardMountStatus, 402, SdCardMountInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(SdCardMountUnexpectedResult, 403, SdCardMountInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(NANDTotalSize, 404, NANDFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(SdCardTotalSize, 405, SDCardFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(ElapsedTimeSinceInitialLaunch, 406, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(ElapsedTimeSincePowerOn, 407, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(ElapsedTimeSinceLastAwake, 408, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(OccurrenceTick, 409, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(RetailInteractiveDisplayFlag, 410, RetailInteractiveDisplayInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(FatFsError, 411, FsProxyErrorInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(FatFsExtraError, 412, FsProxyErrorInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(FatFsErrorDrive, 413, FsProxyErrorInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(FatFsErrorName, 414, FsProxyErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(MonitorManufactureCode, 415, MonitorCapability, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(MonitorProductCode, 416, MonitorCapability, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(MonitorSerialNumber, 417, MonitorCapability, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(MonitorManufactureYear, 418, MonitorCapability, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(PhysicalAddress, 419, MonitorCapability, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(Is4k60Hz, 420, MonitorCapability, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(Is4k30Hz, 421, MonitorCapability, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(Is1080P60Hz, 422, MonitorCapability, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(Is720P60Hz, 423, MonitorCapability, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(PcmChannelMax, 424, MonitorCapability, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(CrashReportHash, 425, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(ErrorReportSharePermission, 426, ErrorReportSharePermissionInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(VideoCodecTypeEnum, 427, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(VideoBitRate, 428, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(VideoFrameRate, 429, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(VideoWidth, 430, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(VideoHeight, 431, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(AudioCodecTypeEnum, 432, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(AudioSampleRate, 433, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(AudioChannelCount, 434, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(AudioBitRate, 435, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(MultimediaContainerType, 436, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(MultimediaProfileType, 437, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(MultimediaLevelType, 438, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(MultimediaCacheSizeEnum, 439, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(MultimediaErrorStatusEnum, 440, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(MultimediaErrorLog, 441, MultimediaInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(ServerFqdn, 442, ErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ServerIpAddress, 443, ErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(TestStringEncrypt, 444, Test, FieldType_String, FieldFlag_Encrypt) \
|
||||
HANDLER(TestU8ArrayEncrypt, 445, Test, FieldType_U8Array, FieldFlag_Encrypt) \
|
||||
HANDLER(TestU32ArrayEncrypt, 446, Test, FieldType_U32Array, FieldFlag_Encrypt) \
|
||||
HANDLER(TestU64ArrayEncrypt, 447, Test, FieldType_U64Array, FieldFlag_Encrypt) \
|
||||
HANDLER(TestI32ArrayEncrypt, 448, Test, FieldType_I32Array, FieldFlag_Encrypt) \
|
||||
HANDLER(TestI64ArrayEncrypt, 449, Test, FieldType_I64Array, FieldFlag_Encrypt) \
|
||||
HANDLER(CipherKey, 450, ErrorInfoAuto, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(FileSystemPath, 451, ErrorInfo, FieldType_String, FieldFlag_Encrypt) \
|
||||
HANDLER(WebMediaPlayerOpenUrl, 452, ErrorInfo, FieldType_String, FieldFlag_Encrypt) \
|
||||
HANDLER(WebMediaPlayerLastSocketErrors, 453, ErrorInfo, FieldType_I32Array, FieldFlag_None ) \
|
||||
HANDLER(UnknownControllerCount, 454, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AttachedControllerCount, 455, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(BluetoothControllerCount, 456, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(UsbControllerCount, 457, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(ControllerTypeList, 458, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(ControllerInterfaceList, 459, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(ControllerStyleList, 460, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(FsPooledBufferPeakFreeSize, 461, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(FsPooledBufferRetriedCount, 462, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(FsPooledBufferReduceAllocationCount, 463, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(FsBufferManagerPeakFreeSize, 464, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(FsBufferManagerRetriedCount, 465, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(FsExpHeapPeakFreeSize, 466, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(FsBufferPoolPeakFreeSize, 467, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(FsPatrolReadAllocateBufferSuccessCount, 468, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(FsPatrolReadAllocateBufferFailureCount, 469, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(SteadyClockInternalOffset, 470, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(SteadyClockCurrentTimePointValue, 471, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(UserClockContextOffset, 472, UserClockContextInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(UserClockContextTimeStampValue, 473, UserClockContextInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(NetworkClockContextOffset, 474, NetworkClockContextInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(NetworkClockContextTimeStampValue, 475, NetworkClockContextInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(SystemAbortFlag, 476, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(ApplicationAbortFlag, 477, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(NifmErrorCode, 478, ConnectionStatusInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(LcsApplicationId, 479, ErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(LcsContentMetaKeyIdList, 480, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \
|
||||
HANDLER(LcsContentMetaKeyVersionList, 481, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(LcsContentMetaKeyTypeList, 482, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(LcsContentMetaKeyInstallTypeList, 483, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(LcsSenderFlag, 484, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(LcsApplicationRequestFlag, 485, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(LcsHasExFatDriverFlag, 486, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(LcsIpAddress, 487, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(AcpStartupUserAccount, 488, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AcpAocRegistrationType, 489, AcpAocSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AcpAttributeFlag, 490, AcpGeneralSettingsInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(AcpSupportedLanguageFlag, 491, AcpGeneralSettingsInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(AcpParentalControlFlag, 492, AcpGeneralSettingsInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(AcpScreenShot, 493, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AcpVideoCapture, 494, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AcpDataLossConfirmation, 495, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AcpPlayLogPolicy, 496, AcpPlayLogSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AcpPresenceGroupId, 497, AcpGeneralSettingsInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(AcpRatingAge, 498, AcpRatingSettingsInfo, FieldType_I8Array, FieldFlag_None ) \
|
||||
HANDLER(AcpAocBaseId, 499, AcpAocSettingsInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(AcpSaveDataOwnerId, 500, AcpStorageSettingsInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(AcpUserAccountSaveDataSize, 501, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpUserAccountSaveDataJournalSize, 502, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpDeviceSaveDataSize, 503, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpDeviceSaveDataJournalSize, 504, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpBcatDeliveryCacheStorageSize, 505, AcpBcatSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpApplicationErrorCodeCategory, 506, AcpGeneralSettingsInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(AcpLocalCommunicationId, 507, AcpGeneralSettingsInfo, FieldType_U64Array, FieldFlag_None ) \
|
||||
HANDLER(AcpLogoType, 508, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AcpLogoHandling, 509, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AcpRuntimeAocInstall, 510, AcpAocSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AcpCrashReport, 511, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AcpHdcp, 512, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AcpSeedForPseudoDeviceId, 513, AcpGeneralSettingsInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(AcpBcatPassphrase, 514, AcpBcatSettingsInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(AcpUserAccountSaveDataSizeMax, 515, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpUserAccountSaveDataJournalSizeMax, 516, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpDeviceSaveDataSizeMax, 517, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpDeviceSaveDataJournalSizeMax, 518, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpTemporaryStorageSize, 519, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpCacheStorageSize, 520, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpCacheStorageJournalSize, 521, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpCacheStorageDataAndJournalSizeMax, 522, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpCacheStorageIndexMax, 523, AcpStorageSettingsInfo, FieldType_NumericI16, FieldFlag_None ) \
|
||||
HANDLER(AcpPlayLogQueryableApplicationId, 524, AcpPlayLogSettingsInfo, FieldType_U64Array, FieldFlag_None ) \
|
||||
HANDLER(AcpPlayLogQueryCapability, 525, AcpPlayLogSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(AcpRepairFlag, 526, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(RunningApplicationPatchStorageLocation, 527, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RunningApplicationVersionNumber, 528, RunningApplicationInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(FsRecoveredByInvalidateCacheCount, 529, FsProxyErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(FsSaveDataIndexCount, 530, FsProxyErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(FsBufferManagerPeakTotalAllocatableSize, 531, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(MonitorCurrentWidth, 532, MonitorSettings, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(MonitorCurrentHeight, 533, MonitorSettings, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(MonitorCurrentRefreshRate, 534, MonitorSettings, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RebootlessSystemUpdateVersion, 535, RebootlessSystemUpdateVersionInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(EncryptedExceptionInfo1, 536, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(EncryptedExceptionInfo2, 537, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(EncryptedExceptionInfo3, 538, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(EncryptedDyingMessage, 539, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(DramId, 540, PowerClockInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NifmConnectionTestRedirectUrl, 541, NifmConnectionTestInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(AcpRequiredNetworkServiceLicenseOnLaunchFlag, 542, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(PciePort0Flags, 543, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(PciePort0Speed, 544, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(PciePort0ResetTimeInUs, 545, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(PciePort0IrqCount, 546, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(PciePort0Statistics, 547, PcieLoggedStateInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(PciePort1Flags, 548, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(PciePort1Speed, 549, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(PciePort1ResetTimeInUs, 550, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(PciePort1IrqCount, 551, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(PciePort1Statistics, 552, PcieLoggedStateInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(PcieFunction0VendorId, 553, PcieLoggedStateInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(PcieFunction0DeviceId, 554, PcieLoggedStateInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(PcieFunction0PmState, 555, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(PcieFunction0IsAcquired, 556, PcieLoggedStateInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(PcieFunction1VendorId, 557, PcieLoggedStateInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(PcieFunction1DeviceId, 558, PcieLoggedStateInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(PcieFunction1PmState, 559, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(PcieFunction1IsAcquired, 560, PcieLoggedStateInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(PcieGlobalRootComplexStatistics, 561, PcieLoggedStateInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(PciePllResistorCalibrationValue, 562, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(CertificateRequestedHostName, 563, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(CertificateCommonName, 564, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(CertificateSANCount, 565, NetworkSecurityCertificateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(CertificateSANs, 566, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(FsBufferPoolMaxAllocateSize, 567, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(CertificateIssuerName, 568, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ApplicationAliveTime, 569, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(ApplicationInFocusTime, 570, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(ApplicationOutOfFocusTime, 571, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(ApplicationBackgroundFocusTime, 572, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
|
||||
HANDLER(AcpUserAccountSwitchLock, 573, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(USB3HostAvailableFlag, 574, USB3AvailableInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(USB3DeviceAvailableFlag, 575, USB3AvailableInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(AcpNeighborDetectionClientConfigurationSendDataId, 576, AcpNeighborDetectionInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(AcpNeighborDetectionClientConfigurationReceivableDataIds, 577, AcpNeighborDetectionInfo, FieldType_U64Array, FieldFlag_None ) \
|
||||
HANDLER(AcpStartupUserAccountOptionFlag, 578, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(ServerErrorCode, 579, ErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(AppletManagerMetaLogTrace, 580, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \
|
||||
HANDLER(ServerCertificateSerialNumber, 581, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ServerCertificatePublicKeyAlgorithm, 582, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ServerCertificateSignatureAlgorithm, 583, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(ServerCertificateNotBefore, 584, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(ServerCertificateNotAfter, 585, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(CertificateAlgorithmInfoBits, 586, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(TlsConnectionPeerIpAddress, 587, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(TlsConnectionLastHandshakeState, 588, NetworkSecurityCertificateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(TlsConnectionInfoBits, 589, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(SslStateBits, 590, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(SslProcessInfoBits, 591, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(SslProcessHeapSize, 592, NetworkSecurityCertificateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(SslBaseErrorCode, 593, NetworkSecurityCertificateInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||
HANDLER(GpuCrashDumpSize, 594, GpuCrashInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(GpuCrashDump, 595, GpuCrashInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(RunningApplicationProgramIndex, 596, RunningApplicationInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(UsbTopology, 597, UsbStateInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(AkamaiReferenceId, 598, ErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(NvHostErrID, 599, NvHostErrInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(NvHostErrDataArrayU32, 600, NvHostErrInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||
HANDLER(HasSyslogFlag, 601, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
|
||||
HANDLER(AcpRuntimeParameterDelivery, 602, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(PlatformRegion, 603, RegionSettingInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RunningUlaApplicationId, 604, RunningUlaInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RunningUlaAppletId, 605, RunningUlaInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||
HANDLER(RunningUlaVersion, 606, RunningUlaInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||
HANDLER(RunningUlaApplicationStorageLocation, 607, RunningUlaInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(RunningUlaPatchStorageLocation, 608, RunningUlaInfo, FieldType_String, FieldFlag_None ) \
|
||||
HANDLER(NANDTotalSizeOfSystem, 609, NANDFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
HANDLER(NANDFreeSpaceOfSystem, 610, NANDFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/erpt/erpt_types.hpp>
|
||||
#include <stratosphere/sf/sf_buffer_tags.hpp>
|
||||
|
||||
namespace ams::erpt {
|
||||
|
||||
constexpr inline u32 CategoriesPerMultipleCategoryContext = 0x10;
|
||||
constexpr inline u32 FieldsPerMultipleCategoryContext = CategoriesPerMultipleCategoryContext * 4;
|
||||
|
||||
struct MultipleCategoryContextEntry : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
|
||||
u32 version;
|
||||
u32 category_count;
|
||||
CategoryId categories[CategoriesPerMultipleCategoryContext];
|
||||
u32 field_counts[CategoriesPerMultipleCategoryContext];
|
||||
u32 array_buf_counts[CategoriesPerMultipleCategoryContext];
|
||||
FieldEntry fields[FieldsPerMultipleCategoryContext];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/os.hpp>
|
||||
#include <stratosphere/time/time_posix_time.hpp>
|
||||
#include <stratosphere/erpt/erpt_ids.autogen.hpp>
|
||||
|
||||
namespace ams::erpt {
|
||||
|
||||
#define GENERATE_ENUM(NAME, ID, ...) NAME = ID,
|
||||
|
||||
enum FieldType {
|
||||
AMS_ERPT_FOREACH_FIELD_TYPE(GENERATE_ENUM)
|
||||
FieldType_Count,
|
||||
};
|
||||
|
||||
#undef GENERATE_ENUM
|
||||
|
||||
#define GENERATE_ENUM(NAME, ID, ...) CategoryId_##NAME = ID,
|
||||
|
||||
enum CategoryId {
|
||||
AMS_ERPT_FOREACH_CATEGORY(GENERATE_ENUM)
|
||||
CategoryId_Count,
|
||||
};
|
||||
|
||||
#undef GENERATE_ENUM
|
||||
|
||||
#define GENERATE_ENUM(NAME, ID, ...) FieldId_##NAME = ID,
|
||||
|
||||
enum FieldId {
|
||||
AMS_ERPT_FOREACH_FIELD(GENERATE_ENUM)
|
||||
FieldId_Count,
|
||||
};
|
||||
|
||||
#undef GENERATE_ENUM
|
||||
|
||||
constexpr inline u32 ArrayBufferSizeDefault = 0x100;
|
||||
constexpr inline u32 ArrayBufferSizeMax = 96_KB;
|
||||
constexpr inline u32 ArrayFieldSizeMax = 16_KB - 1;
|
||||
|
||||
enum ReportType {
|
||||
ReportType_Start = 0,
|
||||
|
||||
ReportType_Visible = ReportType_Start,
|
||||
ReportType_Invisible = 1,
|
||||
|
||||
ReportType_End = 2,
|
||||
|
||||
ReportType_Count = ReportType_End,
|
||||
|
||||
ReportType_Any = ReportType_Count,
|
||||
};
|
||||
|
||||
constexpr inline u32 ReportCountMax = 50;
|
||||
constexpr inline u32 AttachmentsPerReportMax = 5;
|
||||
constexpr inline u32 AttachmentCountMax = ReportCountMax * AttachmentsPerReportMax;
|
||||
|
||||
constexpr inline u32 ReportMetaDataSize = 0x20;
|
||||
struct ReportMetaData {
|
||||
u8 user_data[ReportMetaDataSize];
|
||||
};
|
||||
|
||||
|
||||
constexpr inline u32 ReportIdSize = 20;
|
||||
struct ReportId {
|
||||
union {
|
||||
u8 id[ReportIdSize];
|
||||
util::Uuid uuid;
|
||||
#pragma pack(push, 1)
|
||||
struct {
|
||||
u32 time_low;
|
||||
u16 time_mid;
|
||||
u16 time_high_and_version;
|
||||
u8 clock_high;
|
||||
u8 clock_low;
|
||||
u64 node;
|
||||
} uuid_data;
|
||||
#pragma pack(pop)
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(ReportId) == ReportIdSize);
|
||||
|
||||
inline bool operator==(const ReportId &lhs, const ReportId &rhs) {
|
||||
return std::memcmp(lhs.id, rhs.id, sizeof(lhs.uuid)) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const ReportId &lhs, const ReportId &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
struct ReportFlag {
|
||||
using Transmitted = util::BitFlagSet<BITSIZEOF(u32), ReportFlag>::Flag<0>;
|
||||
using HasAttachment = util::BitFlagSet<BITSIZEOF(u32), ReportFlag>::Flag<1>;
|
||||
};
|
||||
|
||||
using ReportFlagSet = util::BitFlagSet<BITSIZEOF(u32), ReportFlag>;
|
||||
static_assert(std::is_pod<ReportFlagSet>::value);
|
||||
static_assert(sizeof(ReportFlagSet) == sizeof(u32));
|
||||
|
||||
struct ReportInfo {
|
||||
ReportType type;
|
||||
ReportId id;
|
||||
ReportMetaData meta_data;
|
||||
ReportFlagSet flags;
|
||||
time::PosixTime timestamp_user;
|
||||
time::PosixTime timestamp_network;
|
||||
s64 report_size;
|
||||
u64 reserved[3];
|
||||
};
|
||||
|
||||
struct ReportList {
|
||||
u32 report_count;
|
||||
ReportInfo reports[ReportCountMax];
|
||||
};
|
||||
|
||||
constexpr inline u32 AttachmentIdSize = 20;
|
||||
struct AttachmentId {
|
||||
union {
|
||||
u8 id[AttachmentIdSize];
|
||||
util::Uuid uuid;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(AttachmentId) == AttachmentIdSize);
|
||||
|
||||
inline bool operator==(const AttachmentId &lhs, const AttachmentId &rhs) {
|
||||
return std::memcmp(lhs.id, rhs.id, sizeof(lhs.uuid)) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const AttachmentId &lhs, const AttachmentId &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
struct AttachmentFlag {
|
||||
using HasOwner = util::BitFlagSet<BITSIZEOF(u32), AttachmentFlag>::Flag<1>;
|
||||
};
|
||||
|
||||
using AttachmentFlagSet = util::BitFlagSet<BITSIZEOF(u32), AttachmentFlag>;
|
||||
static_assert(std::is_pod<AttachmentFlagSet>::value);
|
||||
static_assert(sizeof(AttachmentFlagSet) == sizeof(u32));
|
||||
|
||||
constexpr inline u32 AttachmentNameSizeMax = 0x20;
|
||||
struct AttachmentInfo {
|
||||
ReportId owner_report_id;
|
||||
AttachmentId attachment_id;
|
||||
AttachmentFlagSet flags;
|
||||
s64 attachment_size;
|
||||
char attachment_name[AttachmentNameSizeMax];
|
||||
};
|
||||
|
||||
struct AttachmentList {
|
||||
u32 attachment_count;
|
||||
AttachmentInfo attachments[AttachmentsPerReportMax];
|
||||
};
|
||||
|
||||
constexpr inline u32 AttachmentSizeMax = 512_KB;
|
||||
|
||||
struct FieldEntry {
|
||||
FieldId id;
|
||||
FieldType type;
|
||||
union {
|
||||
u64 value_u64;
|
||||
u32 value_u32;
|
||||
u16 value_u16;
|
||||
u8 value_u8;
|
||||
s64 value_i64;
|
||||
s32 value_i32;
|
||||
s16 value_i16;
|
||||
s8 value_i8;
|
||||
bool value_bool;
|
||||
struct {
|
||||
u32 start_idx;
|
||||
u32 size;
|
||||
} value_array;
|
||||
};
|
||||
};
|
||||
|
||||
constexpr inline u32 FieldsPerContext = 20;
|
||||
struct ContextEntry {
|
||||
u32 version;
|
||||
u32 field_count;
|
||||
CategoryId category;
|
||||
FieldEntry fields[FieldsPerContext];
|
||||
u8 *array_buffer;
|
||||
u32 array_free_count;
|
||||
u32 array_buffer_size;
|
||||
};
|
||||
|
||||
struct StorageUsageStatistics {
|
||||
util::Uuid journal_uuid;
|
||||
u32 used_storage_size;
|
||||
s64 max_report_size;
|
||||
u32 report_count[ReportType_Count];
|
||||
u32 transmitted_count[ReportType_Count];
|
||||
u32 untransmitted_count[ReportType_Count];
|
||||
};
|
||||
|
||||
/* https://github.com/msgpack/msgpack/blob/master/spec.md#overview */
|
||||
enum class ValueTypeTag {
|
||||
FixMap = 0x80,
|
||||
FixArray = 0x90,
|
||||
FixStr = 0xA0,
|
||||
False = 0xC2,
|
||||
True = 0xC3,
|
||||
Bin8 = 0xC4,
|
||||
Bin16 = 0xC5,
|
||||
U8 = 0xCC,
|
||||
U16 = 0xCD,
|
||||
U32 = 0xCE,
|
||||
U64 = 0xCF,
|
||||
I8 = 0xD0,
|
||||
I16 = 0xD1,
|
||||
I32 = 0xD2,
|
||||
I64 = 0xD3,
|
||||
Str8 = 0xD9,
|
||||
Str16 = 0xDA,
|
||||
Array16 = 0xDC,
|
||||
Map16 = 0xDE,
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/erpt/erpt_types.hpp>
|
||||
|
||||
namespace ams::erpt::sf {
|
||||
|
||||
class IAttachment : public ams::sf::IServiceObject {
|
||||
protected:
|
||||
enum class CommandId {
|
||||
Open = 0,
|
||||
Read = 1,
|
||||
SetFlags = 2,
|
||||
GetFlags = 3,
|
||||
Close = 4,
|
||||
GetSize = 5,
|
||||
};
|
||||
public:
|
||||
/* Actual commands. */
|
||||
virtual Result Open(const AttachmentId &attachment_id) = 0;
|
||||
virtual Result Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer) = 0;
|
||||
virtual Result SetFlags(AttachmentFlagSet flags) = 0;
|
||||
virtual Result GetFlags(ams::sf::Out<AttachmentFlagSet> out) = 0;
|
||||
virtual Result Close() = 0;
|
||||
virtual Result GetSize(ams::sf::Out<s64> out) = 0;
|
||||
public:
|
||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||
MAKE_SERVICE_COMMAND_META(Open),
|
||||
MAKE_SERVICE_COMMAND_META(Read),
|
||||
MAKE_SERVICE_COMMAND_META(SetFlags),
|
||||
MAKE_SERVICE_COMMAND_META(GetFlags),
|
||||
MAKE_SERVICE_COMMAND_META(Close),
|
||||
MAKE_SERVICE_COMMAND_META(GetSize),
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user