Compare commits

2 Commits
main ... dev

Author SHA1 Message Date
Niklas080208
31aeeaabbb Disabled build on push 2026-02-15 16:34:38 +01:00
89994995af Add pre-update/clean backup feature
All checks were successful
Build / Build (push) Successful in 12s
- Backup deletion paths before update to sd:/backup/OmniNX/{version}
- Backup deletion paths before clean install to sd:/backup/OmniNX/pre-omninx
- Best-effort backup: continue install even if some copies fail
- Fix directory creation: ensure parent dirs exist before folder_copy
- Step 1 for update: Backup; Step 1-2 for clean: user data + pre-omninx backup

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-14 16:05:57 +01:00
17 changed files with 838 additions and 1142 deletions

View File

@@ -1,7 +1,7 @@
name: Build name: Build
on: on:
push: #push:
workflow_dispatch: workflow_dispatch:
jobs: jobs:

View File

@@ -46,11 +46,7 @@ LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defs
################################################################################ ################################################################################
RAMTEST_BIN := $(OUTPUTDIR)/RAM-Test.bin .PHONY: all clean release
OBJS_RAMTEST := $(filter-out $(BUILDDIR)/$(TARGET)/main.o,$(OBJS)) \
$(BUILDDIR)/$(TARGET)/ram_test_main.o
.PHONY: all clean release ram-test
all: $(OUTPUTDIR)/$(OUTPUT_NAME) all: $(OUTPUTDIR)/$(OUTPUT_NAME)
$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(OUTPUT_NAME))) $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(OUTPUT_NAME)))
@@ -60,7 +56,6 @@ all: $(OUTPUTDIR)/$(OUTPUT_NAME)
clean: clean:
@rm -rf $(BUILDDIR) @rm -rf $(BUILDDIR)
@rm -rf $(OUTPUTDIR) @rm -rf $(OUTPUTDIR)
@rm -f $(RAMTEST_BIN)
@rm -rf release @rm -rf release
@rm -f $(TARGET)-*.zip @rm -f $(TARGET)-*.zip
@@ -72,20 +67,6 @@ $(OUTPUTDIR)/$(OUTPUT_NAME): $(BUILDDIR)/$(TARGET)/$(TARGET).elf
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) $(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ $(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
$(BUILDDIR)/$(TARGET)/ram_test_main.o: tools/ram_test_main.c
@mkdir -p "$(@D)"
$(CC) $(CFLAGS) $(BDKINC) -I$(SOURCEDIR) -c $< -o $@
$(BUILDDIR)/$(TARGET)/ram_test.elf: $(OBJS_RAMTEST)
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
$(RAMTEST_BIN): $(BUILDDIR)/$(TARGET)/ram_test.elf
@mkdir -p "$(@D)"
$(OBJCOPY) -S -O binary $< $@
@echo "RAM-Test payload: $(RAMTEST_BIN) ($$(wc -c < $@) bytes)"
ram-test: $(RAMTEST_BIN)
$(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.c $(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.c
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(CC) $(CFLAGS) $(BDKINC) -I$(SOURCEDIR) -c $< -o $@ $(CC) $(CFLAGS) $(BDKINC) -I$(SOURCEDIR) -c $< -o $@

View File

@@ -6,14 +6,97 @@
#include "fs.h" #include "fs.h"
#include <libs/fatfs/ff.h> #include <libs/fatfs/ff.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#include <utils/sprintf.h> #include <utils/sprintf.h>
#define BACKUP_PATH_MAX 270
// Check if file/directory exists // Check if file/directory exists
static bool path_exists(const char *path) { static bool path_exists(const char *path) {
FILINFO fno; FILINFO fno;
return (f_stat(path, &fno) == FR_OK); return (f_stat(path, &fno) == FR_OK);
} }
// Create all parent directories for a path (mkdir -p style)
static void ensure_parent_dirs(const char *full_path) {
char buf[BACKUP_PATH_MAX];
int n = (int)strlen(full_path);
if (n >= BACKUP_PATH_MAX) return;
memcpy(buf, full_path, n + 1);
for (int i = 4; i < n; i++) {
if (buf[i] == '/') {
buf[i] = '\0';
f_mkdir(buf);
buf[i] = '/';
}
}
}
// Copy a single path (file or dir) to backup base, preserving SD structure
static int backup_single_path(const char *src_path, const char *backup_base) {
FILINFO fno;
if (f_stat(src_path, &fno) != FR_OK)
return FR_OK;
const char *relative = src_path;
if (strncmp(relative, "sd:/", 4) == 0)
relative += 4;
if (fno.fattrib & AM_DIR) {
const char *last_slash = strrchr(relative, '/');
char parent[BACKUP_PATH_MAX];
if (last_slash && last_slash > relative) {
s_printf(parent, "%s/%.*s", backup_base, (int)(last_slash - relative), relative);
/* Create full parent hierarchy (e.g. atmosphere, atmosphere/contents) */
ensure_parent_dirs(parent);
f_mkdir(parent); /* Ensure parent exists; FR_EXIST is fine */
return folder_copy(src_path, parent);
} else {
ensure_parent_dirs(backup_base);
return folder_copy(src_path, backup_base);
}
} else {
char dst_path[BACKUP_PATH_MAX];
s_printf(dst_path, "%s/%s", backup_base, relative);
ensure_parent_dirs(dst_path);
return file_copy(src_path, dst_path);
}
}
// Backup all paths from varargs lists (same structure as delete_path_lists_grouped)
int backup_deletion_lists(const char *backup_base, ...) {
va_list ap;
const char **list;
int res = FR_OK;
/* FatFS f_mkdir only creates the last component; parent must exist first */
ensure_parent_dirs(BACKUP_BASE_PATH);
res = f_mkdir(BACKUP_BASE_PATH);
if (res != FR_OK && res != FR_EXIST)
return res;
ensure_parent_dirs(backup_base);
res = f_mkdir(backup_base);
if (res != FR_OK && res != FR_EXIST)
return res;
va_start(ap, backup_base);
while ((list = va_arg(ap, const char **)) != NULL) {
for (int i = 0; list[i] != NULL; i++) {
if (path_exists(list[i])) {
int copy_res = backup_single_path(list[i], backup_base);
if (copy_res != FR_OK && res == FR_OK)
res = copy_res; // Remember first error but keep going
}
}
}
va_end(ap);
/* Best-effort: return FR_OK so install continues even if some copies failed */
return FR_OK;
}
// Backup user data before clean install // Backup user data before clean install
int backup_user_data(void) { int backup_user_data(void) {
int res; int res;

View File

@@ -7,6 +7,8 @@
#include <utils/types.h> #include <utils/types.h>
#define TEMP_BACKUP_PATH "sd:/temp_backup" #define TEMP_BACKUP_PATH "sd:/temp_backup"
#define BACKUP_BASE_PATH "sd:/backup/OmniNX"
#define PRE_OMNINX_LABEL "pre-omninx"
// Backup user data (DBI, Tinfoil, prod.keys) before clean install // Backup user data (DBI, Tinfoil, prod.keys) before clean install
int backup_user_data(void); int backup_user_data(void);
@@ -16,3 +18,6 @@ int restore_user_data(void);
// Clean up temporary backup directory // Clean up temporary backup directory
int cleanup_backup(void); int cleanup_backup(void);
// Backup paths from varargs lists to backup_base (pass path arrays, terminate with NULL)
int backup_deletion_lists(const char *backup_base, ...);

View File

@@ -199,8 +199,6 @@ static const char* clean_switch_files_to_delete[] = {
"sd:/switch/DBI/DBI_845_EN.nro", "sd:/switch/DBI/DBI_845_EN.nro",
"sd:/switch/DBI/DBI_849_DE.nro", "sd:/switch/DBI/DBI_849_DE.nro",
"sd:/switch/DBI/DBI_849_EN.nro", "sd:/switch/DBI/DBI_849_EN.nro",
"sd:/switch/DBI/DBI_874_DE.nro",
"sd:/switch/DBI/DBI_874_EN.nro",
"sd:/switch/DBI_810_DE/DBI_810.nro", "sd:/switch/DBI_810_DE/DBI_810.nro",
"sd:/switch/DBI_810_DE/DBI_810_DE.nro", "sd:/switch/DBI_810_DE/DBI_810_DE.nro",
"sd:/switch/DBI_810_EN/DBI_810_EN.nro", "sd:/switch/DBI_810_EN/DBI_810_EN.nro",
@@ -293,6 +291,5 @@ static const char* old_version_files_to_delete[] = {
"sd:/1.4.0-pre-d", "sd:/1.4.0-pre-d",
"sd:/1.4.1", "sd:/1.4.1",
"sd:/1.5.0", "sd:/1.5.0",
"sd:/1.6.0",
NULL NULL
}; };

View File

@@ -122,8 +122,8 @@ static const char* config_dirs_to_delete[] = {
}; };
// Switch directories to delete // Switch directories to delete
// NOTE: .packages is intentionally excluded - UltraHand package cache, preserve during updates
static const char* switch_dirs_to_delete[] = { static const char* switch_dirs_to_delete[] = {
"sd:/switch/.packages",
"sd:/switch/.overlays", "sd:/switch/.overlays",
"sd:/switch/90DNS_tester", "sd:/switch/90DNS_tester",
"sd:/switch/aio-switch-updater", "sd:/switch/aio-switch-updater",
@@ -172,6 +172,7 @@ static const char* switch_dirs_to_delete[] = {
"sd:/switch/Switch-Time", "sd:/switch/Switch-Time",
"sd:/switch/SwitchIdent", "sd:/switch/SwitchIdent",
"sd:/switch/Switch_themes_Installer", "sd:/switch/Switch_themes_Installer",
"sd:/switch/Switchfin",
"sd:/switch/Sys-Clk Manager", "sd:/switch/Sys-Clk Manager",
"sd:/switch/Sys-Con", "sd:/switch/Sys-Con",
"sd:/switch/sys-clk-manager", "sd:/switch/sys-clk-manager",
@@ -222,9 +223,9 @@ static const char* switch_files_to_delete[] = {
"sd:/switch/SimpleModDownloader.nro", "sd:/switch/SimpleModDownloader.nro",
"sd:/switch/SimpleModManager.nro", "sd:/switch/SimpleModManager.nro",
"sd:/switch/sphaira.nro", "sd:/switch/sphaira.nro",
"sd:/switch/swr-ini-tool/swr-ini-tool.nro",
"sd:/switch/SwitchIdent.nro", "sd:/switch/SwitchIdent.nro",
"sd:/switch/Switch_themes_Installer/NXThemesInstaller.nro", "sd:/switch/Switch_themes_Installer/NXThemesInstaller.nro",
"sd:/switch/Switchfin.nro",
"sd:/switch/Sys-Clk Manager/sys-clk-manager.nro", "sd:/switch/Sys-Clk Manager/sys-clk-manager.nro",
"sd:/switch/Sys-Con.nro", "sd:/switch/Sys-Con.nro",
"sd:/switch/sys-clk-manager.nro", "sd:/switch/sys-clk-manager.nro",

View File

@@ -1,46 +0,0 @@
/*
* DRAM capacity from fuse (SKU), not physical probe.
*/
#include "dram_fuse.h"
#include <soc/fuse.h>
#include <soc/hw_init.h>
#include <soc/t210.h>
static int mariko_dram_mib(u32 dram_id)
{
switch (dram_id) {
case 9:
case 13:
case 18:
case 21:
case 23:
case 28:
return 8192;
default:
if (dram_id >= 3 && dram_id <= 28)
return 4096;
return -1;
}
}
static int erista_dram_mib(u32 dram_id)
{
if (dram_id == 4)
return 6144;
if (dram_id <= 6)
return 4096;
return -1;
}
int dram_capacity_mib_from_fuse(void)
{
u32 nid = fuse_read_dramid(false);
u32 chip = hw_get_chip_id();
if (chip == GP_HIDREV_MAJOR_T210)
return erista_dram_mib(nid);
if (chip == GP_HIDREV_MAJOR_T210B01)
return mariko_dram_mib(nid);
return -1;
}

View File

@@ -1,6 +0,0 @@
#pragma once
#include <utils/types.h>
/* DRAM capacity in MiB from fuse DRAM ID + SoC (same table as RAM test payload). */
int dram_capacity_mib_from_fuse(void);

View File

@@ -3,7 +3,6 @@
*/ */
#include "install.h" #include "install.h"
#include "dram_fuse.h"
#include "fs.h" #include "fs.h"
#include "version.h" #include "version.h"
#include "gfx.h" #include "gfx.h"
@@ -114,38 +113,6 @@ void install_combine_path(char *result, size_t size, const char *base, const cha
} }
} }
/* Copy every regular file at staging root to dst_root; subdirs and volume labels skipped. */
int install_copy_staging_root_files(const char *staging, const char *dst_root) {
DIR dir;
FILINFO fno;
char src_full[256];
char dst_full[256];
int res = f_opendir(&dir, staging);
if (res != FR_OK)
return res;
while (1) {
res = f_readdir(&dir, &fno);
if (res != FR_OK || fno.fname[0] == 0)
break;
if (fno.fname[0] == '.' && (fno.fname[1] == '\0' || (fno.fname[1] == '.' && fno.fname[2] == '\0')))
continue;
if (fno.fattrib & (AM_DIR | AM_VOL))
continue;
install_combine_path(src_full, sizeof(src_full), staging, fno.fname);
install_combine_path(dst_full, sizeof(dst_full), dst_root, fno.fname);
res = file_copy(src_full, dst_full);
if (res != FR_OK) {
f_closedir(&dir);
return res;
}
}
f_closedir(&dir);
return FR_OK;
}
// Recursive folder copy with progress tracking // Recursive folder copy with progress tracking
static int folder_copy_progress_recursive(const char *src, const char *dst, int *copied, int total, u32 start_x, u32 start_y, const char *display_name, int *last_percent) { static int folder_copy_progress_recursive(const char *src, const char *dst, int *copied, int total, u32 start_x, u32 start_y, const char *display_name, int *last_percent) {
DIR dir; DIR dir;
@@ -619,58 +586,34 @@ int delete_path_list(const char* paths[], const char* description) {
return (failed == 0) ? FR_OK : FR_DISK_ERR; return (failed == 0) ? FR_OK : FR_DISK_ERR;
} }
#define HEKATE_8GB_SRC "sd:/bootloader/hekate_8gb.bin"
#define PAYLOAD_BIN_DST "sd:/payload.bin"
#define UPDATE_BIN_DST "sd:/bootloader/update.bin"
static void unlink_ignore_err(const char *path)
{
FILINFO fno;
if (f_stat(path, &fno) != FR_OK)
return;
if (fno.fattrib & AM_RDO)
f_chmod(path, fno.fattrib & ~AM_RDO, AM_RDO);
f_unlink(path);
}
/* After pack copy: if >4 GiB fuse RAM, install 8GB Hekate to payload.bin + bootloader/update.bin; always remove hekate_8gb.bin when done or if not used. */
static void install_hekate_8gb_post_copy(void)
{
if (!install_path_exists(HEKATE_8GB_SRC))
return;
int mib = dram_capacity_mib_from_fuse();
if (mib > 4096) {
install_set_color(COLOR_CYAN);
gfx_printf("\nMehr als 4 GB RAM erkannt (Fuse). Die 8-GB-Hekate-Variante wird verwendet.\n");
gfx_printf("Kopiere nach payload.bin und bootloader/update.bin...\n");
install_set_color(COLOR_WHITE);
int r1 = file_copy(HEKATE_8GB_SRC, PAYLOAD_BIN_DST);
int r2 = file_copy(HEKATE_8GB_SRC, UPDATE_BIN_DST);
if (r1 == FR_OK && r2 == FR_OK) {
install_set_color(COLOR_GREEN);
gfx_printf(" [OK] Hekate 8 GB installiert.\n");
install_set_color(COLOR_WHITE);
unlink_ignore_err(HEKATE_8GB_SRC);
} else {
install_set_color(COLOR_ORANGE);
gfx_printf(" [WARN] Kopie fehlgeschlagen (payload: %d, update: %d). hekate_8gb.bin bleibt.\n", r1, r2);
install_set_color(COLOR_WHITE);
}
} else {
unlink_ignore_err(HEKATE_8GB_SRC);
}
}
// Main installation function // Main installation function
int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) { int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
int res; int res;
if (mode == INSTALL_MODE_UPDATE) { if (mode == INSTALL_MODE_UPDATE) {
// Update mode: selective cleanup then install // Update mode: backup, selective cleanup, then install
omninx_status_t status = detect_omninx_installation();
const char *version = (status.version_file[0] != '\0') ? status.version_file : "unknown";
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 1: Bereinigung...\n"); gfx_printf("Schritt 1: Backup vor Update (%s)...\n", version);
install_set_color(COLOR_WHITE);
res = backup_before_update(version);
/* Backup is best-effort; continue install even on failure */
if (res == FR_OK) {
install_set_color(COLOR_GREEN);
gfx_printf(" [OK] Sicherung nach sd:/backup/OmniNX/%s/\n", version);
install_set_color(COLOR_WHITE);
} else {
install_set_color(COLOR_ORANGE);
gfx_printf(" [WARN] Backup fehlgeschlagen, fahre trotzdem fort...\n");
install_set_color(COLOR_WHITE);
}
install_check_and_clear_screen_if_needed();
gfx_printf("\n");
install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 2: Bereinigung...\n");
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
res = update_mode_cleanup(pack_variant); res = update_mode_cleanup(pack_variant);
if (res != FR_OK) return res; if (res != FR_OK) return res;
@@ -678,13 +621,11 @@ int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
gfx_printf("\n"); gfx_printf("\n");
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 2: Dateien kopieren...\n"); gfx_printf("Schritt 3: Dateien kopieren...\n");
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
res = update_mode_install(pack_variant); res = update_mode_install(pack_variant);
if (res != FR_OK) return res; if (res != FR_OK) return res;
install_hekate_8gb_post_copy();
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
// Remove staging directory (installed pack) // Remove staging directory (installed pack)
res = cleanup_staging_directory(pack_variant); res = cleanup_staging_directory(pack_variant);
@@ -693,7 +634,7 @@ int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
res = cleanup_other_staging_directories(pack_variant); res = cleanup_other_staging_directories(pack_variant);
return res; return res;
} else { } else {
// Clean mode: backup, wipe, restore, install // Clean mode: backup user data, backup pre-omninx, wipe, restore, install
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 1: Sichere Benutzerdaten...\n"); gfx_printf("Schritt 1: Sichere Benutzerdaten...\n");
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
@@ -703,7 +644,23 @@ int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
gfx_printf("\n"); gfx_printf("\n");
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 2: Bereinige alte Installation...\n"); gfx_printf("Schritt 2: Backup alter CFW-Dateien (pre-omninx)...\n");
install_set_color(COLOR_WHITE);
res = backup_before_clean();
if (res == FR_OK) {
install_set_color(COLOR_GREEN);
gfx_printf(" [OK] Sicherung nach sd:/backup/OmniNX/pre-omninx/\n");
install_set_color(COLOR_WHITE);
} else {
install_set_color(COLOR_ORANGE);
gfx_printf(" [WARN] Backup fehlgeschlagen, fahre trotzdem fort...\n");
install_set_color(COLOR_WHITE);
}
install_check_and_clear_screen_if_needed();
gfx_printf("\n");
install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 3: Bereinige alte Installation...\n");
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
res = clean_mode_wipe(); res = clean_mode_wipe();
if (res != FR_OK) return res; if (res != FR_OK) return res;
@@ -711,7 +668,7 @@ int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
gfx_printf("\n"); gfx_printf("\n");
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 3: Stelle Benutzerdaten wieder her...\n"); gfx_printf("Schritt 4: Stelle Benutzerdaten wieder her...\n");
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
res = clean_mode_restore(); res = clean_mode_restore();
if (res != FR_OK) return res; if (res != FR_OK) return res;
@@ -719,13 +676,11 @@ int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
gfx_printf("\n"); gfx_printf("\n");
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 4: Dateien kopieren...\n"); gfx_printf("Schritt 5: Dateien kopieren...\n");
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
res = clean_mode_install(pack_variant); res = clean_mode_install(pack_variant);
if (res != FR_OK) return res; if (res != FR_OK) return res;
install_hekate_8gb_post_copy();
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
// Remove staging directory (installed pack) // Remove staging directory (installed pack)
res = cleanup_staging_directory(pack_variant); res = cleanup_staging_directory(pack_variant);

View File

@@ -17,6 +17,7 @@ typedef enum {
int perform_installation(omninx_variant_t pack_variant, install_mode_t mode); int perform_installation(omninx_variant_t pack_variant, install_mode_t mode);
// Update mode operations (install_update.c) // Update mode operations (install_update.c)
int backup_before_update(const char *version);
int update_mode_cleanup(omninx_variant_t variant); int update_mode_cleanup(omninx_variant_t variant);
int update_mode_install(omninx_variant_t variant); int update_mode_install(omninx_variant_t variant);
int cleanup_staging_directory(omninx_variant_t pack_variant); int cleanup_staging_directory(omninx_variant_t pack_variant);
@@ -24,6 +25,7 @@ int cleanup_staging_directory(omninx_variant_t pack_variant);
int cleanup_other_staging_directories(omninx_variant_t installed_variant); int cleanup_other_staging_directories(omninx_variant_t installed_variant);
// Clean install operations (install_clean.c) // Clean install operations (install_clean.c)
int backup_before_clean(void);
int clean_mode_backup(void); int clean_mode_backup(void);
int clean_mode_wipe(void); int clean_mode_wipe(void);
int clean_mode_restore(void); int clean_mode_restore(void);
@@ -35,7 +37,6 @@ void install_check_and_clear_screen_if_needed(void);
bool install_path_exists(const char *path); bool install_path_exists(const char *path);
int install_count_directory_items(const char *path); int install_count_directory_items(const char *path);
void install_combine_path(char *result, size_t size, const char *base, const char *add); void install_combine_path(char *result, size_t size, const char *base, const char *add);
int install_copy_staging_root_files(const char *staging, const char *dst_root);
int delete_path_list(const char* paths[], const char* description); int delete_path_list(const char* paths[], const char* description);
int delete_path_lists_grouped(const char *folder_display_name, ...); int delete_path_lists_grouped(const char *folder_display_name, ...);
int folder_delete_single_with_progress(const char *path, const char *display_name); int folder_delete_single_with_progress(const char *path, const char *display_name);

View File

@@ -11,6 +11,7 @@
#include "gfx.h" #include "gfx.h"
#include "version.h" #include "version.h"
#include <libs/fatfs/ff.h> #include <libs/fatfs/ff.h>
#include <utils/sprintf.h>
#include <string.h> #include <string.h>
#undef COLOR_CYAN #undef COLOR_CYAN
@@ -31,6 +32,26 @@
#define path_exists install_path_exists #define path_exists install_path_exists
#define count_directory_items install_count_directory_items #define count_directory_items install_count_directory_items
// Backup paths before clean install (sd:/backup/OmniNX/pre-omninx)
int backup_before_clean(void) {
char backup_base[270];
s_printf(backup_base, "%s/%s", BACKUP_BASE_PATH, PRE_OMNINX_LABEL);
return backup_deletion_lists(backup_base,
clean_atmosphere_dirs_to_delete,
clean_atmosphere_contents_dirs_to_delete,
clean_atmosphere_files_to_delete,
clean_bootloader_dirs_to_delete,
clean_bootloader_files_to_delete,
clean_config_dirs_to_delete,
clean_switch_dirs_to_delete,
clean_switch_files_to_delete,
clean_root_files_to_delete,
clean_misc_dirs_to_delete,
clean_misc_files_to_delete,
old_version_files_to_delete,
NULL);
}
// Clean mode: Backup user data // Clean mode: Backup user data
int clean_mode_backup(void) { int clean_mode_backup(void) {
set_color(COLOR_CYAN); set_color(COLOR_CYAN);

View File

@@ -4,6 +4,7 @@
*/ */
#include "install.h" #include "install.h"
#include "backup.h"
#include "deletion_lists_update.h" #include "deletion_lists_update.h"
#include "fs.h" #include "fs.h"
#include "version.h" #include "version.h"
@@ -34,6 +35,25 @@
#define path_exists install_path_exists #define path_exists install_path_exists
#define count_directory_items install_count_directory_items #define count_directory_items install_count_directory_items
// Backup paths before update (sd:/backup/OmniNX/{version})
int backup_before_update(const char *version) {
char backup_base[270];
s_printf(backup_base, "%s/%s", BACKUP_BASE_PATH, version);
return backup_deletion_lists(backup_base,
atmosphere_dirs_to_delete,
atmosphere_contents_dirs_to_delete,
atmosphere_files_to_delete,
bootloader_dirs_to_delete,
bootloader_files_to_delete,
config_dirs_to_delete,
switch_dirs_to_delete,
switch_files_to_delete,
root_files_to_delete,
misc_dirs_to_delete,
misc_files_to_delete,
NULL);
}
// Update mode: Cleanup specific directories/files // Update mode: Cleanup specific directories/files
int update_mode_cleanup(omninx_variant_t variant) { int update_mode_cleanup(omninx_variant_t variant) {
(void)variant; (void)variant;
@@ -78,6 +98,7 @@ int update_mode_install(omninx_variant_t variant) {
int res; int res;
const char* staging = get_staging_path(variant); const char* staging = get_staging_path(variant);
char src_path[256]; char src_path[256];
char dst_path[256];
if (!staging) { if (!staging) {
return FR_INVALID_PARAMETER; return FR_INVALID_PARAMETER;
@@ -105,10 +126,6 @@ int update_mode_install(omninx_variant_t variant) {
res = folder_copy_with_progress_v2(src_path, "sd:/", "switch/"); res = folder_copy_with_progress_v2(src_path, "sd:/", "switch/");
if (res != FR_OK && res != FR_NO_FILE) return res; if (res != FR_OK && res != FR_NO_FILE) return res;
s_printf(src_path, "%s/themes", staging);
res = folder_copy_with_progress_v2(src_path, "sd:/", "themes/");
if (res != FR_OK && res != FR_NO_FILE) return res;
s_printf(src_path, "%s/warmboot_mariko", staging); s_printf(src_path, "%s/warmboot_mariko", staging);
res = folder_copy_with_progress_v2(src_path, "sd:/", "warmboot_mariko/"); res = folder_copy_with_progress_v2(src_path, "sd:/", "warmboot_mariko/");
if (res != FR_OK && res != FR_NO_FILE) return res; if (res != FR_OK && res != FR_NO_FILE) return res;
@@ -123,9 +140,29 @@ int update_mode_install(omninx_variant_t variant) {
gfx_printf(" Kopiere Root-Dateien...\n"); gfx_printf(" Kopiere Root-Dateien...\n");
set_color(COLOR_WHITE); set_color(COLOR_WHITE);
res = install_copy_staging_root_files(staging, "sd:/"); s_printf(src_path, "%s/boot.dat", staging);
if (res != FR_OK) s_printf(dst_path, "sd:/boot.dat");
return res; if (path_exists(src_path)) file_copy(src_path, dst_path);
s_printf(src_path, "%s/boot.ini", staging);
s_printf(dst_path, "sd:/boot.ini");
if (path_exists(src_path)) file_copy(src_path, dst_path);
s_printf(src_path, "%s/exosphere.ini", staging);
s_printf(dst_path, "sd:/exosphere.ini");
if (path_exists(src_path)) file_copy(src_path, dst_path);
s_printf(src_path, "%s/hbmenu.nro", staging);
s_printf(dst_path, "sd:/hbmenu.nro");
if (path_exists(src_path)) file_copy(src_path, dst_path);
s_printf(src_path, "%s/loader.bin", staging);
s_printf(dst_path, "sd:/loader.bin");
if (path_exists(src_path)) file_copy(src_path, dst_path);
s_printf(src_path, "%s/payload.bin", staging);
s_printf(dst_path, "sd:/payload.bin");
if (path_exists(src_path)) file_copy(src_path, dst_path);
set_color(COLOR_GREEN); set_color(COLOR_GREEN);
gfx_printf(" Kopie abgeschlossen!\n"); gfx_printf(" Kopie abgeschlossen!\n");

View File

@@ -35,7 +35,6 @@
#include "fs.h" #include "fs.h"
#include "version.h" #include "version.h"
#include "install.h" #include "install.h"
#include "screenshot.h"
// Configuration // Configuration
#define PAYLOAD_PATH "sd:/bootloader/update.bin" #define PAYLOAD_PATH "sd:/bootloader/update.bin"
@@ -116,12 +115,6 @@ static void print_header(void) {
set_color(COLOR_WHITE); set_color(COLOR_WHITE);
} }
/* Console Vol+ and Vol- together (exit / cancel where documented) */
static inline bool cancel_combo_pressed(u8 btn)
{
return (btn & (BTN_VOL_UP | BTN_VOL_DOWN)) == (BTN_VOL_UP | BTN_VOL_DOWN);
}
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) { void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) {
memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ); memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ);
@@ -250,13 +243,11 @@ void ipl_main(void) {
set_color(COLOR_GREEN); set_color(COLOR_GREEN);
gfx_printf("Druecke A-Taste (rechter Joy-Con) oder Power-Taste,\n"); gfx_printf("Druecke A-Taste (rechter Joy-Con) oder Power-Taste,\n");
gfx_printf("um Hekate zu starten...\n"); gfx_printf("um Hekate zu starten...\n");
gfx_printf("Oder Vol+ und Vol- (Konsole) gleichzeitig.\n");
set_color(COLOR_WHITE); set_color(COLOR_WHITE);
} else { } else {
set_color(COLOR_GREEN); set_color(COLOR_GREEN);
gfx_printf("Druecke A-Taste (rechter Joy-Con) oder Power-Taste,\n"); gfx_printf("Druecke A-Taste (rechter Joy-Con) oder Power-Taste,\n");
gfx_printf("um den Neustart zu starten...\n"); gfx_printf("um den Neustart zu starten...\n");
gfx_printf("Oder Vol+ und Vol- (Konsole) gleichzeitig.\n");
set_color(COLOR_WHITE); set_color(COLOR_WHITE);
} }
@@ -273,17 +264,9 @@ void ipl_main(void) {
break; break;
} }
// Check joycon A button; Capture = screenshot // Check joycon A button
jc_gamepad_rpt_t *jc = joycon_poll(); jc_gamepad_rpt_t *jc = joycon_poll();
if (jc) { if (jc && jc->a) {
if (jc->cap)
take_screenshot();
if (jc->a) {
button_pressed = true;
break;
}
}
if (cancel_combo_pressed(btn_state)) {
button_pressed = true; button_pressed = true;
break; break;
} }
@@ -341,14 +324,12 @@ void ipl_main(void) {
gfx_printf("\n"); gfx_printf("\n");
set_color(COLOR_CYAN); set_color(COLOR_CYAN);
gfx_printf("D-Pad / Vol+/-: Auswahl | A oder Power: Bestaetigen\n"); gfx_printf("D-Pad / Vol+/-: Auswahl | A oder Power: Bestaetigen\n");
gfx_printf("Vol+ und Vol- gleichzeitig: Abbrechen (Hekate)\n");
set_color(COLOR_WHITE); set_color(COLOR_WHITE);
// Edge detection: only move on press (not while held) // Edge detection: only move on press (not while held)
bool prev_up = false, prev_down = false; bool prev_up = false, prev_down = false;
bool menu_aborted = false;
while (!confirmed && !menu_aborted) { while (!confirmed) {
// On selection change: redraw only the two affected lines (no full clear) // On selection change: redraw only the two affected lines (no full clear)
if (selected != prev_selected) { if (selected != prev_selected) {
gfx_con_setpos(menu_x, menu_variant_start_y + (u32)prev_selected * 16); gfx_con_setpos(menu_x, menu_variant_start_y + (u32)prev_selected * 16);
@@ -364,14 +345,6 @@ void ipl_main(void) {
jc_gamepad_rpt_t *jc = joycon_poll(); jc_gamepad_rpt_t *jc = joycon_poll();
u8 btn = btn_read(); u8 btn = btn_read();
if (jc && jc->cap)
take_screenshot();
if (cancel_combo_pressed(btn)) {
menu_aborted = true;
break;
}
// D-pad or Vol+ / Vol- for selection (Vol+ = up, Vol- = down) // D-pad or Vol+ / Vol- for selection (Vol+ = up, Vol- = down)
bool cur_up = false, cur_down = false; bool cur_up = false, cur_down = false;
if (jc) { if (jc) {
@@ -397,20 +370,6 @@ void ipl_main(void) {
msleep(50); msleep(50);
} }
if (menu_aborted) {
gfx_printf("\n");
set_color(COLOR_YELLOW);
gfx_printf("Abgebrochen. Starte Hekate...\n");
set_color(COLOR_WHITE);
msleep(500);
if (file_exists(PAYLOAD_PATH)) {
launch_payload(PAYLOAD_PATH);
} else {
power_set_state(POWER_OFF_REBOOT);
}
return;
}
pack_variant = variants_present[selected]; pack_variant = variants_present[selected];
gfx_clear_grey(0x1B); gfx_clear_grey(0x1B);
print_header(); print_header();
@@ -436,19 +395,14 @@ void ipl_main(void) {
gfx_printf("mit angeschlossenem Ladegeraet durchgefuehrt werden.\n\n"); gfx_printf("mit angeschlossenem Ladegeraet durchgefuehrt werden.\n\n");
set_color(COLOR_YELLOW); set_color(COLOR_YELLOW);
gfx_printf("Stecke das Ladegeraet an und warte...\n"); gfx_printf("Stecke das Ladegeraet an und warte...\n");
gfx_printf("Oder Vol+ und Vol- (Konsole) zum Abbrechen.\n"); gfx_printf("Oder druecke + und - zum Abbrechen.\n");
set_color(COLOR_WHITE); set_color(COLOR_WHITE);
jc_init_hw(); jc_init_hw();
while (btn_read() & BTN_POWER) { msleep(50); } while (btn_read() & BTN_POWER) { msleep(50); }
bool user_cancelled = false; bool user_cancelled = false;
while (batt_pct < BATT_LOW_THRESHOLD && !bq24193_charger_connected() && !user_cancelled) { while (batt_pct < BATT_LOW_THRESHOLD && !bq24193_charger_connected() && !user_cancelled) {
u8 pbtn = btn_read();
jc_gamepad_rpt_t *jc = joycon_poll(); jc_gamepad_rpt_t *jc = joycon_poll();
if (jc) { if (jc && jc->plus && jc->minus) {
if (jc->cap)
take_screenshot();
}
if (cancel_combo_pressed(pbtn)) {
user_cancelled = true; user_cancelled = true;
break; break;
} }
@@ -474,84 +428,6 @@ void ipl_main(void) {
gfx_con_setpos(0, 0); gfx_con_setpos(0, 0);
print_header(); print_header();
// UHS class check: recommend U2 / V30 / A2 for emuMMC (speed and reliability)
#define UHS_U2_MIN 2
#define UHS_V30_MIN 30
#define UHS_A2_MIN 2
bool uhs_ok = (sd_storage.ssr.uhs_grade >= UHS_U2_MIN &&
sd_storage.ssr.video_class >= UHS_V30_MIN &&
sd_storage.ssr.app_class >= UHS_A2_MIN);
if (!uhs_ok) {
jc_init_hw();
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
set_color(COLOR_RED);
gfx_printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
gfx_printf("!! WARNUNG - SD-KARTEN-KLASSE !!\n");
gfx_printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n");
set_color(COLOR_WHITE);
gfx_printf("Diese SD-Karte erfuellt NICHT die empfohlenen\n");
gfx_printf("Mindestanforderungen (U2 | V30 | A2).\n\n");
set_color(COLOR_YELLOW);
gfx_printf("Aktuelle Werte: UHS%d | V%d | A%d\n\n",
(u32)sd_storage.ssr.uhs_grade,
(u32)sd_storage.ssr.video_class,
(u32)sd_storage.ssr.app_class);
set_color(COLOR_WHITE);
gfx_printf("Moegliche Folgen bei schwachen Karten:\n");
gfx_printf(" - Langsamere emuMMC / Spiel-Ladezeiten\n");
gfx_printf(" - Hoheres Risiko von Korruption oder Abstuerzen\n");
gfx_printf(" - Instabilitaet beim Schreiben groesserer Daten\n\n");
set_color(COLOR_CYAN);
gfx_printf("Empfohlen: U2 | V30 | A2 oder besser.\n");
gfx_printf("Empfohlene Karten: Samsung EVO Plus, EVO Select und PRO Plus.\n\n");
set_color(COLOR_GREEN);
gfx_printf("Druecke A (oder Power), um trotzdem fortzufahren.\n");
set_color(COLOR_CYAN);
gfx_printf("Vol+ und Vol- (Konsole) gleichzeitig: Abbrechen -> Hekate.\n");
set_color(COLOR_WHITE);
while (btn_read() & BTN_POWER) { msleep(50); }
bool acknowledged = false;
bool uhs_aborted = false;
while (!acknowledged && !uhs_aborted) {
u8 btn_state = btn_read();
if (btn_state & BTN_POWER) acknowledged = true;
jc_gamepad_rpt_t *jc = joycon_poll();
if (jc) {
if (jc->cap)
take_screenshot();
if (jc->a) acknowledged = true;
}
if (cancel_combo_pressed(btn_state)) {
uhs_aborted = true;
break;
}
msleep(50);
}
if (uhs_aborted) {
gfx_printf("\nAbgebrochen. Starte Hekate...\n");
msleep(500);
if (file_exists(PAYLOAD_PATH)) {
launch_payload(PAYLOAD_PATH);
} else {
power_set_state(POWER_OFF_REBOOT);
}
return;
}
// Wait for A and Power to be released so the same press doesn't start the install
while (btn_read() & BTN_POWER) { msleep(50); }
bool released = false;
while (!released) {
jc_gamepad_rpt_t *jc = joycon_poll();
released = (!jc || !jc->a) && !(btn_read() & BTN_POWER);
if (!released) msleep(50);
}
msleep(300); // Short delay so the next screen is visible before accepting input
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
print_header();
}
// Show information // Show information
set_color(COLOR_CYAN); set_color(COLOR_CYAN);
gfx_printf("Installationsmodus: %s\n", mode == INSTALL_MODE_UPDATE ? "Update" : "Saubere Installation"); gfx_printf("Installationsmodus: %s\n", mode == INSTALL_MODE_UPDATE ? "Update" : "Saubere Installation");
@@ -577,7 +453,7 @@ void ipl_main(void) {
gfx_printf("um die Installation zu starten...\n"); gfx_printf("um die Installation zu starten...\n");
set_color(COLOR_WHITE); set_color(COLOR_WHITE);
set_color(COLOR_CYAN); set_color(COLOR_CYAN);
gfx_printf("Vol+ und Vol- (Konsole) gleichzeitig: Abbrechen -> Hekate.\n"); gfx_printf("Druecke + und - gleichzeitig zum Abbrechen (zurueck zu Hekate).\n");
set_color(COLOR_WHITE); set_color(COLOR_WHITE);
// Wait for A/Power to start, or +/- to cancel // Wait for A/Power to start, or +/- to cancel
@@ -597,19 +473,18 @@ void ipl_main(void) {
break; break;
} }
// Check joycon buttons; Capture = screenshot // Check joycon buttons
jc_gamepad_rpt_t *jc = joycon_poll(); jc_gamepad_rpt_t *jc = joycon_poll();
if (jc) { if (jc) {
if (jc->cap)
take_screenshot();
if (jc->a) { if (jc->a) {
button_pressed = true; button_pressed = true;
break; break;
} }
} // + and - simultaneously = cancel, return to hekate
if (cancel_combo_pressed(btn_state)) { if (jc->plus && jc->minus) {
cancelled = true; cancelled = true;
break; break;
}
} }
msleep(50); // Small delay to avoid busy-waiting msleep(50); // Small delay to avoid busy-waiting
@@ -646,7 +521,6 @@ void ipl_main(void) {
// Wait 3 seconds before clearing screen to allow errors to be visible // Wait 3 seconds before clearing screen to allow errors to be visible
msleep(3000); msleep(3000);
// take_screenshot(); // Take a screenshot of the installation summary
// Clear screen for final summary to ensure it's visible // Clear screen for final summary to ensure it's visible
gfx_clear_grey(0x1B); gfx_clear_grey(0x1B);
@@ -699,15 +573,11 @@ void ipl_main(void) {
break; break;
} }
// Check joycon A button; Capture = screenshot // Check joycon A button
jc_gamepad_rpt_t *jc = joycon_poll(); jc_gamepad_rpt_t *jc = joycon_poll();
if (jc) { if (jc && jc->a) {
if (jc->cap) button_pressed = true;
take_screenshot(); break;
if (jc->a) {
button_pressed = true;
break;
}
} }
msleep(50); // Small delay to avoid busy-waiting msleep(50); // Small delay to avoid busy-waiting
@@ -745,13 +615,9 @@ void ipl_main(void) {
} }
jc_gamepad_rpt_t *jc = joycon_poll(); jc_gamepad_rpt_t *jc = joycon_poll();
if (jc) { if (jc && jc->a) {
if (jc->cap) button_pressed = true;
take_screenshot(); break;
if (jc->a) {
button_pressed = true;
break;
}
} }
msleep(50); msleep(50);

View File

@@ -184,11 +184,6 @@ static void _sd_deinit()
void sd_unmount() { _sd_deinit(); } void sd_unmount() { _sd_deinit(); }
void sd_end() { _sd_deinit(); } void sd_end() { _sd_deinit(); }
bool sd_get_card_mounted(void)
{
return sd_mounted;
}
void *sd_file_read(const char *path, u32 *fsize) void *sd_file_read(const char *path, u32 *fsize)
{ {
FIL fp; FIL fp;

View File

@@ -1,111 +0,0 @@
/*
* Screenshot support for OmniNX Installer Payload
* Based on TegraExplorer (AllgemeinerProblemLoeser) TakeScreenshot implementation.
*/
#include "screenshot.h"
#include "gfx.h"
#include "nx_sd.h"
#include <libs/fatfs/ff.h>
#include <mem/heap.h>
#include <display/di.h>
#include <utils/util.h>
#include <utils/sprintf.h>
#include <rtc/max77620-rtc.h>
#include <string.h>
/* BMP file header (54 bytes), matching TegraExplorer tools.h */
typedef struct __attribute__((packed)) _bmp_hdr_t
{
u16 magic;
u32 size;
u32 rsvd;
u32 data_off;
u32 hdr_size;
u32 width;
u32 height;
u16 planes;
u16 pxl_bits;
u32 comp;
u32 img_size;
u32 res_h;
u32 res_v;
u64 rsvd2;
} bmp_hdr_t;
#define BMP_HEADER_SIZE 0x36
#define FB_SIZE 0x384000 /* 1280 * 720 * 4 */
#define SCREEN_W 1280
#define SCREEN_H 720
void take_screenshot(void)
{
static u32 last_timer = 0;
if (!sd_get_card_mounted())
return;
/* 3-second cooldown (same as TegraExplorer) */
u32 now = get_tmr_s();
if (last_timer != 0 && now < last_timer + 3)
return;
last_timer = now;
const char basepath[] = "sd:/switch/screenshot";
char name[48];
char path[80];
rtc_time_t rtc;
max77620_rtc_get_time(&rtc);
s_printf(name, "omninx_installer_%04d%02d%02d_%02d%02d%02d.bmp",
(u32)rtc.year, (u32)rtc.month, (u32)rtc.day,
(u32)rtc.hour, (u32)rtc.min, (u32)rtc.sec);
s_printf(path, "%s/%s", basepath, name);
f_mkdir("sd:/switch");
f_mkdir(basepath);
const u32 file_size = BMP_HEADER_SIZE + FB_SIZE;
u8 *bitmap = (u8 *)malloc(file_size);
u32 *fb_copy = (u32 *)malloc(FB_SIZE);
if (!bitmap || !fb_copy) {
if (bitmap) free(bitmap);
if (fb_copy) free(fb_copy);
return;
}
/* Copy framebuffer with same coordinate flip as TegraExplorer (BGR layout) */
u32 *fb_ptr = gfx_ctxt.fb;
for (int x = SCREEN_W - 1; x >= 0; x--) {
for (int y = SCREEN_H - 1; y >= 0; y--)
fb_copy[y * SCREEN_W + x] = *fb_ptr++;
}
memcpy(bitmap + BMP_HEADER_SIZE, fb_copy, FB_SIZE);
bmp_hdr_t *bmp = (bmp_hdr_t *)bitmap;
bmp->magic = 0x4D42;
bmp->size = file_size;
bmp->rsvd = 0;
bmp->data_off = BMP_HEADER_SIZE;
bmp->hdr_size = 40;
bmp->width = SCREEN_W;
bmp->height = SCREEN_H;
bmp->planes = 1;
bmp->pxl_bits = 32;
bmp->comp = 0;
bmp->img_size = FB_SIZE;
bmp->res_h = 2834;
bmp->res_v = 2834;
bmp->rsvd2 = 0;
sd_save_to_file(bitmap, file_size, path);
free(bitmap);
free(fb_copy);
/* Brief backlight flash (same as TegraExplorer) */
display_backlight_brightness(255, 1000);
msleep(100);
display_backlight_brightness(100, 1000);
}

View File

@@ -1,13 +0,0 @@
/*
* Screenshot support for OmniNX Installer Payload
* Based on TegraExplorer (AllgemeinerProblemLoeser) TakeScreenshot implementation.
*/
#pragma once
#include <utils/types.h>
/* Take a screenshot of the current framebuffer and save as BMP to SD.
* Triggered by Capture button (jc->cap). Uses 3-second cooldown.
* Saves to sd:/switch/screenshot/omninx_installer_YYYYMMDD_HHMMSS.bmp */
void take_screenshot(void);

View File

@@ -1,70 +0,0 @@
/*
* Minimal RAM info test payload (fuse DRAM ID + SK table -> MiB).
* Build: make ram-test -> output/RAM-Test.bin
*/
#include <display/di.h>
#include <mem/heap.h>
#include <mem/minerva.h>
#include <memory_map.h>
#include <soc/bpmp.h>
#include <soc/fuse.h>
#include <soc/hw_init.h>
#include <soc/t210.h>
#include <utils/util.h>
#include "dram_fuse.h"
#include "gfx.h"
#undef COLOR_CYAN
#undef COLOR_WHITE
#define COLOR_CYAN 0xFF00FFFF
#define COLOR_WHITE 0xFFFFFFFF
/* Required by BDK */
boot_cfg_t __attribute__((section("._boot_cfg"))) b_cfg;
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
extern void pivot_stack(u32 stack_top);
void ipl_main(void)
{
hw_init();
pivot_stack(IPL_STACK_TOP);
heap_init(IPL_HEAP_START);
minerva_init();
minerva_change_freq(FREQ_800);
display_init();
u32 *fb = display_init_framebuffer_pitch();
gfx_init_ctxt(fb, 720, 1280, 720);
gfx_con_init();
display_backlight_pwm_init();
display_backlight_brightness(100, 1000);
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
gfx_con_setcol(COLOR_CYAN, gfx_con.fillbg, gfx_con.bgcol);
gfx_printf("RAM test payload\n\n");
gfx_con_setcol(COLOR_WHITE, gfx_con.fillbg, gfx_con.bgcol);
u32 raw = fuse_read_dramid(true);
u32 nid = fuse_read_dramid(false);
u32 chip = hw_get_chip_id();
int mib = dram_capacity_mib_from_fuse();
gfx_printf("SoC: %s\n", chip == GP_HIDREV_MAJOR_T210B01 ? "Mariko (T210B01)" : "Erista (T210)");
gfx_printf("DRAM fuse: raw %d norm %d\n", raw, nid);
if (mib > 0)
gfx_printf("Table MiB: %d (fuse SKU, not probe)\n", mib);
else
gfx_printf("Table MiB: (unknown id for this SoC)\n");
gfx_printf("\nHang — power off or inject payload.\n");
while (1)
msleep(500);
}