Compare commits

..

33 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
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
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
ndeadly
f8a5a6c015 libvapours: add R_DISCARD macro 2026-02-23 01:09:11 +01:00
26 changed files with 368 additions and 128 deletions

View File

@@ -15,6 +15,13 @@
# Desc: Controls whether userland has access to the PMU registers.
# 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.
# Desc: Controls whether PRODINFO should be blanked in sysmmc.
# This will cause the system to see dummied out keys and
@@ -51,6 +58,7 @@ debugmode=1
debugmode_user=0
disable_user_exception_handlers=0
enable_user_pmu_access=0
enable_mem_mode=0
blank_prodinfo_sysmmc=0
blank_prodinfo_emummc=0
allow_writing_to_cal_sysmmc=0

View File

@@ -1,4 +1,25 @@
# 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.

6
emummc/.gitrepo vendored
View File

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

View File

@@ -31,7 +31,7 @@
#define FS_OFFSET_2200_CLKRST_SET_MIN_V_CLK_RATE 0x1CF260
// Misc funcs
#define FS_OFFSET_2200_LOCK_MUTEX 0x1CF260
#define FS_OFFSET_2200_LOCK_MUTEX 0x1A4EF0
#define FS_OFFSET_2200_UNLOCK_MUTEX 0x1A4F40
#define FS_OFFSET_2200_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1AC0B0

View File

@@ -31,7 +31,7 @@
#define FS_OFFSET_2200_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1DA450
// Misc funcs
#define FS_OFFSET_2200_EXFAT_LOCK_MUTEX 0x1DA450
#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

View File

@@ -132,10 +132,13 @@ namespace ams::secmon::smc {
}
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;
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());
}
@@ -146,17 +149,19 @@ namespace ams::secmon::smc {
pkg1::MemorySize memory_size = pkg1::MemorySize_4GB;
util::BitPack32 value = {};
if (const auto &bcd = GetBootConfig().data; bcd.IsDevelopmentFunctionEnabled()) {
memory_size = GetMemorySize(GetMemoryMode(bcd.GetMemoryMode()));
const auto &bcd = GetBootConfig().data;
const auto &sc = GetSecmonConfiguration(); /* Exosphere extensions */
if (bcd.IsDevelopmentFunctionEnabled()) {
value.Set<KernelConfiguration::Flags1>(bcd.GetKernelFlags1());
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. */
const auto &sc = GetSecmonConfiguration();
value.Set<KernelConfiguration::PhysicalMemorySize>(memory_size);
if (!sc.DisableUserModeExceptionHandlers()) {
value.Set<KernelConfiguration::EnableUserExceptionHandlers>(true);
@@ -169,6 +174,27 @@ namespace ams::secmon::smc {
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 bool g_set_true_target_firmware = false;
@@ -178,7 +204,7 @@ namespace ams::secmon::smc {
args.r[1] = GetBootConfig().signed_data.IsProgramVerificationDisabled();
break;
case ConfigItem::DramId:
args.r[1] = fuse::GetDramId();
args.r[1] = GetDramIdAdjusted(); /* Nintendo: fuse::GetDramId() */
break;
case ConfigItem::SecurityEngineInterruptNumber:
args.r[1] = SecurityEngineUserInterruptId;
@@ -471,9 +497,18 @@ namespace ams::secmon::smc {
/* For exosphere's usage. */
pkg1::MemorySize GetPhysicalMemorySize() {
const auto dram_id = fuse::GetDramId();
AMS_ABORT_UNLESS(dram_id < fuse::DramId_Count);
return DramIdToMemorySize[dram_id];
const uintptr_t MC = secmon::MemoryRegionVirtualDeviceMemoryController.GetAddress();
const u32 mem_size = reg::Read(MC + MC_EMEM_CFG) & 0x3FFF;
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

@@ -545,6 +545,12 @@ namespace ams::nxboot {
} else {
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) {
if (!emummc_enabled) {
if (entry.value[0] == '1') {

View File

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

View File

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

View File

@@ -111,6 +111,7 @@ namespace ams::erpt {
struct CreateReportOptionFlag {
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>;

View File

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

View File

@@ -101,6 +101,7 @@ namespace ams::hos {
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,

View File

@@ -19,5 +19,6 @@
namespace ams::erpt::srv {
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_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_GameCardLastDeactivateReasonResult, ei.last_deactivate_reason_result));
R_ABORT_UNLESS(record->Add(FieldId_GameCardLastDeactivateReason, ei.last_deactivate_reason));
/* Submit the record. */
R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record)));
@@ -496,4 +498,27 @@ namespace ams::erpt::srv {
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

@@ -423,7 +423,11 @@ namespace ams::erpt::srv {
auto report = std::make_unique<Report>(record.get(), redirect_new_reports);
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(report->GetSize(std::addressof(record->m_info.report_size)));
@@ -434,7 +438,7 @@ namespace ams::erpt::srv {
} else {
/* 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. */
R_ABORT_UNLESS(JournalForAttachments::DeleteAttachments(report_id));
R_TRY(JournalForAttachments::DeleteAttachments(report_id));
}
R_TRY(Journal::Commit());
@@ -489,6 +493,20 @@ namespace ams::erpt::srv {
static_cast<void>(Context::ClearContext(CategoryId_ErrorInfo));
static_cast<void>(Context::ClearContext(CategoryId_ErrorInfoAuto));
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. */

View File

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

View File

@@ -17,10 +17,10 @@
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
#define ATMOSPHERE_RELEASE_VERSION_MINOR 11
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1
#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 0
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0

View File

@@ -99,8 +99,9 @@
#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_22_0_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_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
@@ -192,6 +193,7 @@ namespace ams {
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,

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)
#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)

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

@@ -1,18 +0,0 @@
/*
* 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/>.
*/
#define AMS_ZSTD_IMPLEMENTATION
#include <stratosphere/util/util_zbic_for_loader.hpp>

View File

@@ -15,7 +15,7 @@
"filesystem_access": {
"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"],
"kernel_capabilities": [{
"type": "kernel_flags",
@@ -87,4 +87,4 @@
"type": "handle_table_size",
"value": 256
}]
}
}

View File

@@ -30,13 +30,14 @@ namespace ams {
fs::InitializeForSystem();
fs::SetAllocator(pgl::srv::Allocate, pgl::srv::Deallocate);
fs::SetEnabledAutoAbort(false);
/* Initialize lr. */
lr::Initialize();
/* Initialize other services we need. */
R_ABORT_UNLESS(setInitialize());
R_ABORT_UNLESS(setsysInitialize());
R_ABORT_UNLESS(pmshellInitialize());
R_ABORT_UNLESS(ldrShellInitialize());
R_ABORT_UNLESS(lrInitialize());
/* Verify that we can sanely execute. */
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;
}
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);