Compare commits

...

66 Commits

Author SHA1 Message Date
5cb085b00c daybreak: Add firmware compatibility gate and German UI
Block unsupported firmware updates via a dedicated dialog using
Exosphere's maximum supported HOS version, and translate the Daybreak
interface to German.
2026-05-17 12:59:14 +02:00
hexkyz
2c7e2bfaae Merge pull request #2800 from masagrator/patch-1
fs.mitm: Add "Until Then" as another game which needs stolen heap for layeredfs
2026-04-25 19:55:43 +01:00
MasaGratoR
e655fd4b01 fs.mitm: Add "Until Then" as another game which needs stolen heap for layeredfs 2026-04-24 22:30:25 +02:00
hexkyz
022000f668 docs: add changelog for 1.11.1
this was missing from the usual enum recognition changes
synchronization will happen at a future release instead
2026-04-07 22:53:21 +01:00
hexkyz
d04c20a049 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "82f1553c4"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "82f1553c4"
git-subrepo:
  version:  "0.4.9"
  origin:   "???"
  commit:   "???"
2026-04-07 17:24:31 +01:00
hexkyz
252f8685b4 Merge pull request #2786 from alula/alula
ams: add enum recognition for 22.1.0
2026-04-07 17:22:46 +01:00
Alula
020ed307b1 ams: add enum recognition for 22.1.0 2026-04-07 03:22:37 +02:00
hexkyz
d9e1d799ab git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "3726bfd65"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "3726bfd65"
git-subrepo:
  version:  "0.4.9"
  origin:   "???"
  commit:   "???"
2026-04-05 20:34:44 +01:00
ndeadly
80bd459516 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "8e9c9ab16"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "8e9c9ab16"
git-subrepo:
  version:  "0.4.9"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "5e0f401"
2026-04-04 16:44:08 +02:00
hexkyz
931e3c37fd docs: add changelog for 1.11.0 2026-04-03 23:34:13 +01:00
hexkyz
4b4db91341 pgl: no need to initialize lr services when already using our own 2026-04-03 23:32:15 +01:00
hexkyz
e3fc339fe5 Merge pull request #2766 from alula/erpt-crash-fix
erpt: Fix rare aborts caused by ResultInvalidPowerState
2026-04-03 23:09:55 +01:00
Alula
a051c3c723 erpt: document unknown 0x20000 flag 2026-04-04 00:06:49 +02:00
Alula
9a1ea02c8c erpt: Add some missed 20.0.0+ FsInfo changes 2026-04-04 00:06:49 +02:00
hexkyz
bae1ad22ec Merge pull request #2768 from masagrator/patch-1
Update services in PGL to match 21.0.0
2026-04-03 22:33:28 +01:00
hexkyz
cd1503a9ca emummc: fix offsets
22.0.0 now boots under emummc
2026-04-03 22:31:19 +01:00
Alula
72e3b0dd34 erpt: Fix rare aborts caused by ResultInvalidPowerState 2026-04-03 22:55:09 +02:00
MasaGratoR
ac120cf84b Match 21.0.0 FW 2026-04-03 22:23:08 +02:00
MasaGratoR
97ffad2ab6 Update service access to match 21.0.0 2026-04-03 22:22:15 +02:00
hexkyz
c8d68a3a8a Merge pull request #2763 from masagrator/patch-1
Fix off by 1 bug + allocation error + missing initialize in PGL
2026-04-03 19:27:56 +01:00
hexkyz
8987d642d1 Merge pull request #2748 from CTCaer/auto_dram_cfg
[Feature] Auto dram cfg & Auto memory mode
2026-04-03 19:27:38 +01:00
hexkyz
7ffb1da2ac Merge pull request #2734 from ndeadly/r_discard
libvapours: add R_DISCARD macro
2026-04-03 19:27:19 +01:00
hexkyz
5c426bf90d loader: remove unused file 2026-04-03 19:09:28 +01:00
MasaGratoR
31ca20f3b7 Add missing libstratosphere lr::Initialize() 2026-04-02 21:09:15 +02:00
MasaGratoR
174da786e4 Override new and delete operators 2026-04-02 20:45:30 +02:00
hexkyz
93a82c0441 loader: patch am to recover homebrew compatibility
This patch is to be removed if/once hbmenu/libnx re-designs the exiting logic
2026-04-02 01:42:53 +01:00
hexkyz
082115187a loader/util: fully implement zstd bic variant
Implement both compression and decompression utilities and simplify loader logic
2026-04-02 01:30:45 +01:00
hexkyz
db388385b0 Merge pull request #2761 from alula/22_support
22.0.0 support part 3
2026-04-02 01:17:19 +01:00
MasaGratoR
4a8f7628c2 Update pgl_srv_shell_host_utils.cpp 2026-04-01 20:44:08 +02:00
MasaGratoR
9d16ee6a74 Update pgl_srv_shell_host_utils.cpp 2026-04-01 20:41:25 +02:00
MasaGratoR
3b9ee08c69 Update pgl_srv_shell_host_utils.cpp 2026-04-01 20:33:27 +02:00
MasaGratoR
2694f31eb3 Update pgl_srv_shell_host_utils.cpp 2026-04-01 20:31:47 +02:00
MasaGratoR
f3f1fa46ed Fix off by 1 bug 2026-04-01 20:17:52 +02:00
Alula
8a7c2872c3 erpt: use official name for erpt::IManager cmd 7 2026-04-01 05:57:28 +02:00
Alula
6acdc05c89 erpt: revert GetReportSizeMax to not potentially break old firmwares 2026-04-01 05:46:04 +02:00
hexkyz
32bb6b17ab Merge pull request #2753 from alula/22_support
Basic ("the console boots and functions as expected") 22.0.0 support - Part 2
2026-04-01 03:10:19 +01:00
Alula
27455329b3 loader: update for 22.0.0 2026-03-28 01:43:19 +01:00
Alula
7d334f09ee loader: the two unknown titles are LGE/LGP for China 2026-03-27 23:57:44 +01:00
Alula
8c0ff851f2 loader/strat: Add amalgamated zstd 1.5.7 with ZBIC patches 2026-03-27 23:51:04 +01:00
hexkyz
b108318996 Merge pull request #2744 from alula/22_support
Basic ("the console boots and functions as expected") 22.0.0 support
2026-03-20 00:22:10 +00:00
hexkyz
5dfdc6e8b0 Merge emummc changes from pull request #2743
Remaining changes are duplicated in pull request #2744
2026-03-20 00:17:19 +00:00
hexkyz
14e63cb04c loader: add USB 3.0 patches for 22.0.0
Additionally remove duplicated entry for 20.1.0, just use the 20.0.0 one.
2026-03-20 00:02:42 +00:00
CTCaer
5dd9816e3c exosphere: allow memory mode to be used on retail 2026-03-19 16:35:36 +02:00
CTCaer
5a5d9b206b exosphere: automatically adjust dram id if needed
Checks if programmed memory size matches the one from fused dram id.
If not, adjust it properly so PCV can do proper training and not crash.
2026-03-19 16:32:12 +02:00
Alula
49e2330ed8 erpt: rename old ControllerStyleList field 2026-03-18 23:40:40 +01:00
Alula
1847db06f8 erpt: Implement 22.0.0 commands and changes
Co-authored-by: nvnprogram <97150065+nvnprogram@users.noreply.github.com>
2026-03-18 23:33:55 +01:00
Alula
f028802fb8 erpt: make FieldType u8 to match Nintendo 2026-03-18 23:30:06 +01:00
Alula
b29dbeae3d kern: don't allow mapping device pages as executable on abi 26.x+ 2026-03-18 23:25:24 +01:00
Alula
4e653f67e5 kern: make KProcess layout accurate to N's code 2026-03-18 23:25:24 +01:00
Alula
a985bdb1d4 kern: N made this an u32 for some reason 2026-03-18 23:25:24 +01:00
Alula
5b0a4830d4 pinmux: add a build time option to configure JC rail uart 2026-03-18 23:25:24 +01:00
Alula
26990b3be9 fs: DisableAutoSaveDataCreation was removed in 22 2026-03-18 23:25:24 +01:00
Alula
76bceffbd5 svc: bump supported kernel version 2026-03-18 23:25:24 +01:00
Alula
0ee6277be9 kern: write thread handle to tls +0x110 on creation 2026-03-18 23:25:24 +01:00
Alula
9cc82c6f80 fusee/exo/ams: update with new keydata/version enums 2026-03-18 23:25:24 +01:00
hexkyz
6b831406d6 erpt: style fix 2026-03-18 21:35:18 +00:00
hexkyz
23ebd4d677 erpt: add new IDs for 22.0.0 2026-03-18 21:32:35 +00:00
hexkyz
00f987dd38 erpt: types are now a byte in 22.0.0 2026-03-18 21:18:05 +00:00
ndeadly
f8a5a6c015 libvapours: add R_DISCARD macro 2026-02-23 01:09:11 +01:00
hexkyz
61ac03e22d Merge pull request #2703 from HydrationMan/master
Update fusee_display.cpp - add missing newline
2026-02-05 21:47:59 +00:00
hexkyz
208b60696c Merge pull request #2726 from ndeadly/svc-shim-compat
libstrat: update GetDebugEvent svc shim for compatibility with libnx changes
2026-02-05 21:37:17 +00:00
ndeadly
dfb936ed11 libstrat: update GetDebugEvent svc shim for compatibility with libnx changes 2026-02-03 22:59:47 +01:00
Michael Scire
5056ab21af git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "9a8703e71"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "9a8703e71"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2026-01-15 15:39:39 -07:00
Michael Scire
eb34f9789c git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "8ab963b0b"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "8ab963b0b"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2026-01-13 23:25:52 -07:00
Michael Scire
1e88f37892 ams/emummc: update for 21.2.0 2026-01-13 23:24:53 -07:00
Kane
cd72f9f33e Update fusee_display.cpp - add missing newline
Add newline that would otherwise cause text concatenation when it comes to suggestedFix content being appended.
2026-01-01 23:16:38 +13:00
77 changed files with 57425 additions and 353 deletions

View File

@@ -15,6 +15,13 @@
# Desc: Controls whether userland has access to the PMU registers. # Desc: Controls whether userland has access to the PMU registers.
# NOTE: It is unknown what effects this has on official code. # NOTE: It is unknown what effects this has on official code.
# Key: enable_mem_mode, default: 0.
# Desc: Controls whether boot config memory mode is taken into account
# for retail units. This does not affect development units.
# NOTE: On retail units max ram size is capped to 4GB.
# Enabling this will use the boot config memory mode parameter,
# which by default is auto and size gets set based on physical size.
# Key: blank_prodinfo_sysmmc, default: 0. # Key: blank_prodinfo_sysmmc, default: 0.
# Desc: Controls whether PRODINFO should be blanked in sysmmc. # Desc: Controls whether PRODINFO should be blanked in sysmmc.
# This will cause the system to see dummied out keys and # This will cause the system to see dummied out keys and
@@ -51,6 +58,7 @@ debugmode=1
debugmode_user=0 debugmode_user=0
disable_user_exception_handlers=0 disable_user_exception_handlers=0
enable_user_pmu_access=0 enable_user_pmu_access=0
enable_mem_mode=0
blank_prodinfo_sysmmc=0 blank_prodinfo_sysmmc=0
blank_prodinfo_emummc=0 blank_prodinfo_emummc=0
allow_writing_to_cal_sysmmc=0 allow_writing_to_cal_sysmmc=0

View File

@@ -1,4 +1,32 @@
# Changelog # Changelog
## 1.11.1
+ Basic support was added for 22.1.0.
+ General system stability improvements to enhance the user's experience.
## 1.11.0
+ Support was added for 22.0.0.
+ Special thanks to @alula for handling a large chunk of the necessary kernel, loader and erpt changes.
+ The console should boot and atmosphère should be fully functional.
+ **Please note**: A change in how applications/applets' lifespan is managed broke the homebrew ecosystem.
+ All applications and applets are expected to perform a clean exit by calling the relevant IPC commands.
+ Homebrew compiled with libnx and hbmenu itself explicitly avoid exiting so it can keep using the same process.
+ Properly fixing this would require a re-design of how homebrew is launched and terminated.
+ As a temporary solution, patches to the `am` sysmodule are now included which allow restoring the previous behavior and regain homebrew compatibility without any further changes.
+ Nonetheless, please report any issues you may face when testing homebrew to ensure no edge cases have been missed.
+ `exosphère` was updated to reflect the latest official secure monitor behavior.
+ `mesosphère` was updated to reflect the latest official kernel behavior.
+ `loader` was updated to reflect the latest official behavior.
+ `erpt` was updated to reflect the latest official behavior.
+ `pgl` was updated to fix a few issues.
+ Support was added for memory modes above 4GB (thanks @CTCaer).
+ A build time option to configure Joy-Con rails as UART for debugging was added (thanks @alula).
+ General system stability improvements to enhance the user's experience.
## 1.10.2
+ Basic support was added for 21.2.0.
+ General system stability improvements to enhance the user's experience.
## 1.10.1
+ Basic support was added for 21.1.0.
+ A bug was fixed that caused some games (e.g. Tomb Raider definitive edition) to fail to launch.
+ General system stability improvements to enhance the user's experience.
## 1.10.0 ## 1.10.0
+ Basic support was added for 21.0.0. + Basic support was added for 21.0.0.
+ The console should boot and atmosphère should be fully functional. + The console should boot and atmosphère should be fully functional.

6
emummc/.gitrepo vendored
View File

@@ -6,7 +6,7 @@
[subrepo] [subrepo]
remote = https://github.com/m4xw/emummc remote = https://github.com/m4xw/emummc
branch = develop branch = develop
commit = 3c57b20ba3820ec87d7dd239d6fcf9ba97510606 commit = 3726bfd659600cdafd138277054568a3edba60a6
parent = d61ee942d9b34cadd80464d5d549c5e2e5bf1689 parent = 80bd459516e813fc6f10268ca31dd72a053a4ef3
method = merge method = merge
cmdver = 0.4.1 cmdver = 0.4.9

2
emummc/README.md vendored
View File

@@ -2,7 +2,7 @@
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw*** *A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
### Supported Horizon Versions ### Supported Horizon Versions
**1.0.0 - 21.0.0** **1.0.0 - 21.2.0**
## Features ## Features
* Arbitrary SDMMC backend selection * Arbitrary SDMMC backend selection

View File

@@ -81,6 +81,10 @@
#include "offsets/2010_exfat.h" #include "offsets/2010_exfat.h"
#include "offsets/2100.h" #include "offsets/2100.h"
#include "offsets/2100_exfat.h" #include "offsets/2100_exfat.h"
#include "offsets/2120.h"
#include "offsets/2120_exfat.h"
#include "offsets/2200.h"
#include "offsets/2200_exfat.h"
#include "../utils/fatal.h" #include "../utils/fatal.h"
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers #define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
@@ -173,6 +177,10 @@ DEFINE_OFFSET_STRUCT(_2010);
DEFINE_OFFSET_STRUCT(_2010_EXFAT); DEFINE_OFFSET_STRUCT(_2010_EXFAT);
DEFINE_OFFSET_STRUCT(_2100); DEFINE_OFFSET_STRUCT(_2100);
DEFINE_OFFSET_STRUCT(_2100_EXFAT); DEFINE_OFFSET_STRUCT(_2100_EXFAT);
DEFINE_OFFSET_STRUCT(_2120);
DEFINE_OFFSET_STRUCT(_2120_EXFAT);
DEFINE_OFFSET_STRUCT(_2200);
DEFINE_OFFSET_STRUCT(_2200_EXFAT);
const fs_offsets_t *get_fs_offsets(enum FS_VER version) { const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
switch (version) { switch (version) {
@@ -306,6 +314,14 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
return &(GET_OFFSET_STRUCT_NAME(_2100)); return &(GET_OFFSET_STRUCT_NAME(_2100));
case FS_VER_21_0_0_EXFAT: case FS_VER_21_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_2100_EXFAT)); return &(GET_OFFSET_STRUCT_NAME(_2100_EXFAT));
case FS_VER_21_2_0:
return &(GET_OFFSET_STRUCT_NAME(_2120));
case FS_VER_21_2_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_2120_EXFAT));
case FS_VER_22_0_0:
return &(GET_OFFSET_STRUCT_NAME(_2200));
case FS_VER_22_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_2200_EXFAT));
default: default:
fatal_abort(Fatal_UnknownVersion); fatal_abort(Fatal_UnknownVersion);
} }

View File

@@ -119,6 +119,12 @@ enum FS_VER
FS_VER_21_0_0, FS_VER_21_0_0,
FS_VER_21_0_0_EXFAT, FS_VER_21_0_0_EXFAT,
FS_VER_21_2_0,
FS_VER_21_2_0_EXFAT,
FS_VER_22_0_0,
FS_VER_22_0_0_EXFAT,
FS_VER_MAX, FS_VER_MAX,
}; };

59
emummc/source/FS/offsets/2120.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_2120_H__
#define __FS_2120_H__
// Accessor vtable getters
#define FS_OFFSET_2120_SDMMC_ACCESSOR_GC 0x1AC970
#define FS_OFFSET_2120_SDMMC_ACCESSOR_SD 0x1AE980
#define FS_OFFSET_2120_SDMMC_ACCESSOR_NAND 0x1ACFA0
// Hooks
#define FS_OFFSET_2120_SDMMC_WRAPPER_READ 0x1A8850
#define FS_OFFSET_2120_SDMMC_WRAPPER_WRITE 0x1A88B0
#define FS_OFFSET_2120_RTLD 0x2E1C0
#define FS_OFFSET_2120_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2120_CLKRST_SET_MIN_V_CLK_RATE 0x1CB9B0
// Misc funcs
#define FS_OFFSET_2120_LOCK_MUTEX 0x1A17D0
#define FS_OFFSET_2120_UNLOCK_MUTEX 0x1A1830
#define FS_OFFSET_2120_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1A8810
#define FS_OFFSET_2120_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1A8830
// Misc Data
#define FS_OFFSET_2120_SD_MUTEX 0xFEE408
#define FS_OFFSET_2120_NAND_MUTEX 0xFE9CF0
#define FS_OFFSET_2120_ACTIVE_PARTITION 0xFE9D30
#define FS_OFFSET_2120_SDMMC_DAS_HANDLE 0xFCBB18
// NOPs
#define FS_OFFSET_2120_SD_DAS_INIT 0x2B5C8
// Nintendo Paths
#define FS_OFFSET_2120_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x000718CC, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x000824F4, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008AF18, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x000A0B8C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_2120_H__

59
emummc/source/FS/offsets/2120_exfat.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_2120_EXFAT_EXFAT_H__
#define __FS_2120_EXFAT_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_2120_EXFAT_SDMMC_ACCESSOR_GC 0x1B7AD0
#define FS_OFFSET_2120_EXFAT_SDMMC_ACCESSOR_SD 0x1B9AE0
#define FS_OFFSET_2120_EXFAT_SDMMC_ACCESSOR_NAND 0x1B8100
// Hooks
#define FS_OFFSET_2120_EXFAT_SDMMC_WRAPPER_READ 0x1B39B0
#define FS_OFFSET_2120_EXFAT_SDMMC_WRAPPER_WRITE 0x1B3A10
#define FS_OFFSET_2120_EXFAT_RTLD 0x2E1C0
#define FS_OFFSET_2120_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2120_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1D6B10
// Misc funcs
#define FS_OFFSET_2120_EXFAT_LOCK_MUTEX 0x1AC930
#define FS_OFFSET_2120_EXFAT_UNLOCK_MUTEX 0x1AC990
#define FS_OFFSET_2120_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1B3970
#define FS_OFFSET_2120_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1B3990
// Misc Data
#define FS_OFFSET_2120_EXFAT_SD_MUTEX 0xFFF408
#define FS_OFFSET_2120_EXFAT_NAND_MUTEX 0xFFACF0
#define FS_OFFSET_2120_EXFAT_ACTIVE_PARTITION 0xFFAD30
#define FS_OFFSET_2120_EXFAT_SDMMC_DAS_HANDLE 0xFD8B18
// NOPs
#define FS_OFFSET_2120_EXFAT_SD_DAS_INIT 0x2B5C8
// Nintendo Paths
#define FS_OFFSET_2120_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x000718CC, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x000824F4, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008AF18, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x000A0B8C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_2120_EXFAT_EXFAT_H__

59
emummc/source/FS/offsets/2200.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_2200_H__
#define __FS_2200_H__
// Accessor vtable getters
#define FS_OFFSET_2200_SDMMC_ACCESSOR_GC 0x1B01C0
#define FS_OFFSET_2200_SDMMC_ACCESSOR_SD 0x1B21C0
#define FS_OFFSET_2200_SDMMC_ACCESSOR_NAND 0x1B07F0
// Hooks
#define FS_OFFSET_2200_SDMMC_WRAPPER_READ 0x1AC0F0
#define FS_OFFSET_2200_SDMMC_WRAPPER_WRITE 0x1AC150
#define FS_OFFSET_2200_RTLD 0x2DED0
#define FS_OFFSET_2200_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2200_CLKRST_SET_MIN_V_CLK_RATE 0x1CF260
// Misc funcs
#define FS_OFFSET_2200_LOCK_MUTEX 0x1A4EF0
#define FS_OFFSET_2200_UNLOCK_MUTEX 0x1A4F40
#define FS_OFFSET_2200_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1AC0B0
#define FS_OFFSET_2200_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1AC0D0
// Misc Data
#define FS_OFFSET_2200_SD_MUTEX 0xFF1408
#define FS_OFFSET_2200_NAND_MUTEX 0xFECD00
#define FS_OFFSET_2200_ACTIVE_PARTITION 0xFECD40
#define FS_OFFSET_2200_SDMMC_DAS_HANDLE 0xFCEB98
// NOPs
#define FS_OFFSET_2200_SD_DAS_INIT 0x2B438
// Nintendo Paths
#define FS_OFFSET_2200_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x000715EC, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00082E64, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008B888, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x000A1B1C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_2200_H__

59
emummc/source/FS/offsets/2200_exfat.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_2200_EXFAT_H__
#define __FS_2200_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_2200_EXFAT_SDMMC_ACCESSOR_GC 0x1BB3B0
#define FS_OFFSET_2200_EXFAT_SDMMC_ACCESSOR_SD 0x1BD3B0
#define FS_OFFSET_2200_EXFAT_SDMMC_ACCESSOR_NAND 0x1BB9E0
// Hooks
#define FS_OFFSET_2200_EXFAT_SDMMC_WRAPPER_READ 0x1B72E0
#define FS_OFFSET_2200_EXFAT_SDMMC_WRAPPER_WRITE 0x1B7340
#define FS_OFFSET_2200_EXFAT_RTLD 0x2DED0
#define FS_OFFSET_2200_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2200_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1DA450
// Misc funcs
#define FS_OFFSET_2200_EXFAT_LOCK_MUTEX 0x1B00E0
#define FS_OFFSET_2200_EXFAT_UNLOCK_MUTEX 0x1B0130
#define FS_OFFSET_2200_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1B72A0
#define FS_OFFSET_2200_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1B72C0
// Misc Data
#define FS_OFFSET_2200_EXFAT_SD_MUTEX 0x1002408
#define FS_OFFSET_2200_EXFAT_NAND_MUTEX 0xFFDD00
#define FS_OFFSET_2200_EXFAT_ACTIVE_PARTITION 0xFFDD40
#define FS_OFFSET_2200_EXFAT_SDMMC_DAS_HANDLE 0xFDBB98
// NOPs
#define FS_OFFSET_2200_EXFAT_SD_DAS_INIT 0x2B438
// Nintendo Paths
#define FS_OFFSET_2200_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x000715EC, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00082E64, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008B888, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x000A1B1C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_2200_EXFAT_H__

View File

@@ -85,10 +85,10 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
/* We can get away with only including latest because exosphere supports newer-than-expected master key in engine. */ /* We can get away with only including latest because exosphere supports newer-than-expected master key in engine. */
/* TODO: Update on next change of keys. */ /* TODO: Update on next change of keys. */
/* Mariko Development Master Kek Source. */ /* Mariko Development Master Kek Source. */
.byte 0x11, 0x1C, 0x13, 0x90, 0xD9, 0x5E, 0xB0, 0xA2, 0xE3, 0xD0, 0x0E, 0x5D, 0xC4, 0xFB, 0x9E, 0xDB .byte 0x2E, 0x27, 0x44, 0xEA, 0x32, 0xF8, 0x2C, 0xF0, 0x6F, 0xCA, 0xCD, 0x77, 0xAE, 0xAE, 0x1A, 0x1B
/* Mariko Production Master Kek Source. */ /* Mariko Production Master Kek Source. */
.byte 0xEB, 0xF3, 0x5B, 0x2D, 0x4A, 0x2D, 0xCE, 0x45, 0x3A, 0x6F, 0x61, 0x38, 0x0B, 0x00, 0x3B, 0x46 .byte 0x82, 0xE2, 0x0A, 0x59, 0x67, 0xDF, 0xBF, 0x51, 0x47, 0x62, 0x11, 0xF2, 0x41, 0xD3, 0xEE, 0x13
/* Development Master Key Vectors. */ /* Development Master Key Vectors. */
.byte 0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE /* Zeroes encrypted with Master Key 00. */ .byte 0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE /* Zeroes encrypted with Master Key 00. */
@@ -112,6 +112,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0x90, 0x64, 0xF9, 0x08, 0x29, 0x88, 0xD4, 0xDC, 0x73, 0xA4, 0xA1, 0x13, 0x9E, 0x59, 0x85, 0xA0 /* Master key 11 encrypted with Master key 12. */ .byte 0x90, 0x64, 0xF9, 0x08, 0x29, 0x88, 0xD4, 0xDC, 0x73, 0xA4, 0xA1, 0x13, 0x9E, 0x59, 0x85, 0xA0 /* Master key 11 encrypted with Master key 12. */
.byte 0x94, 0x46, 0x3B, 0xFA, 0x7D, 0xB9, 0xE2, 0x94, 0xC2, 0x9D, 0xB9, 0xA4, 0xB2, 0x56, 0xCA, 0xFE /* Master key 12 encrypted with Master key 13. */ .byte 0x94, 0x46, 0x3B, 0xFA, 0x7D, 0xB9, 0xE2, 0x94, 0xC2, 0x9D, 0xB9, 0xA4, 0xB2, 0x56, 0xCA, 0xFE /* Master key 12 encrypted with Master key 13. */
.byte 0x74, 0xB2, 0x5F, 0xA0, 0x4B, 0x74, 0x6D, 0x47, 0x5B, 0xA9, 0xF5, 0x26, 0x46, 0xD7, 0x4B, 0x6E /* Master key 13 encrypted with Master key 14. */ .byte 0x74, 0xB2, 0x5F, 0xA0, 0x4B, 0x74, 0x6D, 0x47, 0x5B, 0xA9, 0xF5, 0x26, 0x46, 0xD7, 0x4B, 0x6E /* Master key 13 encrypted with Master key 14. */
.byte 0x97, 0xB3, 0x61, 0x88, 0x5C, 0x0D, 0xA1, 0x38, 0x73, 0xA4, 0x2F, 0x1A, 0x46, 0xA1, 0x09, 0xBF /* Master key 14 encrypted with Master key 15. */
/* Production Master Key Vectors. */ /* Production Master Key Vectors. */
.byte 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D /* Zeroes encrypted with Master Key 00. */ .byte 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D /* Zeroes encrypted with Master Key 00. */
@@ -135,6 +136,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 /* Master key 11 encrypted with Master key 12. */ .byte 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 /* Master key 11 encrypted with Master key 12. */
.byte 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 /* Master key 12 encrypted with Master key 13. */ .byte 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 /* Master key 12 encrypted with Master key 13. */
.byte 0xF7, 0x92, 0xC0, 0xEC, 0xF3, 0xA4, 0x8C, 0xB7, 0x0D, 0xB3, 0xF3, 0xAB, 0x10, 0x9B, 0x18, 0xBA /* Master key 13 encrypted with Master key 14. */ .byte 0xF7, 0x92, 0xC0, 0xEC, 0xF3, 0xA4, 0x8C, 0xB7, 0x0D, 0xB3, 0xF3, 0xAB, 0x10, 0x9B, 0x18, 0xBA /* Master key 13 encrypted with Master key 14. */
.byte 0x14, 0xCB, 0x60, 0x29, 0x3D, 0xE0, 0xFB, 0xF2, 0x5B, 0x60, 0xB6, 0xC5, 0x2E, 0x77, 0x8F, 0x98 /* Master key 14 encrypted with Master key 15. */
/* Device Master Key Source Sources. */ /* Device Master Key Source Sources. */
.byte 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D /* 4.0.0 Device Master Key Source Source. */ .byte 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D /* 4.0.0 Device Master Key Source Source. */
@@ -155,6 +157,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 /* 19.0.0 Device Master Key Source Source. */ .byte 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 /* 19.0.0 Device Master Key Source Source. */
.byte 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 /* 20.0.0 Device Master Key Source Source. */ .byte 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 /* 20.0.0 Device Master Key Source Source. */
.byte 0xF9, 0x62, 0x05, 0x99, 0xE0, 0xB9, 0xA6, 0x9B, 0x9D, 0xAA, 0xB4, 0x12, 0x0B, 0x0F, 0xF5, 0x8F /* 21.0.0 Device Master Key Source Source. */ .byte 0xF9, 0x62, 0x05, 0x99, 0xE0, 0xB9, 0xA6, 0x9B, 0x9D, 0xAA, 0xB4, 0x12, 0x0B, 0x0F, 0xF5, 0x8F /* 21.0.0 Device Master Key Source Source. */
.byte 0xF8, 0xF4, 0x22, 0xA4, 0x34, 0xAE, 0x0E, 0x0C, 0x4D, 0x5C, 0x5B, 0xA1, 0x1B, 0x46, 0x1C, 0x78 /* 22.0.0 Device Master Key Source Source. */
/* Development Device Master Kek Sources. */ /* Development Device Master Kek Sources. */
.byte 0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34 /* 4.0.0 Device Master Kek Source. */ .byte 0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34 /* 4.0.0 Device Master Kek Source. */
@@ -175,6 +178,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0xAE, 0x78, 0x36, 0xB6, 0x91, 0xEB, 0xAF, 0x9C, 0x18, 0xF1, 0xC0, 0xD5, 0x8A, 0x0C, 0x7C, 0xA1 /* 19.0.0 Device Master Kek Source. */ .byte 0xAE, 0x78, 0x36, 0xB6, 0x91, 0xEB, 0xAF, 0x9C, 0x18, 0xF1, 0xC0, 0xD5, 0x8A, 0x0C, 0x7C, 0xA1 /* 19.0.0 Device Master Kek Source. */
.byte 0x09, 0x12, 0x4F, 0x26, 0x90, 0xB9, 0xA6, 0xF5, 0xA5, 0x18, 0x74, 0xB6, 0x8D, 0x80, 0x59, 0x3D /* 20.0.0 Device Master Kek Source. */ .byte 0x09, 0x12, 0x4F, 0x26, 0x90, 0xB9, 0xA6, 0xF5, 0xA5, 0x18, 0x74, 0xB6, 0x8D, 0x80, 0x59, 0x3D /* 20.0.0 Device Master Kek Source. */
.byte 0x7A, 0x4C, 0x38, 0xB7, 0x03, 0x6B, 0x1E, 0x81, 0x20, 0x53, 0x14, 0x99, 0xA4, 0x21, 0x92, 0x9F /* 21.0.0 Device Master Kek Source. */ .byte 0x7A, 0x4C, 0x38, 0xB7, 0x03, 0x6B, 0x1E, 0x81, 0x20, 0x53, 0x14, 0x99, 0xA4, 0x21, 0x92, 0x9F /* 21.0.0 Device Master Kek Source. */
.byte 0xF3, 0xBC, 0xB5, 0xB5, 0x5F, 0x01, 0x50, 0x2B, 0x69, 0x69, 0x3A, 0x6B, 0xF9, 0x2C, 0x11, 0x9F /* 22.0.0 Device Master Kek Source. */
/* Production Device Master Kek Sources. */ /* Production Device Master Kek Sources. */
.byte 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D /* 4.0.0 Device Master Kek Source. */ .byte 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D /* 4.0.0 Device Master Kek Source. */
@@ -194,4 +198,5 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
.byte 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B /* 18.0.0 Device Master Kek Source. */ .byte 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B /* 18.0.0 Device Master Kek Source. */
.byte 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F /* 19.0.0 Device Master Kek Source. */ .byte 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F /* 19.0.0 Device Master Kek Source. */
.byte 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 /* 20.0.0 Device Master Kek Source. */ .byte 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 /* 20.0.0 Device Master Kek Source. */
.byte 0x92, 0xBF, 0x37, 0x80, 0x0E, 0x79, 0x56, 0x8C, 0x57, 0x75, 0x72, 0x0A, 0x48, 0xD8, 0x15, 0x39 /* 21.0.0 Device Master Kek Source. */ .byte 0x92, 0xBF, 0x37, 0x80, 0x0E, 0x79, 0x56, 0x8C, 0x57, 0x75, 0x72, 0x0A, 0x48, 0xD8, 0x15, 0x39 /* 21.0.0 Device Master Kek Source. */
.byte 0xC4, 0x6F, 0x0E, 0x72, 0x43, 0xCE, 0x87, 0xFC, 0x38, 0x95, 0x9B, 0xC9, 0x31, 0x44, 0x97, 0x63 /* 22.0.0 Device Master Kek Source. */

View File

@@ -94,7 +94,7 @@ namespace ams::secmon::boot {
} }
/* Check that the key generation is one that we can use. */ /* Check that the key generation is one that we can use. */
static_assert(pkg1::KeyGeneration_Count == 21); static_assert(pkg1::KeyGeneration_Count == 22);
if (key_generation >= pkg1::KeyGeneration_Count) { if (key_generation >= pkg1::KeyGeneration_Count) {
return false; return false;
} }

View File

@@ -132,10 +132,13 @@ namespace ams::secmon::smc {
} }
u32 GetMemoryMode() { u32 GetMemoryMode() {
/* Unless development function is enabled, we're 4 GB. */ /* Unless development function or forced boot config memory size is enabled, we're 4 GB. */
u32 memory_mode = pkg1::MemoryMode_4GB; u32 memory_mode = pkg1::MemoryMode_4GB;
if (const auto &bcd = GetBootConfig().data; bcd.IsDevelopmentFunctionEnabled()) { const auto &bcd = GetBootConfig().data;
const auto &sc = GetSecmonConfiguration(); /* Exosphere extensions */
if (bcd.IsDevelopmentFunctionEnabled() || sc.IsBootConfigMemoryModeEnabled()) {
memory_mode = GetMemoryMode(bcd.GetMemoryMode()); memory_mode = GetMemoryMode(bcd.GetMemoryMode());
} }
@@ -146,17 +149,19 @@ namespace ams::secmon::smc {
pkg1::MemorySize memory_size = pkg1::MemorySize_4GB; pkg1::MemorySize memory_size = pkg1::MemorySize_4GB;
util::BitPack32 value = {}; util::BitPack32 value = {};
if (const auto &bcd = GetBootConfig().data; bcd.IsDevelopmentFunctionEnabled()) { const auto &bcd = GetBootConfig().data;
memory_size = GetMemorySize(GetMemoryMode(bcd.GetMemoryMode())); const auto &sc = GetSecmonConfiguration(); /* Exosphere extensions */
if (bcd.IsDevelopmentFunctionEnabled()) {
value.Set<KernelConfiguration::Flags1>(bcd.GetKernelFlags1()); value.Set<KernelConfiguration::Flags1>(bcd.GetKernelFlags1());
value.Set<KernelConfiguration::Flags0>(bcd.GetKernelFlags0()); value.Set<KernelConfiguration::Flags0>(bcd.GetKernelFlags0());
} }
value.Set<KernelConfiguration::PhysicalMemorySize>(memory_size); if (bcd.IsDevelopmentFunctionEnabled() || sc.IsBootConfigMemoryModeEnabled()) {
memory_size = GetMemorySize(GetMemoryMode(bcd.GetMemoryMode()));
}
/* Exosphere extensions. */ value.Set<KernelConfiguration::PhysicalMemorySize>(memory_size);
const auto &sc = GetSecmonConfiguration();
if (!sc.DisableUserModeExceptionHandlers()) { if (!sc.DisableUserModeExceptionHandlers()) {
value.Set<KernelConfiguration::EnableUserExceptionHandlers>(true); value.Set<KernelConfiguration::EnableUserExceptionHandlers>(true);
@@ -169,6 +174,27 @@ namespace ams::secmon::smc {
return value.value; return value.value;
} }
fuse::DramId GetDramIdAdjusted() {
const auto dram_id = fuse::GetDramId();
AMS_ABORT_UNLESS(dram_id < fuse::DramId_Count);
const auto fuse_mem_size = DramIdToMemorySize[dram_id];
const auto phys_mem_size = GetPhysicalMemorySize();
AMS_ABORT_UNLESS(fuse_mem_size <= phys_mem_size);
if (fuse_mem_size == phys_mem_size) {
return dram_id;
}
/* Adjust Dram ID to match density/ranks. */
if (GetSocType() == fuse::SocType_Erista) {
return fuse::DramId_IcosaSamsung6GB;
} else { /* fuse::SocType_Mariko */
return fuse::DramId_IowaSamsung1y8GBX;
}
}
constinit u64 g_payload_address = 0; constinit u64 g_payload_address = 0;
constinit bool g_set_true_target_firmware = false; constinit bool g_set_true_target_firmware = false;
@@ -178,7 +204,7 @@ namespace ams::secmon::smc {
args.r[1] = GetBootConfig().signed_data.IsProgramVerificationDisabled(); args.r[1] = GetBootConfig().signed_data.IsProgramVerificationDisabled();
break; break;
case ConfigItem::DramId: case ConfigItem::DramId:
args.r[1] = fuse::GetDramId(); args.r[1] = GetDramIdAdjusted(); /* Nintendo: fuse::GetDramId() */
break; break;
case ConfigItem::SecurityEngineInterruptNumber: case ConfigItem::SecurityEngineInterruptNumber:
args.r[1] = SecurityEngineUserInterruptId; args.r[1] = SecurityEngineUserInterruptId;
@@ -471,9 +497,18 @@ namespace ams::secmon::smc {
/* For exosphere's usage. */ /* For exosphere's usage. */
pkg1::MemorySize GetPhysicalMemorySize() { pkg1::MemorySize GetPhysicalMemorySize() {
const auto dram_id = fuse::GetDramId(); const uintptr_t MC = secmon::MemoryRegionVirtualDeviceMemoryController.GetAddress();
AMS_ABORT_UNLESS(dram_id < fuse::DramId_Count); const u32 mem_size = reg::Read(MC + MC_EMEM_CFG) & 0x3FFF;
return DramIdToMemorySize[dram_id];
switch (mem_size >> 10) {
case 4:
default:
return pkg1::MemorySize_4GB;
case 6:
return pkg1::MemorySize_6GB;
case 8:
return pkg1::MemorySize_8GB;
}
} }
} }

View File

@@ -602,7 +602,7 @@ namespace ams::nxboot {
Print("\n"); Print("\n");
if (R_SUCCEEDED(save_result)) { if (R_SUCCEEDED(save_result)) {
Print("Report saved to /atmosphere/fatal_errors/report_%016" PRIx64 ".bin", f_ctx->report_identifier); Print("Report saved to /atmosphere/fatal_errors/report_%016" PRIx64 ".bin\n", f_ctx->report_identifier);
} else { } else {
Print("Failed to save report to the SD card! (%08" PRIx32 ")\n", save_result.GetValue()); Print("Failed to save report to the SD card! (%08" PRIx32 ")\n", save_result.GetValue());
} }

View File

@@ -23,17 +23,17 @@ namespace ams::nxboot {
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSource[se::AesBlockSize] = { alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSource[se::AesBlockSize] = {
/* TODO: Update on next change of keys. */ /* TODO: Update on next change of keys. */
0xEB, 0xF3, 0x5B, 0x2D, 0x4A, 0x2D, 0xCE, 0x45, 0x3A, 0x6F, 0x61, 0x38, 0x0B, 0x00, 0x3B, 0x46 0x82, 0xE2, 0x0A, 0x59, 0x67, 0xDF, 0xBF, 0x51, 0x47, 0x62, 0x11, 0xF2, 0x41, 0xD3, 0xEE, 0x13
}; };
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = { alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = {
/* TODO: Update on next change of keys. */ /* TODO: Update on next change of keys. */
0x11, 0x1C, 0x13, 0x90, 0xD9, 0x5E, 0xB0, 0xA2, 0xE3, 0xD0, 0x0E, 0x5D, 0xC4, 0xFB, 0x9E, 0xDB 0x2E, 0x27, 0x44, 0xEA, 0x32, 0xF8, 0x2C, 0xF0, 0x6F, 0xCA, 0xCD, 0x77, 0xAE, 0xAE, 0x1A, 0x1B
}; };
alignas(se::AesBlockSize) constexpr inline const u8 EristaMasterKekSource[se::AesBlockSize] = { alignas(se::AesBlockSize) constexpr inline const u8 EristaMasterKekSource[se::AesBlockSize] = {
/* TODO: Update on next change of keys. */ /* TODO: Update on next change of keys. */
0x66, 0xC8, 0xCB, 0x3D, 0xEC, 0xF4, 0x59, 0x73, 0x54, 0x88, 0xE1, 0x2E, 0xE6, 0x3D, 0x68, 0x46 0x15, 0xAC, 0x96, 0x34, 0xF5, 0x32, 0x56, 0x68, 0xFE, 0x5B, 0x9D, 0xD7, 0xED, 0x19, 0xB7, 0x8E
}; };
alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = { alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = {
@@ -75,6 +75,7 @@ namespace ams::nxboot {
{ 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 }, /* 19.0.0 Device Master Key Source Source. */ { 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 }, /* 19.0.0 Device Master Key Source Source. */
{ 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 }, /* 20.0.0 Device Master Key Source Source. */ { 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 }, /* 20.0.0 Device Master Key Source Source. */
{ 0xF9, 0x62, 0x05, 0x99, 0xE0, 0xB9, 0xA6, 0x9B, 0x9D, 0xAA, 0xB4, 0x12, 0x0B, 0x0F, 0xF5, 0x8F }, /* 21.0.0 Device Master Key Source Source. */ { 0xF9, 0x62, 0x05, 0x99, 0xE0, 0xB9, 0xA6, 0x9B, 0x9D, 0xAA, 0xB4, 0x12, 0x0B, 0x0F, 0xF5, 0x8F }, /* 21.0.0 Device Master Key Source Source. */
{ 0xF8, 0xF4, 0x22, 0xA4, 0x34, 0xAE, 0x0E, 0x0C, 0x4D, 0x5C, 0x5B, 0xA1, 0x1B, 0x46, 0x1C, 0x78 }, /* 22.0.0 Device Master Key Source Source. */
}; };
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = { alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
@@ -96,6 +97,7 @@ namespace ams::nxboot {
{ 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F }, /* 19.0.0 Device Master Kek Source. */ { 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F }, /* 19.0.0 Device Master Kek Source. */
{ 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 }, /* 20.0.0 Device Master Kek Source. */ { 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 }, /* 20.0.0 Device Master Kek Source. */
{ 0x92, 0xBF, 0x37, 0x80, 0x0E, 0x79, 0x56, 0x8C, 0x57, 0x75, 0x72, 0x0A, 0x48, 0xD8, 0x15, 0x39 }, /* 21.0.0 Device Master Kek Source. */ { 0x92, 0xBF, 0x37, 0x80, 0x0E, 0x79, 0x56, 0x8C, 0x57, 0x75, 0x72, 0x0A, 0x48, 0xD8, 0x15, 0x39 }, /* 21.0.0 Device Master Kek Source. */
{ 0xC4, 0x6F, 0x0E, 0x72, 0x43, 0xCE, 0x87, 0xFC, 0x38, 0x95, 0x9B, 0xC9, 0x31, 0x44, 0x97, 0x63 }, /* 22.0.0 Device Master Kek Source. */
}; };
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = { alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
@@ -117,6 +119,7 @@ namespace ams::nxboot {
{ 0xAE, 0x78, 0x36, 0xB6, 0x91, 0xEB, 0xAF, 0x9C, 0x18, 0xF1, 0xC0, 0xD5, 0x8A, 0x0C, 0x7C, 0xA1 }, /* 19.0.0 Device Master Kek Source. */ { 0xAE, 0x78, 0x36, 0xB6, 0x91, 0xEB, 0xAF, 0x9C, 0x18, 0xF1, 0xC0, 0xD5, 0x8A, 0x0C, 0x7C, 0xA1 }, /* 19.0.0 Device Master Kek Source. */
{ 0x09, 0x12, 0x4F, 0x26, 0x90, 0xB9, 0xA6, 0xF5, 0xA5, 0x18, 0x74, 0xB6, 0x8D, 0x80, 0x59, 0x3D }, /* 20.0.0 Device Master Kek Source. */ { 0x09, 0x12, 0x4F, 0x26, 0x90, 0xB9, 0xA6, 0xF5, 0xA5, 0x18, 0x74, 0xB6, 0x8D, 0x80, 0x59, 0x3D }, /* 20.0.0 Device Master Kek Source. */
{ 0x7A, 0x4C, 0x38, 0xB7, 0x03, 0x6B, 0x1E, 0x81, 0x20, 0x53, 0x14, 0x99, 0xA4, 0x21, 0x92, 0x9F }, /* 21.0.0 Device Master Kek Source. */ { 0x7A, 0x4C, 0x38, 0xB7, 0x03, 0x6B, 0x1E, 0x81, 0x20, 0x53, 0x14, 0x99, 0xA4, 0x21, 0x92, 0x9F }, /* 21.0.0 Device Master Kek Source. */
{ 0xF3, 0xBC, 0xB5, 0xB5, 0x5F, 0x01, 0x50, 0x2B, 0x69, 0x69, 0x3A, 0x6B, 0xF9, 0x2C, 0x11, 0x9F }, /* 22.0.0 Device Master Kek Source. */
}; };
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySources[pkg1::KeyGeneration_Count][se::AesBlockSize] = { alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySources[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
@@ -141,6 +144,7 @@ namespace ams::nxboot {
{ 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 }, /* Master key 11 encrypted with Master key 12. */ { 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 }, /* Master key 11 encrypted with Master key 12. */
{ 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 }, /* Master key 12 encrypted with Master key 13. */ { 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 }, /* Master key 12 encrypted with Master key 13. */
{ 0xF7, 0x92, 0xC0, 0xEC, 0xF3, 0xA4, 0x8C, 0xB7, 0x0D, 0xB3, 0xF3, 0xAB, 0x10, 0x9B, 0x18, 0xBA }, /* Master key 13 encrypted with Master key 14. */ { 0xF7, 0x92, 0xC0, 0xEC, 0xF3, 0xA4, 0x8C, 0xB7, 0x0D, 0xB3, 0xF3, 0xAB, 0x10, 0x9B, 0x18, 0xBA }, /* Master key 13 encrypted with Master key 14. */
{ 0x14, 0xCB, 0x60, 0x29, 0x3D, 0xE0, 0xFB, 0xF2, 0x5B, 0x60, 0xB6, 0xC5, 0x2E, 0x77, 0x8F, 0x98 }, /* Master key 14 encrypted with Master key 15. */
}; };
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySourcesDev[pkg1::KeyGeneration_Count][se::AesBlockSize] = { alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySourcesDev[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
@@ -165,6 +169,7 @@ namespace ams::nxboot {
{ 0x90, 0x64, 0xF9, 0x08, 0x29, 0x88, 0xD4, 0xDC, 0x73, 0xA4, 0xA1, 0x13, 0x9E, 0x59, 0x85, 0xA0 }, /* Master key 11 encrypted with Master key 12. */ { 0x90, 0x64, 0xF9, 0x08, 0x29, 0x88, 0xD4, 0xDC, 0x73, 0xA4, 0xA1, 0x13, 0x9E, 0x59, 0x85, 0xA0 }, /* Master key 11 encrypted with Master key 12. */
{ 0x94, 0x46, 0x3B, 0xFA, 0x7D, 0xB9, 0xE2, 0x94, 0xC2, 0x9D, 0xB9, 0xA4, 0xB2, 0x56, 0xCA, 0xFE }, /* Master key 12 encrypted with Master key 13. */ { 0x94, 0x46, 0x3B, 0xFA, 0x7D, 0xB9, 0xE2, 0x94, 0xC2, 0x9D, 0xB9, 0xA4, 0xB2, 0x56, 0xCA, 0xFE }, /* Master key 12 encrypted with Master key 13. */
{ 0x74, 0xB2, 0x5F, 0xA0, 0x4B, 0x74, 0x6D, 0x47, 0x5B, 0xA9, 0xF5, 0x26, 0x46, 0xD7, 0x4B, 0x6E }, /* Master key 13 encrypted with Master key 14. */ { 0x74, 0xB2, 0x5F, 0xA0, 0x4B, 0x74, 0x6D, 0x47, 0x5B, 0xA9, 0xF5, 0x26, 0x46, 0xD7, 0x4B, 0x6E }, /* Master key 13 encrypted with Master key 14. */
{ 0x97, 0xB3, 0x61, 0x88, 0x5C, 0x0D, 0xA1, 0x38, 0x73, 0xA4, 0x2F, 0x1A, 0x46, 0xA1, 0x09, 0xBF }, /* Master key 14 encrypted with Master key 15. */
}; };
alignas(se::AesBlockSize) constinit u8 MasterKeys[pkg1::OldMasterKeyCount][se::AesBlockSize] = {}; alignas(se::AesBlockSize) constinit u8 MasterKeys[pkg1::OldMasterKeyCount][se::AesBlockSize] = {};

View File

@@ -80,7 +80,7 @@ namespace ams::nxboot {
} }
/* Check that the key generation is one that we can use. */ /* Check that the key generation is one that we can use. */
static_assert(pkg1::KeyGeneration_Count == 21); static_assert(pkg1::KeyGeneration_Count == 22);
if (key_generation >= pkg1::KeyGeneration_Count) { if (key_generation >= pkg1::KeyGeneration_Count) {
return false; return false;
} }

View File

@@ -267,6 +267,8 @@ namespace ams::nxboot {
return ams::TargetFirmware_20_0_0; return ams::TargetFirmware_20_0_0;
} else if (std::memcmp(package1 + 0x10, "20251009", 8) == 0) { } else if (std::memcmp(package1 + 0x10, "20251009", 8) == 0) {
return ams::TargetFirmware_21_0_0; return ams::TargetFirmware_21_0_0;
} else if (std::memcmp(package1 + 0x10, "20260123", 8) == 0) {
return ams::TargetFirmware_22_0_0;
} }
break; break;
default: default:
@@ -543,6 +545,12 @@ namespace ams::nxboot {
} else { } else {
storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess; storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess;
} }
} else if (std::strcmp(entry.key, "enable_mem_mode") == 0) {
if (entry.value[0] == '1') {
storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_BootConfigMemoryModeEnabled;
} else {
storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_BootConfigMemoryModeEnabled;
}
} else if (std::strcmp(entry.key, "blank_prodinfo_sysmmc") == 0) { } else if (std::strcmp(entry.key, "blank_prodinfo_sysmmc") == 0) {
if (!emummc_enabled) { if (!emummc_enabled) {
if (entry.value[0] == '1') { if (entry.value[0] == '1') {

View File

@@ -189,6 +189,12 @@ namespace ams::nxboot {
FsVersion_21_0_0, FsVersion_21_0_0,
FsVersion_21_0_0_Exfat, FsVersion_21_0_0_Exfat,
FsVersion_21_2_0,
FsVersion_21_2_0_Exfat,
FsVersion_22_0_0,
FsVersion_22_0_0_Exfat,
FsVersion_Count, FsVersion_Count,
}; };
@@ -290,6 +296,12 @@ namespace ams::nxboot {
{ 0xEE, 0x4B, 0x30, 0x12, 0xA6, 0x84, 0x02, 0x25 }, /* FsVersion_21_0_0 */ { 0xEE, 0x4B, 0x30, 0x12, 0xA6, 0x84, 0x02, 0x25 }, /* FsVersion_21_0_0 */
{ 0x6E, 0x2B, 0xD9, 0xBA, 0xA3, 0xB9, 0x10, 0xF1 }, /* FsVersion_21_0_0_Exfat */ { 0x6E, 0x2B, 0xD9, 0xBA, 0xA3, 0xB9, 0x10, 0xF1 }, /* FsVersion_21_0_0_Exfat */
{ 0xAF, 0x1D, 0xBD, 0xC7, 0x82, 0x98, 0x3C, 0xBD }, /* FsVersion_21_2_0 */
{ 0x56, 0x25, 0x17, 0xA1, 0x92, 0xC3, 0xC8, 0xF0 }, /* FsVersion_21_2_0_Exfat */
{ 0xB7, 0xA2, 0x97, 0x39, 0xB7, 0xED, 0xDE, 0xFC }, /* FsVersion_22_0_0 */
{ 0xFB, 0x0B, 0x68, 0xDB, 0x24, 0x03, 0xD1, 0x19 }, /* FsVersion_22_0_0_Exfat */
}; };
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) { const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
@@ -692,15 +704,27 @@ namespace ams::nxboot {
AddPatch(fs_meta, 0x187B70, NogcPatch1, sizeof(NogcPatch1)); AddPatch(fs_meta, 0x187B70, NogcPatch1, sizeof(NogcPatch1));
break; break;
case FsVersion_21_0_0: case FsVersion_21_0_0:
case FsVersion_21_2_0:
AddPatch(fs_meta, 0x1AC9ED, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x1AC9ED, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x1ACA05 , NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x1ACA05, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x17FBE0, NogcPatch1, sizeof(NogcPatch1)); AddPatch(fs_meta, 0x17FBE0, NogcPatch1, sizeof(NogcPatch1));
break; break;
case FsVersion_21_0_0_Exfat: case FsVersion_21_0_0_Exfat:
case FsVersion_21_2_0_Exfat:
AddPatch(fs_meta, 0x1B7B4D, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x1B7B4D, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x1B7B65, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x1B7B65, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x18AD40, NogcPatch1, sizeof(NogcPatch1)); AddPatch(fs_meta, 0x18AD40, NogcPatch1, sizeof(NogcPatch1));
break; break;
case FsVersion_22_0_0:
AddPatch(fs_meta, 0x1B023D, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x1B0255, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x183060, NogcPatch1, sizeof(NogcPatch1));
break;
case FsVersion_22_0_0_Exfat:
AddPatch(fs_meta, 0x1BB42D, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x1BB445, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x18E250, NogcPatch1, sizeof(NogcPatch1));
break;
default: default:
break; break;
} }

View File

@@ -6,7 +6,7 @@
[subrepo] [subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master branch = master
commit = 6cc765fcaa5f83b9cd6dc5b424bae31a0f33b29f commit = 82f1553c4c7e68364f7e630b1c68f2aee8681dee
parent = 3cb5d5f957020d07f5bdb3fb89521f29bea5d79d parent = 252f8685b493d0dfd428e9439b0296109776b935
method = merge method = merge
cmdver = 0.4.1 cmdver = 0.4.9

View File

@@ -41,6 +41,7 @@ namespace ams::pkg1 {
KeyGeneration_19_0_0 = 0x12, KeyGeneration_19_0_0 = 0x12,
KeyGeneration_20_0_0 = 0x13, KeyGeneration_20_0_0 = 0x13,
KeyGeneration_21_0_0 = 0x14, KeyGeneration_21_0_0 = 0x14,
KeyGeneration_22_0_0 = 0x15,
KeyGeneration_Count, KeyGeneration_Count,

View File

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

View File

@@ -30,6 +30,7 @@ namespace ams::secmon {
SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary = (1u << 5), SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary = (1u << 5),
SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc = (1u << 6), SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc = (1u << 6),
SecureMonitorConfigurationFlag_ForceEnableUsb30 = (1u << 7), SecureMonitorConfigurationFlag_ForceEnableUsb30 = (1u << 7),
SecureMonitorConfigurationFlag_BootConfigMemoryModeEnabled = (1u << 8),
SecureMonitorConfigurationFlag_Default = SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel, SecureMonitorConfigurationFlag_Default = SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel,
}; };
@@ -103,6 +104,7 @@ namespace ams::secmon {
constexpr bool ShouldUseBlankCalibrationBinary() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary) != 0; } constexpr bool ShouldUseBlankCalibrationBinary() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary) != 0; }
constexpr bool AllowWritingToCalibrationBinarySysmmc() const { return (this->flags[0] & SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc) != 0; } constexpr bool AllowWritingToCalibrationBinarySysmmc() const { return (this->flags[0] & SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc) != 0; }
constexpr bool IsUsb30ForceEnabled() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ForceEnableUsb30) != 0; } constexpr bool IsUsb30ForceEnabled() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ForceEnableUsb30) != 0; }
constexpr bool IsBootConfigMemoryModeEnabled() const { return (this->flags[0] & SecureMonitorConfigurationFlag_BootConfigMemoryModeEnabled) != 0; }
constexpr bool IsDevelopmentFunctionEnabled(bool for_kern) const { return for_kern ? this->IsDevelopmentFunctionEnabledForKernel() : this->IsDevelopmentFunctionEnabledForUser(); } constexpr bool IsDevelopmentFunctionEnabled(bool for_kern) const { return for_kern ? this->IsDevelopmentFunctionEnabledForKernel() : this->IsDevelopmentFunctionEnabledForUser(); }
}; };

View File

@@ -177,6 +177,7 @@ namespace ams::fuse {
} }
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = { constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
TargetFirmware_22_0_0,
TargetFirmware_21_0_0, TargetFirmware_21_0_0,
TargetFirmware_20_0_0, TargetFirmware_20_0_0,
TargetFirmware_19_0_0, TargetFirmware_19_0_0,

View File

@@ -200,6 +200,7 @@ namespace ams::kern {
bool m_is_kernel; bool m_is_kernel;
bool m_enable_aslr; bool m_enable_aslr;
bool m_enable_device_address_space_merge; bool m_enable_device_address_space_merge;
bool m_allowed_exec_device_mapping;
KMemoryBlockSlabManager *m_memory_block_slab_manager; KMemoryBlockSlabManager *m_memory_block_slab_manager;
KBlockInfoManager *m_block_info_manager; KBlockInfoManager *m_block_info_manager;
KResourceLimit *m_resource_limit; KResourceLimit *m_resource_limit;
@@ -217,7 +218,7 @@ namespace ams::kern {
m_alias_code_region_end(Null<KProcessAddress>), m_code_region_start(Null<KProcessAddress>), m_code_region_end(Null<KProcessAddress>), m_alias_code_region_end(Null<KProcessAddress>), m_code_region_start(Null<KProcessAddress>), m_code_region_end(Null<KProcessAddress>),
m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(), m_mapped_ipc_server_memory(), m_alias_region_extra_size(), m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(), m_mapped_ipc_server_memory(), m_alias_region_extra_size(),
m_general_lock(), m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize), m_general_lock(), m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize),
m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(), m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(), m_allowed_exec_device_mapping(),
m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), m_cached_physical_heap_region(), m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), m_cached_physical_heap_region(),
m_heap_fill_value(), m_ipc_fill_value(), m_stack_fill_value() m_heap_fill_value(), m_ipc_fill_value(), m_stack_fill_value()
{ {
@@ -520,6 +521,8 @@ namespace ams::kern {
size_t GetAliasCodeDataSize() const; size_t GetAliasCodeDataSize() const;
u32 GetAllocateOption() const { return m_allocate_option; } u32 GetAllocateOption() const { return m_allocate_option; }
void AllowDeviceMappingOfExecPages() { m_allowed_exec_device_mapping = true; }
public: public:
static ALWAYS_INLINE KVirtualAddress GetLinearMappedVirtualAddress(KPhysicalAddress addr) { static ALWAYS_INLINE KVirtualAddress GetLinearMappedVirtualAddress(KPhysicalAddress addr) {
return KMemoryLayout::GetLinearVirtualAddress(addr); return KMemoryLayout::GetLinearVirtualAddress(addr);

View File

@@ -102,8 +102,8 @@ namespace ams::kern {
IoRegionList m_io_region_list; IoRegionList m_io_region_list;
bool m_is_suspended; bool m_is_suspended;
bool m_is_immortal; bool m_is_immortal;
bool m_is_jit_debug;
bool m_is_handle_table_initialized; bool m_is_handle_table_initialized;
bool m_is_jit_debug;
ams::svc::DebugEvent m_jit_debug_event_type; ams::svc::DebugEvent m_jit_debug_event_type;
ams::svc::DebugException m_jit_debug_exception_type; ams::svc::DebugException m_jit_debug_exception_type;
uintptr_t m_jit_debug_params[4]; uintptr_t m_jit_debug_params[4];

View File

@@ -285,7 +285,7 @@ namespace ams::kern {
MESOSPHERE_INIT_ABORT_UNLESS(expected_size != 0); MESOSPHERE_INIT_ABORT_UNLESS(expected_size != 0);
/* Ensure that the size we need to reserve is as we expect it to be. */ /* Ensure that the size we need to reserve is as we expect it to be. */
const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize); const u32 total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize);
MESOSPHERE_ABORT_UNLESS(total_size == expected_size); MESOSPHERE_ABORT_UNLESS(total_size == expected_size);
MESOSPHERE_ABORT_UNLESS(total_size <= InitialProcessBinarySizeMax); MESOSPHERE_ABORT_UNLESS(total_size <= InitialProcessBinarySizeMax);

View File

@@ -211,6 +211,7 @@ namespace ams::kern {
/* Set other basic fields. */ /* Set other basic fields. */
m_enable_aslr = (flags & ams::svc::CreateProcessFlag_EnableAslr) != 0; m_enable_aslr = (flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
m_enable_device_address_space_merge = (flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0; m_enable_device_address_space_merge = (flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
m_allowed_exec_device_mapping = false;
m_address_space_start = start; m_address_space_start = start;
m_address_space_end = end; m_address_space_end = end;
m_is_kernel = false; m_is_kernel = false;
@@ -3077,7 +3078,9 @@ namespace ams::kern {
const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap) | (check_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_None); const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap) | (check_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_None);
size_t num_allocator_blocks; size_t num_allocator_blocks;
KMemoryState old_state; KMemoryState old_state;
R_TRY(this->CheckMemoryState(std::addressof(old_state), nullptr, nullptr, std::addressof(num_allocator_blocks), address, size, test_state, test_state, perm, perm, KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None, KMemoryAttribute_DeviceShared)); const KMemoryPermission perm_mask = static_cast<KMemoryPermission>(perm | (m_allowed_exec_device_mapping ? KMemoryPermission_None : KMemoryPermission_UserExecute));
R_TRY(this->CheckMemoryState(std::addressof(old_state), nullptr, nullptr, std::addressof(num_allocator_blocks), address, size, test_state, test_state, perm_mask, perm, KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None, KMemoryAttribute_DeviceShared));
/* Create an update allocator. */ /* Create an update allocator. */
Result allocator_result; Result allocator_result;

View File

@@ -185,6 +185,11 @@ namespace ams::kern {
/* Validate that the intended kernel version isn't too high for us to support. */ /* Validate that the intended kernel version isn't too high for us to support. */
R_UNLESS(m_capabilities.GetIntendedKernelVersion() <= ams::svc::SupportedKernelVersion, svc::ResultInvalidCombination()); R_UNLESS(m_capabilities.GetIntendedKernelVersion() <= ams::svc::SupportedKernelVersion, svc::ResultInvalidCombination());
/* Enable mapping device pages as executable on legacy processes. */
if (m_capabilities.GetIntendedKernelMajorVersion() < 26) {
m_page_table.GetBasePageTable().AllowDeviceMappingOfExecPages();
}
/* Create and clear the process local region. */ /* Create and clear the process local region. */
R_TRY(this->CreateThreadLocalRegion(std::addressof(m_plr_address))); R_TRY(this->CreateThreadLocalRegion(std::addressof(m_plr_address)));
m_plr_heap_address = this->GetThreadLocalRegionPointer(m_plr_address); m_plr_heap_address = this->GetThreadLocalRegionPointer(m_plr_address);
@@ -976,6 +981,9 @@ namespace ams::kern {
/* Set the thread arguments. */ /* Set the thread arguments. */
main_thread->GetContext().SetArguments(0, thread_handle); main_thread->GetContext().SetArguments(0, thread_handle);
/* Pass the thread handle to the thread local region. */
static_cast<ams::svc::ThreadLocalRegion *>(main_thread->GetThreadLocalRegionHeapAddress())->thread_handle = thread_handle;
/* Update our state. */ /* Update our state. */
this->ChangeState((state == State_Created) ? State_Running : State_RunningAttached); this->ChangeState((state == State_Created) ? State_Running : State_RunningAttached);
ON_RESULT_FAILURE_2 { this->ChangeState(state); }; ON_RESULT_FAILURE_2 { this->ChangeState(state); };

View File

@@ -66,6 +66,9 @@ namespace ams::kern::svc {
/* Add the thread to the handle table. */ /* Add the thread to the handle table. */
R_TRY(process.GetHandleTable().Add(out, thread)); R_TRY(process.GetHandleTable().Add(out, thread));
/* Pass the thread handle to the thread local region. */
static_cast<ams::svc::ThreadLocalRegion *>(thread->GetThreadLocalRegionHeapAddress())->thread_handle = *out;
R_SUCCEED(); R_SUCCEED();
} }

View File

@@ -661,7 +661,7 @@
HANDLER(UsbControllerCount, 457, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(UsbControllerCount, 457, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(ControllerTypeList, 458, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ControllerTypeList, 458, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(ControllerInterfaceList, 459, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ControllerInterfaceList, 459, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(ControllerStyleList, 460, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ControllerStyleListDeprecated, 460, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(FsPooledBufferPeakFreeSize, 461, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FsPooledBufferPeakFreeSize, 461, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(FsPooledBufferRetriedCount, 462, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FsPooledBufferRetriedCount, 462, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(FsPooledBufferReduceAllocationCount, 463, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FsPooledBufferReduceAllocationCount, 463, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
@@ -974,6 +974,11 @@
HANDLER(RomFsRecoveredAesFailedCount, 772, FsProxyErrorInfo3, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(RomFsRecoveredAesFailedCount, 772, FsProxyErrorInfo3, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(DriverRecoveredAesFailedCount, 773, FsProxyErrorInfo3, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(DriverRecoveredAesFailedCount, 773, FsProxyErrorInfo3, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(BluetoothIsHalted, 774, BluetoothErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(BluetoothIsHalted, 774, BluetoothErrorInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(BluetoothHaltedHciCommandOpcode, 775, ErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(AcpSupportedLanguageFlagForNxAddon, 776, AcpGeneralSettingsInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(FsSaveDataFileSystemPeakMountCount, 777, FsProxyErrorInfo3, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(TestBool, 778, Test, FieldType_Bool, FieldFlag_None ) \
HANDLER(TestI8Array, 779, Test, FieldType_I8Array, FieldFlag_None ) \
HANDLER(TestStringNx, 1000, TestNx, FieldType_String, FieldFlag_None ) \ HANDLER(TestStringNx, 1000, TestNx, FieldType_String, FieldFlag_None ) \
HANDLER(BoostModeCurrentLimit, 1001, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(BoostModeCurrentLimit, 1001, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(ChargeConfiguration, 1002, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(ChargeConfiguration, 1002, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
@@ -1008,5 +1013,5 @@
HANDLER(LastDvfsThresholdTripped, 1031, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(LastDvfsThresholdTripped, 1031, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(ModuleClockEnableFlags, 1032, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ModuleClockEnableFlags, 1032, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(ModulePowerEnableFlags, 1033, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ModulePowerEnableFlags, 1033, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(BluetoothAudioConnectionCount, 1034, BluetoothAudioInfo, FieldType_NumericU8, FieldFlag_None ) HANDLER(BluetoothAudioConnectionCount, 1034, BluetoothAudioInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(ControllerStyleList, 1035, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None )

View File

@@ -23,7 +23,7 @@ namespace ams::erpt {
#define GENERATE_ENUM(NAME, ID, ...) NAME = ID, #define GENERATE_ENUM(NAME, ID, ...) NAME = ID,
enum FieldType { enum FieldType: u8 {
AMS_ERPT_FOREACH_FIELD_TYPE(GENERATE_ENUM) AMS_ERPT_FOREACH_FIELD_TYPE(GENERATE_ENUM)
FieldType_Count, FieldType_Count,
}; };
@@ -111,6 +111,7 @@ namespace ams::erpt {
struct CreateReportOptionFlag { struct CreateReportOptionFlag {
using SubmitFsInfo = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>::Flag<0>; using SubmitFsInfo = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>::Flag<0>;
using Unknown0x20000 = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>::Flag<17>; /* TODO: What is this, it's checked in Reporter::CreateReport or below */
}; };
using CreateReportOptionFlagSet = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>; using CreateReportOptionFlagSet = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>;
@@ -243,4 +244,33 @@ namespace ams::erpt {
Map16 = 0xDE, Map16 = 0xDE,
}; };
constexpr inline u32 ErrorCodeSizeMax = 15;
constexpr inline u32 ProgramIdSizeMax = 17;
struct NotifiableErrorCodeReportEntry {
char error_code[ErrorCodeSizeMax];
char program_id[ProgramIdSizeMax];
u8 is_visible;
u8 is_system_abort;
u8 is_application_abort;
};
static_assert(sizeof(NotifiableErrorCodeReportEntry) == 35);
struct NotifiableErrorCodesData : public sf::LargeData, public sf::PrefersAutoSelectTransferMode {
u32 entry_count;
NotifiableErrorCodeReportEntry entries[50];
char firmware_display_version[0x18];
char private_os_version[96];
char product_model[16];
char region_code[34];
};
static_assert(sizeof(NotifiableErrorCodesData) == 0x784);
struct SystemInfo {
char os_version[0x18];
char private_os_version[96];
char product_model[16];
const char *region;
};
} }

View File

@@ -25,6 +25,7 @@
AMS_SF_METHOD_INFO(C, H, 4, Result, GetStorageUsageStatistics, (ams::sf::Out<erpt::StorageUsageStatistics> out), (out), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GetStorageUsageStatistics, (ams::sf::Out<erpt::StorageUsageStatistics> out), (out), hos::Version_5_0_0) \
AMS_SF_METHOD_INFO(C, H, 5, Result, GetAttachmentListDeprecated, (const ams::sf::OutBuffer &out_buf, const erpt::ReportId &report_id), (out_buf, report_id), hos::Version_8_0_0, hos::Version_19_0_1) \ AMS_SF_METHOD_INFO(C, H, 5, Result, GetAttachmentListDeprecated, (const ams::sf::OutBuffer &out_buf, const erpt::ReportId &report_id), (out_buf, report_id), hos::Version_8_0_0, hos::Version_19_0_1) \
AMS_SF_METHOD_INFO(C, H, 6, Result, GetAttachmentList, (ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buf, const erpt::ReportId &report_id), (out_count, out_buf, report_id), hos::Version_20_0_0) \ AMS_SF_METHOD_INFO(C, H, 6, Result, GetAttachmentList, (ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buf, const erpt::ReportId &report_id), (out_count, out_buf, report_id), hos::Version_20_0_0) \
AMS_SF_METHOD_INFO(C, H, 7, Result, PopNotifiableErrorCodes, (ams::sf::Out<erpt::NotifiableErrorCodesData> out), (out), hos::Version_22_0_0) \
AMS_SF_METHOD_INFO(C, H, 10, Result, GetReportSizeMax, (ams::sf::Out<u32> out), (out), hos::Version_20_0_0) AMS_SF_METHOD_INFO(C, H, 10, Result, GetReportSizeMax, (ams::sf::Out<u32> out), (out), hos::Version_20_0_0)

View File

@@ -21,7 +21,9 @@ namespace ams::erpt::srv {
Result Initialize(u8 *mem, size_t mem_size); Result Initialize(u8 *mem, size_t mem_size);
Result InitializeAndStartService(); Result InitializeAndStartService();
Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len); const SystemInfo &GetSystemInfo();
Result SetSerialNumber(const char *sn, u32 sn_len);
Result SetProductModel(const char *model, u32 model_len); Result SetProductModel(const char *model, u32 model_len);
Result SetRegionSetting(const char *region, u32 region_len); Result SetRegionSetting(const char *region, u32 region_len);

View File

@@ -52,7 +52,8 @@ namespace ams::fs {
struct GameCardErrorReportInfo { struct GameCardErrorReportInfo {
u16 game_card_crc_error_num; u16 game_card_crc_error_num;
u16 reserved1; u8 last_deactivate_reason;
u8 reserved1;
u16 asic_crc_error_num; u16 asic_crc_error_num;
u16 reserved2; u16 reserved2;
u16 refresh_num; u16 refresh_num;
@@ -73,7 +74,8 @@ namespace ams::fs {
u32 awaken_count; u32 awaken_count;
u32 read_count_from_insert; u32 read_count_from_insert;
u32 read_count_from_awaken; u32 read_count_from_awaken;
u8 reserved5[8]; u32 last_deactivate_reason_result;
u32 reserved5;
}; };
static_assert(util::is_pod<GameCardErrorReportInfo>::value); static_assert(util::is_pod<GameCardErrorReportInfo>::value);
static_assert(sizeof(GameCardErrorReportInfo) == 0x40); static_assert(sizeof(GameCardErrorReportInfo) == 0x40);

View File

@@ -132,7 +132,7 @@
AMS_SF_METHOD_INFO(C, H, 1000, Result, SetBisRootForHost, (u32 id, const fssrv::sf::FspPath &path), (id, path), hos::Version_Min, hos::Version_9_2_0) \ AMS_SF_METHOD_INFO(C, H, 1000, Result, SetBisRootForHost, (u32 id, const fssrv::sf::FspPath &path), (id, path), hos::Version_Min, hos::Version_9_2_0) \
AMS_SF_METHOD_INFO(C, H, 1001, Result, SetSaveDataSize, (s64 size, s64 journal_size), (size, journal_size)) \ AMS_SF_METHOD_INFO(C, H, 1001, Result, SetSaveDataSize, (s64 size, s64 journal_size), (size, journal_size)) \
AMS_SF_METHOD_INFO(C, H, 1002, Result, SetSaveDataRootPath, (const fssrv::sf::FspPath &path), (path)) \ AMS_SF_METHOD_INFO(C, H, 1002, Result, SetSaveDataRootPath, (const fssrv::sf::FspPath &path), (path)) \
AMS_SF_METHOD_INFO(C, H, 1003, Result, DisableAutoSaveDataCreation, (), ()) \ AMS_SF_METHOD_INFO(C, H, 1003, Result, DisableAutoSaveDataCreation, (), (), hos::Version_Min, hos::Version_21_2_0) \
AMS_SF_METHOD_INFO(C, H, 1004, Result, SetGlobalAccessLogMode, (u32 mode), (mode)) \ AMS_SF_METHOD_INFO(C, H, 1004, Result, SetGlobalAccessLogMode, (u32 mode), (mode)) \
AMS_SF_METHOD_INFO(C, H, 1005, Result, GetGlobalAccessLogMode, (ams::sf::Out<u32> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 1005, Result, GetGlobalAccessLogMode, (ams::sf::Out<u32> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 1006, Result, OutputAccessLogToSdCard, (const ams::sf::InBuffer &buf), (buf)) \ AMS_SF_METHOD_INFO(C, H, 1006, Result, OutputAccessLogToSdCard, (const ams::sf::InBuffer &buf), (buf)) \

View File

@@ -99,6 +99,9 @@ namespace ams::hos {
Version_21_0_0 = ::ams::TargetFirmware_21_0_0, Version_21_0_0 = ::ams::TargetFirmware_21_0_0,
Version_21_0_1 = ::ams::TargetFirmware_21_0_1, Version_21_0_1 = ::ams::TargetFirmware_21_0_1,
Version_21_1_0 = ::ams::TargetFirmware_21_1_0, Version_21_1_0 = ::ams::TargetFirmware_21_1_0,
Version_21_2_0 = ::ams::TargetFirmware_21_2_0,
Version_22_0_0 = ::ams::TargetFirmware_22_0_0,
Version_22_1_0 = ::ams::TargetFirmware_22_1_0,
Version_Current = ::ams::TargetFirmware_Current, Version_Current = ::ams::TargetFirmware_Current,

View File

@@ -94,13 +94,14 @@ namespace ams::ldr {
}; };
enum Flag : u32 { enum Flag : u32 {
Flag_CompressedText = (1 << 0), Flag_CompressedText = (1 << 0),
Flag_CompressedRo = (1 << 1), Flag_CompressedRo = (1 << 1),
Flag_CompressedRw = (1 << 2), Flag_CompressedRw = (1 << 2),
Flag_CheckHashText = (1 << 3), Flag_CheckHashText = (1 << 3),
Flag_CheckHashRo = (1 << 4), Flag_CheckHashRo = (1 << 4),
Flag_CheckHashRw = (1 << 5), Flag_CheckHashRw = (1 << 5),
Flag_PreventCodeReads = (1 << 6), Flag_PreventCodeReads = (1 << 6),
Flag_UseZbicCompression = (1 << 7),
}; };
struct SegmentInfo { struct SegmentInfo {

View File

@@ -388,7 +388,7 @@
} }
ALWAYS_INLINE Result GetDebugEvent(::ams::svc::UserPointer< ::ams::svc::lp64::DebugEventInfo *> out_info, ::ams::svc::Handle debug_handle) { ALWAYS_INLINE Result GetDebugEvent(::ams::svc::UserPointer< ::ams::svc::lp64::DebugEventInfo *> out_info, ::ams::svc::Handle debug_handle) {
R_RETURN(::svcGetDebugEvent(out_info.GetPointerUnsafe(), debug_handle)); R_RETURN(::svcGetDebugEvent(reinterpret_cast<::DebugEventInfo *>(out_info.GetPointerUnsafe()), debug_handle));
} }
ALWAYS_INLINE Result ContinueDebugEvent(::ams::svc::Handle debug_handle, uint32_t flags, ::ams::svc::UserPointer<const uint64_t *> thread_ids, int32_t num_thread_ids) { ALWAYS_INLINE Result ContinueDebugEvent(::ams::svc::Handle debug_handle, uint32_t flags, ::ams::svc::UserPointer<const uint64_t *> thread_ids, int32_t num_thread_ids) {

View File

@@ -21,8 +21,11 @@ namespace ams::util {
/* Compression utilities. */ /* Compression utilities. */
int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size); int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size);
size_t CompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size);
/* Decompression utilities. */ /* Decompression utilities. */
int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size); int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size);
size_t DecompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size);
bool DecompressZstdForLoader(void* workspace, size_t workspace_size, void *dst, size_t dst_size, size_t expected_dec_size, const void *src, size_t src_size);
} }

View File

@@ -19,5 +19,6 @@
namespace ams::erpt::srv { namespace ams::erpt::srv {
Result SubmitFsInfo(); Result SubmitFsInfo();
void ClearFsInfo();
} }

View File

@@ -363,6 +363,8 @@ namespace ams::erpt::srv {
R_ABORT_UNLESS(record->Add(FieldId_GameCardReadCountFromAwaken, ei.read_count_from_awaken)); R_ABORT_UNLESS(record->Add(FieldId_GameCardReadCountFromAwaken, ei.read_count_from_awaken));
R_ABORT_UNLESS(record->Add(FieldId_GameCardLastReadErrorPageAddress, ei.last_read_error_page_address)); R_ABORT_UNLESS(record->Add(FieldId_GameCardLastReadErrorPageAddress, ei.last_read_error_page_address));
R_ABORT_UNLESS(record->Add(FieldId_GameCardLastReadErrorPageCount, ei.last_read_error_page_count)); R_ABORT_UNLESS(record->Add(FieldId_GameCardLastReadErrorPageCount, ei.last_read_error_page_count));
R_ABORT_UNLESS(record->Add(FieldId_GameCardLastDeactivateReasonResult, ei.last_deactivate_reason_result));
R_ABORT_UNLESS(record->Add(FieldId_GameCardLastDeactivateReason, ei.last_deactivate_reason));
/* Submit the record. */ /* Submit the record. */
R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record)));
@@ -496,4 +498,27 @@ namespace ams::erpt::srv {
R_SUCCEED(); R_SUCCEED();
} }
void ClearFsInfo() {
Context::ClearContext(CategoryId_NANDTypeInfo);
Context::ClearContext(CategoryId_NANDSpeedModeInfo);
Context::ClearContext(CategoryId_NANDExtendedCsd);
Context::ClearContext(CategoryId_NANDPatrolInfo);
Context::ClearContext(CategoryId_NANDErrorInfo);
Context::ClearContext(CategoryId_NANDDriverLog);
Context::ClearContext(CategoryId_MicroSDTypeInfo);
Context::ClearContext(CategoryId_MicroSDSpeedModeInfo);
Context::ClearContext(CategoryId_SdCardSizeSpec);
Context::ClearContext(CategoryId_SdCardActivationInfo);
Context::ClearContext(CategoryId_SdCardErrorInfo);
Context::ClearContext(CategoryId_SdCardDriverLog);
Context::ClearContext(CategoryId_GameCardCIDInfo);
Context::ClearContext(CategoryId_GameCardErrorInfo);
Context::ClearContext(CategoryId_GameCardDetailedErrorInfo);
Context::ClearContext(CategoryId_GameCardLogInfo);
Context::ClearContext(CategoryId_FsProxyErrorInfo);
Context::ClearContext(CategoryId_FsProxyErrorInfo2);
Context::ClearContext(CategoryId_FsProxyErrorInfo3);
Context::ClearContext(CategoryId_FsMemoryInfo);
}
} }

View File

@@ -84,7 +84,7 @@ namespace ams::erpt::srv {
Result JournalForAttachments::GetAttachmentList(u32 *out_count, AttachmentInfo *out_infos, size_t max_out_infos, ReportId report_id) { Result JournalForAttachments::GetAttachmentList(u32 *out_count, AttachmentInfo *out_infos, size_t max_out_infos, ReportId report_id) {
if (hos::GetVersion() >= hos::Version_20_0_0) { if (hos::GetVersion() >= hos::Version_20_0_0) {
/* TODO: What define gives a minimum of 10? */ /* TODO: What define gives a minimum of 10? */
R_UNLESS(max_out_infos >= 10, erpt::ResultInvalidArgument()); R_UNLESS(max_out_infos >= 10, erpt::ResultTooManyOutAttachments());
} }
u32 count = 0; u32 count = 0;

View File

@@ -21,6 +21,7 @@
#include "erpt_srv_journal.hpp" #include "erpt_srv_journal.hpp"
#include "erpt_srv_service.hpp" #include "erpt_srv_service.hpp"
#include "erpt_srv_forced_shutdown.hpp" #include "erpt_srv_forced_shutdown.hpp"
#include "erpt_srv_notifiable_errors.hpp"
namespace ams::erpt::srv { namespace ams::erpt::srv {
@@ -33,6 +34,7 @@ namespace ams::erpt::srv {
constexpr u32 SystemSaveDataFlags = fs::SaveDataFlags_KeepAfterResettingSystemSaveDataWithoutUserSaveData; constexpr u32 SystemSaveDataFlags = fs::SaveDataFlags_KeepAfterResettingSystemSaveDataWithoutUserSaveData;
constexpr s64 SystemSaveDataSize = 11_MB; constexpr s64 SystemSaveDataSize = 11_MB;
constexpr s64 SystemSaveDataJournalSize = 2720_KB; constexpr s64 SystemSaveDataJournalSize = 2720_KB;
constexpr u32 DefaultThrottleTimeWindowSeconds = 3;
constinit bool g_automatic_report_cleanup_enabled = true; constinit bool g_automatic_report_cleanup_enabled = true;
@@ -53,7 +55,9 @@ namespace ams::erpt::srv {
} }
Result MountSystemSaveData() { Result MountSystemSaveData() {
fs::DisableAutoSaveDataCreation(); if (hos::GetVersion() < hos::Version_21_0_0) {
fs::DisableAutoSaveDataCreation();
}
/* Extend the system save data. */ /* Extend the system save data. */
/* NOTE: Nintendo used to not check the result of this; they do now, but . */ /* NOTE: Nintendo used to not check the result of this; they do now, but . */
@@ -71,6 +75,72 @@ namespace ams::erpt::srv {
} }
namespace {
int MakeProductModelString(char *dst, size_t dst_size, settings::system::ProductModel model) {
switch (model) {
case settings::system::ProductModel_Invalid: return util::Strlcpy(dst, "Invalid", static_cast<int>(dst_size));
case settings::system::ProductModel_Nx: return util::Strlcpy(dst, "NX", static_cast<int>(dst_size));
default: return util::SNPrintf(dst, dst_size, "%d", static_cast<int>(model));
}
}
const char *GetRegionString(settings::system::RegionCode code) {
switch (code) {
case settings::system::RegionCode_Japan: return "Japan";
case settings::system::RegionCode_Usa: return "Usa";
case settings::system::RegionCode_Europe: return "Europe";
case settings::system::RegionCode_Australia: return "Australia";
case settings::system::RegionCode_HongKongTaiwanKorea: return "HongKongTaiwanKorea";
case settings::system::RegionCode_China: return "China";
default: return "RegionUnknown";
}
}
}
const erpt::SystemInfo &GetSystemInfo() {
static const erpt::SystemInfo s_info = [] {
erpt::SystemInfo info = {};
settings::system::FirmwareVersion firmware_version = {};
settings::system::GetFirmwareVersion(std::addressof(firmware_version));
util::Strlcpy(info.os_version, firmware_version.display_version, sizeof(info.os_version));
const auto os_priv_len = util::SNPrintf(info.private_os_version, sizeof(info.private_os_version), "%s (%.8s)", firmware_version.display_name, firmware_version.revision);
AMS_ASSERT(static_cast<size_t>(os_priv_len) < sizeof(info.private_os_version));
AMS_UNUSED(os_priv_len);
const auto pm_len = MakeProductModelString(info.product_model, sizeof(info.product_model), settings::system::GetProductModel());
AMS_ASSERT(static_cast<size_t>(pm_len) < sizeof(info.product_model));
AMS_UNUSED(pm_len);
settings::system::RegionCode region_code;
settings::system::GetRegionCode(std::addressof(region_code));
info.region = GetRegionString(region_code);
return info;
}();
return s_info;
}
u32 GetThrottleTimeWindowSecondsImpl() {
u32 seconds = DefaultThrottleTimeWindowSeconds;
if (settings::fwdbg::GetSettingsItemValue(std::addressof(seconds), sizeof(seconds), "erpt", "throttle_time_window_seconds") != sizeof(seconds)) {
return DefaultThrottleTimeWindowSeconds;
}
return seconds;
}
void SetReportThrottleTimeSpan() {
u32 seconds = GetThrottleTimeWindowSecondsImpl();
const TimeSpan time_span = TimeSpan::FromSeconds(static_cast<s64>(seconds));
Reporter::SetThrottleTimeSpan(time_span);
}
Result Initialize(u8 *mem, size_t mem_size) { Result Initialize(u8 *mem, size_t mem_size) {
R_ABORT_UNLESS(time::Initialize()); R_ABORT_UNLESS(time::Initialize());
@@ -101,6 +171,10 @@ namespace ams::erpt::srv {
} }
} }
if (hos::GetVersion() >= hos::Version_22_0_0) {
SetReportThrottleTimeSpan();
}
R_ABORT_UNLESS(MountSystemSaveData()); R_ABORT_UNLESS(MountSystemSaveData());
g_sf_allocator.Attach(g_heap_handle); g_sf_allocator.Attach(g_heap_handle);
@@ -110,8 +184,18 @@ namespace ams::erpt::srv {
AMS_ABORT_UNLESS(ctx != nullptr); AMS_ABORT_UNLESS(ctx != nullptr);
} }
if (R_FAILED(Journal::Restore())) { if (hos::GetVersion() >= hos::Version_21_0_0) {
/* TODO: Nintendo deletes system savedata when this fails. Should we?. */ /* >= 21.0.0, Nintendo checks the result of restore and deletes the save data if it fails. */
if (R_FAILED(Journal::Restore())) {
/* Delete and recreate the system save data. */
fs::Unmount(ReportStoragePath);
R_ABORT_UNLESS(fs::DeleteSystemSaveData(fs::SaveDataSpaceId::System, SystemSaveDataId, fs::InvalidUserId));
R_ABORT_UNLESS(MountSystemSaveData());
}
} else{
/* Pre 21.0.0, Nintendo just calls restore and ignores the result. */
Journal::Restore();
} }
Reporter::UpdatePowerOnTime(); Reporter::UpdatePowerOnTime();
@@ -128,8 +212,8 @@ namespace ams::erpt::srv {
R_RETURN(InitializeService()); R_RETURN(InitializeService());
} }
Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len) { Result SetSerialNumber(const char *sn, u32 sn_len) {
R_RETURN(Reporter::SetSerialNumberAndOsVersion(sn, sn_len, os, os_len, os_priv, os_priv_len)); R_RETURN(Reporter::SetSerialNumber(sn, sn_len));
} }
Result SetProductModel(const char *model, u32 model_len) { Result SetProductModel(const char *model, u32 model_len) {

View File

@@ -16,6 +16,7 @@
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "erpt_srv_manager_impl.hpp" #include "erpt_srv_manager_impl.hpp"
#include "erpt_srv_journal.hpp" #include "erpt_srv_journal.hpp"
#include "erpt_srv_notifiable_errors.hpp"
namespace ams::erpt::srv { namespace ams::erpt::srv {
@@ -59,6 +60,7 @@ namespace ams::erpt::srv {
Result ManagerImpl::CleanupReports() { Result ManagerImpl::CleanupReports() {
Journal::CleanupReports(); Journal::CleanupReports();
Journal::CleanupAttachments(); Journal::CleanupAttachments();
NotifiableErrorCodeReport::Clear();
R_RETURN(Journal::Commit()); R_RETURN(Journal::Commit());
} }
@@ -104,4 +106,10 @@ namespace ams::erpt::srv {
R_SUCCEED(); R_SUCCEED();
} }
Result ManagerImpl::PopNotifiableErrorCodes(ams::sf::Out<NotifiableErrorCodesData> out) {
NotifiableErrorCodeReport::PopNotifiableErrorCodes(out.GetPointer());
R_SUCCEED();
}
} }

View File

@@ -36,6 +36,7 @@ namespace ams::erpt::srv {
Result GetStorageUsageStatistics(ams::sf::Out<StorageUsageStatistics> out); Result GetStorageUsageStatistics(ams::sf::Out<StorageUsageStatistics> out);
Result GetAttachmentListDeprecated(const ams::sf::OutBuffer &out_buf, const ReportId &report_id); Result GetAttachmentListDeprecated(const ams::sf::OutBuffer &out_buf, const ReportId &report_id);
Result GetAttachmentList(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buf, const ReportId &report_id); Result GetAttachmentList(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buf, const ReportId &report_id);
Result PopNotifiableErrorCodes(ams::sf::Out<NotifiableErrorCodesData> out);
Result GetReportSizeMax(ams::sf::Out<u32> out); Result GetReportSizeMax(ams::sf::Out<u32> out);
}; };
static_assert(erpt::sf::IsIManager<ManagerImpl>); static_assert(erpt::sf::IsIManager<ManagerImpl>);

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "erpt_srv_notifiable_errors.hpp"
namespace ams::erpt::srv {
namespace {
constexpr size_t MaxEntriesPerType = 25;
struct NotifiableErrorCodeReportState {
u32 report_counts[ReportType_Count];
NotifiableErrorCodeReportEntry report_entries[ReportType_Count][MaxEntriesPerType];
os::Tick last_tick;
u32 consecutive_count;
};
constinit NotifiableErrorCodeReportState g_state = {
.report_counts = {},
.report_entries = {},
.last_tick = os::Tick{},
.consecutive_count = 0,
};
}
void NotifiableErrorCodeReport::PushEntry(const char *error_code, const char *program_id, ReportType type, bool is_system_abort, bool is_application_abort) {
u32 &count = g_state.report_counts[type];
NotifiableErrorCodeReportEntry *entries = g_state.report_entries[type];
/* If we're full, shift the oldest entry out. */
if (count >= MaxEntriesPerType) {
std::memmove(entries, entries + 1, sizeof(NotifiableErrorCodeReportEntry) * (MaxEntriesPerType - 1));
count = MaxEntriesPerType - 1;
}
/* Fill the new entry. */
NotifiableErrorCodeReportEntry &entry = entries[count];
util::Strlcpy(entry.error_code, error_code, sizeof(entry.error_code));
util::Strlcpy(entry.program_id, program_id, sizeof(entry.program_id));
entry.is_visible = (type == ReportType_Visible);
entry.is_system_abort = is_system_abort;
entry.is_application_abort = is_application_abort;
count++;
}
void NotifiableErrorCodeReport::PopNotifiableErrorCodes(NotifiableErrorCodesData *out) {
/* Fill basic info from lazily-initialized system info. */
const auto &sys_info = srv::GetSystemInfo();
util::Strlcpy(out->firmware_display_version, sys_info.os_version, sizeof(out->firmware_display_version));
util::Strlcpy(out->private_os_version, sys_info.private_os_version, sizeof(out->private_os_version));
util::Strlcpy(out->product_model, sys_info.product_model, sizeof(out->product_model));
util::Strlcpy(out->region_code, sys_info.region, sizeof(out->region_code));
u32 total_count = 0;
/* Copy entries. */
for (u32 i = 0; i < ReportType_Count; i++) {
if (g_state.report_counts[i] == 0) {
continue;
}
std::memcpy(out->entries + total_count, g_state.report_entries[i], sizeof(NotifiableErrorCodeReportEntry) * g_state.report_counts[i]);
total_count += g_state.report_counts[i];
/* Reset count (destructive read). */
g_state.report_counts[i] = 0;
}
out->entry_count = total_count;
}
void NotifiableErrorCodeReport::Clear() {
for (u32 i = 0; i < ReportType_Count; i++) {
g_state.report_counts[i] = 0;
}
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::erpt::srv {
class NotifiableErrorCodeReport {
public:
static void PushEntry(const char *error_code, const char *program_id, ReportType type, bool is_system_abort, bool is_application_abort);
static void PopNotifiableErrorCodes(NotifiableErrorCodesData *out);
static void Clear();
};
}

View File

@@ -20,13 +20,12 @@
#include "erpt_srv_context_record.hpp" #include "erpt_srv_context_record.hpp"
#include "erpt_srv_context.hpp" #include "erpt_srv_context.hpp"
#include "erpt_srv_fs_info.hpp" #include "erpt_srv_fs_info.hpp"
#include "erpt_srv_notifiable_errors.hpp"
namespace ams::erpt::srv { namespace ams::erpt::srv {
constinit bool Reporter::s_redirect_new_reports = true; constinit bool Reporter::s_redirect_new_reports = true;
constinit char Reporter::s_serial_number[24] = "Unknown"; constinit char Reporter::s_serial_number[24] = "Unknown";
constinit char Reporter::s_os_version[24] = "Unknown";
constinit char Reporter::s_private_os_version[96] = "Unknown";
constinit util::optional<os::Tick> Reporter::s_application_launch_time; constinit util::optional<os::Tick> Reporter::s_application_launch_time;
constinit util::optional<os::Tick> Reporter::s_awake_time; constinit util::optional<os::Tick> Reporter::s_awake_time;
constinit util::optional<os::Tick> Reporter::s_power_on_time; constinit util::optional<os::Tick> Reporter::s_power_on_time;
@@ -212,18 +211,83 @@ namespace ams::erpt::srv {
} }
#endif #endif
Result ValidateCreateReportContext(const ContextEntry *ctx) { Result ValidateAndGetErrorCode(const ContextEntry *ctx, char *out_error_code) {
R_UNLESS(ctx->category == CategoryId_ErrorInfo, erpt::ResultRequiredContextMissing()); R_UNLESS(ctx->category == CategoryId_ErrorInfo, erpt::ResultRequiredContextMissing());
R_UNLESS(ctx->field_count <= FieldsPerContext, erpt::ResultInvalidArgument()); R_UNLESS(ctx->field_count <= FieldsPerContext, erpt::ResultInvalidArgument());
const bool found_error_code = util::range::any_of(MakeSpan(ctx->fields, ctx->field_count), [] (const FieldEntry &entry) { const auto fields_span = MakeSpan(ctx->fields, ctx->field_count);
return entry.id == FieldId_ErrorCode; const u8 *array_data = static_cast<const u8 *>(ctx->array_buffer);
});
R_UNLESS(found_error_code, erpt::ResultRequiredFieldMissing()); const FieldEntry *error_code_field = nullptr;
for (const auto &field : fields_span) {
if (field.id != FieldId_ErrorCode){
continue;
}
error_code_field = &field;
break;
}
R_UNLESS(error_code_field != nullptr, erpt::ResultRequiredFieldMissing());
R_UNLESS(error_code_field->type == FieldType_String, erpt::ResultFieldTypeMismatch());
R_UNLESS(error_code_field->value_array.size <= ErrorCodeSizeMax, erpt::ResultArrayFieldTooLarge());
const char *error_code = reinterpret_cast<const char *>(array_data + error_code_field->value_array.start_idx);
util::Strlcpy(out_error_code, error_code, ErrorCodeSizeMax);
R_SUCCEED(); R_SUCCEED();
} }
namespace {
struct ThrottleState {
TimeSpan throttle_time_span;
char last_error_code[ErrorCodeSizeMax];
u32 consecutive_count;
os::Tick last_tick;
};
constinit ThrottleState g_throttle_state = {
.throttle_time_span = TimeSpan{},
.last_error_code = {},
.consecutive_count = 0,
.last_tick = os::Tick{},
};
};
bool IsThrottledReport(const ContextEntry *ctx, ReportType type, const char *error_code) {
if (hos::GetVersion() < hos::Version_22_0_0) {
return false;
}
const auto fields_span = MakeSpan(ctx->fields, ctx->field_count);
bool is_crash_report = false;
for (const auto &field : fields_span) {
if (field.id != FieldId_CrashReportFlag){
continue;
}
is_crash_report = field.value_bool;
break;
}
if(type == ReportType_Visible || is_crash_report){
return false;
}
const auto now = os::GetSystemTick();
const TimeSpan elapsed = (now - g_throttle_state.last_tick).ToTimeSpan();
if (std::strcmp(g_throttle_state.last_error_code, error_code) == 0 && elapsed < g_throttle_state.throttle_time_span) {
if (g_throttle_state.consecutive_count >= 5) {
return true;
}
g_throttle_state.consecutive_count++;
} else {
util::Strlcpy(g_throttle_state.last_error_code, error_code, sizeof(g_throttle_state.last_error_code));
g_throttle_state.last_tick = now;
g_throttle_state.consecutive_count = 1;
}
return false;
}
Result SubmitReportDefaults(const ContextEntry *ctx) { Result SubmitReportDefaults(const ContextEntry *ctx) {
AMS_ASSERT(ctx->category == CategoryId_ErrorInfo); AMS_ASSERT(ctx->category == CategoryId_ErrorInfo);
@@ -359,7 +423,11 @@ namespace ams::erpt::srv {
auto report = std::make_unique<Report>(record.get(), redirect_new_reports); auto report = std::make_unique<Report>(record.get(), redirect_new_reports);
R_UNLESS(report != nullptr, erpt::ResultOutOfMemory()); R_UNLESS(report != nullptr, erpt::ResultOutOfMemory());
auto report_guard = SCOPE_GUARD { const auto delete_res = report->Delete(); R_ASSERT(delete_res); AMS_UNUSED(delete_res); }; auto report_guard = SCOPE_GUARD {
const auto delete_res = report->Delete();
R_ASSERT(delete_res);
AMS_UNUSED(delete_res);
};
R_TRY(Context::WriteContextsToReport(report.get())); R_TRY(Context::WriteContextsToReport(report.get()));
R_TRY(report->GetSize(std::addressof(record->m_info.report_size))); R_TRY(report->GetSize(std::addressof(record->m_info.report_size)));
@@ -370,7 +438,7 @@ namespace ams::erpt::srv {
} else { } else {
/* If we are redirecting new reports, we don't want to store the report in the journal. */ /* If we are redirecting new reports, we don't want to store the report in the journal. */
/* We should take this opportunity to delete any attachments associated with the report. */ /* We should take this opportunity to delete any attachments associated with the report. */
R_ABORT_UNLESS(JournalForAttachments::DeleteAttachments(report_id)); R_TRY(JournalForAttachments::DeleteAttachments(report_id));
} }
R_TRY(Journal::Commit()); R_TRY(Journal::Commit());
@@ -381,6 +449,9 @@ namespace ams::erpt::srv {
} }
void Reporter::SetThrottleTimeSpan(TimeSpan time_span) {
g_throttle_state.throttle_time_span = time_span;
}
Result Reporter::RegisterRunningApplet(ncm::ProgramId program_id) { Result Reporter::RegisterRunningApplet(ncm::ProgramId program_id) {
g_applet_active_time_info_list.Register(program_id); g_applet_active_time_info_list.Register(program_id);
R_SUCCEED(); R_SUCCEED();
@@ -422,17 +493,70 @@ namespace ams::erpt::srv {
static_cast<void>(Context::ClearContext(CategoryId_ErrorInfo)); static_cast<void>(Context::ClearContext(CategoryId_ErrorInfo));
static_cast<void>(Context::ClearContext(CategoryId_ErrorInfoAuto)); static_cast<void>(Context::ClearContext(CategoryId_ErrorInfoAuto));
static_cast<void>(Context::ClearContext(CategoryId_ErrorInfoDefaults)); static_cast<void>(Context::ClearContext(CategoryId_ErrorInfoDefaults));
#if defined(ATMOSPHERE_OS_HORIZON)
/* TODO: What else is missing? */
if (hos::GetVersion() >= hos::Version_17_0_0 && flags.Test<CreateReportOptionFlag::SubmitFsInfo>()) {
ClearFsInfo();
}
/* if (erpt::ResultInvalidPowerState::Includes(...)) {
* Nintendo ignores this and sends "power_state_violation" play report if this error happens.
* } else {
* Nintendo sends "write_failure" play report if any other error happens.
* }
*/
#endif
}; };
/* Get the context entry pointer. */ /* Get the context entry pointer. */
const ContextEntry *ctx = record->GetContextEntryPtr(); const ContextEntry *ctx = record->GetContextEntryPtr();
/* Validate the context. */ /* Validate the context and retrieve the error code. */
R_TRY(ValidateCreateReportContext(ctx)); char error_code[ErrorCodeSizeMax];
R_TRY(ValidateAndGetErrorCode(ctx, error_code));
if (hos::GetVersion() >= hos::Version_22_0_0) {
/* Check if we should throttle the report. */
if (IsThrottledReport(ctx, type, error_code)) {
R_SUCCEED();
}
}
/* Submit report defaults. */ /* Submit report defaults. */
R_TRY(SubmitReportDefaults(ctx)); R_TRY(SubmitReportDefaults(ctx));
/* Push to recent reports. */
if (hos::GetVersion() >= hos::Version_22_0_0) {
const auto fields_span = MakeSpan(ctx->fields, ctx->field_count);
const u8 *array_data = static_cast<const u8 *>(ctx->array_buffer);
char program_id[ProgramIdSizeMax] = {};
bool is_system_abort = false;
bool is_application_abort = false;
for (const auto &field : fields_span) {
switch (field.id) {
case FieldId_ProgramId:
if(field.type != FieldType_String){
break;
}
util::Strlcpy(program_id, reinterpret_cast<const char *>(array_data + field.value_array.start_idx), sizeof(program_id));
break;
case FieldId_SystemAbortFlag:
is_system_abort = field.value_bool;
break;
case FieldId_ApplicationAbortFlag:
is_application_abort = field.value_bool;
break;
default:
break;
}
}
NotifiableErrorCodeReport::PushEntry(error_code, program_id, type, is_system_abort, is_application_abort);
}
/* Generate report id. */ /* Generate report id. */
const ReportId report_id = specified_report_id ? *specified_report_id : ReportId{ .uuid = util::GenerateUuid() }; const ReportId report_id = specified_report_id ? *specified_report_id : ReportId{ .uuid = util::GenerateUuid() };
@@ -480,8 +604,9 @@ namespace ams::erpt::srv {
R_ABORT_UNLESS(time::GetStandardSteadyClockCurrentTimePoint(std::addressof(steady_clock_current_timepoint))); R_ABORT_UNLESS(time::GetStandardSteadyClockCurrentTimePoint(std::addressof(steady_clock_current_timepoint)));
/* Add automatic fields. */ /* Add automatic fields. */
static_cast<void>(auto_record->Add(FieldId_OsVersion, s_os_version, util::Strnlen(s_os_version, sizeof(s_os_version)))); const auto &sys_info = srv::GetSystemInfo();
static_cast<void>(auto_record->Add(FieldId_PrivateOsVersion, s_private_os_version, util::Strnlen(s_private_os_version, sizeof(s_private_os_version)))); static_cast<void>(auto_record->Add(FieldId_OsVersion, sys_info.os_version, util::Strnlen(sys_info.os_version, sizeof(sys_info.os_version))));
static_cast<void>(auto_record->Add(FieldId_PrivateOsVersion, sys_info.private_os_version, util::Strnlen(sys_info.private_os_version, sizeof(sys_info.private_os_version))));
static_cast<void>(auto_record->Add(FieldId_SerialNumber, s_serial_number, util::Strnlen(s_serial_number, sizeof(s_serial_number)))); static_cast<void>(auto_record->Add(FieldId_SerialNumber, s_serial_number, util::Strnlen(s_serial_number, sizeof(s_serial_number))));
static_cast<void>(auto_record->Add(FieldId_ReportIdentifier, identifier_str, util::Strnlen(identifier_str, sizeof(identifier_str)))); static_cast<void>(auto_record->Add(FieldId_ReportIdentifier, identifier_str, util::Strnlen(identifier_str, sizeof(identifier_str))));
static_cast<void>(auto_record->Add(FieldId_OccurrenceTimestamp, timestamp_user.value)); static_cast<void>(auto_record->Add(FieldId_OccurrenceTimestamp, timestamp_user.value));

View File

@@ -23,8 +23,6 @@ namespace ams::erpt::srv {
private: private:
static bool s_redirect_new_reports; static bool s_redirect_new_reports;
static char s_serial_number[24]; static char s_serial_number[24];
static char s_os_version[24];
static char s_private_os_version[96];
static util::optional<os::Tick> s_application_launch_time; static util::optional<os::Tick> s_application_launch_time;
static util::optional<os::Tick> s_awake_time; static util::optional<os::Tick> s_awake_time;
static util::optional<os::Tick> s_power_on_time; static util::optional<os::Tick> s_power_on_time;
@@ -39,14 +37,11 @@ namespace ams::erpt::srv {
static void UpdateAwakeTime() { s_awake_time = os::GetSystemTick(); } static void UpdateAwakeTime() { s_awake_time = os::GetSystemTick(); }
static void UpdatePowerOnTime() { s_power_on_time = os::GetSystemTick(); } static void UpdatePowerOnTime() { s_power_on_time = os::GetSystemTick(); }
static Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len) { static void SetThrottleTimeSpan(TimeSpan time_span);
R_UNLESS(sn_len <= sizeof(s_serial_number), erpt::ResultInvalidArgument());
R_UNLESS(os_len <= sizeof(s_os_version), erpt::ResultInvalidArgument());
R_UNLESS(os_priv_len <= sizeof(s_private_os_version), erpt::ResultInvalidArgument());
static Result SetSerialNumber(const char *sn, u32 sn_len) {
R_UNLESS(sn_len <= sizeof(s_serial_number), erpt::ResultInvalidArgument());
std::memcpy(s_serial_number, sn, sn_len); std::memcpy(s_serial_number, sn, sn_len);
std::memcpy(s_os_version, os, os_len);
std::memcpy(s_private_os_version, os_priv, os_priv_len);
R_SUCCEED(); R_SUCCEED();
} }

View File

@@ -42,6 +42,10 @@ namespace ams::fs {
} }
void DisableAutoSaveDataCreation() { void DisableAutoSaveDataCreation() {
if (hos::GetVersion() >= hos::Version_22_0_0) {
return;
}
auto fsp = impl::GetFileSystemProxyServiceObject(); auto fsp = impl::GetFileSystemProxyServiceObject();
AMS_FS_R_ABORT_UNLESS(fsp->DisableAutoSaveDataCreation()); AMS_FS_R_ABORT_UNLESS(fsp->DisableAutoSaveDataCreation());
} }

View File

@@ -21,7 +21,7 @@ namespace ams::fs::impl {
#define ADD_ENUM_CASE(v) case v: return #v #define ADD_ENUM_CASE(v) case v: return #v
template<> const char *IdString::ToString<pkg1::KeyGeneration>(pkg1::KeyGeneration id) { template<> const char *IdString::ToString<pkg1::KeyGeneration>(pkg1::KeyGeneration id) {
static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_21_0_0); static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_22_0_0);
switch (id) { switch (id) {
using enum pkg1::KeyGeneration; using enum pkg1::KeyGeneration;
case KeyGeneration_1_0_0: return "1.0.0-2.3.0"; case KeyGeneration_1_0_0: return "1.0.0-2.3.0";
@@ -44,7 +44,8 @@ namespace ams::fs::impl {
case KeyGeneration_18_0_0: return "18.0.0-18.1.0"; case KeyGeneration_18_0_0: return "18.0.0-18.1.0";
case KeyGeneration_19_0_0: return "19.0.0-19.0.1"; case KeyGeneration_19_0_0: return "19.0.0-19.0.1";
case KeyGeneration_20_0_0: return "20.0.0-20.5.0"; case KeyGeneration_20_0_0: return "20.0.0-20.5.0";
case KeyGeneration_21_0_0: return "21.0.0-"; case KeyGeneration_21_0_0: return "21.0.0-21.2.0";
case KeyGeneration_22_0_0: return "22.0.0";
default: return "Unknown"; default: return "Unknown";
} }
} }

View File

@@ -75,15 +75,15 @@ namespace ams::pgl::srv {
NON_COPYABLE(HostPackageReader); NON_COPYABLE(HostPackageReader);
NON_MOVEABLE(HostPackageReader); NON_MOVEABLE(HostPackageReader);
private: private:
char m_content_path[fs::EntryNameLengthMax] = {}; char m_content_path[fs::EntryNameLengthMax] = {};
ExtensionType m_extension_type = ExtensionType::None; ExtensionType m_extension_type = ExtensionType::None;
char m_mount_name[fs::MountNameLengthMax] = {}; char m_mount_name[fs::MountNameLengthMax + 1] = {};
bool m_is_mounted = false; bool m_is_mounted = false;
ncm::AutoBuffer m_content_meta_buffer; ncm::AutoBuffer m_content_meta_buffer;
ncm::ProgramId m_program_id = ncm::InvalidProgramId; ncm::ProgramId m_program_id = ncm::InvalidProgramId;
u32 m_program_version = 0; u32 m_program_version = 0;
ncm::ContentMetaType m_content_meta_type = static_cast<ncm::ContentMetaType>(0); ncm::ContentMetaType m_content_meta_type = static_cast<ncm::ContentMetaType>(0);
u8 m_program_index = 0; u8 m_program_index = 0;
public: public:
HostPackageReader() : m_content_meta_buffer() { /* ... */ } HostPackageReader() : m_content_meta_buffer() { /* ... */ }
~HostPackageReader() { ~HostPackageReader() {

View File

@@ -17,6 +17,7 @@
#include "pinmux_pad_index.hpp" #include "pinmux_pad_index.hpp"
#include "pinmux_board_driver_api.hpp" #include "pinmux_board_driver_api.hpp"
#include "pinmux_platform_pads.hpp" #include "pinmux_platform_pads.hpp"
#include "pinmux_build_config.hpp"
namespace ams::pinmux::driver::board::nintendo::nx { namespace ams::pinmux::driver::board::nintendo::nx {
@@ -99,6 +100,31 @@ namespace ams::pinmux::driver::board::nintendo::nx {
UpdateSinglePinmuxPad({ PinmuxPadIndex_Sdmmc2Dat6, 0x2000, 0x2000 }); UpdateSinglePinmuxPad({ PinmuxPadIndex_Sdmmc2Dat6, 0x2000, 0x2000 });
UpdateSinglePinmuxPad({ PinmuxPadIndex_Sdmmc2Dat7, 0x2000, 0x2000 }); UpdateSinglePinmuxPad({ PinmuxPadIndex_Sdmmc2Dat7, 0x2000, 0x2000 });
} }
#if defined(AMS_PINMUX_CONFIG_RIGHT_RAIL_AS_UART)
UpdateSinglePinmuxPad({
.index = PinmuxPadIndex_Uart2Tx,
.option = 0, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output */
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
});
UpdateSinglePinmuxPad({
.index = PinmuxPadIndex_Uart2Cts,
.option = 0x20, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input */
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
});
#endif
#if defined(AMS_PINMUX_CONFIG_LEFT_RAIL_AS_UART)
UpdateSinglePinmuxPad({
.index = PinmuxPadIndex_Uart3Tx,
.option = 0, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output */
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
});
UpdateSinglePinmuxPad({
.index = PinmuxPadIndex_Uart3Cts,
.option = 0x20, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input */
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
});
#endif
} }
void SetInitialDrivePadConfig() { void SetInitialDrivePadConfig() {

View File

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

View File

@@ -15,6 +15,9 @@
*/ */
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "lz4.h" #include "lz4.h"
#define ZSTD_STATIC_LINKING_ONLY
#define ZSTD_ZBIC_SUPPORT 1
#include "zstd.h"
namespace ams::util { namespace ams::util {
@@ -27,6 +30,23 @@ namespace ams::util {
/* This is just a thin wrapper around LZ4. */ /* This is just a thin wrapper around LZ4. */
return LZ4_compress_default(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dst), static_cast<int>(src_size), static_cast<int>(dst_size)); return LZ4_compress_default(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dst), static_cast<int>(src_size), static_cast<int>(dst_size));
} }
size_t CompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Basic size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
/* Additionally, we must check the compression boundary. */
auto bound = ZSTD_compressBound(src_size);
AMS_ABORT_UNLESS(!ZSTD_isError(bound));
AMS_ABORT_UNLESS(dst_size >= bound);
/* Use Zstd default level. */
int compressionLevel = 3;
/* This is just a wrapper around Zstd. */
return ZSTD_compress(dst, dst_size, src, src_size, compressionLevel);
}
/* Decompression utilities. */ /* Decompression utilities. */
int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) { int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
@@ -37,5 +57,54 @@ namespace ams::util {
/* This is just a thin wrapper around LZ4. */ /* This is just a thin wrapper around LZ4. */
return LZ4_decompress_safe(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dst), static_cast<int>(src_size), static_cast<int>(dst_size)); return LZ4_decompress_safe(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dst), static_cast<int>(src_size), static_cast<int>(dst_size));
} }
size_t DecompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Basic size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
/* Additionally, we must check the decompression boundary. */
auto bound = ZSTD_decompressBound(src, src_size);
AMS_ABORT_UNLESS(!ZSTD_isError(bound));
AMS_ABORT_UNLESS(dst_size >= bound);
/* This is just a wrapper around Zstd. */
return ZSTD_decompress(dst, dst_size, src, src_size);
}
bool DecompressZstdForLoader(void* workspace, size_t workspace_size, void *dst, size_t dst_size, size_t expected_dec_size, const void *src, size_t src_size) {
/* Check decompression margin. */
auto margin = ZSTD_decompressionMargin(src, src_size);
if (ZSTD_isError(margin)) {
return false;
}
/* Don't overflow from margin. */
if (!util::CanAddWithoutOverflow(margin, expected_dec_size)) {
return false;
}
/* Make sure we fit in the destination buffer. */
if (margin + expected_dec_size > dst_size) {
return false;
}
/* This is a runtime assert in Loader code. We replicate it here. */
AMS_ABORT_UNLESS(ZSTD_estimateDCtxSize() == workspace_size);
/* Decompress using a static decompression context. */
auto dctx = ZSTD_initStaticDCtx(workspace, workspace_size);
size_t dec_size = ZSTD_decompressDCtx(dctx, dst, dst_size, src, src_size);
if (ZSTD_isError(dec_size)) {
return false;
}
if (dec_size != expected_dec_size) {
return false;
}
return true;
}
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#ifndef ZSTD_ERRORS_H_398273423
#define ZSTD_ERRORS_H_398273423
#if defined (__cplusplus)
extern "C" {
#endif
/* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */
#ifndef ZSTDERRORLIB_VISIBLE
/* Backwards compatibility with old macro name */
# ifdef ZSTDERRORLIB_VISIBILITY
# define ZSTDERRORLIB_VISIBLE ZSTDERRORLIB_VISIBILITY
# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__)
# define ZSTDERRORLIB_VISIBLE __attribute__ ((visibility ("default")))
# else
# define ZSTDERRORLIB_VISIBLE
# endif
#endif
#ifndef ZSTDERRORLIB_HIDDEN
# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__)
# define ZSTDERRORLIB_HIDDEN __attribute__ ((visibility ("hidden")))
# else
# define ZSTDERRORLIB_HIDDEN
# endif
#endif
#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)
# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBLE
#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)
# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
#else
# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBLE
#endif
/*-*********************************************
* Error codes list
*-*********************************************
* Error codes _values_ are pinned down since v1.3.1 only.
* Therefore, don't rely on values if you may link to any version < v1.3.1.
*
* Only values < 100 are considered stable.
*
* note 1 : this API shall be used with static linking only.
* dynamic linking is not yet officially supported.
* note 2 : Prefer relying on the enum than on its value whenever possible
* This is the only supported way to use the error list < v1.3.1
* note 3 : ZSTD_isError() is always correct, whatever the library version.
**********************************************/
typedef enum {
ZSTD_error_no_error = 0,
ZSTD_error_GENERIC = 1,
ZSTD_error_prefix_unknown = 10,
ZSTD_error_version_unsupported = 12,
ZSTD_error_frameParameter_unsupported = 14,
ZSTD_error_frameParameter_windowTooLarge = 16,
ZSTD_error_corruption_detected = 20,
ZSTD_error_checksum_wrong = 22,
ZSTD_error_literals_headerWrong = 24,
ZSTD_error_dictionary_corrupted = 30,
ZSTD_error_dictionary_wrong = 32,
ZSTD_error_dictionaryCreation_failed = 34,
ZSTD_error_parameter_unsupported = 40,
ZSTD_error_parameter_combination_unsupported = 41,
ZSTD_error_parameter_outOfBound = 42,
ZSTD_error_tableLog_tooLarge = 44,
ZSTD_error_maxSymbolValue_tooLarge = 46,
ZSTD_error_maxSymbolValue_tooSmall = 48,
ZSTD_error_cannotProduce_uncompressedBlock = 49,
ZSTD_error_stabilityCondition_notRespected = 50,
ZSTD_error_stage_wrong = 60,
ZSTD_error_init_missing = 62,
ZSTD_error_memory_allocation = 64,
ZSTD_error_workSpace_tooSmall= 66,
ZSTD_error_dstSize_tooSmall = 70,
ZSTD_error_srcSize_wrong = 72,
ZSTD_error_dstBuffer_null = 74,
ZSTD_error_noForwardProgress_destFull = 80,
ZSTD_error_noForwardProgress_inputEmpty = 82,
/* following error codes are __NOT STABLE__, they can be removed or changed in future versions */
ZSTD_error_frameIndex_tooLarge = 100,
ZSTD_error_seekableIO = 102,
ZSTD_error_dstBuffer_wrong = 104,
ZSTD_error_srcBuffer_wrong = 105,
ZSTD_error_sequenceProducer_failed = 106,
ZSTD_error_externalSequences_invalid = 107,
ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
} ZSTD_ErrorCode;
ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */
#if defined (__cplusplus)
}
#endif
#endif /* ZSTD_ERRORS_H_398273423 */

View File

@@ -16,11 +16,11 @@
#pragma once #pragma once
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1 #define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
#define ATMOSPHERE_RELEASE_VERSION_MINOR 10 #define ATMOSPHERE_RELEASE_VERSION_MINOR 11
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1 #define ATMOSPHERE_RELEASE_VERSION_MICRO 1
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO #define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 21 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 22
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0

View File

@@ -97,8 +97,11 @@
#define ATMOSPHERE_TARGET_FIRMWARE_21_0_0 ATMOSPHERE_TARGET_FIRMWARE(21, 0, 0) #define ATMOSPHERE_TARGET_FIRMWARE_21_0_0 ATMOSPHERE_TARGET_FIRMWARE(21, 0, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_21_0_1 ATMOSPHERE_TARGET_FIRMWARE(21, 0, 1) #define ATMOSPHERE_TARGET_FIRMWARE_21_0_1 ATMOSPHERE_TARGET_FIRMWARE(21, 0, 1)
#define ATMOSPHERE_TARGET_FIRMWARE_21_1_0 ATMOSPHERE_TARGET_FIRMWARE(21, 1, 0) #define ATMOSPHERE_TARGET_FIRMWARE_21_1_0 ATMOSPHERE_TARGET_FIRMWARE(21, 1, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_21_2_0 ATMOSPHERE_TARGET_FIRMWARE(21, 2, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_22_0_0 ATMOSPHERE_TARGET_FIRMWARE(22, 0, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_22_1_0 ATMOSPHERE_TARGET_FIRMWARE(22, 1, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_21_1_0 #define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_22_1_0
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0) #define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT #define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
@@ -188,6 +191,9 @@ namespace ams {
TargetFirmware_21_0_0 = ATMOSPHERE_TARGET_FIRMWARE_21_0_0, TargetFirmware_21_0_0 = ATMOSPHERE_TARGET_FIRMWARE_21_0_0,
TargetFirmware_21_0_1 = ATMOSPHERE_TARGET_FIRMWARE_21_0_1, TargetFirmware_21_0_1 = ATMOSPHERE_TARGET_FIRMWARE_21_0_1,
TargetFirmware_21_1_0 = ATMOSPHERE_TARGET_FIRMWARE_21_1_0, TargetFirmware_21_1_0 = ATMOSPHERE_TARGET_FIRMWARE_21_1_0,
TargetFirmware_21_2_0 = ATMOSPHERE_TARGET_FIRMWARE_21_2_0,
TargetFirmware_22_0_0 = ATMOSPHERE_TARGET_FIRMWARE_22_0_0,
TargetFirmware_22_1_0 = ATMOSPHERE_TARGET_FIRMWARE_22_1_0,
TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT, TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT,

View File

@@ -40,5 +40,6 @@ namespace ams::erpt {
R_DEFINE_ERROR_RESULT(InvalidPowerState, 17); R_DEFINE_ERROR_RESULT(InvalidPowerState, 17);
R_DEFINE_ERROR_RESULT(ArrayFieldTooLarge, 18); R_DEFINE_ERROR_RESULT(ArrayFieldTooLarge, 18);
R_DEFINE_ERROR_RESULT(AlreadyOwned, 19); R_DEFINE_ERROR_RESULT(AlreadyOwned, 19);
R_DEFINE_ERROR_RESULT(TooManyOutAttachments, 51);
} }

View File

@@ -452,6 +452,9 @@ namespace ams::result::impl {
} \ } \
} }
/// Explicitly discards the result returned by an expression.
#define R_DISCARD(res_expr) (static_cast<void>(res_expr))
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_IS_STRATOSPHERE) && !defined(AMS_ENABLE_DETAILED_ASSERTIONS) && !defined(AMS_BUILD_FOR_DEBUGGING) && !defined(AMS_BUILD_FOR_AUDITING) #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_IS_STRATOSPHERE) && !defined(AMS_ENABLE_DETAILED_ASSERTIONS) && !defined(AMS_BUILD_FOR_DEBUGGING) && !defined(AMS_BUILD_FOR_AUDITING)
#define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false) #define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false)
#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false) #define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false)

View File

@@ -27,8 +27,9 @@ namespace ams::svc::arch::arm {
volatile u16 interrupt_flag; volatile u16 interrupt_flag;
volatile u8 cache_maintenance_flag; volatile u8 cache_maintenance_flag;
volatile s64 thread_cpu_time; volatile s64 thread_cpu_time;
volatile ams::svc::Handle thread_handle;
/* TODO: Should we bother adding the Nintendo aarch32 thread local context here? */ /* TODO: Should we bother adding the Nintendo aarch32 thread local context here? */
uintptr_t TODO[(0x200 - 0x110) / sizeof(uintptr_t)]; uintptr_t TODO[(0x200 - 0x114) / sizeof(uintptr_t)];
}; };
ALWAYS_INLINE ThreadLocalRegion *GetThreadLocalRegion() { ALWAYS_INLINE ThreadLocalRegion *GetThreadLocalRegion() {

View File

@@ -27,8 +27,9 @@ namespace ams::svc::arch::arm64 {
volatile u16 interrupt_flag; volatile u16 interrupt_flag;
volatile u8 cache_maintenance_flag; volatile u8 cache_maintenance_flag;
volatile s64 thread_cpu_time; volatile s64 thread_cpu_time;
volatile ams::svc::Handle thread_handle;
/* TODO: How should we handle libnx vs Nintendo user thread local space? */ /* TODO: How should we handle libnx vs Nintendo user thread local space? */
uintptr_t TODO[(0x200 - 0x110) / sizeof(uintptr_t)]; uintptr_t TODO[(0x200 - 0x114) / sizeof(uintptr_t)];
}; };
static_assert(__builtin_offsetof(ThreadLocalRegion, disable_count) == 0x100); static_assert(__builtin_offsetof(ThreadLocalRegion, disable_count) == 0x100);
static_assert(__builtin_offsetof(ThreadLocalRegion, interrupt_flag) == 0x102); static_assert(__builtin_offsetof(ThreadLocalRegion, interrupt_flag) == 0x102);

View File

@@ -57,8 +57,8 @@ namespace ams::svc {
/* This is the highest SVC version supported by Atmosphere, to be updated on new kernel releases. */ /* This is the highest SVC version supported by Atmosphere, to be updated on new kernel releases. */
/* NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor. */ /* NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor. */
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(20); constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(22);
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 5); constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 2);
constexpr inline u32 SupportedKernelVersion = EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion); constexpr inline u32 SupportedKernelVersion = EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);

View File

@@ -36,6 +36,11 @@ namespace ams::mitm::fs {
}; };
constexpr const ApplicationWithDynamicHeapInfo ApplicationsWithDynamicHeap[] = { constexpr const ApplicationWithDynamicHeapInfo ApplicationsWithDynamicHeap[] = {
/* Until Then. */
/* Requirement ~34 MB. */
/* No particular heap sensitivity. */
{ 0x010019C023004000, 16_MB, 0_MB },
/* Trails in the Sky 1st Chapter. */ /* Trails in the Sky 1st Chapter. */
/* Requirement ? MB. 16 MB stolen heap fixes a crash, though. */ /* Requirement ? MB. 16 MB stolen heap fixes a crash, though. */
/* Unknown heap sensitivity. */ /* Unknown heap sensitivity. */

View File

@@ -26,26 +26,6 @@ namespace ams {
} }
int MakeProductModelString(char *dst, size_t dst_size, settings::system::ProductModel model) {
switch (model) {
case settings::system::ProductModel_Invalid: return util::Strlcpy(dst, "Invalid", static_cast<int>(dst_size));
case settings::system::ProductModel_Nx: return util::Strlcpy(dst, "NX", static_cast<int>(dst_size));
default: return util::SNPrintf(dst, dst_size, "%d", static_cast<int>(model));
}
}
const char *GetRegionString(settings::system::RegionCode code) {
switch (code) {
case settings::system::RegionCode_Japan: return "Japan";
case settings::system::RegionCode_Usa: return "Usa";
case settings::system::RegionCode_Europe: return "Europe";
case settings::system::RegionCode_Australia: return "Australia";
case settings::system::RegionCode_HongKongTaiwanKorea: return "HongKongTaiwanKorea";
case settings::system::RegionCode_China: return "China";
default: return "RegionUnknown";
}
}
} }
namespace init { namespace init {
@@ -94,42 +74,19 @@ namespace ams {
/* Atmosphere always wants to redirect new reports to the SD card, to prevent them from being logged. */ /* Atmosphere always wants to redirect new reports to the SD card, to prevent them from being logged. */
erpt::srv::SetRedirectNewReportsToSdCard(true); erpt::srv::SetRedirectNewReportsToSdCard(true);
/* Configure the OS version. */ /* Configure the serial number, OS version, product model, and region. */
{ {
settings::system::FirmwareVersion firmware_version = {}; const auto &sys_info = erpt::srv::GetSystemInfo();
settings::system::SerialNumber serial_number = {}; settings::system::SerialNumber serial_number = {};
settings::system::GetFirmwareVersion(std::addressof(firmware_version));
settings::system::GetSerialNumber(std::addressof(serial_number)); settings::system::GetSerialNumber(std::addressof(serial_number));
char os_private[0x60]; R_ABORT_UNLESS(erpt::srv::SetSerialNumber(serial_number.str,
const auto os_priv_len = util::SNPrintf(os_private, sizeof(os_private), "%s (%.8s)", firmware_version.display_name, firmware_version.revision); strnlen(serial_number.str, sizeof(serial_number.str) - 1) + 1));
AMS_ASSERT(static_cast<size_t>(os_priv_len) < sizeof(os_private));
AMS_UNUSED(os_priv_len);
R_ABORT_UNLESS(erpt::srv::SetSerialNumberAndOsVersion(serial_number.str, R_ABORT_UNLESS(erpt::srv::SetProductModel(sys_info.product_model, static_cast<u32>(std::strlen(sys_info.product_model))));
strnlen(serial_number.str, sizeof(serial_number.str) - 1) + 1,
firmware_version.display_version,
strnlen(firmware_version.display_version, sizeof(firmware_version.display_version) - 1) + 1,
os_private,
strnlen(os_private, sizeof(os_private) - 1) + 1));
}
/* Configure the product model. */ R_ABORT_UNLESS(erpt::srv::SetRegionSetting(sys_info.region, static_cast<u32>(std::strlen(sys_info.region))));
{
char product_model[0x10];
const auto pm_len = erpt::MakeProductModelString(product_model, sizeof(product_model), settings::system::GetProductModel());
AMS_ASSERT(static_cast<size_t>(pm_len) < sizeof(product_model));
AMS_UNUSED(pm_len);
R_ABORT_UNLESS(erpt::srv::SetProductModel(product_model, static_cast<u32>(std::strlen(product_model))));
}
/* Configure the region. */
{
settings::system::RegionCode code;
settings::system::GetRegionCode(std::addressof(code));
const char *region_str = erpt::GetRegionString(code);
R_ABORT_UNLESS(erpt::srv::SetRegionSetting(region_str, static_cast<u32>(std::strlen(region_str))));
} }
/* Start the erpt server. */ /* Start the erpt server. */

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Patch teardown function call to NOP. */
constexpr inline const EmbeddedPatchEntry AmDisableTeardownPatches_22_0_0[] = {
{ 0x5CC4C, "\x1F\x20\x03\xD5", 4 },
};
constexpr inline const EmbeddedPatch AmDisableTeardownPatches[] = {
{ ParseModuleId("B337F7C5AD53E55F3D920FCD394B4DE7C3B7D606"), util::size(AmDisableTeardownPatches_22_0_0), AmDisableTeardownPatches_22_0_0 }, /* 22.0.0 */
};

View File

@@ -74,16 +74,16 @@ constexpr inline const EmbeddedPatchEntry Usb30ForceEnablePatches_20_0_0[] = {
{ 0x7090, "\x20\x00\x80\x52\xC0\x03\x5F\xD6", 8 }, { 0x7090, "\x20\x00\x80\x52\xC0\x03\x5F\xD6", 8 },
}; };
constexpr inline const EmbeddedPatchEntry Usb30ForceEnablePatches_20_1_0[] = {
{ 0x7010, "\x20\x00\x80\x52\xC0\x03\x5F\xD6", 8 },
{ 0x7090, "\x20\x00\x80\x52\xC0\x03\x5F\xD6", 8 },
};
constexpr inline const EmbeddedPatchEntry Usb30ForceEnablePatches_21_0_0[] = { constexpr inline const EmbeddedPatchEntry Usb30ForceEnablePatches_21_0_0[] = {
{ 0x6D60, "\x20\x00\x80\x52\xC0\x03\x5F\xD6", 8 }, { 0x6D60, "\x20\x00\x80\x52\xC0\x03\x5F\xD6", 8 },
{ 0x6DE0, "\x20\x00\x80\x52\xC0\x03\x5F\xD6", 8 }, { 0x6DE0, "\x20\x00\x80\x52\xC0\x03\x5F\xD6", 8 },
}; };
constexpr inline const EmbeddedPatchEntry Usb30ForceEnablePatches_22_0_0[] = {
{ 0x6C90, "\x20\x00\x80\x52\xC0\x03\x5F\xD6", 8 },
{ 0x6D10, "\x20\x00\x80\x52\xC0\x03\x5F\xD6", 8 },
};
constexpr inline const EmbeddedPatch Usb30ForceEnablePatches[] = { constexpr inline const EmbeddedPatch Usb30ForceEnablePatches[] = {
{ ParseModuleId("C0D3F4E87E8B0FE9BBE9F1968A20767F3DC08E03"), util::size(Usb30ForceEnablePatches_9_0_0), Usb30ForceEnablePatches_9_0_0 }, { ParseModuleId("C0D3F4E87E8B0FE9BBE9F1968A20767F3DC08E03"), util::size(Usb30ForceEnablePatches_9_0_0), Usb30ForceEnablePatches_9_0_0 },
{ ParseModuleId("B9C700CA8335F8BAA0D2041D8D09F772890BA988"), util::size(Usb30ForceEnablePatches_10_0_0), Usb30ForceEnablePatches_10_0_0 }, { ParseModuleId("B9C700CA8335F8BAA0D2041D8D09F772890BA988"), util::size(Usb30ForceEnablePatches_10_0_0), Usb30ForceEnablePatches_10_0_0 },
@@ -98,6 +98,7 @@ constexpr inline const EmbeddedPatch Usb30ForceEnablePatches[] = {
{ ParseModuleId("4F21AE15E814FA46515C0401BB23D4F7ADCBF3F4"), util::size(Usb30ForceEnablePatches_18_0_0), Usb30ForceEnablePatches_18_0_0 }, /* 18.0.0 */ { ParseModuleId("4F21AE15E814FA46515C0401BB23D4F7ADCBF3F4"), util::size(Usb30ForceEnablePatches_18_0_0), Usb30ForceEnablePatches_18_0_0 }, /* 18.0.0 */
{ ParseModuleId("54BB9BB32C958E02752DC5E4AE8D016BFE1F5418"), util::size(Usb30ForceEnablePatches_19_0_0), Usb30ForceEnablePatches_19_0_0 }, /* 19.0.0 */ { ParseModuleId("54BB9BB32C958E02752DC5E4AE8D016BFE1F5418"), util::size(Usb30ForceEnablePatches_19_0_0), Usb30ForceEnablePatches_19_0_0 }, /* 19.0.0 */
{ ParseModuleId("40E80E7442C0DFC985315E6F9E8C77229818AC0F"), util::size(Usb30ForceEnablePatches_20_0_0), Usb30ForceEnablePatches_20_0_0 }, /* 20.0.0 */ { ParseModuleId("40E80E7442C0DFC985315E6F9E8C77229818AC0F"), util::size(Usb30ForceEnablePatches_20_0_0), Usb30ForceEnablePatches_20_0_0 }, /* 20.0.0 */
{ ParseModuleId("A5EF8D22EDF8A384E4135270ED596C1D2D524159"), util::size(Usb30ForceEnablePatches_20_1_0), Usb30ForceEnablePatches_20_1_0 }, /* 20.1.0 - 20.5.0 */ { ParseModuleId("A5EF8D22EDF8A384E4135270ED596C1D2D524159"), util::size(Usb30ForceEnablePatches_20_0_0), Usb30ForceEnablePatches_20_0_0 }, /* 20.1.0 - 20.5.0 */
{ ParseModuleId("766D0C2277207B40AD9B8DE309396D50CCE94885"), util::size(Usb30ForceEnablePatches_21_0_0), Usb30ForceEnablePatches_21_0_0 }, /* 21.0.0 */ { ParseModuleId("766D0C2277207B40AD9B8DE309396D50CCE94885"), util::size(Usb30ForceEnablePatches_21_0_0), Usb30ForceEnablePatches_21_0_0 }, /* 21.0.0 */
{ ParseModuleId("B734339F2280170AF0200573F9B943242CEF8C15"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 22.0.0 */
}; };

View File

@@ -108,6 +108,7 @@ namespace ams::ldr {
}; };
#include "ldr_embedded_usb_patches.inc" #include "ldr_embedded_usb_patches.inc"
#include "ldr_embedded_am_patches.inc"
} }
@@ -140,6 +141,18 @@ namespace ams::ldr {
} }
} }
} }
/* TODO: Remove this if/when a cleaner solution is implemented by hbmenu/libnx. */
for (const auto &patch : AmDisableTeardownPatches) {
if (std::memcmp(std::addressof(patch.module_id), std::addressof(module_id), sizeof(module_id)) == 0) {
for (size_t i = 0; i < patch.num_entries; ++i) {
const auto &entry = patch.entries[i];
if (entry.offset + entry.size <= mapped_size) {
std::memcpy(reinterpret_cast<void *>(mapped_nso + entry.offset), entry.data, entry.size);
}
}
}
}
} }
} }

View File

@@ -92,6 +92,8 @@ namespace ams::ldr {
struct ProcessInfo { struct ProcessInfo {
os::NativeHandle process_handle; os::NativeHandle process_handle;
uintptr_t code_address;
size_t total_size;
uintptr_t args_address; uintptr_t args_address;
size_t args_size; size_t args_size;
uintptr_t nso_address[Nso_Count]; uintptr_t nso_address[Nso_Count];
@@ -103,12 +105,25 @@ namespace ams::ldr {
bool has_main; bool has_main;
bool has_sdk; bool has_sdk;
bool has_subsdk; bool has_subsdk;
bool has_nso[Nso_Count]; s8 nso_indices[Nso_Count];
};
struct AutoLoadModuleContext {
NsoHeader *headers;
int nso_count;
int rtld_idx;
int main_nso_idx;
int sdk_nso_idx;
AutoLoadModuleInfo ali;
}; };
/* Global NSO header cache. */ /* Global NSO header cache. */
NsoHeader g_nso_headers[Nso_Count]; NsoHeader g_nso_headers[Nso_Count];
/* Global Zstd decompression context. */
constexpr size_t ZstdDctxWorkspaceSize = 0x176E8;
alignas(8) u8 g_zstd_dctx_workspace[ZstdDctxWorkspaceSize];
Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) { Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) {
/* No version verification is done before 8.1.0. */ /* No version verification is done before 8.1.0. */
R_SUCCEED_IF(hos::GetVersion() < hos::Version_8_1_0); R_SUCCEED_IF(hos::GetVersion() < hos::Version_8_1_0);
@@ -169,10 +184,15 @@ namespace ams::ldr {
return static_cast<Acid::PoolPartition>((meta->acid->flags & Acid::AcidFlag_PoolPartitionMask) >> Acid::AcidFlag_PoolPartitionShift); return static_cast<Acid::PoolPartition>((meta->acid->flags & Acid::AcidFlag_PoolPartitionMask) >> Acid::AcidFlag_PoolPartitionShift);
} }
Result LoadAutoLoadHeaders(NsoHeader *nso_headers, AutoLoadModuleInfo *ali, u32 acid_flags) { Result LoadAutoLoadHeaders(AutoLoadModuleContext &ctx, u32 acid_flags) {
/* Clear NSOs. */ /* Clear NSOs. */
std::memset(nso_headers, 0, sizeof(*nso_headers) * Nso_Count); std::memset(g_nso_headers, 0, sizeof(g_nso_headers));
*ali = {}; ctx.headers = g_nso_headers;
ctx.nso_count = 0;
ctx.rtld_idx = -1;
ctx.main_nso_idx = -1;
ctx.sdk_nso_idx = -1;
ctx.ali = {};
for (size_t i = 0; i < Nso_Count; i++) { for (size_t i = 0; i < Nso_Count; i++) {
/* Only load browser DLLs if acid flags say to do so. */ /* Only load browser DLLs if acid flags say to do so. */
@@ -199,16 +219,18 @@ namespace ams::ldr {
/* Read NSO header. */ /* Read NSO header. */
size_t read_size; size_t read_size;
R_TRY(fs::ReadFile(std::addressof(read_size), file, 0, nso_headers + i, sizeof(*nso_headers))); R_TRY(fs::ReadFile(std::addressof(read_size), file, 0, g_nso_headers + ctx.nso_count, sizeof(NsoHeader)));
R_UNLESS(read_size == sizeof(*nso_headers), ldr::ResultInvalidNso()); R_UNLESS(read_size == sizeof(NsoHeader), ldr::ResultInvalidNso());
/* Note nso is present. */ /* Note nso is present. */
switch (i) { switch (i) {
case Nso_Rtld: case Nso_Rtld:
ali->has_rtld = true; ctx.rtld_idx = ctx.nso_count;
ctx.ali.has_rtld = true;
break; break;
case Nso_Main: case Nso_Main:
ali->has_main = true; ctx.main_nso_idx = ctx.nso_count;
ctx.ali.has_main = true;
break; break;
case Nso_SubSdk0: case Nso_SubSdk0:
case Nso_SubSdk1: case Nso_SubSdk1:
@@ -220,64 +242,65 @@ namespace ams::ldr {
case Nso_SubSdk7: case Nso_SubSdk7:
case Nso_SubSdk8: case Nso_SubSdk8:
case Nso_SubSdk9: case Nso_SubSdk9:
ali->has_subsdk = true; ctx.ali.has_subsdk = true;
break; break;
case Nso_Sdk: case Nso_Sdk:
ali->has_sdk = true; ctx.sdk_nso_idx = ctx.nso_count;
ctx.ali.has_sdk = true;
break; break;
} }
ali->has_nso[i] = true; ctx.ali.nso_indices[ctx.nso_count] = static_cast<s8>(i);
ctx.nso_count++;
} }
} }
R_SUCCEED(); R_SUCCEED();
} }
Result CheckAutoLoad(const NsoHeader *nso_headers, const AutoLoadModuleInfo *ali, u32 acid_flags) { Result CheckAutoLoad(const AutoLoadModuleContext &ctx, u32 acid_flags) {
/* We must always have a main. */ /* We must always have a main. */
R_UNLESS(ali->has_main, ldr::ResultInvalidNso()); R_UNLESS(ctx.ali.has_main, ldr::ResultInvalidNso());
/* All NSOs must not be --X. */ /* Validate flags and extents for all present NSOs. */
/* This is "probably" not checked on Ounce? */ for (int i = 0; i < ctx.nso_count; ++i) {
for (size_t i = 0; i < Nso_Count; ++i) { const auto &hdr = ctx.headers[i];
R_UNLESS((nso_headers[i].flags & NsoHeader::Flag_PreventCodeReads) == 0, ldr::ResultInvalidNso());
}
/* If we don't have an RTLD, we must only have a main. */ /* All NSOs must not be --X. */
const bool has_browser_dll = (acid_flags & Acid::AcidFlag_LoadBrowserCoreDll) != 0; /* This is "probably" not checked on Ounce? */
if (!ali->has_rtld) { R_UNLESS((hdr.flags & NsoHeader::Flag_PreventCodeReads) == 0, ldr::ResultInvalidNso());
/* If don't have rtld, we must also not have sdk. */
R_UNLESS(!ali->has_sdk, ldr::ResultInvalidNso());
/* We must also not have both subsdk and browser dll. */ /* Zstd compression only allowed on main, and only when both rtld+sdk are present. */
R_UNLESS(!(ali->has_subsdk && has_browser_dll), ldr::ResultInvalidNso()); if (i != ctx.main_nso_idx || ctx.rtld_idx < 0 || ctx.sdk_nso_idx < 0) {
} else { R_UNLESS((hdr.flags & NsoHeader::Flag_UseZbicCompression) == 0, ldr::ResultInvalidNso());
/* If we have rtld, we must not have browser core dll. */
R_UNLESS(!has_browser_dll, ldr::ResultInvalidNso());
}
/* Check NSO extents. */
for (size_t i = 0; i < Nso_Count; i++) {
/* Only validate the nsos we have. */
if (!ali->has_nso[i]) {
continue;
} }
/* NSOs must have page-aligned segments. */ /* NSOs must have page-aligned segments. */
R_UNLESS(util::IsAligned(nso_headers[i].text_dst_offset, os::MemoryPageSize), ldr::ResultInvalidNso()); R_UNLESS(util::IsAligned(hdr.text_dst_offset, os::MemoryPageSize), ldr::ResultInvalidNso());
R_UNLESS(util::IsAligned(nso_headers[i].ro_dst_offset, os::MemoryPageSize), ldr::ResultInvalidNso()); R_UNLESS(util::IsAligned(hdr.ro_dst_offset, os::MemoryPageSize), ldr::ResultInvalidNso());
R_UNLESS(util::IsAligned(nso_headers[i].rw_dst_offset, os::MemoryPageSize), ldr::ResultInvalidNso()); R_UNLESS(util::IsAligned(hdr.rw_dst_offset, os::MemoryPageSize), ldr::ResultInvalidNso());
/* NSOs must have zero text offset. */ /* NSOs must have zero text offset. */
R_UNLESS(nso_headers[i].text_dst_offset == 0, ldr::ResultInvalidNso()); R_UNLESS(hdr.text_dst_offset == 0, ldr::ResultInvalidNso());
/* NSO .text must precede .rodata. */ /* NSO .text must precede .rodata. */
const size_t text_end = static_cast<size_t>(nso_headers[i].text_dst_offset) + static_cast<size_t>(nso_headers[i].text_size); const size_t text_end = static_cast<size_t>(hdr.text_dst_offset) + static_cast<size_t>(hdr.text_size);
R_UNLESS(text_end <= static_cast<size_t>(nso_headers[i].ro_dst_offset), ldr::ResultInvalidNso()); R_UNLESS(text_end <= static_cast<size_t>(hdr.ro_dst_offset), ldr::ResultInvalidNso());
/* NSO .rodata must precede .rwdata. */ /* NSO .rodata must precede .rwdata. */
const size_t ro_end = static_cast<size_t>(nso_headers[i].ro_dst_offset) + static_cast<size_t>(nso_headers[i].ro_size); const size_t ro_end = static_cast<size_t>(hdr.ro_dst_offset) + static_cast<size_t>(hdr.ro_size);
R_UNLESS(ro_end <= static_cast<size_t>(nso_headers[i].rw_dst_offset), ldr::ResultInvalidNso()); R_UNLESS(ro_end <= static_cast<size_t>(hdr.rw_dst_offset), ldr::ResultInvalidNso());
}
const bool has_browser_dll = (acid_flags & Acid::AcidFlag_LoadBrowserCoreDll) != 0;
if (ctx.ali.has_rtld || ctx.ali.has_sdk) {
/* If we have sdk we must have rtld. */
R_UNLESS(ctx.ali.has_rtld, ldr::ResultInvalidNso());
/* If we have rtld, we must not have browser core dll. */
R_UNLESS(!has_browser_dll, ldr::ResultInvalidNso());
} else {
/* We must not have both subsdk and browser dll. */
R_UNLESS(!(ctx.ali.has_subsdk && has_browser_dll), ldr::ResultInvalidNso());
} }
R_SUCCEED(); R_SUCCEED();
@@ -293,8 +316,8 @@ namespace ams::ldr {
{ 0x010049900F546001 }, /* Super Mario 3D All-Stars: Super Mario 64 */ { 0x010049900F546001 }, /* Super Mario 3D All-Stars: Super Mario 64 */
{ 0x010057D00ECE4000 }, /* Nintendo Switch Online (Nintendo 64) [for Japan] */ { 0x010057D00ECE4000 }, /* Nintendo Switch Online (Nintendo 64) [for Japan] */
{ 0x01006F8002326000 }, /* Animal Crossing: New Horizons */ { 0x01006F8002326000 }, /* Animal Crossing: New Horizons */
{ 0x01006FB00F50E000 }, /* [???] */ { 0x01006FB00F50E000 }, /* 宝可梦 走吧!伊布 [Pokemon: Let's Go, Eevee! for China] */
{ 0x010070300F50C000 }, /* [???] */ { 0x010070300F50C000 }, /* 宝可梦 走吧!皮卡丘 [Pokemon: Let's Go, Pikachu! for China] */
{ 0x010075100E8EC000 }, /* 马力欧卡丁车8 豪华版 [Mario Kart 8 Deluxe for China] */ { 0x010075100E8EC000 }, /* 马力欧卡丁车8 豪华版 [Mario Kart 8 Deluxe for China] */
{ 0x01008DB008C2C000 }, /* Pokemon Shield */ { 0x01008DB008C2C000 }, /* Pokemon Shield */
{ 0x01009AD008C4C000 }, /* Pokemon: Let's Go, Pikachu! [Kiosk] */ { 0x01009AD008C4C000 }, /* Pokemon: Let's Go, Pikachu! [Kiosk] */
@@ -514,7 +537,7 @@ namespace ams::ldr {
return rand % (max + 1); return rand % (max + 1);
} }
Result DecideAddressSpaceLayout(ProcessInfo *out, svc::CreateProcessParameter *out_param, const NsoHeader *nso_headers, const AutoLoadModuleInfo *ali, const ArgumentStore::Entry *argument) { Result DecideAddressSpaceLayout(ProcessInfo *out, svc::CreateProcessParameter *out_param, const AutoLoadModuleContext &ctx, const ArgumentStore::Entry *argument) {
/* Clear output. */ /* Clear output. */
out->args_address = 0; out->args_address = 0;
out->args_size = 0; out->args_size = 0;
@@ -525,35 +548,33 @@ namespace ams::ldr {
bool argument_allocated = false; bool argument_allocated = false;
/* Calculate base offsets. */ /* Calculate base offsets. */
for (size_t i = 0; i < Nso_Count; i++) { for (int i = 0; i < ctx.nso_count; i++) {
if (ali->has_nso[i]) { out->nso_address[i] = total_size;
out->nso_address[i] = total_size; const size_t text_end = static_cast<size_t>(ctx.headers[i].text_dst_offset) + static_cast<size_t>(ctx.headers[i].text_size);
const size_t text_end = static_cast<size_t>(nso_headers[i].text_dst_offset) + static_cast<size_t>(nso_headers[i].text_size); const size_t ro_end = static_cast<size_t>(ctx.headers[i].ro_dst_offset) + static_cast<size_t>(ctx.headers[i].ro_size);
const size_t ro_end = static_cast<size_t>(nso_headers[i].ro_dst_offset) + static_cast<size_t>(nso_headers[i].ro_size); const size_t rw_end = static_cast<size_t>(ctx.headers[i].rw_dst_offset) + static_cast<size_t>(ctx.headers[i].rw_size);
const size_t rw_end = static_cast<size_t>(nso_headers[i].rw_dst_offset) + static_cast<size_t>(nso_headers[i].rw_size); out->nso_size[i] = text_end;
out->nso_size[i] = text_end; out->nso_size[i] = std::max(out->nso_size[i], ro_end);
out->nso_size[i] = std::max(out->nso_size[i], ro_end); out->nso_size[i] = std::max(out->nso_size[i], rw_end);
out->nso_size[i] = std::max(out->nso_size[i], rw_end); out->nso_size[i] += static_cast<size_t>(ctx.headers[i].bss_size);
out->nso_size[i] += static_cast<size_t>(nso_headers[i].bss_size);
const size_t aligned_up_size = util::AlignUp(out->nso_size[i], os::MemoryPageSize) & (AutoLoadModuleSizeMax - 1); const size_t aligned_up_size = util::AlignUp(out->nso_size[i], os::MemoryPageSize) & (AutoLoadModuleSizeMax - 1);
R_UNLESS(out->nso_size[i] <= aligned_up_size, ldr::ResultInvalidNso()); R_UNLESS(out->nso_size[i] <= aligned_up_size, ldr::ResultInvalidNso());
R_UNLESS(aligned_up_size > 0, ldr::ResultInvalidNso()); R_UNLESS(aligned_up_size > 0, ldr::ResultInvalidNso());
out->nso_size[i] = aligned_up_size; out->nso_size[i] = aligned_up_size;
R_UNLESS(util::CanAddWithoutOverflow(total_size, out->nso_size[i]), ldr::ResultInvalidNso()); R_UNLESS(util::CanAddWithoutOverflow(total_size, out->nso_size[i]), ldr::ResultInvalidNso());
total_size += out->nso_size[i]; total_size += out->nso_size[i];
if (!argument_allocated && argument != nullptr) { if (!argument_allocated && argument != nullptr) {
out->args_address = total_size; out->args_address = total_size;
out->args_size = util::AlignUp(2 * sizeof(u32) + argument->argument_size * 2 + ArgumentStore::ArgumentBufferSize, os::MemoryPageSize); out->args_size = util::AlignUp(2 * sizeof(u32) + argument->argument_size * 2 + ArgumentStore::ArgumentBufferSize, os::MemoryPageSize);
R_UNLESS(util::CanAddWithoutOverflow(total_size, out->args_size), ldr::ResultInvalidNso()); R_UNLESS(util::CanAddWithoutOverflow(total_size, out->args_size), ldr::ResultInvalidNso());
total_size += out->args_size; total_size += out->args_size;
argument_allocated = true; argument_allocated = true;
}
} }
} }
@@ -598,11 +619,9 @@ namespace ams::ldr {
/* Set out. */ /* Set out. */
aslr_start += aslr_slide; aslr_start += aslr_slide;
for (size_t i = 0; i < Nso_Count; i++) { for (int i = 0; i < ctx.nso_count; i++) {
if (ali->has_nso[i]) { R_UNLESS(util::CanAddWithoutOverflow(out->nso_address[i], aslr_start), ldr::ResultInvalidNso());
R_UNLESS(util::CanAddWithoutOverflow(out->nso_address[i], aslr_start), ldr::ResultInvalidNso()); out->nso_address[i] += aslr_start;
out->nso_address[i] += aslr_start;
}
} }
if (out->args_address) { if (out->args_address) {
R_UNLESS(util::CanAddWithoutOverflow(out->args_address, aslr_start), ldr::ResultInvalidNso()); R_UNLESS(util::CanAddWithoutOverflow(out->args_address, aslr_start), ldr::ResultInvalidNso());
@@ -611,69 +630,88 @@ namespace ams::ldr {
out_param->code_address = aslr_start; out_param->code_address = aslr_start;
out_param->code_num_pages = total_size >> 12; out_param->code_num_pages = total_size >> 12;
out->total_size = total_size;
R_SUCCEED(); R_SUCCEED();
} }
Result LoadAutoLoadModuleSegment(fs::FileHandle file, const NsoHeader::SegmentInfo *segment, size_t file_size, const u8 *file_hash, bool is_compressed, bool check_hash, uintptr_t map_base, uintptr_t map_end) { Result LoadAutoLoadModuleSegment(fs::FileHandle file, size_t file_offset, size_t compressed_size, size_t segment_size, bool is_compressed, bool is_zstd, uintptr_t map_base, uintptr_t map_end) {
/* Select read size based on compression. */ /* Select read size based on compression. */
if (!is_compressed) { size_t file_size = is_compressed ? compressed_size : segment_size;
file_size = segment->size;
}
/* Validate size. */ /* Validate size. */
R_UNLESS(file_size <= segment->size, ldr::ResultInvalidNso()); R_UNLESS(file_size <= segment_size, ldr::ResultInvalidNso());
R_UNLESS(segment->size <= std::numeric_limits<s32>::max(), ldr::ResultInvalidNso()); R_UNLESS(file_size <= std::numeric_limits<s32>::max(), ldr::ResultInvalidNso());
R_UNLESS(segment_size <= std::numeric_limits<s32>::max(), ldr::ResultInvalidNso());
/* Load data from file. */ /* Load data from file. */
uintptr_t load_address = is_compressed ? map_end - file_size : map_base; uintptr_t load_address = is_compressed ? map_end - compressed_size : map_base;
size_t read_size; size_t read_size;
R_TRY(fs::ReadFile(std::addressof(read_size), file, segment->file_offset, reinterpret_cast<void *>(load_address), file_size)); R_TRY(fs::ReadFile(std::addressof(read_size), file, file_offset, reinterpret_cast<void *>(load_address), file_size));
R_UNLESS(read_size == file_size, ldr::ResultInvalidNso()); R_UNLESS(read_size == file_size, ldr::ResultInvalidNso());
/* Uncompress if necessary. */ /* Uncompress if necessary. */
if (is_compressed) { R_SUCCEED_IF(!is_compressed);
bool decompressed = (util::DecompressLZ4(reinterpret_cast<void *>(map_base), segment->size, reinterpret_cast<const void *>(load_address), file_size) == static_cast<int>(segment->size));
auto compressed_data_buf = reinterpret_cast<const void *>(load_address);
if (is_zstd) {
bool decompressed = util::DecompressZstdForLoader(reinterpret_cast<void *>(g_zstd_dctx_workspace), ZstdDctxWorkspaceSize, reinterpret_cast<void *>(map_base), static_cast<size_t>(map_end - map_base), segment_size, compressed_data_buf, file_size);
R_UNLESS(decompressed, ldr::ResultInvalidNso());
} else {
bool decompressed = (util::DecompressLZ4(reinterpret_cast<void *>(map_base), segment_size, compressed_data_buf, file_size) == static_cast<int>(segment_size));
R_UNLESS(decompressed, ldr::ResultInvalidNso()); R_UNLESS(decompressed, ldr::ResultInvalidNso());
}
/* Check hash if necessary. */
if (check_hash) {
u8 hash[crypto::Sha256Generator::HashSize];
crypto::GenerateSha256(hash, sizeof(hash), reinterpret_cast<void *>(map_base), segment->size);
R_UNLESS(std::memcmp(hash, file_hash, sizeof(hash)) == 0, ldr::ResultInvalidNso());
} }
R_SUCCEED(); R_SUCCEED();
} }
Result LoadAutoLoadModule(os::NativeHandle process_handle, fs::FileHandle file, const NsoHeader *nso_header, uintptr_t nso_address, size_t nso_size) { Result CheckSegmentHash(const NsoHeader *nso_header, uintptr_t map_address, NsoHeader::Segment segment) {
if ((nso_header->flags & (NsoHeader::Flag_CheckHashText << segment)) == 0) {
R_SUCCEED();
}
u8 hash[crypto::Sha256Generator::HashSize];
crypto::GenerateSha256(hash, sizeof(hash),
reinterpret_cast<void *>(map_address + nso_header->segments[segment].dst_offset),
nso_header->segments[segment].size);
R_UNLESS(std::memcmp(hash, nso_header->segment_hashes[segment], sizeof(hash)) == 0, ldr::ResultInvalidNso());
R_SUCCEED();
}
Result LoadAutoLoadModule(os::NativeHandle process_handle, fs::FileHandle file, const NsoHeader *nso_header, uintptr_t nso_address, size_t nso_size, size_t map_size) {
const bool is_zstd = (nso_header->flags & NsoHeader::Flag_UseZbicCompression) != 0;
/* Map and read data from file. */ /* Map and read data from file. */
{ {
/* Map the process memory. */ /* Map the process memory. */
void *mapped_memory = nullptr; void *mapped_memory = nullptr;
R_TRY(os::MapProcessMemory(std::addressof(mapped_memory), process_handle, nso_address, nso_size, GenerateSecureRandom)); R_TRY(os::MapProcessMemory(std::addressof(mapped_memory), process_handle, nso_address, map_size, GenerateSecureRandom));
ON_SCOPE_EXIT { os::UnmapProcessMemory(mapped_memory, process_handle, nso_address, nso_size); }; ON_SCOPE_EXIT { os::UnmapProcessMemory(mapped_memory, process_handle, nso_address, map_size); };
const uintptr_t map_address = reinterpret_cast<uintptr_t>(mapped_memory); const uintptr_t map_address = reinterpret_cast<uintptr_t>(mapped_memory);
const uintptr_t map_end = map_address + map_size;
/* Load NSO segments. */ /* Load NSO segments. */
R_TRY(LoadAutoLoadModuleSegment(file, std::addressof(nso_header->segments[NsoHeader::Segment_Text]), nso_header->text_compressed_size, nso_header->text_hash, (nso_header->flags & NsoHeader::Flag_CompressedText) != 0, R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Text].file_offset, nso_header->text_compressed_size, nso_header->text_size,
(nso_header->flags & NsoHeader::Flag_CheckHashText) != 0, map_address + nso_header->text_dst_offset, map_address + nso_size)); (nso_header->flags & NsoHeader::Flag_CompressedText) != 0, is_zstd, map_address + nso_header->text_dst_offset, map_end));
R_TRY(LoadAutoLoadModuleSegment(file, std::addressof(nso_header->segments[NsoHeader::Segment_Ro]), nso_header->ro_compressed_size, nso_header->ro_hash, (nso_header->flags & NsoHeader::Flag_CompressedRo) != 0, R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Ro].file_offset, nso_header->ro_compressed_size, nso_header->ro_size,
(nso_header->flags & NsoHeader::Flag_CheckHashRo) != 0, map_address + nso_header->ro_dst_offset, map_address + nso_size)); (nso_header->flags & NsoHeader::Flag_CompressedRo) != 0, is_zstd, map_address + nso_header->ro_dst_offset, map_end));
R_TRY(LoadAutoLoadModuleSegment(file, std::addressof(nso_header->segments[NsoHeader::Segment_Rw]), nso_header->rw_compressed_size, nso_header->rw_hash, (nso_header->flags & NsoHeader::Flag_CompressedRw) != 0, R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Rw].file_offset, nso_header->rw_compressed_size, nso_header->rw_size,
(nso_header->flags & NsoHeader::Flag_CheckHashRw) != 0, map_address + nso_header->rw_dst_offset, map_address + nso_size)); (nso_header->flags & NsoHeader::Flag_CompressedRw) != 0, is_zstd, map_address + nso_header->rw_dst_offset, map_end));
/* Clear unused space to zero. */ /* Clear unused space to zero. */
const size_t text_end = static_cast<size_t>(nso_header->text_dst_offset) + static_cast<size_t>(nso_header->text_size); const size_t text_end = static_cast<size_t>(nso_header->text_dst_offset) + static_cast<size_t>(nso_header->text_size);
const size_t ro_end = static_cast<size_t>(nso_header->ro_dst_offset) + static_cast<size_t>(nso_header->ro_size); const size_t ro_end = static_cast<size_t>(nso_header->ro_dst_offset) + static_cast<size_t>(nso_header->ro_size);
const size_t rw_end = static_cast<size_t>(nso_header->rw_dst_offset) + static_cast<size_t>(nso_header->rw_size); const size_t rw_end = static_cast<size_t>(nso_header->rw_dst_offset) + static_cast<size_t>(nso_header->rw_size);
std::memset(reinterpret_cast<void *>(map_address + 0), 0, nso_header->text_dst_offset);
std::memset(reinterpret_cast<void *>(map_address + text_end), 0, nso_header->ro_dst_offset - text_end); std::memset(reinterpret_cast<void *>(map_address + text_end), 0, nso_header->ro_dst_offset - text_end);
std::memset(reinterpret_cast<void *>(map_address + ro_end), 0, nso_header->rw_dst_offset - ro_end); std::memset(reinterpret_cast<void *>(map_address + ro_end), 0, nso_header->rw_dst_offset - ro_end);
std::memset(reinterpret_cast<void *>(map_address + rw_end), 0, nso_header->bss_size); std::memset(reinterpret_cast<void *>(map_address + rw_end), 0, nso_size - rw_end);
/* Check segment hashes. */
R_TRY(CheckSegmentHash(nso_header, map_address, NsoHeader::Segment_Text));
R_TRY(CheckSegmentHash(nso_header, map_address, NsoHeader::Segment_Ro));
R_TRY(CheckSegmentHash(nso_header, map_address, NsoHeader::Segment_Rw));
/* Apply embedded patches. */ /* Apply embedded patches. */
ApplyEmbeddedPatchesToModule(nso_header->module_id, map_address, nso_size); ApplyEmbeddedPatchesToModule(nso_header->module_id, map_address, nso_size);
@@ -691,25 +729,31 @@ namespace ams::ldr {
R_TRY(os::SetProcessMemoryPermission(process_handle, nso_address + nso_header->text_dst_offset, text_size, prevent_code_reads ? os::MemoryPermission_ExecuteOnly : os::MemoryPermission_ReadExecute)); R_TRY(os::SetProcessMemoryPermission(process_handle, nso_address + nso_header->text_dst_offset, text_size, prevent_code_reads ? os::MemoryPermission_ExecuteOnly : os::MemoryPermission_ReadExecute));
} }
if (ro_size) { if (ro_size) {
R_TRY(os::SetProcessMemoryPermission(process_handle, nso_address + nso_header->ro_dst_offset, ro_size, os::MemoryPermission_ReadOnly)); R_TRY(os::SetProcessMemoryPermission(process_handle, nso_address + nso_header->ro_dst_offset, ro_size, os::MemoryPermission_ReadOnly));
} }
if (rw_size) { if (rw_size) {
R_TRY(os::SetProcessMemoryPermission(process_handle, nso_address + nso_header->rw_dst_offset, rw_size, os::MemoryPermission_ReadWrite)); R_TRY(os::SetProcessMemoryPermission(process_handle, nso_address + nso_header->rw_dst_offset, rw_size, os::MemoryPermission_ReadWrite));
} }
R_SUCCEED(); R_SUCCEED();
} }
Result LoadAutoLoadModules(const ProcessInfo *process_info, const NsoHeader *nso_headers, const AutoLoadModuleInfo *ali, const ArgumentStore::Entry *argument) { Result LoadAutoLoadModules(const ProcessInfo *process_info, const AutoLoadModuleContext &ctx, const ArgumentStore::Entry *argument) {
/* Load each NSO. */ /* Load each NSO. */
for (size_t i = 0; i < Nso_Count; i++) { const uintptr_t total_end = process_info->code_address + process_info->total_size;
if (ali->has_nso[i]) {
fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), GetNsoPath(i), fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
R_TRY(LoadAutoLoadModule(process_info->process_handle, file, nso_headers + i, process_info->nso_address[i], process_info->nso_size[i])); for (int i = 0; i < ctx.nso_count; i++) {
} const NsoIndex nso_idx = static_cast<NsoIndex>(ctx.ali.nso_indices[i]);
fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), GetNsoPath(nso_idx), fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
const bool is_zstd = (ctx.headers[i].flags & NsoHeader::Flag_UseZbicCompression) != 0;
const size_t map_size = is_zstd ? (total_end - process_info->nso_address[i]) : process_info->nso_size[i];
R_TRY(LoadAutoLoadModule(process_info->process_handle, file, ctx.headers + i,
process_info->nso_address[i], process_info->nso_size[i], map_size));
} }
/* Load arguments, if present. */ /* Load arguments, if present. */
@@ -735,13 +779,13 @@ namespace ams::ldr {
R_SUCCEED(); R_SUCCEED();
} }
Result CreateProcessAndLoadAutoLoadModules(ProcessInfo *out, const Meta *meta, const NsoHeader *nso_headers, const AutoLoadModuleInfo *ali, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit) { Result CreateProcessAndLoadAutoLoadModules(ProcessInfo *out, const Meta *meta, const AutoLoadModuleContext &ctx, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit) {
/* Get CreateProcessParameter. */ /* Get CreateProcessParameter. */
svc::CreateProcessParameter param; svc::CreateProcessParameter param;
R_TRY(GetCreateProcessParameter(std::addressof(param), meta, flags, resource_limit)); R_TRY(GetCreateProcessParameter(std::addressof(param), meta, flags, resource_limit));
/* Decide on an NSO layout. */ /* Decide on an NSO layout. */
R_TRY(DecideAddressSpaceLayout(out, std::addressof(param), nso_headers, ali, argument)); R_TRY(DecideAddressSpaceLayout(out, std::addressof(param), ctx, argument));
/* Actually create process. */ /* Actually create process. */
svc::Handle process_handle; svc::Handle process_handle;
@@ -749,10 +793,11 @@ namespace ams::ldr {
/* Set the output handle, and ensure that if we fail after this point we clean it up. */ /* Set the output handle, and ensure that if we fail after this point we clean it up. */
out->process_handle = process_handle; out->process_handle = process_handle;
out->code_address = param.code_address;
ON_RESULT_FAILURE { svc::CloseHandle(process_handle); }; ON_RESULT_FAILURE { svc::CloseHandle(process_handle); };
/* Load all auto load modules. */ /* Load all auto load modules. */
R_RETURN(LoadAutoLoadModules(out, nso_headers, ali, argument)); R_RETURN(LoadAutoLoadModules(out, ctx, argument));
} }
} }
@@ -793,13 +838,13 @@ namespace ams::ldr {
} }
/* Load, validate NSO headers. */ /* Load, validate NSO headers. */
AutoLoadModuleInfo auto_load_info = {}; AutoLoadModuleContext ctx;
R_TRY(LoadAutoLoadHeaders(g_nso_headers, std::addressof(auto_load_info), meta.acid->flags)); R_TRY(LoadAutoLoadHeaders(ctx, meta.acid->flags));
R_TRY(CheckAutoLoad(g_nso_headers, std::addressof(auto_load_info), meta.acid->flags)); R_TRY(CheckAutoLoad(ctx, meta.acid->flags));
/* Actually create the process and load NSOs into process memory. */ /* Actually create the process and load NSOs into process memory. */
ProcessInfo info; ProcessInfo info;
R_TRY(CreateProcessAndLoadAutoLoadModules(std::addressof(info), std::addressof(meta), g_nso_headers, std::addressof(auto_load_info), argument, flags, resource_limit)); R_TRY(CreateProcessAndLoadAutoLoadModules(std::addressof(info), std::addressof(meta), ctx, argument, flags, resource_limit));
/* Register NSOs with the RoManager. */ /* Register NSOs with the RoManager. */
{ {
@@ -811,10 +856,8 @@ namespace ams::ldr {
RoManager::GetInstance().RegisterProcess(pin_id, process_id, meta.aci->program_id, as_type == Npdm::AddressSpaceType_64Bit || as_type == Npdm::AddressSpaceType_64BitDeprecated); RoManager::GetInstance().RegisterProcess(pin_id, process_id, meta.aci->program_id, as_type == Npdm::AddressSpaceType_64Bit || as_type == Npdm::AddressSpaceType_64BitDeprecated);
/* Register all NSOs. */ /* Register all NSOs. */
for (size_t i = 0; i < Nso_Count; i++) { for (int i = 0; i < ctx.nso_count; i++) {
if (auto_load_info.has_nso[i]) { RoManager::GetInstance().AddNso(pin_id, ctx.headers[i].module_id, info.nso_address[i], info.nso_size[i]);
RoManager::GetInstance().AddNso(pin_id, g_nso_headers[i].module_id, info.nso_address[i], info.nso_size[i]);
}
} }
} }

View File

@@ -15,7 +15,7 @@
"filesystem_access": { "filesystem_access": {
"permissions": "0xFFFFFFFFFFFFFFFF" "permissions": "0xFFFFFFFFFFFFFFFF"
}, },
"service_access": ["erpt:c", "fatal:u", "fsp-srv", "ldr:shel", "lm", "lr", "pm:shell", "set", "set:sys"], "service_access": ["fatal:u", "fsp-srv", "ldr:shel", "lr", "pm:shell", "set:sys"],
"service_host": ["pgl"], "service_host": ["pgl"],
"kernel_capabilities": [{ "kernel_capabilities": [{
"type": "kernel_flags", "type": "kernel_flags",
@@ -87,4 +87,4 @@
"type": "handle_table_size", "type": "handle_table_size",
"value": 256 "value": 256
}] }]
} }

View File

@@ -30,13 +30,14 @@ namespace ams {
fs::InitializeForSystem(); fs::InitializeForSystem();
fs::SetAllocator(pgl::srv::Allocate, pgl::srv::Deallocate); fs::SetAllocator(pgl::srv::Allocate, pgl::srv::Deallocate);
fs::SetEnabledAutoAbort(false); fs::SetEnabledAutoAbort(false);
/* Initialize lr. */
lr::Initialize();
/* Initialize other services we need. */ /* Initialize other services we need. */
R_ABORT_UNLESS(setInitialize());
R_ABORT_UNLESS(setsysInitialize()); R_ABORT_UNLESS(setsysInitialize());
R_ABORT_UNLESS(pmshellInitialize()); R_ABORT_UNLESS(pmshellInitialize());
R_ABORT_UNLESS(ldrShellInitialize()); R_ABORT_UNLESS(ldrShellInitialize());
R_ABORT_UNLESS(lrInitialize());
/* Verify that we can sanely execute. */ /* Verify that we can sanely execute. */
ams::CheckApiVersion(); ams::CheckApiVersion();
@@ -58,3 +59,36 @@ namespace ams {
} }
} }
/* Override operator new. */
void *operator new(size_t size) {
return ams::pgl::srv::Allocate(size);
}
void *operator new(size_t size, const std::nothrow_t &) {
return ams::pgl::srv::Allocate(size);
}
void operator delete(void *p) {
return ams::pgl::srv::Deallocate(p, 0);
}
void operator delete(void *p, size_t size) {
return ams::pgl::srv::Deallocate(p, size);
}
void *operator new[](size_t size) {
return ams::pgl::srv::Allocate(size);
}
void *operator new[](size_t size, const std::nothrow_t &) {
return ams::pgl::srv::Allocate(size);
}
void operator delete[](void *p) {
return ams::pgl::srv::Deallocate(p, 0);
}
void operator delete[](void *p, size_t size) {
return ams::pgl::srv::Deallocate(p, size);
}

View File

@@ -141,8 +141,31 @@ namespace dbk {
return rc; return rc;
} }
u32 EncodeVersion(u32 major, u32 minor, u32 micro, u32 relstep = 0) { u32 EncodeVersion(u32 major, u32 minor, u32 micro) {
return ((major & 0xFF) << 24) | ((minor & 0xFF) << 16) | ((micro & 0xFF) << 8) | ((relstep & 0xFF) << 8); return ((major & 0xFF) << 24) | ((minor & 0xFF) << 16) | ((micro & 0xFF) << 8);
}
u32 NcmVersionToHosVersion(u32 ncm_version) {
const u32 major = (ncm_version >> 26) & 0x1f;
const u32 minor = (ncm_version >> 20) & 0x1f;
const u32 micro = (ncm_version >> 16) & 0xf;
return EncodeVersion(major, minor, micro);
}
bool IsHosVersionSupported(u32 hos_version) {
return hos_version <= g_supported_version;
}
std::shared_ptr<Menu> CreateUpdateMenuAfterPathSelection(std::shared_ptr<Menu> prev_menu) {
AmsSuUpdateInformation update_info = {};
if (R_SUCCEEDED(amssuGetUpdateInformation(&update_info, g_update_path))) {
const u32 update_hos_version = NcmVersionToHosVersion(update_info.version);
if (!IsHosVersionSupported(update_hos_version)) {
return std::make_shared<FirmwareNotSupportedMenu>(prev_menu, update_info.version, g_supported_version);
}
}
return std::make_shared<ValidateUpdateMenu>(prev_menu);
} }
} }
@@ -347,7 +370,7 @@ namespace dbk {
/* Copy result text if there is a result. */ /* Copy result text if there is a result. */
if (R_FAILED(rc)) { if (R_FAILED(rc)) {
snprintf(m_result_text, sizeof(m_result_text), "Result: 0x%08x", rc); snprintf(m_result_text, sizeof(m_result_text), "Ergebnis: 0x%08x", rc);
} }
} }
@@ -375,7 +398,7 @@ namespace dbk {
const float button_width = WindowWidth - HorizontalInset * 2.0f; const float button_width = WindowWidth - HorizontalInset * 2.0f;
/* Add buttons. */ /* Add buttons. */
this->AddButton(ExitButtonId, "Exit", x + HorizontalInset, button_y, button_width, ButtonHeight); this->AddButton(ExitButtonId, "Beenden", x + HorizontalInset, button_y, button_width, ButtonHeight);
this->SetButtonSelected(ExitButtonId, true); this->SetButtonSelected(ExitButtonId, true);
} }
@@ -412,8 +435,8 @@ namespace dbk {
const float button_y = y + TitleGap + SubTextHeight + VerticalGap * 2.0f + (R_FAILED(m_rc) ? SubTextHeight : 0.0f); const float button_y = y + TitleGap + SubTextHeight + VerticalGap * 2.0f + (R_FAILED(m_rc) ? SubTextHeight : 0.0f);
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap; const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
this->AddButton(BackButtonId, "Back", x + HorizontalInset, button_y, button_width, ButtonHeight); this->AddButton(BackButtonId, "Zurück", x + HorizontalInset, button_y, button_width, ButtonHeight);
this->AddButton(ContinueButtonId, "Continue", x + HorizontalInset + button_width + ButtonHorizontalGap, button_y, button_width, ButtonHeight); this->AddButton(ContinueButtonId, "Weiter", x + HorizontalInset + button_width + ButtonHorizontalGap, button_y, button_width, ButtonHeight);
this->SetButtonSelected(ContinueButtonId, true); this->SetButtonSelected(ContinueButtonId, true);
} }
@@ -446,12 +469,75 @@ namespace dbk {
} }
} }
namespace {
struct FirmwareNotSupportedSubtext {
char value[0x100];
FirmwareNotSupportedSubtext(u32 update_ncm_version, u32 max_supported_hos_version) {
snprintf(this->value, sizeof(this->value),
"Maximal unterstützte Firmware ist %u.%u.%u.\n"
"Aktualisiere Atmosphere, bevor du diese Firmware installierst.",
(max_supported_hos_version >> 24) & 0xff, (max_supported_hos_version >> 16) & 0xff, (max_supported_hos_version >> 8) & 0xff);
}
operator const char *() const {
return this->value;
}
};
}
FirmwareNotSupportedMenu::FirmwareNotSupportedMenu(std::shared_ptr<Menu> prev_menu, u32 update_ncm_version, u32 max_supported_hos_version)
: AlertMenu(prev_menu, "Nicht unterstützte Firmware-Version", FirmwareNotSupportedSubtext(update_ncm_version, max_supported_hos_version), 0) {
const float window_height = WindowHeight + SubTextAreaHeight;
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
const float y = g_screen_height / 2.0f - window_height / 2.0f;
const float button_y = y + TitleGap + SubTextAreaHeight + VerticalGap * 2.0f;
const float button_width = WindowWidth - HorizontalInset * 2.0f;
this->AddButton(BackButtonId, "Zurück", x + HorizontalInset, button_y, button_width, ButtonHeight);
this->SetButtonSelected(BackButtonId, true);
}
void FirmwareNotSupportedMenu::Draw(NVGcontext *vg, u64 ns) {
const float window_height = WindowHeight + SubTextAreaHeight;
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
const float y = g_screen_height / 2.0f - window_height / 2.0f;
DrawWindow(vg, m_text, x, y, WindowWidth, window_height);
DrawTextBlock(vg, m_subtext, x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2.0f, SubTextAreaHeight);
this->DrawButtons(vg, ns);
}
void FirmwareNotSupportedMenu::Update(u64 ns) {
u64 k_down = padGetButtonsDown(&g_pad);
if (k_down & HidNpadButton_B) {
ReturnToPreviousMenu();
return;
}
if (const Button *activated_button = this->GetActivatedButton(); activated_button != nullptr) {
if (activated_button->id == BackButtonId) {
ReturnToPreviousMenu();
return;
}
}
this->UpdateButtons();
if (const Button *selected_button = this->GetSelectedButton(); k_down && selected_button == nullptr) {
this->SetButtonSelected(BackButtonId, true);
}
}
MainMenu::MainMenu() : Menu(nullptr) { MainMenu::MainMenu() : Menu(nullptr) {
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f; const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
this->AddButton(InstallButtonId, "Install", x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2, ButtonHeight); this->AddButton(InstallButtonId, "Installieren", x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2, ButtonHeight);
this->AddButton(ExitButtonId, "Exit", x + HorizontalInset, y + TitleGap + ButtonHeight + VerticalGap, WindowWidth - HorizontalInset * 2, ButtonHeight); this->AddButton(ExitButtonId, "Beenden", x + HorizontalInset, y + TitleGap + ButtonHeight + VerticalGap, WindowWidth - HorizontalInset * 2, ButtonHeight);
this->SetButtonSelected(InstallButtonId, true); this->SetButtonSelected(InstallButtonId, true);
} }
@@ -475,24 +561,24 @@ namespace dbk {
u64 is_emummc; u64 is_emummc;
if (R_FAILED(rc = splGetConfig(SplConfigItem_HardwareType, &hardware_type))) { if (R_FAILED(rc = splGetConfig(SplConfigItem_HardwareType, &hardware_type))) {
ChangeMenu(std::make_shared<ErrorMenu>("An error has occurred", "Failed to get hardware type.", rc)); ChangeMenu(std::make_shared<ErrorMenu>("Ein Fehler ist aufgetreten", "Hardwaretyp konnte nicht ermittelt werden.", rc));
return; return;
} }
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereHasRcmBugPatch), &has_rcm_bug_patch))) { if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereHasRcmBugPatch), &has_rcm_bug_patch))) {
ChangeMenu(std::make_shared<ErrorMenu>("An error has occurred", "Failed to check RCM bug status.", rc)); ChangeMenu(std::make_shared<ErrorMenu>("Ein Fehler ist aufgetreten", "RCM-Bug-Status konnte nicht geprüft werden.", rc));
return; return;
} }
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereEmummcType), &is_emummc))) { if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereEmummcType), &is_emummc))) {
ChangeMenu(std::make_shared<ErrorMenu>("An error has occurred", "Failed to check emuMMC status.", rc)); ChangeMenu(std::make_shared<ErrorMenu>("Ein Fehler ist aufgetreten", "emuMMC-Status konnte nicht geprüft werden.", rc));
return; return;
} }
/* Warn if we're working with a patched unit. */ /* Warn if we're working with a patched unit. */
const bool is_erista = hardware_type == 0 || hardware_type == 1; const bool is_erista = hardware_type == 0 || hardware_type == 1;
if (is_erista && has_rcm_bug_patch && !is_emummc) { if (is_erista && has_rcm_bug_patch && !is_emummc) {
ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, file_menu, "Warning: Patched unit detected", "You may burn fuses or render your switch inoperable.")); ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, file_menu, "Warnung: Gepatchte Konsole erkannt", "Sicherungen können durchgebrannt werden oder die Konsole unbrauchbar gemacht werden."));
} else { } else {
ChangeMenu(file_menu); ChangeMenu(file_menu);
} }
@@ -688,7 +774,7 @@ namespace dbk {
snprintf(g_update_path, sizeof(g_update_path), "%s", current_path); snprintf(g_update_path, sizeof(g_update_path), "%s", current_path);
/* Change the menu. */ /* Change the menu. */
ChangeMenu(std::make_shared<ValidateUpdateMenu>(g_current_menu)); ChangeMenu(CreateUpdateMenuAfterPathSelection(g_current_menu));
} else { } else {
ChangeMenu(std::make_shared<FileMenu>(g_current_menu, current_path)); ChangeMenu(std::make_shared<FileMenu>(g_current_menu, current_path));
} }
@@ -739,7 +825,7 @@ namespace dbk {
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f; const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
DrawWindow(vg, "Select an update directory", x, y, WindowWidth, WindowHeight); DrawWindow(vg, "Update-Ordner auswählen", x, y, WindowWidth, WindowHeight);
DrawTextBackground(vg, x + TextBackgroundOffset, y + TitleGap, WindowWidth - TextBackgroundOffset * 2.0f, (FileRowHeight + FileRowGap) * MaxFileRows + FileRowGap); DrawTextBackground(vg, x + TextBackgroundOffset, y + TitleGap, WindowWidth - TextBackgroundOffset * 2.0f, (FileRowHeight + FileRowGap) * MaxFileRows + FileRowGap);
nvgSave(vg); nvgSave(vg);
@@ -765,8 +851,8 @@ namespace dbk {
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap; const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
/* Add buttons. */ /* Add buttons. */
this->AddButton(BackButtonId, "Back", x + HorizontalInset, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight); this->AddButton(BackButtonId, "Zurück", x + HorizontalInset, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight);
this->AddButton(ContinueButtonId, "Continue", x + HorizontalInset + button_width + ButtonHorizontalGap, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight); this->AddButton(ContinueButtonId, "Weiter", x + HorizontalInset + button_width + ButtonHorizontalGap, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight);
this->SetButtonEnabled(BackButtonId, false); this->SetButtonEnabled(BackButtonId, false);
this->SetButtonEnabled(ContinueButtonId, false); this->SetButtonEnabled(ContinueButtonId, false);
@@ -776,32 +862,33 @@ namespace dbk {
this->SetButtonSelected(BackButtonId, true); this->SetButtonSelected(BackButtonId, true);
} else { } else {
/* Log this early so it is printed out before validation causes stalling. */ /* Log this early so it is printed out before validation causes stalling. */
this->LogText("Validating update, this may take a moment...\n"); this->LogText("Update wird geprüft, bitte warten...\n");
} }
} }
Result ValidateUpdateMenu::GetUpdateInformation() { Result ValidateUpdateMenu::GetUpdateInformation() {
Result rc = 0; Result rc = 0;
this->LogText("Directory %s\n", g_update_path); this->LogText("Verzeichnis %s\n", g_update_path);
/* Attempt to get the update information. */ /* Attempt to get the update information. */
if (R_FAILED(rc = amssuGetUpdateInformation(&m_update_info, g_update_path))) { if (R_FAILED(rc = amssuGetUpdateInformation(&m_update_info, g_update_path))) {
if (rc == 0x1a405) { if (rc == 0x1a405) {
this->LogText("No update found in folder.\nEnsure your ncas are named correctly!\nResult: 0x%08x\n", rc); this->LogText("Kein Update im Ordner gefunden.\nStelle sicher, dass die NCAs korrekt benannt sind!\nErgebnis: 0x%08x\n", rc);
} else { } else {
this->LogText("Failed to get update information.\nResult: 0x%08x\n", rc); this->LogText("Update-Informationen konnten nicht abgerufen werden.\nErgebnis: 0x%08x\n", rc);
} }
return rc; return rc;
} }
/* Print update information. */ /* Print update information. */
this->LogText("- Version: %d.%d.%d\n", (m_update_info.version >> 26) & 0x1f, (m_update_info.version >> 20) & 0x1f, (m_update_info.version >> 16) & 0xf); this->LogText("- Version: %d.%d.%d\n", (m_update_info.version >> 26) & 0x1f, (m_update_info.version >> 20) & 0x1f, (m_update_info.version >> 16) & 0xf);
this->LogText("- Von Atmosphere max. unterstützt: %d.%d.%d\n", (g_supported_version >> 24) & 0xff, (g_supported_version >> 16) & 0xff, (g_supported_version >> 8) & 0xff);
if (m_update_info.exfat_supported) { if (m_update_info.exfat_supported) {
this->LogText("- exFAT: Supported\n"); this->LogText("- exFAT: Unterstützt\n");
} else { } else {
this->LogText("- exFAT: Unsupported\n"); this->LogText("- exFAT: Nicht unterstützt\n");
} }
this->LogText("- Firmware variations: %d\n", m_update_info.num_firmware_variations); this->LogText("- Firmware-Varianten: %d\n", m_update_info.num_firmware_variations);
/* Mark as having obtained update info. */ /* Mark as having obtained update info. */
m_has_info = true; m_has_info = true;
@@ -813,21 +900,21 @@ namespace dbk {
/* Validate the update. */ /* Validate the update. */
if (R_FAILED(rc = amssuValidateUpdate(&m_validation_info, g_update_path))) { if (R_FAILED(rc = amssuValidateUpdate(&m_validation_info, g_update_path))) {
this->LogText("Failed to validate update.\nResult: 0x%08x\n", rc); this->LogText("Update konnte nicht validiert werden.\nErgebnis: 0x%08x\n", rc);
return; return;
} }
/* Check the result. */ /* Check the result. */
if (R_SUCCEEDED(m_validation_info.result)) { if (R_SUCCEEDED(m_validation_info.result)) {
this->LogText("Update is valid!\n"); this->LogText("Update ist gültig!\n");
if (R_FAILED(m_validation_info.exfat_result)) { if (R_FAILED(m_validation_info.exfat_result)) {
const u32 version = m_validation_info.invalid_key.version; const u32 version = m_validation_info.invalid_key.version;
this->LogText("exFAT Validation failed with result: 0x%08x\n", m_validation_info.exfat_result); this->LogText("exFAT-Validierung fehlgeschlagen, Ergebnis: 0x%08x\n", m_validation_info.exfat_result);
this->LogText("Missing content:\n- Program id: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf); this->LogText("Fehlender Inhalt:\n- Programm-ID: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf);
/* Log the missing content id. */ /* Log the missing content id. */
this->LogText("- Content id: "); this->LogText("- Inhalts-ID: ");
for (size_t i = 0; i < sizeof(NcmContentId); i++) { for (size_t i = 0; i < sizeof(NcmContentId); i++) {
this->LogText("%02x", m_validation_info.invalid_content_id.c[i]); this->LogText("%02x", m_validation_info.invalid_content_id.c[i]);
} }
@@ -841,11 +928,11 @@ namespace dbk {
} else { } else {
/* Log the missing content info. */ /* Log the missing content info. */
const u32 version = m_validation_info.invalid_key.version; const u32 version = m_validation_info.invalid_key.version;
this->LogText("Validation failed with result: 0x%08x\n", m_validation_info.result); this->LogText("Validierung fehlgeschlagen, Ergebnis: 0x%08x\n", m_validation_info.result);
this->LogText("Missing content:\n- Program id: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf); this->LogText("Fehlender Inhalt:\n- Programm-ID: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf);
/* Log the missing content id. */ /* Log the missing content id. */
this->LogText("- Content id: "); this->LogText("- Inhalts-ID: ");
for (size_t i = 0; i < sizeof(NcmContentId); i++) { for (size_t i = 0; i < sizeof(NcmContentId); i++) {
this->LogText("%02x", m_validation_info.invalid_content_id.c[i]); this->LogText("%02x", m_validation_info.invalid_content_id.c[i]);
} }
@@ -897,13 +984,7 @@ namespace dbk {
/* Warn the user if they're updating with exFAT supposed to be supported but not present/corrupted. */ /* Warn the user if they're updating with exFAT supposed to be supported but not present/corrupted. */
if (m_update_info.exfat_supported && R_FAILED(m_validation_info.exfat_result)) { if (m_update_info.exfat_supported && R_FAILED(m_validation_info.exfat_result)) {
next_menu = std::make_shared<WarningMenu>(g_current_menu, next_menu, "Warning: exFAT firmware is missing or corrupt", "Are you sure you want to proceed?"); next_menu = std::make_shared<WarningMenu>(g_current_menu, next_menu, "Warnung: exFAT-Firmware fehlt oder ist beschädigt", "Möchtest du wirklich fortfahren?");
}
/* Warn the user if they're updating to a version higher than supported. */
const u32 version = m_validation_info.invalid_key.version;
if (EncodeVersion((version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf) > g_supported_version) {
next_menu = std::make_shared<WarningMenu>(g_current_menu, next_menu, "Warning: firmware is too new and not known to be supported", "Are you sure you want to proceed?");
} }
/* Change to the next menu. */ /* Change to the next menu. */
@@ -919,7 +1000,7 @@ namespace dbk {
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f; const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
DrawWindow(vg, "Update information", x, y, WindowWidth, WindowHeight); DrawWindow(vg, "Update-Informationen", x, y, WindowWidth, WindowHeight);
DrawTextBackground(vg, x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2.0f, TextAreaHeight); DrawTextBackground(vg, x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2.0f, TextAreaHeight);
DrawTextBlock(vg, m_log_buffer, x + HorizontalInset + TextHorizontalInset, y + TitleGap + TextVerticalInset, WindowWidth - (HorizontalInset + TextHorizontalInset) * 2.0f, TextAreaHeight - TextVerticalInset * 2.0f); DrawTextBlock(vg, m_log_buffer, x + HorizontalInset + TextHorizontalInset, y + TitleGap + TextVerticalInset, WindowWidth - (HorizontalInset + TextHorizontalInset) * 2.0f, TextAreaHeight - TextVerticalInset * 2.0f);
@@ -933,8 +1014,8 @@ namespace dbk {
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap; const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
/* Add buttons. */ /* Add buttons. */
this->AddButton(ResetToFactorySettingsButtonId, "Reset to factory settings", x + HorizontalInset, y + TitleGap, button_width, ButtonHeight); this->AddButton(ResetToFactorySettingsButtonId, "Werkseinstellungen", x + HorizontalInset, y + TitleGap, button_width, ButtonHeight);
this->AddButton(PreserveSettingsButtonId, "Preserve settings", x + HorizontalInset + button_width + ButtonHorizontalGap, y + TitleGap, button_width, ButtonHeight); this->AddButton(PreserveSettingsButtonId, "Einstellungen behalten", x + HorizontalInset + button_width + ButtonHorizontalGap, y + TitleGap, button_width, ButtonHeight);
this->SetButtonSelected(PreserveSettingsButtonId, true); this->SetButtonSelected(PreserveSettingsButtonId, true);
} }
@@ -963,11 +1044,11 @@ namespace dbk {
if (g_exfat_supported) { if (g_exfat_supported) {
next_menu = std::make_shared<ChooseExfatMenu>(g_current_menu); next_menu = std::make_shared<ChooseExfatMenu>(g_current_menu);
} else { } else {
next_menu = std::make_shared<WarningMenu>(g_current_menu, std::make_shared<InstallUpdateMenu>(g_current_menu), "Ready to begin update installation", "Are you sure you want to proceed?"); next_menu = std::make_shared<WarningMenu>(g_current_menu, std::make_shared<InstallUpdateMenu>(g_current_menu), "Bereit zur Update-Installation", "Möchtest du wirklich fortfahren?");
} }
if (g_reset_to_factory) { if (g_reset_to_factory) {
ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, next_menu, "Warning: Factory reset selected", "Saves and installed games will be permanently deleted.")); ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, next_menu, "Warnung: Werkseinstellungen ausgewählt", "Spielstände und installierte Spiele werden dauerhaft gelöscht."));
} else { } else {
ChangeMenu(next_menu); ChangeMenu(next_menu);
} }
@@ -985,7 +1066,7 @@ namespace dbk {
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f; const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
DrawWindow(vg, "Select settings mode", x, y, WindowWidth, WindowHeight); DrawWindow(vg, "Einstellungsmodus wählen", x, y, WindowWidth, WindowHeight);
this->DrawButtons(vg, ns); this->DrawButtons(vg, ns);
} }
@@ -1029,7 +1110,7 @@ namespace dbk {
break; break;
} }
ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, std::make_shared<InstallUpdateMenu>(g_current_menu), "Ready to begin update installation", "Are you sure you want to proceed?")); ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, std::make_shared<InstallUpdateMenu>(g_current_menu), "Bereit zur Update-Installation", "Möchtest du wirklich fortfahren?"));
} }
this->UpdateButtons(); this->UpdateButtons();
@@ -1044,7 +1125,7 @@ namespace dbk {
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f; const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
DrawWindow(vg, "Select driver variant", x, y, WindowWidth, WindowHeight); DrawWindow(vg, "Treibervariante wählen", x, y, WindowWidth, WindowHeight);
this->DrawButtons(vg, ns); this->DrawButtons(vg, ns);
} }
@@ -1054,8 +1135,8 @@ namespace dbk {
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap; const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
/* Add buttons. */ /* Add buttons. */
this->AddButton(ShutdownButtonId, "Shutdown", x + HorizontalInset, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight); this->AddButton(ShutdownButtonId, "Ausschalten", x + HorizontalInset, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight);
this->AddButton(RebootButtonId, "Reboot", x + HorizontalInset + button_width + ButtonHorizontalGap, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight); this->AddButton(RebootButtonId, "Neustart", x + HorizontalInset + button_width + ButtonHorizontalGap, y + WindowHeight - BottomInset - ButtonHeight, button_width, ButtonHeight);
this->SetButtonEnabled(ShutdownButtonId, false); this->SetButtonEnabled(ShutdownButtonId, false);
this->SetButtonEnabled(RebootButtonId, false); this->SetButtonEnabled(RebootButtonId, false);
@@ -1075,34 +1156,34 @@ namespace dbk {
if (m_install_state == InstallState::NeedsSetup) { if (m_install_state == InstallState::NeedsSetup) {
/* Setup the update. */ /* Setup the update. */
if (R_FAILED(rc = amssuSetupUpdate(nullptr, UpdateTaskBufferSize, g_update_path, g_use_exfat))) { if (R_FAILED(rc = amssuSetupUpdate(nullptr, UpdateTaskBufferSize, g_update_path, g_use_exfat))) {
this->LogText("Failed to setup update.\nResult: 0x%08x\n", rc); this->LogText("Update-Einrichtung fehlgeschlagen.\nErgebnis: 0x%08x\n", rc);
this->MarkForReboot(); this->MarkForReboot();
return rc; return rc;
} }
/* Log setup completion. */ /* Log setup completion. */
this->LogText("Update setup complete.\n"); this->LogText("Update-Einrichtung abgeschlossen.\n");
m_install_state = InstallState::NeedsPrepare; m_install_state = InstallState::NeedsPrepare;
} else if (m_install_state == InstallState::NeedsPrepare) { } else if (m_install_state == InstallState::NeedsPrepare) {
/* Request update preparation. */ /* Request update preparation. */
if (R_FAILED(rc = amssuRequestPrepareUpdate(&m_prepare_result))) { if (R_FAILED(rc = amssuRequestPrepareUpdate(&m_prepare_result))) {
this->LogText("Failed to request update preparation.\nResult: 0x%08x\n", rc); this->LogText("Update-Vorbereitung konnte nicht angefordert werden.\nErgebnis: 0x%08x\n", rc);
this->MarkForReboot(); this->MarkForReboot();
return rc; return rc;
} }
/* Log awaiting prepare. */ /* Log awaiting prepare. */
this->LogText("Preparing update...\n"); this->LogText("Update wird vorbereitet...\n");
m_install_state = InstallState::AwaitingPrepare; m_install_state = InstallState::AwaitingPrepare;
} else if (m_install_state == InstallState::AwaitingPrepare) { } else if (m_install_state == InstallState::AwaitingPrepare) {
/* Check if preparation has a result. */ /* Check if preparation has a result. */
if (R_FAILED(rc = asyncResultWait(&m_prepare_result, 0)) && rc != 0xea01) { if (R_FAILED(rc = asyncResultWait(&m_prepare_result, 0)) && rc != 0xea01) {
this->LogText("Failed to check update preparation result.\nResult: 0x%08x\n", rc); this->LogText("Ergebnis der Update-Vorbereitung konnte nicht geprüft werden.\nErgebnis: 0x%08x\n", rc);
this->MarkForReboot(); this->MarkForReboot();
return rc; return rc;
} else if (R_SUCCEEDED(rc)) { } else if (R_SUCCEEDED(rc)) {
if (R_FAILED(rc = asyncResultGet(&m_prepare_result))) { if (R_FAILED(rc = asyncResultGet(&m_prepare_result))) {
this->LogText("Failed to prepare update.\nResult: 0x%08x\n", rc); this->LogText("Update konnte nicht vorbereitet werden.\nErgebnis: 0x%08x\n", rc);
this->MarkForReboot(); this->MarkForReboot();
return rc; return rc;
} }
@@ -1111,14 +1192,14 @@ namespace dbk {
/* Check if the update has been prepared. */ /* Check if the update has been prepared. */
bool prepared; bool prepared;
if (R_FAILED(rc = amssuHasPreparedUpdate(&prepared))) { if (R_FAILED(rc = amssuHasPreparedUpdate(&prepared))) {
this->LogText("Failed to check if update has been prepared.\nResult: 0x%08x\n", rc); this->LogText("Prüfung, ob das Update vorbereitet wurde, fehlgeschlagen.\nErgebnis: 0x%08x\n", rc);
this->MarkForReboot(); this->MarkForReboot();
return rc; return rc;
} }
/* Mark for application if preparation complete. */ /* Mark for application if preparation complete. */
if (prepared) { if (prepared) {
this->LogText("Update preparation complete.\nApplying update...\n"); this->LogText("Update-Vorbereitung abgeschlossen.\nUpdate wird angewendet...\n");
m_install_state = InstallState::NeedsApply; m_install_state = InstallState::NeedsApply;
return rc; return rc;
} }
@@ -1126,7 +1207,7 @@ namespace dbk {
/* Check update progress. */ /* Check update progress. */
NsSystemUpdateProgress update_progress = {}; NsSystemUpdateProgress update_progress = {};
if (R_FAILED(rc = amssuGetPrepareUpdateProgress(&update_progress))) { if (R_FAILED(rc = amssuGetPrepareUpdateProgress(&update_progress))) {
this->LogText("Failed to check update progress.\nResult: 0x%08x\n", rc); this->LogText("Update-Fortschritt konnte nicht geprüft werden.\nErgebnis: 0x%08x\n", rc);
this->MarkForReboot(); this->MarkForReboot();
return rc; return rc;
} }
@@ -1140,28 +1221,28 @@ namespace dbk {
} else if (m_install_state == InstallState::NeedsApply) { } else if (m_install_state == InstallState::NeedsApply) {
/* Apply the prepared update. */ /* Apply the prepared update. */
if (R_FAILED(rc = amssuApplyPreparedUpdate())) { if (R_FAILED(rc = amssuApplyPreparedUpdate())) {
this->LogText("Failed to apply update.\nResult: 0x%08x\n", rc); this->LogText("Update konnte nicht angewendet werden.\nErgebnis: 0x%08x\n", rc);
} else { } else {
/* Log success. */ /* Log success. */
this->LogText("Update applied successfully.\n"); this->LogText("Update erfolgreich angewendet.\n");
if (g_reset_to_factory) { if (g_reset_to_factory) {
if (R_FAILED(rc = nsResetToFactorySettingsForRefurbishment())) { if (R_FAILED(rc = nsResetToFactorySettingsForRefurbishment())) {
/* Fallback on ResetToFactorySettings. */ /* Fallback on ResetToFactorySettings. */
if (rc == MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer)) { if (rc == MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer)) {
if (R_FAILED(rc = nsResetToFactorySettings())) { if (R_FAILED(rc = nsResetToFactorySettings())) {
this->LogText("Failed to reset to factory settings.\nResult: 0x%08x\n", rc); this->LogText("Zurücksetzen auf Werkseinstellungen fehlgeschlagen.\nErgebnis: 0x%08x\n", rc);
this->MarkForReboot(); this->MarkForReboot();
return rc; return rc;
} }
} else { } else {
this->LogText("Failed to reset to factory settings for refurbishment.\nResult: 0x%08x\n", rc); this->LogText("Zurücksetzen für Aufbereitung fehlgeschlagen.\nErgebnis: 0x%08x\n", rc);
this->MarkForReboot(); this->MarkForReboot();
return rc; return rc;
} }
} }
this->LogText("Successfully reset to factory settings.\n", rc); this->LogText("Erfolgreich auf Werkseinstellungen zurückgesetzt.\n", rc);
} }
} }
@@ -1201,7 +1282,7 @@ namespace dbk {
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f; const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f; const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
DrawWindow(vg, "Installing update", x, y, WindowWidth, WindowHeight); DrawWindow(vg, "Update wird installiert", x, y, WindowWidth, WindowHeight);
DrawProgressText(vg, x + HorizontalInset, y + TitleGap, m_progress_percent); DrawProgressText(vg, x + HorizontalInset, y + TitleGap, m_progress_percent);
DrawProgressBar(vg, x + HorizontalInset, y + TitleGap + ProgressTextHeight, WindowWidth - HorizontalInset * 2.0f, ProgressBarHeight, m_progress_percent); DrawProgressBar(vg, x + HorizontalInset, y + TitleGap + ProgressTextHeight, WindowWidth - HorizontalInset * 2.0f, ProgressBarHeight, m_progress_percent);
DrawTextBackground(vg, x + HorizontalInset, y + TitleGap + ProgressTextHeight + ProgressBarHeight + VerticalGap, WindowWidth - HorizontalInset * 2.0f, TextAreaHeight); DrawTextBackground(vg, x + HorizontalInset, y + TitleGap + ProgressTextHeight + ProgressBarHeight + VerticalGap, WindowWidth - HorizontalInset * 2.0f, TextAreaHeight);
@@ -1211,7 +1292,7 @@ namespace dbk {
/* We have drawn now, allow setup to occur. */ /* We have drawn now, allow setup to occur. */
if (m_install_state == InstallState::NeedsDraw) { if (m_install_state == InstallState::NeedsDraw) {
this->LogText("Beginning update setup...\n"); this->LogText("Update-Einrichtung wird gestartet...\n");
m_install_state = InstallState::NeedsSetup; m_install_state = InstallState::NeedsSetup;
} }
} }
@@ -1236,7 +1317,7 @@ namespace dbk {
/* Attempt to get the exosphere version. */ /* Attempt to get the exosphere version. */
u64 version; u64 version;
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereApiVersionConfigItem), &version))) { if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereApiVersionConfigItem), &version))) {
ChangeMenu(std::make_shared<ErrorMenu>("Atmosphere not found", "Daybreak requires Atmosphere to be installed.", rc)); ChangeMenu(std::make_shared<ErrorMenu>("Atmosphere nicht gefunden", "Daybreak benötigt eine installierte Atmosphere-Umgebung.", rc));
return false; return false;
} }
@@ -1247,20 +1328,22 @@ namespace dbk {
/* Validate the exosphere version. */ /* Validate the exosphere version. */
const bool ams_supports_sysupdate_api = EncodeVersion(version_major, version_minor, version_micro) >= EncodeVersion(0, 14, 0); const bool ams_supports_sysupdate_api = EncodeVersion(version_major, version_minor, version_micro) >= EncodeVersion(0, 14, 0);
if (!ams_supports_sysupdate_api) { if (!ams_supports_sysupdate_api) {
ChangeMenu(std::make_shared<ErrorMenu>("Outdated Atmosphere version", "Daybreak requires Atmosphere 0.14.0 or later.", rc)); ChangeMenu(std::make_shared<ErrorMenu>("Veraltete Atmosphere-Version", "Daybreak benötigt Atmosphere 0.14.0 oder neuer.", rc));
return false; return false;
} }
/* Ensure DayBreak is ran as a NRO. */ /* Ensure DayBreak is ran as a NRO. */
if (envIsNso()) { if (envIsNso()) {
ChangeMenu(std::make_shared<ErrorMenu>("Unsupported Environment", "Please launch Daybreak via the Homebrew menu.", rc)); ChangeMenu(std::make_shared<ErrorMenu>("Nicht unterstützte Umgebung", "Bitte starte Daybreak über das Homebrew-Menü.", rc));
return false; return false;
} }
/* Attempt to get the supported version. */ /* Get the maximum HOS version supported by this Atmosphere build (hos::Version_Max). */
if (R_SUCCEEDED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereSupportedHosVersion), &version))) { if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereSupportedHosVersion), &version))) {
g_supported_version = static_cast<u32>(version); ChangeMenu(std::make_shared<ErrorMenu>("Atmosphere nicht gefunden", "Maximal unterstützte Firmware-Version konnte nicht ermittelt werden.", rc));
return false;
} }
g_supported_version = static_cast<u32>(version);
/* Initialize ams:su. */ /* Initialize ams:su. */
if (R_FAILED(rc = amssuInitialize())) { if (R_FAILED(rc = amssuInitialize())) {
@@ -1280,7 +1363,7 @@ namespace dbk {
strncpy(g_update_path, update_path, sizeof(g_update_path)-1); strncpy(g_update_path, update_path, sizeof(g_update_path)-1);
/* Change the menu. */ /* Change the menu. */
ChangeMenu(std::make_shared<ValidateUpdateMenu>(g_current_menu)); ChangeMenu(CreateUpdateMenuAfterPathSelection(g_current_menu));
return true; return true;
} }

View File

@@ -120,6 +120,17 @@ namespace dbk {
virtual void Update(u64 ns) override; virtual void Update(u64 ns) override;
}; };
class FirmwareNotSupportedMenu : public AlertMenu {
private:
static constexpr u32 BackButtonId = 0;
static constexpr float SubTextAreaHeight = 72.0f;
public:
FirmwareNotSupportedMenu(std::shared_ptr<Menu> prev_menu, u32 update_ncm_version, u32 max_supported_hos_version);
virtual void Update(u64 ns) override;
virtual void Draw(NVGcontext *vg, u64 ns) override;
};
class MainMenu : public Menu { class MainMenu : public Menu {
private: private:
static constexpr u32 InstallButtonId = 0; static constexpr u32 InstallButtonId = 0;

View File

@@ -148,7 +148,7 @@ namespace dbk {
void DrawProgressText(NVGcontext *vg, float x, float y, float progress) { void DrawProgressText(NVGcontext *vg, float x, float y, float progress) {
char progress_text[32] = {}; char progress_text[32] = {};
snprintf(progress_text, sizeof(progress_text)-1, "%d%% complete", static_cast<int>(progress * 100.0f)); snprintf(progress_text, sizeof(progress_text)-1, "%d%% abgeschlossen", static_cast<int>(progress * 100.0f));
nvgFontSize(vg, 24.0f); nvgFontSize(vg, 24.0f);
nvgFontFace(vg, SwitchStandardFont); nvgFontFace(vg, SwitchStandardFont);

View File

@@ -344,7 +344,7 @@ def get_full(nxo):
full = put_qword(full, offset, addend + LOAD_BASE) full = put_qword(full, offset, addend + LOAD_BASE)
else: else:
print('TODO r_type %d' % (r_type,)) print('TODO r_type %d' % (r_type,))
with open('E:\\full.bin', 'wb') as f: with open('full.bin', 'wb') as f:
f.write(full) f.write(full)
return full return full
@@ -415,10 +415,14 @@ def find_types(full, num_fields):
KNOWN = range(10) + [4, 4, 2, 4] KNOWN = range(10) + [4, 4, 2, 4]
KNOWN_OLD = range(10) + [4, 4, 0, 4] KNOWN_OLD = range(10) + [4, 4, 0, 4]
try: try:
ind = full.index(''.join(pk('<I', i) for i in KNOWN)) ind = full.index(''.join(pk('<B', i) for i in KNOWN))
return list(up('<'+'B'*num_fields, full[ind:ind+num_fields]))
except ValueError: except ValueError:
ind = full.index(''.join(pk('<I', i) for i in KNOWN_OLD)) try:
return list(up('<'+'I'*num_fields, full[ind:ind+4*num_fields])) ind = full.index(''.join(pk('<I', i) for i in KNOWN))
except ValueError:
ind = full.index(''.join(pk('<I', i) for i in KNOWN_OLD))
return list(up('<'+'I'*num_fields, full[ind:ind+4*num_fields]))
def find_flags(full, num_fields, magic_idx): def find_flags(full, num_fields, magic_idx):
KNOWN = '\x00' + ('\x01'*6) + '\x00\x01\x01\x00' KNOWN = '\x00' + ('\x01'*6) + '\x00\x01\x01\x00'