Compare commits

..

29 Commits

Author SHA1 Message Date
26b1ec7ca8 Merge upstream Atmosphere-NX/Atmosphere master 2026-07-17 12:07:12 +02:00
hexkyz
3ace80cc7b loader/util: support regular zstd alongside zbic 2026-06-24 22:08:13 +01:00
hexkyz
10722de8b9 Merge pull request #2817 from alula/fix-zbic-games
Fix zbic games + misc changes
2026-06-24 20:32:18 +01:00
Alula
59846adcb7 ams: fix a copy paste mistake in makefile 2026-06-24 21:01:43 +02:00
Alula
94e62a7b1b loader: add non-release build debug logging 2026-06-24 20:54:42 +02:00
Alula
fbeea26919 ams: add R_UNLESS_LOG() 2026-06-24 20:51:39 +02:00
Alula
38251801df loader/strat: fix/refactor zstd-zbic integration 2026-06-24 20:50:41 +02:00
Alula
7b6ee4916e pinmux: use the actual option definitions instead of magic numbers 2026-06-24 20:46:23 +02:00
Alula
556e628478 ams: add dist-no-debug targets to main makefile 2026-06-23 16:10:39 +02:00
hexkyz
5388824be1 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "d3083af18"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "d3083af18"
git-subrepo:
  version:  "0.4.9"
  origin:   "???"
  commit:   "???"
2026-06-16 22:11:17 +01:00
hexkyz
974a1025b8 erpt: add new ID for 22.5.0 2026-06-16 22:10:07 +01:00
hexkyz
9d21cfca4c git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "f6b3a28ec"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "f6b3a28ec"
git-subrepo:
  version:  "0.4.9"
  origin:   "???"
  commit:   "???"
2026-06-16 21:21:53 +01:00
hexkyz
1478f3443e emummc: update readme for 22.5.0 2026-06-16 21:21:24 +01:00
hexkyz
f527e7fc48 git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "24946ac76"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "24946ac76"
git-subrepo:
  version:  "0.4.9"
  origin:   "???"
  commit:   "???"
2026-06-16 21:17:37 +01:00
hexkyz
7dccf3bffa git subrepo pull (merge) emummc
subrepo:
  subdir:   "emummc"
  merged:   "6cecd09b2"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "bde9957f1"
git-subrepo:
  version:  "0.4.9"
  origin:   "???"
  commit:   "???"
2026-06-16 21:17:11 +01:00
hexkyz
4ea042510b git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "e4100b5f5"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "e4100b5f5"
git-subrepo:
  version:  "0.4.9"
  origin:   "???"
  commit:   "???"
2026-06-16 21:15:53 +01:00
hexkyz
d97f520058 docs: add gcc16 to changelog 2026-06-16 21:12:42 +01:00
hexkyz
3a3a2ca99b ams: basic support for compiling with gcc 16 2026-06-16 21:10:23 +01:00
hexkyz
fcd46b4419 docs: add changelog for 1.11.2 2026-06-16 19:32:59 +01:00
hexkyz
c046eeacdd meso: fix longstanding bad asm copy-paste 2026-06-16 19:22:54 +01:00
hexkyz
4181169f80 emummc: update for 22.5.0 2026-06-16 19:18:26 +01:00
hexkyz
47cfe05bb0 loader: update USB 3.0 patches for 22.5.0 2026-06-16 18:51:10 +01:00
hexkyz
c497ffda75 ams: add enum recognition for 22.5.0 2026-06-16 18:41:32 +01:00
hexkyz
15c434f185 Merge pull request #2811 from ZachyCatGames/patch-1
pgl: GetHostContentMetaInfo returns a ncm::ContentMetaType
2026-05-30 00:32:39 +01:00
Zachary Kirtz
7d38bf16cd pgl: GetHostContentMetaInfo returns a ncm::ContentMetaType 2026-05-29 01:16:11 -05:00
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
40 changed files with 728 additions and 327 deletions

View File

@@ -13,6 +13,10 @@ $(strip $1):
@echo "Building $(strip $1)"
@$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)
dist-no-debug-$(strip $1):
@echo "Building $(strip $1)"
@$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk dist-no-debug ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)
clean-$(strip $1):
@echo "Cleaning $(strip $1)"
@$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)

View File

@@ -54,7 +54,7 @@ dist: dist-no-debug
cp $(CURRENT_DIRECTORY)/troposphere/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf
cp $(CURRENT_DIRECTORY)/troposphere/haze/haze.elf $(DIST_DIR)/haze.elf
cp $(CURRENT_DIRECTORY)/troposphere/reboot_to_payload/reboot_to_payload.elf $(DIST_DIR)/reboot_to_payload.elf
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../;
cd $(DIST_DIR); zip -1 -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../;
rm -rf $(DIST_DIR)
dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)

View File

@@ -1,4 +1,11 @@
# Changelog
## 1.11.2
+ Basic support was added for 22.5.0.
+ Atmosphère was updated to use GCC 16/newlib (latest devkitA64/devkitARM releases).
+ General system stability improvements to enhance the user's experience.
## 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.

4
emummc/.gitrepo vendored
View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/m4xw/emummc
branch = develop
commit = 3726bfd659600cdafd138277054568a3edba60a6
parent = 80bd459516e813fc6f10268ca31dd72a053a4ef3
commit = f6b3a28ecea9834f96151a526de66abd11033b70
parent = 1478f3443e8f04534edac8c15bf2d504663d0384
method = merge
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***
### Supported Horizon Versions
**1.0.0 - 21.2.0**
**1.0.0 - 22.5.0**
## Features
* Arbitrary SDMMC backend selection

View File

@@ -85,6 +85,8 @@
#include "offsets/2120_exfat.h"
#include "offsets/2200.h"
#include "offsets/2200_exfat.h"
#include "offsets/2250.h"
#include "offsets/2250_exfat.h"
#include "../utils/fatal.h"
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
@@ -181,6 +183,8 @@ DEFINE_OFFSET_STRUCT(_2120);
DEFINE_OFFSET_STRUCT(_2120_EXFAT);
DEFINE_OFFSET_STRUCT(_2200);
DEFINE_OFFSET_STRUCT(_2200_EXFAT);
DEFINE_OFFSET_STRUCT(_2250);
DEFINE_OFFSET_STRUCT(_2250_EXFAT);
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
switch (version) {
@@ -322,6 +326,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
return &(GET_OFFSET_STRUCT_NAME(_2200));
case FS_VER_22_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_2200_EXFAT));
case FS_VER_22_5_0:
return &(GET_OFFSET_STRUCT_NAME(_2250));
case FS_VER_22_5_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_2250_EXFAT));
default:
fatal_abort(Fatal_UnknownVersion);
}

View File

@@ -124,6 +124,9 @@ enum FS_VER
FS_VER_22_0_0,
FS_VER_22_0_0_EXFAT,
FS_VER_22_5_0,
FS_VER_22_5_0_EXFAT,
FS_VER_MAX,
};

59
emummc/source/FS/offsets/2250.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_2250_H__
#define __FS_2250_H__
// Accessor vtable getters
#define FS_OFFSET_2250_SDMMC_ACCESSOR_GC 0x1B01C0
#define FS_OFFSET_2250_SDMMC_ACCESSOR_SD 0x1B21C0
#define FS_OFFSET_2250_SDMMC_ACCESSOR_NAND 0x1B07F0
// Hooks
#define FS_OFFSET_2250_SDMMC_WRAPPER_READ 0x1AC0F0
#define FS_OFFSET_2250_SDMMC_WRAPPER_WRITE 0x1AC150
#define FS_OFFSET_2250_RTLD 0x2DED0
#define FS_OFFSET_2250_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2250_CLKRST_SET_MIN_V_CLK_RATE 0x1CF260
// Misc funcs
#define FS_OFFSET_2250_LOCK_MUTEX 0x1A4EF0
#define FS_OFFSET_2250_UNLOCK_MUTEX 0x1A4F40
#define FS_OFFSET_2250_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1AC0B0
#define FS_OFFSET_2250_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1AC0D0
// Misc Data
#define FS_OFFSET_2250_SD_MUTEX 0xFF1408
#define FS_OFFSET_2250_NAND_MUTEX 0xFECD00
#define FS_OFFSET_2250_ACTIVE_PARTITION 0xFECD40
#define FS_OFFSET_2250_SDMMC_DAS_HANDLE 0xFCEB98
// NOPs
#define FS_OFFSET_2250_SD_DAS_INIT 0x2B438
// Nintendo Paths
#define FS_OFFSET_2250_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_2250_H__

59
emummc/source/FS/offsets/2250_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_2250_EXFAT_H__
#define __FS_2250_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_2250_EXFAT_SDMMC_ACCESSOR_GC 0x1BB3B0
#define FS_OFFSET_2250_EXFAT_SDMMC_ACCESSOR_SD 0x1BD3B0
#define FS_OFFSET_2250_EXFAT_SDMMC_ACCESSOR_NAND 0x1BB9E0
// Hooks
#define FS_OFFSET_2250_EXFAT_SDMMC_WRAPPER_READ 0x1B72E0
#define FS_OFFSET_2250_EXFAT_SDMMC_WRAPPER_WRITE 0x1B7340
#define FS_OFFSET_2250_EXFAT_RTLD 0x2DED0
#define FS_OFFSET_2250_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2250_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1DA450
// Misc funcs
#define FS_OFFSET_2250_EXFAT_LOCK_MUTEX 0x1B00E0
#define FS_OFFSET_2250_EXFAT_UNLOCK_MUTEX 0x1B0130
#define FS_OFFSET_2250_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1B72A0
#define FS_OFFSET_2250_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1B72C0
// Misc Data
#define FS_OFFSET_2250_EXFAT_SD_MUTEX 0x1002408
#define FS_OFFSET_2250_EXFAT_NAND_MUTEX 0xFFDD00
#define FS_OFFSET_2250_EXFAT_ACTIVE_PARTITION 0xFFDD40
#define FS_OFFSET_2250_EXFAT_SDMMC_DAS_HANDLE 0xFDBB98
// NOPs
#define FS_OFFSET_2250_EXFAT_SD_DAS_INIT 0x2B438
// Nintendo Paths
#define FS_OFFSET_2250_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_2250_EXFAT_H__

View File

@@ -194,6 +194,9 @@ namespace ams::nxboot {
FsVersion_22_0_0,
FsVersion_22_0_0_Exfat,
FsVersion_22_5_0,
FsVersion_22_5_0_Exfat,
FsVersion_Count,
};
@@ -302,6 +305,9 @@ namespace ams::nxboot {
{ 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 */
{ 0x53, 0x6D, 0x93, 0x84, 0x69, 0xFE, 0x73, 0xBE }, /* FsVersion_22_5_0 */
{ 0xD4, 0x45, 0x28, 0x29, 0x5B, 0x41, 0x92, 0xBA }, /* FsVersion_22_5_0_Exfat */
};
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
@@ -716,11 +722,13 @@ namespace ams::nxboot {
AddPatch(fs_meta, 0x18AD40, NogcPatch1, sizeof(NogcPatch1));
break;
case FsVersion_22_0_0:
case FsVersion_22_5_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:
case FsVersion_22_5_0_Exfat:
AddPatch(fs_meta, 0x1BB42D, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x1BB445, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x18E250, NogcPatch1, sizeof(NogcPatch1));

View File

@@ -1355,6 +1355,9 @@ namespace ams::nxboot {
uint32_t emc_zcal_wait_cnt_new = dst_timing->burst_regs.emc_zcal_wait_cnt;
emc_zcal_wait_cnt_old &= ~0x7ff;
emc_zcal_wait_cnt_new &= ~0x7ff;
/* TODO: Unused variable. */
AMS_UNUSED(emc_zcal_wait_cnt_old);
if (dram_type == DRAM_TYPE_LPDDR4) {
zq_wait_long = std::max<u32>(1, util::DivideUp(1000000, destination_clock_period));

View File

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

View File

@@ -104,7 +104,10 @@ namespace ams::se {
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 0) : 0;
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 1) : 0;
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 2) : 0;
/* TODO: Unused variable. */
AMS_UNUSED(value);
reg::Write(SE->SE_RSA_KEYTABLE_ACCESS[slot], SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYREAD, (flags & KeySlotLockFlags_KeyRead) != 0, DISABLE, ENABLE),
SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUPDATE, (flags & KeySlotLockFlags_KeyWrite) != 0, DISABLE, ENABLE),
SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUSE, (flags & KeySlotLockFlags_KeyUse) != 0, DISABLE, ENABLE));

View File

@@ -729,6 +729,9 @@ namespace ams::kern::arch::arm64 {
}
}
MESOSPHERE_ASSERT(mapped_pages == num_pages);
/* TODO: Unused variable. */
AMS_UNUSED(mapped_pages);
/* Perform what coalescing we can. */
this->MergePages(orig_virt_addr, num_pages, page_list);

View File

@@ -682,7 +682,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory32BitEPvPKvm:
mov x30, x10
/* Write the word to io. */
sttr w9, [x5]
sttr w9, [x4]
dsb sy
2: /* Continue. */
@@ -727,7 +727,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory16BitEPvPKvm:
mov x30, x10
/* Write the word to io. */
sttrh w9, [x5]
sttrh w9, [x4]
dsb sy
2: /* Continue. */
@@ -772,7 +772,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17WriteIoMemory8BitEPvPKvm:
mov x30, x10
/* Write the word to io. */
sttrb w9, [x5]
sttrb w9, [x4]
dsb sy
2: /* Continue. */

View File

@@ -756,11 +756,13 @@ namespace ams::kern {
case ams::svc::DebugException_UndefinedSystemCall:
{
MESOSPHERE_ASSERT(num_params >= 3);
info->info.exception.exception_address = params[1];
info->info.exception.exception_data_count = 1;
info->info.exception.exception_data[0] = params[2];
/* Keep the compiler happy, even though the assert has us covered. */
if (num_params >= 3) {
info->info.exception.exception_address = params[1];
info->info.exception.exception_data_count = 1;
info->info.exception.exception_data[0] = params[2];
}
}
break;
case ams::svc::DebugException_DebuggerAttached:
@@ -773,9 +775,12 @@ namespace ams::kern {
case ams::svc::DebugException_UserBreak:
{
MESOSPHERE_ASSERT(num_params >= 2);
info->info.exception.exception_address = params[1];
/* Keep the compiler happy, even though the assert has us covered. */
if (num_params >= 2) {
info->info.exception.exception_address = params[1];
}
info->info.exception.exception_data_count = 0;
for (size_t i = 2; i < num_params; ++i) {
info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i];
@@ -805,8 +810,11 @@ namespace ams::kern {
default:
{
MESOSPHERE_ASSERT(num_params >= 2);
info->info.exception.exception_address = params[1];
/* Keep the compiler happy, even though the assert has us covered. */
if (num_params >= 2) {
info->info.exception.exception_address = params[1];
}
}
break;
}

View File

@@ -979,6 +979,7 @@
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(SslProcessHeapAllocatable, 781, NetworkSecurityCertificateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(TestStringNx, 1000, TestNx, FieldType_String, FieldFlag_None ) \
HANDLER(BoostModeCurrentLimit, 1001, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(ChargeConfiguration, 1002, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \

View File

@@ -102,6 +102,7 @@ namespace ams::hos {
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_22_5_0 = ::ams::TargetFirmware_22_5_0,
Version_Current = ::ams::TargetFirmware_Current,

View File

@@ -41,7 +41,8 @@ namespace ams::pgl {
u32 version;
ncm::ContentType content_type;
u8 id_offset;
u8 reserved_0E[2];
ncm::ContentMetaType content_meta_type;
u8 reserved_0F;
static constexpr ContentMetaInfo Make(u64 id, u32 version, ncm::ContentType content_type, u8 id_offset) {
return {

View File

@@ -18,14 +18,18 @@
#include <vapours.hpp>
namespace ams::util {
constexpr size_t DecompressZstdWithBicWorkBufferSizeDefault = 0x176E8;
/* Compression utilities. */
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);
size_t CompressZstdWithBic(void *dst, size_t dst_size, const void *src, size_t src_size);
/* Decompression utilities. */
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);
size_t DecompressZstdWithBic(void *dst, size_t dst_size, const void *src, size_t src_size);
bool DecompressZstdWithBic(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

@@ -47,7 +47,7 @@ namespace ams::hos {
#endif
exosphere::ApiInfo GetExosphereApiInfo(bool allow_approximate) {
exosphere::ApiInfo info;
exosphere::ApiInfo info = exosphere::ApiInfo{ util::BitPack64{0} };
#if defined(ATMOSPHERE_OS_HORIZON)
while (true) {
if (R_SUCCEEDED(GetExosphereApiInfo(std::addressof(info)))) {

View File

@@ -220,6 +220,9 @@ namespace ams::ncm {
/* Assert that we copied the right number of infos. */
AMS_ASSERT(count == fragment_count);
/* TODO: Unused variable. */
AMS_UNUSED(count);
R_SUCCEED();
}
@@ -432,6 +435,9 @@ namespace ams::ncm {
/* Assert that we copied the right number of infos. */
AMS_ASSERT(count == fragment_count);
/* TODO: Unused variable. */
AMS_UNUSED(count);
R_SUCCEED();
}

View File

@@ -345,10 +345,11 @@ namespace ams::pgl::srv {
/* Get the content meta info. */
*out = {
.id = reader.GetProgramId().value,
.version = reader.GetProgramVersion(),
.content_type = ncm::ContentType::Program,
.id_offset = reader.GetProgramIndex(),
.id = reader.GetProgramId().value,
.version = reader.GetProgramVersion(),
.content_type = ncm::ContentType::Program,
.id_offset = reader.GetProgramIndex(),
.content_meta_type = reader.GetContentMetaType(),
};
R_SUCCEED();

View File

@@ -104,25 +104,25 @@ namespace ams::pinmux::driver::board::nintendo::nx {
#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 */
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output,
.option_mask = (u32)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 */
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input,
.option_mask = (u32)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 */
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output,
.option_mask = (u32)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 */
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input,
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
});
#endif
}

View File

@@ -24,170 +24,6 @@ namespace ams::pinmux::driver::board::nintendo::nx {
uintptr_t g_apb_misc_virtual_address = dd::QueryIoMapping(0x70000000, 0x4000);
enum PinmuxPadMask : u32 {
PinmuxPadMask_Pm = 0x3,
PinmuxPadMask_Pupd = 0xC,
PinmuxPadMask_Tristate = 0x10,
PinmuxPadMask_Park = 0x20,
PinmuxPadMask_EInput = 0x40,
PinmuxPadMask_Lock = 0x80,
PinmuxPadMask_ELpdr = 0x100,
PinmuxPadMask_EHsm = 0x200,
PinmuxPadMask_EIoHv = 0x400,
PinmuxPadMask_EOd = 0x800,
PinmuxPadMask_ESchmt = 0x1000,
PinmuxPadMask_DrvType = 0x6000,
PinmuxPadMask_Preemp = 0x8000,
PinmuxPadMask_IoReset = 0x10000,
};
enum PinmuxPadBitOffset : u32 {
PinmuxPadBitOffset_Pm = 0x0,
PinmuxPadBitOffset_Pupd = 0x2,
PinmuxPadBitOffset_Tristate = 0x4,
PinmuxPadBitOffset_Park = 0x5,
PinmuxPadBitOffset_EInput = 0x6,
PinmuxPadBitOffset_Lock = 0x7,
PinmuxPadBitOffset_ELpdr = 0x8,
PinmuxPadBitOffset_EHsm = 0x9,
PinmuxPadBitOffset_EIoHv = 0xA,
PinmuxPadBitOffset_EOd = 0xB,
PinmuxPadBitOffset_ESchmt = 0xC,
PinmuxPadBitOffset_DrvType = 0xD,
PinmuxPadBitOffset_Preemp = 0xF,
PinmuxPadBitOffset_IoReset = 0x10,
};
enum PinmuxOptBitMask : u32 {
PinmuxOptBitMask_Pm = 0x7,
PinmuxOptBitMask_Pupd = 0x18,
PinmuxOptBitMask_Dir = 0x60,
PinmuxOptBitMask_Lock = 0x80,
PinmuxOptBitMask_IoReset = 0x100,
PinmuxOptBitMask_IoHv = 0x200,
PinmuxOptBitMask_Park = 0x400,
PinmuxOptBitMask_Lpdr = 0x800,
PinmuxOptBitMask_Hsm = 0x1000,
PinmuxOptBitMask_Schmt = 0x2000,
PinmuxOptBitMask_DrvType = 0xC000,
PinmuxOptBitMask_Preemp = 0x10000,
};
enum PinmuxOptBitOffset {
PinmuxOptBitOffset_Pm = 0x0,
PinmuxOptBitOffset_Pupd = 0x3,
PinmuxOptBitOffset_Dir = 0x5,
PinmuxOptBitOffset_Lock = 0x7,
PinmuxOptBitOffset_IoReset = 0x8,
PinmuxOptBitOffset_IoHv = 0x9,
PinmuxOptBitOffset_Park = 0xA,
PinmuxOptBitOffset_Lpdr = 0xB,
PinmuxOptBitOffset_Hsm = 0xC,
PinmuxOptBitOffset_Schmt = 0xD,
PinmuxOptBitOffset_DrvType = 0xE,
PinmuxOptBitOffset_Preemp = 0x10,
};
enum PinmuxDrivePadMask : u32{
PinmuxDrivePadMask_DrvDn = 0x0001F000,
PinmuxDrivePadMask_DrvUp = 0x01F00000,
PinmuxDrivePadMask_CzDrvDn = 0x0007F000,
PinmuxDrivePadMask_CzDrvUp = 0x07F00000,
PinmuxDrivePadMask_SlwR = 0x30000000,
PinmuxDrivePadMask_SlwF = 0xC0000000,
};
enum PinmuxDrivePadBitOffset : u32 {
PinmuxDrivePadBitOffset_DrvDn = 12,
PinmuxDrivePadBitOffset_DrvUp = 20,
PinmuxDrivePadBitOffset_CzDrvDn = 12,
PinmuxDrivePadBitOffset_CzDrvUp = 20,
PinmuxDrivePadBitOffset_SlwR = 28,
PinmuxDrivePadBitOffset_SlwF = 30,
};
enum PinmuxDriveOptBitMask : u32 {
PinmuxDriveOptBitMask_DrvDn = 0x0001F000,
PinmuxDriveOptBitMask_DrvUp = 0x01F00000,
PinmuxDriveOptBitMask_CzDrvDn = 0x0007F000,
PinmuxDriveOptBitMask_CzDrvUp = 0x07F00000,
PinmuxDriveOptBitMask_SlwR = 0x30000000,
PinmuxDriveOptBitMask_SlwF = 0xC0000000,
};
enum PinmuxDriveOptBitOffset : u32 {
PinmuxDriveOptBitOffset_DrvDn = 12,
PinmuxDriveOptBitOffset_DrvUp = 20,
PinmuxDriveOptBitOffset_CzDrvDn = 12,
PinmuxDriveOptBitOffset_CzDrvUp = 20,
PinmuxDriveOptBitOffset_SlwR = 28,
PinmuxDriveOptBitOffset_SlwF = 30,
};
enum PinmuxOpt : u32 {
/* Pm */
PinmuxOpt_Gpio = 0x4,
PinmuxOpt_Unused = 0x5,
/* Pupd */
PinmuxOpt_NoPupd = 0x0,
PinmuxOpt_PullDown = 0x8,
PinmuxOpt_PullUp = 0x10,
/* Dir */
PinmuxOpt_Output = 0x0,
PinmuxOpt_Input = 0x20,
PinmuxOpt_Bidirection = 0x40,
PinmuxOpt_OpenDrain = 0x60,
/* Lock */
PinmuxOpt_Unlock = 0x0,
PinmuxOpt_Lock = 0x80,
/* IoReset */
PinmuxOpt_DisableIoReset = 0x0,
PinmuxOpt_EnableIoReset = 0x100,
/* IoHv */
PinmuxOpt_NormalVoltage = 0x0,
PinmuxOpt_HighVoltage = 0x200,
/* Park */
PinmuxOpt_ResetOnLowPower = 0x0,
PinmuxOpt_ParkOnLowPower = 0x400,
/* Lpdr */
PinmuxOpt_DisableBaseDriver = 0x0,
PinmuxOpt_EnableBaseDriver = 0x800,
/* Hsm */
PinmuxOpt_DisableHighSpeedMode = 0x0,
PinmuxOpt_EnableHighSpeedMode = 0x1000,
/* Schmt */
PinmuxOpt_CmosMode = 0x0,
PinmuxOpt_SchmittTrigger = 0x2000,
/* DrvType */
PinmuxOpt_DrvType1X = 0x0,
PinmuxOpt_DrvType2X = 0x4000,
PinmuxOpt_DrvType3X = 0x8000,
PinmuxOpt_DrvType4X = 0xC000,
/* Preemp */
PinmuxOpt_DisablePreemp = 0x0,
PinmuxOpt_EnablePreemp = 0x10000,
};
enum PinmuxPadPm : u32 {
PinmuxPadPm_Default = 0xFFFFFFFF,
PinmuxPadPm_Pm0 = 0x0,
PinmuxPadPm_Pm1 = 0x1,
PinmuxPadPm_Pm2 = 0x2,
PinmuxPadPm_Pm3 = 0x3,
PinmuxPadPm_Safe = 0x4,
};
struct PinmuxPadCharacter {
u32 reg_offset;
u32 reg_mask;

View File

@@ -30,6 +30,170 @@ namespace ams::pinmux::driver::board::nintendo::nx {
u32 option_mask;
};
enum PinmuxPadMask : u32 {
PinmuxPadMask_Pm = 0x3,
PinmuxPadMask_Pupd = 0xC,
PinmuxPadMask_Tristate = 0x10,
PinmuxPadMask_Park = 0x20,
PinmuxPadMask_EInput = 0x40,
PinmuxPadMask_Lock = 0x80,
PinmuxPadMask_ELpdr = 0x100,
PinmuxPadMask_EHsm = 0x200,
PinmuxPadMask_EIoHv = 0x400,
PinmuxPadMask_EOd = 0x800,
PinmuxPadMask_ESchmt = 0x1000,
PinmuxPadMask_DrvType = 0x6000,
PinmuxPadMask_Preemp = 0x8000,
PinmuxPadMask_IoReset = 0x10000,
};
enum PinmuxPadBitOffset : u32 {
PinmuxPadBitOffset_Pm = 0x0,
PinmuxPadBitOffset_Pupd = 0x2,
PinmuxPadBitOffset_Tristate = 0x4,
PinmuxPadBitOffset_Park = 0x5,
PinmuxPadBitOffset_EInput = 0x6,
PinmuxPadBitOffset_Lock = 0x7,
PinmuxPadBitOffset_ELpdr = 0x8,
PinmuxPadBitOffset_EHsm = 0x9,
PinmuxPadBitOffset_EIoHv = 0xA,
PinmuxPadBitOffset_EOd = 0xB,
PinmuxPadBitOffset_ESchmt = 0xC,
PinmuxPadBitOffset_DrvType = 0xD,
PinmuxPadBitOffset_Preemp = 0xF,
PinmuxPadBitOffset_IoReset = 0x10,
};
enum PinmuxOptBitMask : u32 {
PinmuxOptBitMask_Pm = 0x7,
PinmuxOptBitMask_Pupd = 0x18,
PinmuxOptBitMask_Dir = 0x60,
PinmuxOptBitMask_Lock = 0x80,
PinmuxOptBitMask_IoReset = 0x100,
PinmuxOptBitMask_IoHv = 0x200,
PinmuxOptBitMask_Park = 0x400,
PinmuxOptBitMask_Lpdr = 0x800,
PinmuxOptBitMask_Hsm = 0x1000,
PinmuxOptBitMask_Schmt = 0x2000,
PinmuxOptBitMask_DrvType = 0xC000,
PinmuxOptBitMask_Preemp = 0x10000,
};
enum PinmuxOptBitOffset {
PinmuxOptBitOffset_Pm = 0x0,
PinmuxOptBitOffset_Pupd = 0x3,
PinmuxOptBitOffset_Dir = 0x5,
PinmuxOptBitOffset_Lock = 0x7,
PinmuxOptBitOffset_IoReset = 0x8,
PinmuxOptBitOffset_IoHv = 0x9,
PinmuxOptBitOffset_Park = 0xA,
PinmuxOptBitOffset_Lpdr = 0xB,
PinmuxOptBitOffset_Hsm = 0xC,
PinmuxOptBitOffset_Schmt = 0xD,
PinmuxOptBitOffset_DrvType = 0xE,
PinmuxOptBitOffset_Preemp = 0x10,
};
enum PinmuxDrivePadMask : u32 {
PinmuxDrivePadMask_DrvDn = 0x0001F000,
PinmuxDrivePadMask_DrvUp = 0x01F00000,
PinmuxDrivePadMask_CzDrvDn = 0x0007F000,
PinmuxDrivePadMask_CzDrvUp = 0x07F00000,
PinmuxDrivePadMask_SlwR = 0x30000000,
PinmuxDrivePadMask_SlwF = 0xC0000000,
};
enum PinmuxDrivePadBitOffset : u32 {
PinmuxDrivePadBitOffset_DrvDn = 12,
PinmuxDrivePadBitOffset_DrvUp = 20,
PinmuxDrivePadBitOffset_CzDrvDn = 12,
PinmuxDrivePadBitOffset_CzDrvUp = 20,
PinmuxDrivePadBitOffset_SlwR = 28,
PinmuxDrivePadBitOffset_SlwF = 30,
};
enum PinmuxDriveOptBitMask : u32 {
PinmuxDriveOptBitMask_DrvDn = 0x0001F000,
PinmuxDriveOptBitMask_DrvUp = 0x01F00000,
PinmuxDriveOptBitMask_CzDrvDn = 0x0007F000,
PinmuxDriveOptBitMask_CzDrvUp = 0x07F00000,
PinmuxDriveOptBitMask_SlwR = 0x30000000,
PinmuxDriveOptBitMask_SlwF = 0xC0000000,
};
enum PinmuxDriveOptBitOffset : u32 {
PinmuxDriveOptBitOffset_DrvDn = 12,
PinmuxDriveOptBitOffset_DrvUp = 20,
PinmuxDriveOptBitOffset_CzDrvDn = 12,
PinmuxDriveOptBitOffset_CzDrvUp = 20,
PinmuxDriveOptBitOffset_SlwR = 28,
PinmuxDriveOptBitOffset_SlwF = 30,
};
enum PinmuxOpt : u32 {
/* Pm */
PinmuxOpt_Gpio = 0x4,
PinmuxOpt_Unused = 0x5,
/* Pupd */
PinmuxOpt_NoPupd = 0x0,
PinmuxOpt_PullDown = 0x8,
PinmuxOpt_PullUp = 0x10,
/* Dir */
PinmuxOpt_Output = 0x0,
PinmuxOpt_Input = 0x20,
PinmuxOpt_Bidirection = 0x40,
PinmuxOpt_OpenDrain = 0x60,
/* Lock */
PinmuxOpt_Unlock = 0x0,
PinmuxOpt_Lock = 0x80,
/* IoReset */
PinmuxOpt_DisableIoReset = 0x0,
PinmuxOpt_EnableIoReset = 0x100,
/* IoHv */
PinmuxOpt_NormalVoltage = 0x0,
PinmuxOpt_HighVoltage = 0x200,
/* Park */
PinmuxOpt_ResetOnLowPower = 0x0,
PinmuxOpt_ParkOnLowPower = 0x400,
/* Lpdr */
PinmuxOpt_DisableBaseDriver = 0x0,
PinmuxOpt_EnableBaseDriver = 0x800,
/* Hsm */
PinmuxOpt_DisableHighSpeedMode = 0x0,
PinmuxOpt_EnableHighSpeedMode = 0x1000,
/* Schmt */
PinmuxOpt_CmosMode = 0x0,
PinmuxOpt_SchmittTrigger = 0x2000,
/* DrvType */
PinmuxOpt_DrvType1X = 0x0,
PinmuxOpt_DrvType2X = 0x4000,
PinmuxOpt_DrvType3X = 0x8000,
PinmuxOpt_DrvType4X = 0xC000,
/* Preemp */
PinmuxOpt_DisablePreemp = 0x0,
PinmuxOpt_EnablePreemp = 0x10000,
};
enum PinmuxPadPm : u32 {
PinmuxPadPm_Default = 0xFFFFFFFF,
PinmuxPadPm_Pm0 = 0x0,
PinmuxPadPm_Pm1 = 0x1,
PinmuxPadPm_Pm2 = 0x2,
PinmuxPadPm_Pm3 = 0x3,
PinmuxPadPm_Safe = 0x4,
};
void InitializePlatformPads();
void UpdateSinglePinmuxPad(const PinmuxPadConfig &config);

View File

@@ -0,0 +1,39 @@
/*
* 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 "lz4.h"
namespace ams::util {
int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
/* 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));
}
int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
/* 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));
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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>
#define ZSTD_STATIC_LINKING_ONLY
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#define ZSTDLIB_VISIBLE static
#define ZSTDLIB_HIDDEN static
#include "zstd.h"
#include "zstd.inc"
#pragma GCC diagnostic pop
namespace ams::util {
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);
}
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);
}
}

View File

@@ -14,24 +14,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "lz4.h"
#define ZSTD_STATIC_LINKING_ONLY
#define ZSTD_ZBIC_SUPPORT 1
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#define ZSTDLIB_VISIBLE static
#define ZSTDLIB_HIDDEN static
#include "zstd.h"
#include "zstd.inc"
#pragma GCC diagnostic pop
namespace ams::util {
static_assert(sizeof(ZSTD_DCtx) <= DecompressZstdWithBicWorkBufferSizeDefault);
/* Compression utilities. */
int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
/* 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));
}
size_t CompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
size_t CompressZstdWithBic(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());
@@ -44,21 +41,11 @@ namespace ams::util {
/* Use Zstd default level. */
int compressionLevel = 3;
/* This is just a wrapper around Zstd. */
/* This is just a wrapper around Zstd with BIC support enabled. */
return ZSTD_compress(dst, dst_size, src, src_size, compressionLevel);
}
/* Decompression utilities. */
int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
/* 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));
}
size_t DecompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
size_t DecompressZstdWithBic(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());
@@ -68,14 +55,22 @@ namespace ams::util {
AMS_ABORT_UNLESS(!ZSTD_isError(bound));
AMS_ABORT_UNLESS(dst_size >= bound);
/* This is just a wrapper around Zstd. */
/* This is just a wrapper around Zstd with BIC support enabled. */
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) {
bool DecompressZstdWithBic(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)) {
auto error_code = ZSTD_getErrorCode(margin);
auto error_string = ZSTD_getErrorString(error_code);
AMS_LOG("[util] Can't determine decompression margin: %u (%s)\n", error_code, error_string);
/* TODO: Unused variables in non-debug build. */
AMS_UNUSED(error_code, error_string);
return false;
}
@@ -86,20 +81,30 @@ namespace ams::util {
/* Make sure we fit in the destination buffer. */
if (margin + expected_dec_size > dst_size) {
AMS_LOG("[util] Not enough space for decompression %lu + %lu > %lu\n", 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);
/* This is a runtime assert in Loader code. Note that Nintendo does == comparison 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)) {
auto error_code = ZSTD_getErrorCode(margin);
auto error_string = ZSTD_getErrorString(error_code);
AMS_LOG("[util] Decompression failed: %u (%s)\n", error_code, error_string);
/* TODO: Unused variables in non-debug build. */
AMS_UNUSED(error_code, error_string);
return false;
}
/* Make sure we match the expected size. */
if (dec_size != expected_dec_size) {
return false;
}

View File

@@ -17,10 +17,10 @@
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
#define ATMOSPHERE_RELEASE_VERSION_MINOR 11
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1
#define ATMOSPHERE_RELEASE_VERSION_MICRO 2
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 22
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 5
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0

View File

@@ -100,8 +100,9 @@
#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_22_5_0 ATMOSPHERE_TARGET_FIRMWARE(22, 5, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_22_1_0
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_22_5_0
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
@@ -194,6 +195,7 @@ namespace ams {
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_22_5_0 = ATMOSPHERE_TARGET_FIRMWARE_22_5_0,
TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT,

View File

@@ -494,6 +494,14 @@ namespace ams::result::impl {
} \
}
#define R_UNLESS_LOG(expr, res, ...) \
{ \
if (!(expr)) { \
AMS_LOG(__VA_ARGS__); \
R_THROW(res); \
} \
}
/// Evaluates a boolean expression, and succeeds if that expression is true.
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess())

View File

@@ -185,7 +185,10 @@ namespace ams::svc::codegen::impl {
/* Process all arguments, in order. */
size_t i = 0;
(layout.ProcessArgument<AbiType, ArgumentTypes>(i++, NGRN, NSAA), ...);
/* TODO: Unused variable. */
AMS_UNUSED(i);
return layout;
}

View File

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

View File

@@ -100,5 +100,6 @@ constexpr inline const EmbeddedPatch Usb30ForceEnablePatches[] = {
{ ParseModuleId("40E80E7442C0DFC985315E6F9E8C77229818AC0F"), util::size(Usb30ForceEnablePatches_20_0_0), Usb30ForceEnablePatches_20_0_0 }, /* 20.0.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("B734339F2280170AF0200573F9B943242CEF8C15"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 22.0.0 */
{ ParseModuleId("B734339F2280170AF0200573F9B943242CEF8C15"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 22.0.0 - 22.1.0 */
{ ParseModuleId("AD8D36F2029822A4C498F055ADBDAA789EB913C6"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 22.5.0 */
};

View File

@@ -121,8 +121,7 @@ namespace ams::ldr {
NsoHeader g_nso_headers[Nso_Count];
/* Global Zstd decompression context. */
constexpr size_t ZstdDctxWorkspaceSize = 0x176E8;
alignas(8) u8 g_zstd_dctx_workspace[ZstdDctxWorkspaceSize];
alignas(8) u8 g_zstd_dctx_workspace[util::DecompressZstdWithBicWorkBufferSizeDefault];
Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) {
/* No version verification is done before 8.1.0. */
@@ -220,7 +219,7 @@ namespace ams::ldr {
/* Read NSO header. */
size_t read_size;
R_TRY(fs::ReadFile(std::addressof(read_size), file, 0, g_nso_headers + ctx.nso_count, sizeof(NsoHeader)));
R_UNLESS(read_size == sizeof(NsoHeader), ldr::ResultInvalidNso());
R_UNLESS_LOG(read_size == sizeof(NsoHeader), ldr::ResultInvalidNso(), "[ldr] NSO header truncated!\n");
/* Note nso is present. */
switch (i) {
@@ -259,7 +258,7 @@ namespace ams::ldr {
Result CheckAutoLoad(const AutoLoadModuleContext &ctx, u32 acid_flags) {
/* We must always have a main. */
R_UNLESS(ctx.ali.has_main, ldr::ResultInvalidNso());
R_UNLESS_LOG(ctx.ali.has_main, ldr::ResultInvalidNso(), "[ldr] Missing main!\n");
/* Validate flags and extents for all present NSOs. */
for (int i = 0; i < ctx.nso_count; ++i) {
@@ -267,11 +266,11 @@ namespace ams::ldr {
/* All NSOs must not be --X. */
/* This is "probably" not checked on Ounce? */
R_UNLESS((hdr.flags & NsoHeader::Flag_PreventCodeReads) == 0, ldr::ResultInvalidNso());
R_UNLESS_LOG((hdr.flags & NsoHeader::Flag_PreventCodeReads) == 0, ldr::ResultInvalidNso(), "[ldr] NSO[%d] --x not allowed!\n", i);
/* Zstd compression only allowed on main, and only when both rtld+sdk are present. */
if (i != ctx.main_nso_idx || ctx.rtld_idx < 0 || ctx.sdk_nso_idx < 0) {
R_UNLESS((hdr.flags & NsoHeader::Flag_UseZbicCompression) == 0, ldr::ResultInvalidNso());
R_UNLESS_LOG((hdr.flags & NsoHeader::Flag_UseZbicCompression) == 0, ldr::ResultInvalidNso(), "[ldr] NSO[%d] zbic not allowed!\n", i);
}
/* NSOs must have page-aligned segments. */
@@ -294,13 +293,13 @@ namespace ams::ldr {
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());
R_UNLESS_LOG(ctx.ali.has_rtld, ldr::ResultInvalidNso(), "[ldr] Missing rtld!\n");
/* If we have rtld, we must not have browser core dll. */
R_UNLESS(!has_browser_dll, ldr::ResultInvalidNso());
R_UNLESS_LOG(!has_browser_dll, ldr::ResultInvalidNso(), "[ldr] BrowserCoreDll must not be present!\n");
} else {
/* We must not have both subsdk and browser dll. */
R_UNLESS(!(ctx.ali.has_subsdk && has_browser_dll), ldr::ResultInvalidNso());
R_UNLESS_LOG(!(ctx.ali.has_subsdk && has_browser_dll), ldr::ResultInvalidNso(), "[ldr] Can't have both subsdk and BrowserCoreDll!\n");
}
R_SUCCEED();
@@ -385,6 +384,8 @@ namespace ams::ldr {
/* If the signature check fails, we need to check if this is allowable. */
if (!is_signature_valid) {
AMS_LOG("[ldr] invalid signature!\n");
/* We have to enforce signature checks on prod and when we have a signature to check on dev. */
R_UNLESS(IsDevelopmentForAcidProductionCheck(), ldr::ResultInvalidNcaSignature());
R_UNLESS(!code_verification_data.has_data, ldr::ResultInvalidNcaSignature());
@@ -635,10 +636,13 @@ namespace ams::ldr {
R_SUCCEED();
}
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) {
Result LoadAutoLoadModuleSegment(fs::FileHandle file, size_t file_offset, size_t compressed_size, size_t segment_size, bool is_compressed, bool is_zbic, uintptr_t map_base, uintptr_t map_end) {
/* Select read size based on compression. */
size_t file_size = is_compressed ? compressed_size : segment_size;
AMS_LOG("[ldr] Loading segment @ 0x%016lx: compressed=%d, file_size=0x%08lx, compressed_size=0x%08lx, segment_size=0x%08lx\n",
map_base, is_compressed, file_size, compressed_size, segment_size);
/* Validate size. */
R_UNLESS(file_size <= segment_size, ldr::ResultInvalidNso());
R_UNLESS(file_size <= std::numeric_limits<s32>::max(), ldr::ResultInvalidNso());
@@ -648,19 +652,19 @@ namespace ams::ldr {
uintptr_t load_address = is_compressed ? map_end - compressed_size : map_base;
size_t read_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_LOG(read_size == file_size, ldr::ResultInvalidNso(), "[ldr] Couldn't read segment from file!\n");
/* Uncompress if necessary. */
R_SUCCEED_IF(!is_compressed);
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());
if (is_zbic) {
bool decompressed = util::DecompressZstdWithBic(reinterpret_cast<void *>(g_zstd_dctx_workspace), sizeof(g_zstd_dctx_workspace), reinterpret_cast<void *>(map_base), static_cast<size_t>(map_end - map_base), segment_size, compressed_data_buf, file_size);
R_UNLESS_LOG(decompressed, ldr::ResultInvalidNso(), "[ldr] Failed to decompress segment with zbic!\n");
} 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_LOG(decompressed, ldr::ResultInvalidNso(), "[ldr] Failed to decompress segment with lz4!\n");
}
R_SUCCEED();
@@ -675,12 +679,12 @@ namespace ams::ldr {
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_UNLESS_LOG(std::memcmp(hash, nso_header->segment_hashes[segment], sizeof(hash)) == 0, ldr::ResultInvalidNso(), "[ldr] Invalid segment hash!\n");
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;
const bool is_zbic = (nso_header->flags & NsoHeader::Flag_UseZbicCompression) != 0;
/* Map and read data from file. */
{
@@ -694,11 +698,11 @@ namespace ams::ldr {
/* Load NSO segments. */
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_CompressedText) != 0, is_zstd, map_address + nso_header->text_dst_offset, map_end));
(nso_header->flags & NsoHeader::Flag_CompressedText) != 0, is_zbic, map_address + nso_header->text_dst_offset, map_end));
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_CompressedRo) != 0, is_zstd, map_address + nso_header->ro_dst_offset, map_end));
(nso_header->flags & NsoHeader::Flag_CompressedRo) != 0, is_zbic, map_address + nso_header->ro_dst_offset, map_end));
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_CompressedRw) != 0, is_zstd, map_address + nso_header->rw_dst_offset, map_end));
(nso_header->flags & NsoHeader::Flag_CompressedRw) != 0, is_zbic, map_address + nso_header->rw_dst_offset, map_end));
/* 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);
@@ -744,14 +748,15 @@ namespace ams::ldr {
for (int i = 0; i < ctx.nso_count; i++) {
const NsoIndex nso_idx = static_cast<NsoIndex>(ctx.ali.nso_indices[i]);
const bool is_zbic = (ctx.headers[i].flags & NsoHeader::Flag_UseZbicCompression) != 0;
const size_t map_size = is_zbic ? (total_end - process_info->nso_address[i]) : process_info->nso_size[i];
AMS_LOG("[ldr] module[%d]: idx=%d, path='%s', zbic=%d\n", i, (int)nso_idx, GetNsoPath(nso_idx), is_zbic);
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));
}

View File

@@ -141,8 +141,31 @@ namespace dbk {
return rc;
}
u32 EncodeVersion(u32 major, u32 minor, u32 micro, u32 relstep = 0) {
return ((major & 0xFF) << 24) | ((minor & 0xFF) << 16) | ((micro & 0xFF) << 8) | ((relstep & 0xFF) << 8);
u32 EncodeVersion(u32 major, u32 minor, u32 micro) {
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. */
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;
/* 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);
}
@@ -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_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
this->AddButton(BackButtonId, "Back", x + HorizontalInset, button_y, button_width, ButtonHeight);
this->AddButton(ContinueButtonId, "Continue", x + HorizontalInset + button_width + ButtonHorizontalGap, button_y, button_width, ButtonHeight);
this->AddButton(BackButtonId, "Zurück", x + HorizontalInset, button_y, button_width, ButtonHeight);
this->AddButton(ContinueButtonId, "Weiter", x + HorizontalInset + button_width + ButtonHorizontalGap, button_y, button_width, ButtonHeight);
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) {
const float x = g_screen_width / 2.0f - WindowWidth / 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(ExitButtonId, "Exit", x + HorizontalInset, y + TitleGap + ButtonHeight + VerticalGap, WindowWidth - HorizontalInset * 2, ButtonHeight);
this->AddButton(InstallButtonId, "Installieren", x + HorizontalInset, y + TitleGap, WindowWidth - HorizontalInset * 2, ButtonHeight);
this->AddButton(ExitButtonId, "Beenden", x + HorizontalInset, y + TitleGap + ButtonHeight + VerticalGap, WindowWidth - HorizontalInset * 2, ButtonHeight);
this->SetButtonSelected(InstallButtonId, true);
}
@@ -475,24 +561,24 @@ namespace dbk {
u64 is_emummc;
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;
}
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;
}
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;
}
/* Warn if we're working with a patched unit. */
const bool is_erista = hardware_type == 0 || hardware_type == 1;
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 {
ChangeMenu(file_menu);
}
@@ -688,7 +774,7 @@ namespace dbk {
snprintf(g_update_path, sizeof(g_update_path), "%s", current_path);
/* Change the menu. */
ChangeMenu(std::make_shared<ValidateUpdateMenu>(g_current_menu));
ChangeMenu(CreateUpdateMenuAfterPathSelection(g_current_menu));
} else {
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 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);
nvgSave(vg);
@@ -765,8 +851,8 @@ namespace dbk {
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
/* Add buttons. */
this->AddButton(BackButtonId, "Back", 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(BackButtonId, "Zurück", x + HorizontalInset, 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(ContinueButtonId, false);
@@ -776,32 +862,33 @@ namespace dbk {
this->SetButtonSelected(BackButtonId, true);
} else {
/* 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 rc = 0;
this->LogText("Directory %s\n", g_update_path);
this->LogText("Verzeichnis %s\n", g_update_path);
/* Attempt to get the update information. */
if (R_FAILED(rc = amssuGetUpdateInformation(&m_update_info, g_update_path))) {
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 {
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;
}
/* 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("- 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) {
this->LogText("- exFAT: Supported\n");
this->LogText("- exFAT: Unterstützt\n");
} 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. */
m_has_info = true;
@@ -813,21 +900,21 @@ namespace dbk {
/* Validate the update. */
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;
}
/* Check the 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)) {
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("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("exFAT-Validierung fehlgeschlagen, Ergebnis: 0x%08x\n", m_validation_info.exfat_result);
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. */
this->LogText("- Content id: ");
this->LogText("- Inhalts-ID: ");
for (size_t i = 0; i < sizeof(NcmContentId); i++) {
this->LogText("%02x", m_validation_info.invalid_content_id.c[i]);
}
@@ -841,11 +928,11 @@ namespace dbk {
} else {
/* Log the missing content info. */
const u32 version = m_validation_info.invalid_key.version;
this->LogText("Validation failed with result: 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("Validierung fehlgeschlagen, Ergebnis: 0x%08x\n", m_validation_info.result);
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. */
this->LogText("- Content id: ");
this->LogText("- Inhalts-ID: ");
for (size_t i = 0; i < sizeof(NcmContentId); 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. */
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?");
}
/* 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?");
next_menu = std::make_shared<WarningMenu>(g_current_menu, next_menu, "Warnung: exFAT-Firmware fehlt oder ist beschädigt", "Möchtest du wirklich fortfahren?");
}
/* Change to the next menu. */
@@ -919,7 +1000,7 @@ namespace dbk {
const float x = g_screen_width / 2.0f - WindowWidth / 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);
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;
/* Add buttons. */
this->AddButton(ResetToFactorySettingsButtonId, "Reset to factory settings", x + HorizontalInset, y + TitleGap, button_width, ButtonHeight);
this->AddButton(PreserveSettingsButtonId, "Preserve settings", x + HorizontalInset + button_width + ButtonHorizontalGap, y + TitleGap, button_width, ButtonHeight);
this->AddButton(ResetToFactorySettingsButtonId, "Werkseinstellungen", x + HorizontalInset, y + TitleGap, button_width, ButtonHeight);
this->AddButton(PreserveSettingsButtonId, "Einstellungen behalten", x + HorizontalInset + button_width + ButtonHorizontalGap, y + TitleGap, button_width, ButtonHeight);
this->SetButtonSelected(PreserveSettingsButtonId, true);
}
@@ -963,11 +1044,11 @@ namespace dbk {
if (g_exfat_supported) {
next_menu = std::make_shared<ChooseExfatMenu>(g_current_menu);
} 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) {
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 {
ChangeMenu(next_menu);
}
@@ -985,7 +1066,7 @@ namespace dbk {
const float x = g_screen_width / 2.0f - WindowWidth / 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);
}
@@ -1029,7 +1110,7 @@ namespace dbk {
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();
@@ -1044,7 +1125,7 @@ namespace dbk {
const float x = g_screen_width / 2.0f - WindowWidth / 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);
}
@@ -1054,8 +1135,8 @@ namespace dbk {
const float button_width = (WindowWidth - HorizontalInset * 2.0f) / 2.0f - ButtonHorizontalGap;
/* Add buttons. */
this->AddButton(ShutdownButtonId, "Shutdown", 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(ShutdownButtonId, "Ausschalten", x + HorizontalInset, 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(RebootButtonId, false);
@@ -1075,34 +1156,34 @@ namespace dbk {
if (m_install_state == InstallState::NeedsSetup) {
/* Setup the update. */
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();
return rc;
}
/* Log setup completion. */
this->LogText("Update setup complete.\n");
this->LogText("Update-Einrichtung abgeschlossen.\n");
m_install_state = InstallState::NeedsPrepare;
} else if (m_install_state == InstallState::NeedsPrepare) {
/* Request update preparation. */
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();
return rc;
}
/* Log awaiting prepare. */
this->LogText("Preparing update...\n");
this->LogText("Update wird vorbereitet...\n");
m_install_state = InstallState::AwaitingPrepare;
} else if (m_install_state == InstallState::AwaitingPrepare) {
/* Check if preparation has a result. */
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();
return rc;
} else if (R_SUCCEEDED(rc)) {
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();
return rc;
}
@@ -1111,14 +1192,14 @@ namespace dbk {
/* Check if the update has been prepared. */
bool 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();
return rc;
}
/* Mark for application if preparation complete. */
if (prepared) {
this->LogText("Update preparation complete.\nApplying update...\n");
this->LogText("Update-Vorbereitung abgeschlossen.\nUpdate wird angewendet...\n");
m_install_state = InstallState::NeedsApply;
return rc;
}
@@ -1126,7 +1207,7 @@ namespace dbk {
/* Check update progress. */
NsSystemUpdateProgress 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();
return rc;
}
@@ -1140,28 +1221,28 @@ namespace dbk {
} else if (m_install_state == InstallState::NeedsApply) {
/* Apply the prepared update. */
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 {
/* Log success. */
this->LogText("Update applied successfully.\n");
this->LogText("Update erfolgreich angewendet.\n");
if (g_reset_to_factory) {
if (R_FAILED(rc = nsResetToFactorySettingsForRefurbishment())) {
/* Fallback on ResetToFactorySettings. */
if (rc == MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer)) {
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();
return rc;
}
} 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();
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 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);
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);
@@ -1211,7 +1292,7 @@ namespace dbk {
/* We have drawn now, allow setup to occur. */
if (m_install_state == InstallState::NeedsDraw) {
this->LogText("Beginning update setup...\n");
this->LogText("Update-Einrichtung wird gestartet...\n");
m_install_state = InstallState::NeedsSetup;
}
}
@@ -1236,7 +1317,7 @@ namespace dbk {
/* Attempt to get the exosphere version. */
u64 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;
}
@@ -1247,20 +1328,22 @@ namespace dbk {
/* Validate the exosphere version. */
const bool ams_supports_sysupdate_api = EncodeVersion(version_major, version_minor, version_micro) >= EncodeVersion(0, 14, 0);
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;
}
/* Ensure DayBreak is ran as a NRO. */
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;
}
/* Attempt to get the supported version. */
if (R_SUCCEEDED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereSupportedHosVersion), &version))) {
g_supported_version = static_cast<u32>(version);
/* Get the maximum HOS version supported by this Atmosphere build (hos::Version_Max). */
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereSupportedHosVersion), &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. */
if (R_FAILED(rc = amssuInitialize())) {
@@ -1280,7 +1363,7 @@ namespace dbk {
strncpy(g_update_path, update_path, sizeof(g_update_path)-1);
/* Change the menu. */
ChangeMenu(std::make_shared<ValidateUpdateMenu>(g_current_menu));
ChangeMenu(CreateUpdateMenuAfterPathSelection(g_current_menu));
return true;
}

View File

@@ -120,6 +120,17 @@ namespace dbk {
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 {
private:
static constexpr u32 InstallButtonId = 0;

View File

@@ -148,7 +148,7 @@ namespace dbk {
void DrawProgressText(NVGcontext *vg, float x, float y, float progress) {
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);
nvgFontFace(vg, SwitchStandardFont);