From e1d75f008457884a5cefcabbe3ab02309ad1a33f Mon Sep 17 00:00:00 2001 From: Lightos1 <124387232+Lightos1@users.noreply.github.com> Date: Sun, 12 Apr 2026 22:00:45 +0200 Subject: [PATCH 1/2] add oc_log files --- .../loader/source/oc/oc_common.hpp | 1 + .../stratosphere/loader/source/oc/oc_log.cpp | 128 ++++++++++++++++++ .../stratosphere/loader/source/oc/oc_log.hpp | 27 ++++ 3 files changed, 156 insertions(+) create mode 100644 Source/Atmosphere/stratosphere/loader/source/oc/oc_log.cpp create mode 100644 Source/Atmosphere/stratosphere/loader/source/oc/oc_log.hpp diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp index bf05e26f..2e900f72 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp @@ -28,6 +28,7 @@ #endif #include "customize.hpp" +#include "oc_log.hpp" #define PATCH_OFFSET(offset, value) \ static_assert(sizeof(__typeof__(offset)) <= sizeof(u64)); \ diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_log.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_log.cpp new file mode 100644 index 00000000..911ccfae --- /dev/null +++ b/Source/Atmosphere/stratosphere/loader/source/oc/oc_log.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2019 m4xw + * Copyright (c) 2019 Atmosphere-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* See https://github.com/lulle2007200/emuMMC/blob/internal-emummc/source/ */ + +#include "oc_common.hpp" + +#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING) +#include "fatal_handler_bin.h" +#endif + +namespace ams::ldr::hoc { + + #define ATMOSPHERE_REBOOT_TO_FATAL_MAGIC 0x32454641 + #define ATMOSPHERE_IRAM_PAYLOAD_BASE 0x40010000 + #define ATMOSPHERE_FATAL_ERROR_ADDR 0x4003E000 + + _Alignas(4096) u8 working_buf[4096]; + + void SmcRebootToIramPayload() { + SecmonArgs args; + args.X[0] = 0xC3000401; + args.X[1] = 65001; + args.X[2] = 0; + args.X[3] = 2; + svcCallSecureMonitor(&args); + } + + Result SmcCopyToIram(uintptr_t dest, const void *src, u32 size) { + SecmonArgs args; + args.X[0] = 0xF0000201; + args.X[1] = (u64)src; + args.X[2] = (u64)dest; + args.X[3] = size; + args.X[4] = 1; + svcCallSecureMonitor(&args); + Result rc = 0; + if (args.X[0] != 0) { + rc = (26u | ((u32)args.X[0] << 9u)); + } + return rc; + } + + Result SmcCopyFromIram(void *dest, uintptr_t src, u32 size) { + SecmonArgs args; + args.X[0] = 0xF0000201; + args.X[1] = (u64)dest; + args.X[2] = (u64)src; + args.X[3] = size; + args.X[4] = 0; + svcCallSecureMonitor(&args); + Result rc = 0; + if (args.X[0] != 0) { + rc = (26u | ((u32)args.X[0] << 9u)); + } + return rc; + } + + struct log_ctx_t { + u32 magic; + u32 sz; + u32 start; + u32 end; + char buf[]; + }; + + #define IRAM_LOG_CTX_ADDR 0x4003C000 + #define IRAM_LOG_MAX_SZ 4096 + + #if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING) + void Log(const char *data, ...) { + static const u32 max_log_sz = sizeof(working_buf) - sizeof(log_ctx_t); + static bool initDone = false; + log_ctx_t *log_ctx = (log_ctx_t*)working_buf; + + SmcCopyFromIram(working_buf, IRAM_LOG_CTX_ADDR, sizeof(working_buf)); + + if (!initDone) { + initDone = true; + log_ctx->buf[0] = '\0'; + log_ctx->magic = 0xaabbccdd; + log_ctx->start = 0; + log_ctx->end = 0; + } + + va_list args; + va_start(args, data); + s32 res = vsnprintf(log_ctx->buf + log_ctx->end, max_log_sz - log_ctx->end, data, args); + va_end(args); + + if (res < 0 || res >= (static_cast(max_log_sz - log_ctx->end))) { + SmcCopyToIram(IRAM_LOG_CTX_ADDR, working_buf, sizeof(working_buf)); + return; + } + + log_ctx->end += res; + SmcCopyToIram(IRAM_LOG_CTX_ADDR, working_buf, sizeof(working_buf)); + } + #endif + + #if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING) + void ViewLog() { + constexpr size_t PageSize = 4096; + for (size_t ofs = 0; ofs < fatal_handler_bin_size; ofs += PageSize) { + memcpy(&working_buf, fatal_handler_bin + ofs, std::min(fatal_handler_bin_size - ofs, PageSize)); + SmcCopyToIram(ATMOSPHERE_IRAM_PAYLOAD_BASE + ofs, &working_buf, std::min(fatal_handler_bin_size - ofs, PageSize)); + } + + SmcRebootToIramPayload(); + + while(true){} + } + #endif +} diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_log.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_log.hpp new file mode 100644 index 00000000..615405ea --- /dev/null +++ b/Source/Atmosphere/stratosphere/loader/source/oc/oc_log.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2019 m4xw + * Copyright (c) 2019 Atmosphere-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* See https://github.com/lulle2007200/emuMMC/blob/internal-emummc/source/ */ + +#pragma once + +namespace ams::ldr::hoc { + + void Log(const char *data, ...); + void ViewLog(); + +} From 985ecdc98080e21adca0f3728e349abb8930b615 Mon Sep 17 00:00:00 2001 From: Lightos1 <124387232+Lightos1@users.noreply.github.com> Date: Sun, 12 Apr 2026 22:04:19 +0200 Subject: [PATCH 2/2] add fatal handler payload --- Source/fatal_handler_payload/Makefile | 81 +++ .../fatal_handler_payload/compile_flags.txt | 0 .../fatal_handler/gfx/gfx.c | 558 ++++++++++++++++++ .../fatal_handler/gfx/gfx.h | 94 +++ .../fatal_handler/hos/secmon_exo.c | 114 ++++ .../fatal_handler/hos/secmon_exo.h | 24 + .../fatal_handler/link.ld | 25 + .../fatal_handler/main.c | 92 +++ .../fatal_handler/start.S | 78 +++ 9 files changed, 1066 insertions(+) create mode 100644 Source/fatal_handler_payload/Makefile create mode 100644 Source/fatal_handler_payload/compile_flags.txt create mode 100644 Source/fatal_handler_payload/fatal_handler/gfx/gfx.c create mode 100644 Source/fatal_handler_payload/fatal_handler/gfx/gfx.h create mode 100644 Source/fatal_handler_payload/fatal_handler/hos/secmon_exo.c create mode 100644 Source/fatal_handler_payload/fatal_handler/hos/secmon_exo.h create mode 100644 Source/fatal_handler_payload/fatal_handler/link.ld create mode 100644 Source/fatal_handler_payload/fatal_handler/main.c create mode 100644 Source/fatal_handler_payload/fatal_handler/start.S diff --git a/Source/fatal_handler_payload/Makefile b/Source/fatal_handler_payload/Makefile new file mode 100644 index 00000000..bacb922c --- /dev/null +++ b/Source/fatal_handler_payload/Makefile @@ -0,0 +1,81 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif +include $(DEVKITARM)/base_rules +################################################################################ +IPL_LOAD_ADDR := 0x40010000 +################################################################################ +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +BUILDDIR := build +OUTPUTDIR := out +SOURCEDIR = fatal_handler +BDKDIR := bdk +GFXDIR := fatal_handler/gfx +TARGET := fatal_handler +BDKINC := -I$(BDKDIR) +GFXINC := -I$(GFXDIR) +GFX_INC := '"gfx.h"' +VPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/)) +VPATH += $(dir $(wildcard ./$(BDKDIR)/)) $(dir $(wildcard ./$(BDKDIR)/*/)) $(dir $(wildcard ./$(BDKDIR)/*/*/)) +OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \ + start.o exception_handlers.o irq.o main.o \ + timer.o heap.o hw_init.o clock.o i2c.o gpio.o \ + max7762x.o di.o util.o fuse.o pinmux.o \ + secmon_exo.o gfx.o bpmp.o sdram.o minerva.o btn.o max77620-rtc.o se.o mc.o) +################################################################################ +# BDK defines. +CUSTOMDEFINES := -DGFX_INC=$(GFX_INC) +CUSTOMDEFINES += -DBDK_MALLOC_NO_DEFRAG -DBDK_MC_ENABLE_AHB_REDIRECT -DBDK_EMUMMC_ENABLE +CUSTOMDEFINES += -DBDK_WATCHDOG_FIQ_ENABLE -DBDK_RESTART_BL_ON_WDT +INCDIRS := $(BDKINC) $(GFXINC) +WARNINGS := -Wall -Wsign-compare -Wno-array-bounds -Wno-stringop-overflow +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork +CFLAGS = $(ARCH) -O2 -g -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES) +LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR) +################################################################################ + +BIN_TARGET := $(OUTPUTDIR)/$(TARGET).bin +BIN_OBJ := $(OUTPUTDIR)/$(TARGET).bin.o +BIN_HEADER := $(OUTPUTDIR)/$(TARGET)_bin.h +BIN_SYM := $(subst .,_,$(subst /,_,$(TARGET)))_bin + +define bin2o + $(eval SYM := $(BIN_SYM)) + $(eval BIN_SIZE := $(shell wc -c < $(BIN_TARGET))) + @$(OBJCOPY) --input-target binary --output-target elf32-littlearm --binary-architecture arm \ + --redefine-sym _binary_$(shell echo $(BIN_TARGET) | tr '/.-' '___')_start=$(SYM) \ + --redefine-sym _binary_$(shell echo $(BIN_TARGET) | tr '/.-' '___')_end=$(SYM)_end \ + --redefine-sym _binary_$(shell echo $(BIN_TARGET) | tr '/.-' '___')_size=$(SYM)_size \ + $(BIN_TARGET) $(BIN_OBJ) + @printf '#pragma once\n#include \n#include \nextern const uint8_t $(SYM)[];\nextern const uint8_t $(SYM)_end[];\n#if __cplusplus >= 201103L\nstatic constexpr size_t $(SYM)_size=$(BIN_SIZE);\n#else\nstatic const size_t $(SYM)_size=$(BIN_SIZE);\n#endif\n' > $(BIN_HEADER) +endef + +################################################################################ +.PHONY: all clean +all: $(BIN_OBJ) $(BIN_HEADER) + +$(BIN_OBJ) $(BIN_HEADER): $(BIN_TARGET) + $(bin2o) + +$(BIN_TARGET): $(BUILDDIR)/$(TARGET)/$(TARGET).elf + $(OBJCOPY) -S -O binary $< $(BIN_TARGET) + +clean: + @rm -rf $(OBJS) $(BIN_OBJ) $(BIN_HEADER) + +$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) + @$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ + +$(BUILDDIR)/$(TARGET)/%.o: %.c + @$(CC) $(CFLAGS) $(INCDIRS) -c $< -o $@ + +$(BUILDDIR)/$(TARGET)/%.o: %.S + @$(CC) $(CFLAGS) -c $< -o $@ + +$(OBJS): $(BUILDDIR)/$(TARGET) + +$(BUILDDIR)/$(TARGET): + @mkdir -p "$(BUILDDIR)" + @mkdir -p "$(BUILDDIR)/$(TARGET)" + @mkdir -p "$(OUTPUTDIR)" diff --git a/Source/fatal_handler_payload/compile_flags.txt b/Source/fatal_handler_payload/compile_flags.txt new file mode 100644 index 00000000..e69de29b diff --git a/Source/fatal_handler_payload/fatal_handler/gfx/gfx.c b/Source/fatal_handler_payload/fatal_handler/gfx/gfx.c new file mode 100644 index 00000000..37d7c372 --- /dev/null +++ b/Source/fatal_handler_payload/fatal_handler/gfx/gfx.c @@ -0,0 +1,558 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2022 CTCaer + * + * 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 . + */ + +#include +#include +#include "gfx.h" + +// Global gfx console and context. +gfx_ctxt_t gfx_ctxt; +gfx_con_t gfx_con; + +static bool gfx_con_init_done = false; + +static const u8 _gfx_font[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( ) + 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!) + 0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (") + 0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, // Char 035 (#) + 0x00, 0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, // Char 036 ($) + 0x00, 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, // Char 037 (%) + 0x00, 0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, // Char 038 (&) + 0x00, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, // Char 039 (') + 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, // Char 040 (() + 0x00, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x00, // Char 041 ()) + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // Char 042 (*) + 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // Char 043 (+) + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 044 (,) + 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, // Char 045 (-) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // Char 046 (.) + 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, // Char 047 (/) + 0x00, 0x3C, 0x66, 0x76, 0x6E, 0x66, 0x3C, 0x00, // Char 048 (0) + 0x00, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00, // Char 049 (1) + 0x00, 0x3C, 0x62, 0x30, 0x0C, 0x06, 0x7E, 0x00, // Char 050 (2) + 0x00, 0x3C, 0x62, 0x38, 0x60, 0x66, 0x3C, 0x00, // Char 051 (3) + 0x00, 0x6C, 0x6C, 0x66, 0xFE, 0x60, 0x60, 0x00, // Char 052 (4) + 0x00, 0x7E, 0x06, 0x7E, 0x60, 0x66, 0x3C, 0x00, // Char 053 (5) + 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00, // Char 054 (6) + 0x00, 0x7E, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, // Char 055 (7) + 0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // Char 056 (8) + 0x00, 0x3C, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, // Char 057 (9) + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, // Char 058 (:) + 0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 059 (;) + 0x00, 0x70, 0x1C, 0x06, 0x06, 0x1C, 0x70, 0x00, // Char 060 (<) + 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, // Char 061 (=) + 0x00, 0x0E, 0x38, 0x60, 0x60, 0x38, 0x0E, 0x00, // Char 062 (>) + 0x00, 0x3C, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, // Char 063 (?) + 0x00, 0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, // Char 064 (@) + 0x00, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 065 (A) + 0x00, 0x3E, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 066 (B) + 0x00, 0x3C, 0x66, 0x06, 0x06, 0x66, 0x3C, 0x00, // Char 067 (C) + 0x00, 0x1E, 0x36, 0x66, 0x66, 0x36, 0x1E, 0x00, // Char 068 (D) + 0x00, 0x7E, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00, // Char 069 (E) + 0x00, 0x3E, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00, // Char 070 (F) + 0x00, 0x3C, 0x66, 0x06, 0x76, 0x66, 0x3C, 0x00, // Char 071 (G) + 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 072 (H) + 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 073 (I) + 0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, // Char 074 (J) + 0x00, 0x66, 0x36, 0x1E, 0x1E, 0x36, 0x66, 0x00, // Char 075 (K) + 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00, // Char 076 (L) + 0x00, 0x46, 0x6E, 0x7E, 0x56, 0x46, 0x46, 0x00, // Char 077 (M) + 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, // Char 078 (N) + 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 079 (O) + 0x00, 0x3E, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, // Char 080 (P) + 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00, // Char 081 (Q) + 0x00, 0x3E, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00, // Char 082 (R) + 0x00, 0x3C, 0x66, 0x0C, 0x30, 0x66, 0x3C, 0x00, // Char 083 (S) + 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // Char 084 (T) + 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 085 (U) + 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 086 (V) + 0x00, 0x46, 0x46, 0x56, 0x7E, 0x6E, 0x46, 0x00, // Char 087 (W) + 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, // Char 088 (X) + 0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, // Char 089 (Y) + 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00, // Char 090 (Z) + 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, // Char 091 ([) + 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, // Char 092 (\) + 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, // Char 093 (]) + 0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, // Char 094 (^) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // Char 095 (_) + 0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, // Char 096 (`) + 0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00, // Char 097 (a) + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 098 (b) + 0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00, // Char 099 (c) + 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, // Char 100 (d) + 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00, // Char 101 (e) + 0x00, 0x38, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00, // Char 102 (f) + 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x40, 0x3C, 0x00, // Char 103 (g) + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00, // Char 104 (h) + 0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00, // Char 105 (i) + 0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1E, 0x00, // Char 106 (j) + 0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00, // Char 107 (k) + 0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 108 (l) + 0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, // Char 109 (m) + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00, // Char 110 (n) + 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 111 (o) + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x00, // Char 112 (p) + 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, // Char 113 (q) + 0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00, // Char 114 (r) + 0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00, // Char 115 (s) + 0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00, // Char 116 (t) + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, // Char 117 (u) + 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 118 (v) + 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, // Char 119 (w) + 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // Char 120 (x) + 0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00, // Char 121 (y) + 0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, // Char 122 (z) + 0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, 0x18, // Char 123 ({) + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // Char 124 (|) + 0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08, 0x0C, // Char 125 (}) + 0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~) +}; + +void gfx_clear_grey(u8 color) +{ + memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4); +} + +void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height) +{ + memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride); +} + +void gfx_clear_color(u32 color) +{ + for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++) + gfx_ctxt.fb[i] = color; +} + +void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride) +{ + gfx_ctxt.fb = fb; + gfx_ctxt.width = width; + gfx_ctxt.height = height; + gfx_ctxt.stride = stride; +} + +void gfx_con_init() +{ + gfx_con.gfx_ctxt = &gfx_ctxt; + gfx_con.fntsz = 16; + gfx_con.x = 0; + gfx_con.y = 0; + gfx_con.savedx = 0; + gfx_con.savedy = 0; + gfx_con.fgcol = TXT_CLR_DEFAULT; + gfx_con.fillbg = 1; + gfx_con.bgcol = TXT_CLR_BG; + gfx_con.mute = 0; + + gfx_con_init_done = true; +} + +void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol) +{ + gfx_con.fgcol = fgcol; + gfx_con.fillbg = fillbg; + gfx_con.bgcol = bgcol; +} + +void gfx_con_getpos(u32 *x, u32 *y) +{ + *x = gfx_con.x; + *y = gfx_con.y; +} + +void gfx_con_setpos(u32 x, u32 y) +{ + gfx_con.x = x; + gfx_con.y = y; +} + +void gfx_putc(char c) +{ + // Duplicate code for performance reasons. + switch (gfx_con.fntsz) + { + case 16: + if (c >= 32 && c <= 126) + { + u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; + u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride; + + for (u32 i = 0; i < 16; i += 2) + { + u8 v = *cbuf; + for (u32 k = 0; k < 2; k++) + { + for (u32 j = 0; j < 8; j++) + { + if (v & 1) + { + *fb = gfx_con.fgcol; + fb++; + *fb = gfx_con.fgcol; + } + else if (gfx_con.fillbg) + { + *fb = gfx_con.bgcol; + fb++; + *fb = gfx_con.bgcol; + } + else + fb++; + v >>= 1; + fb++; + } + fb += gfx_ctxt.stride - 16; + v = *cbuf; + } + cbuf++; + } + gfx_con.x += 16; + } + else if (c == '\n') + { + gfx_con.x = 0; + gfx_con.y += 16; + if (gfx_con.y > gfx_ctxt.height - 16) + gfx_con.y = 0; + } + break; + case 8: + default: + if (c >= 32 && c <= 126) + { + u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; + u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride; + for (u32 i = 0; i < 8; i++) + { + u8 v = *cbuf++; + for (u32 j = 0; j < 8; j++) + { + if (v & 1) + *fb = gfx_con.fgcol; + else if (gfx_con.fillbg) + *fb = gfx_con.bgcol; + v >>= 1; + fb++; + } + fb += gfx_ctxt.stride - 8; + } + gfx_con.x += 8; + } + else if (c == '\n') + { + gfx_con.x = 0; + gfx_con.y += 8; + if (gfx_con.y > gfx_ctxt.height - 8) + gfx_con.y = 0; + } + break; + } +} + +void gfx_puts(const char *s) +{ + if (!s || !gfx_con_init_done || gfx_con.mute) + return; + + for (; *s; s++) + gfx_putc(*s); +} + +static void _gfx_putn(u32 v, int base, char fill, int fcnt) +{ + static const char digits[] = "0123456789ABCDEF"; + + char *p; + char buf[65]; + int c = fcnt; + bool negative = false; + + if (base != 10 && base != 16) + return; + + // Account for negative numbers. + if (base == 10 && v & 0x80000000) + { + negative = true; + v = (int)v * -1; + c--; + } + + p = buf + 64; + *p = 0; + do + { + c--; + *--p = digits[v % base]; + v /= base; + } while (v); + + if (negative) + *--p = '-'; + + if (fill != 0) + { + while (c > 0 && p > buf) + { + *--p = fill; + c--; + } + } + + gfx_puts(p); +} + +void gfx_put_small_sep() +{ + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 8; + gfx_putc('\n'); + gfx_con.fntsz = prevFontSize; +} + +void gfx_put_big_sep() +{ + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 16; + gfx_putc('\n'); + gfx_con.fntsz = prevFontSize; +} + +void gfx_printf(const char *fmt, ...) +{ + if (!gfx_con_init_done || gfx_con.mute) + return; + + va_list ap; + int fill, fcnt; + + va_start(ap, fmt); + while (*fmt) + { + if (*fmt == '%') + { + fmt++; + fill = 0; + fcnt = 0; + if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') + { + fcnt = *fmt; + fmt++; + if (*fmt >= '0' && *fmt <= '9') + { + fill = fcnt; + fcnt = *fmt - '0'; + fmt++; + } + else + { + fill = ' '; + fcnt -= '0'; + } + } + switch(*fmt) + { + case 'c': + gfx_putc(va_arg(ap, u32)); + break; + case 's': + gfx_puts(va_arg(ap, char *)); + break; + case 'd': + _gfx_putn(va_arg(ap, u32), 10, fill, fcnt); + break; + case 'p': + case 'P': + case 'x': + case 'X': + _gfx_putn(va_arg(ap, u32), 16, fill, fcnt); + break; + case 'k': + gfx_con.fgcol = va_arg(ap, u32); + break; + case 'K': + gfx_con.bgcol = va_arg(ap, u32); + gfx_con.fillbg = 1; + break; + case '%': + gfx_putc('%'); + break; + case '\0': + goto out; + default: + gfx_putc('%'); + gfx_putc(*fmt); + break; + } + } + else + gfx_putc(*fmt); + fmt++; + } + + out: + va_end(ap); +} + +static void _gfx_cputs(u32 color, const char *s) +{ + gfx_con.fgcol = color; + gfx_puts(s); + gfx_putc('\n'); + gfx_con.fgcol = TXT_CLR_DEFAULT; +} + +void gfx_wputs(const char *s) { _gfx_cputs(TXT_CLR_WARNING, s); } +void gfx_eputs(const char *s) { _gfx_cputs(TXT_CLR_ERROR, s); } + +void gfx_hexdump(u32 base, const void *buf, u32 len) +{ + if (!gfx_con_init_done || gfx_con.mute) + return; + + u8 *buff = (u8 *)buf; + + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 8; + for (u32 i = 0; i < len; i++) + { + if (i % 0x10 == 0) + { + if (i != 0) + { + gfx_puts("| "); + for (u32 j = 0; j < 0x10; j++) + { + u8 c = buff[i - 0x10 + j]; + if (c >= 32 && c <= 126) + gfx_putc(c); + else + gfx_putc('.'); + } + gfx_putc('\n'); + } + gfx_printf("%08x: ", base + i); + } + gfx_printf("%02x ", buff[i]); + if (i == len - 1) + { + int ln = len % 0x10 != 0; + u32 k = 0x10 - 1; + if (ln) + { + k = (len & 0xF) - 1; + for (u32 j = 0; j < 0x10 - k; j++) + gfx_puts(" "); + } + gfx_puts("| "); + for (u32 j = 0; j < (ln ? k : k + 1); j++) + { + u8 c = buff[i - k + j]; + if (c >= 32 && c <= 126) + gfx_putc(c); + else + gfx_putc('.'); + } + gfx_putc('\n'); + } + } + gfx_putc('\n'); + gfx_con.fntsz = prevFontSize; +} + +static int abs(int x) +{ + if (x < 0) + return -x; + return x; +} + +void gfx_set_pixel(u32 x, u32 y, u32 color) +{ + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color; +} + +void gfx_line(int x0, int y0, int x1, int y1, u32 color) +{ + int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1; + int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1; + int err = (dx > dy ? dx : -dy) / 2, e2; + + while (1) + { + gfx_set_pixel(x0, y0, color); + if (x0 == x1 && y0 == y1) + break; + e2 = err; + if (e2 >-dx) + { + err -= dy; + x0 += sx; + } + if (e2 < dy) + { + err += dx; + y0 += sy; + } + } +} + +void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +{ + u32 pos = 0; + for (u32 y = pos_y; y < (pos_y + size_y); y++) + { + for (u32 x = pos_x; x < (pos_x + size_x); x++) + { + memset(&gfx_ctxt.fb[x + y*gfx_ctxt.stride], buf[pos], 4); + pos++; + } + } +} + + +void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +{ + u32 pos = 0; + for (u32 y = pos_y; y < (pos_y + size_y); y++) + { + for (u32 x = pos_x; x < (pos_x + size_x); x++) + { + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16); + pos+=3; + } + } +} + +void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +{ + u32 *ptr = (u32 *)buf; + for (u32 y = pos_y; y < (pos_y + size_y); y++) + for (u32 x = pos_x; x < (pos_x + size_x); x++) + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = *ptr++; +} + +void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) +{ + for (u32 y = pos_y; y < (pos_y + size_y); y++) + { + for (u32 x = pos_x; x < (pos_x + size_x); x++) + gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x]; + } +} diff --git a/Source/fatal_handler_payload/fatal_handler/gfx/gfx.h b/Source/fatal_handler_payload/fatal_handler/gfx/gfx.h new file mode 100644 index 00000000..b2fa9152 --- /dev/null +++ b/Source/fatal_handler_payload/fatal_handler/gfx/gfx.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2021 CTCaer + * Copyright (c) 2018 M4xw + * + * 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 . + */ + +#ifndef _GFX_H_ +#define _GFX_H_ + +#include + +#define TXT_CLR_BG 0xFF1B1B1B // Dark Grey. +#define TXT_CLR_DEFAULT 0xFFCCCCCC // Light Grey. +#define TXT_CLR_WARNING 0xFFFFDD00 // Yellow. +#define TXT_CLR_ERROR 0xFFFF0000 // Red. +#define TXT_CLR_CYAN_L 0xFF00CCFF // Light Cyan. +#define TXT_CLR_TURQUOISE 0xFF00FFCC // Turquoise. +#define TXT_CLR_ORANGE 0xFFFFBA00 // Orange. +#define TXT_CLR_GREENISH 0xFF96FF00 // Toxic Green. +#define TXT_CLR_GREEN_D 0xFF008800 // Dark Green. +#define TXT_CLR_RED_D 0xFF880000 // Dark Red. +#define TXT_CLR_GREY_D 0xFF303030 // Darkest Grey. +#define TXT_CLR_GREY_DM 0xFF444444 // Darker Grey. +#define TXT_CLR_GREY_M 0xFF555555 // Dark Grey. +#define TXT_CLR_GREY 0xFF888888 // Grey. + +#define EPRINTF(text) gfx_eputs(text) +#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", TXT_CLR_ERROR, args, TXT_CLR_DEFAULT) +#define WPRINTF(text) gfx_wputs(text) +#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", TXT_CLR_WARNING, args, TXT_CLR_DEFAULT) + +typedef struct _gfx_ctxt_t +{ + u32 *fb; + u32 width; + u32 height; + u32 stride; +} gfx_ctxt_t; + +typedef struct _gfx_con_t +{ + gfx_ctxt_t *gfx_ctxt; + u32 fntsz; + u32 x; + u32 y; + u32 savedx; + u32 savedy; + u32 fgcol; + int fillbg; + u32 bgcol; + bool mute; +} gfx_con_t; + +// Global gfx console and context. +extern gfx_ctxt_t gfx_ctxt; +extern gfx_con_t gfx_con; + +void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride); +void gfx_clear_grey(u8 color); +void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height); +void gfx_clear_color(u32 color); +void gfx_con_init(); +void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol); +void gfx_con_getpos(u32 *x, u32 *y); +void gfx_con_setpos(u32 x, u32 y); +void gfx_putc(char c); +void gfx_puts(const char *s); +void gfx_wputs(const char *s); +void gfx_eputs(const char *s); +void gfx_printf(const char *fmt, ...) /* __attribute__((format(printf, 1, 2))) */; +void gfx_hexdump(u32 base, const void *buf, u32 len); + +void gfx_set_pixel(u32 x, u32 y, u32 color); +void gfx_line(int x0, int y0, int x1, int y1, u32 color); +void gfx_put_small_sep(); +void gfx_put_big_sep(); +void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); +void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); +void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); +void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); + +#endif diff --git a/Source/fatal_handler_payload/fatal_handler/hos/secmon_exo.c b/Source/fatal_handler_payload/fatal_handler/hos/secmon_exo.c new file mode 100644 index 00000000..57f22bae --- /dev/null +++ b/Source/fatal_handler_payload/fatal_handler/hos/secmon_exo.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2018-2024 CTCaer + * Copyright (c) 2019 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 . + */ + +#include +#include "secmon_exo.h" + +// Atmosphère reboot-to-fatal-error. +typedef struct _atm_fatal_error_ctx +{ + u32 magic; + u32 error_desc; + u64 title_id; + union + { + u64 gprs[32]; + struct + { + u64 _gprs[29]; + u64 fp; + u64 lr; + u64 sp; + }; + }; + u64 pc; + u64 module_base; + u32 pstate; + u32 afsr0; + u32 afsr1; + u32 esr; + u64 far; + u64 report_identifier; // Normally just system tick. + u64 stack_trace_size; + u64 stack_dump_size; + u64 stack_trace[0x20]; + u8 stack_dump[0x100]; + u8 tls[0x100]; +} atm_fatal_error_ctx; + + + +#define ATM_FATAL_ERR_CTX_ADDR 0x4003E000 +#define ATM_FATAL_MAGIC 0x30454641 // AFE0 + +#define HOS_PID_BOOT2 0x8 + + +static const char *get_error_desc(u32 error_desc) +{ + switch (error_desc) + { + case 0x100: + return "IABRT"; // Instruction Abort. + case 0x101: + return "DABRT"; // Data Abort. + case 0x102: + return "IUA"; // Instruction Unaligned Access. + case 0x103: + return "DUA"; // Data Unaligned Access. + case 0x104: + return "UDF"; // Undefined Instruction. + case 0x106: + return "SYS"; // System Error. + case 0x301: + return "SVC"; // Bad arguments or unimplemented SVC. + case 0xF00: + return "KRNL"; // Kernel panic. + case 0xFFD: + return "SO"; // Stack Overflow. + case 0xFFE: + return "std::abort"; + default: + return "UNK"; + } +} + +void secmon_exo_check_panic() +{ + volatile atm_fatal_error_ctx *rpt = (atm_fatal_error_ctx *)ATM_FATAL_ERR_CTX_ADDR; + + // Mask magic to maintain compatibility with any AFE version, thanks to additive struct members. + if ((rpt->magic & 0xF0FFFFFF) != ATM_FATAL_MAGIC) + return; + + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + WPRINTF("Panic occurred while running Atmosphere.\n\n"); + WPRINTFARGS("Title ID: %08X%08X", (u32)((u64)rpt->title_id >> 32), (u32)rpt->title_id); + WPRINTFARGS("Error: %s (0x%x)\n", get_error_desc(rpt->error_desc), rpt->error_desc); + + // Check if mixed atmosphere sysmodules. + if ((u32)rpt->title_id == HOS_PID_BOOT2) + WPRINTF("Mismatched Atmosphere files?\n"); + + + // Change magic to invalid, to prevent double-display of error/bootlooping. + rpt->magic = 0; + + display_backlight_brightness(100, 1000); +} diff --git a/Source/fatal_handler_payload/fatal_handler/hos/secmon_exo.h b/Source/fatal_handler_payload/fatal_handler/hos/secmon_exo.h new file mode 100644 index 00000000..1a84362a --- /dev/null +++ b/Source/fatal_handler_payload/fatal_handler/hos/secmon_exo.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018-2021 CTCaer + * + * 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 . + */ + +#ifndef _SECMON_EXO_H_ +#define _SECMON_EXO_H_ + +#include + +void secmon_exo_check_panic(); + +#endif diff --git a/Source/fatal_handler_payload/fatal_handler/link.ld b/Source/fatal_handler_payload/fatal_handler/link.ld new file mode 100644 index 00000000..335be025 --- /dev/null +++ b/Source/fatal_handler_payload/fatal_handler/link.ld @@ -0,0 +1,25 @@ +ENTRY(_start) + +SECTIONS { + PROVIDE(__ipl_start = IPL_LOAD_ADDR); + . = __ipl_start; + .text : { + *(.text._start); + KEEP(*(._boot_cfg)); + KEEP(*(._ipl_version)); + *(.text._irq_setup); + *(.text*); + } + .data : { + *(.data*); + *(.rodata*); + } + . = ALIGN(0x10); + __ipl_end = .; + .bss : { + __bss_start = .; + *(COMMON) + *(.bss*) + __bss_end = .; + } +} diff --git a/Source/fatal_handler_payload/fatal_handler/main.c b/Source/fatal_handler_payload/fatal_handler/main.c new file mode 100644 index 00000000..440d8f63 --- /dev/null +++ b/Source/fatal_handler_payload/fatal_handler/main.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2018 naehrwert + * + * Copyright (c) 2018-2024 CTCaer + * + * 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 . + */ + +#include +#include "hos/secmon_exo.h" + +typedef struct _log_ctx +{ + u32 magic; + u32 sz; + u32 start; + u32 end; + char buf[]; +} log_ctx_t; + +#define IRAM_LOG_CTX_ADDR 0x4003C000 + +static void check_log(){ + volatile log_ctx_t *log_ctx = (log_ctx_t*)IRAM_LOG_CTX_ADDR; + + if(log_ctx->magic == 0xaabbccdd){ + gfx_printf("\nLogs:\n"); + gfx_printf((char*)log_ctx->buf); + } +} + +volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR; + +extern void pivot_stack(u32 stack_top); + +void ipl_main() +{ + // Do initial HW configuration. This is compatible with consecutive reruns without a reset. + hw_init(); + // Pivot the stack under IPL. (Only max 4KB is needed). + pivot_stack(IPL_LOAD_ADDR); + + // Place heap at a place outside of L4T/HOS configuration and binaries. + heap_init((void *)IPL_HEAP_START); + + // Prep RTC regs for read. Needed for T210B01 R2C. + max77620_rtc_prep_read(); + + // Initialize display. + display_init(); + + u32 *fb = display_init_window_a_pitch(); + gfx_init_ctxt(fb, 720, 1280, 720); + gfx_con_init(); + + // Initialize backlight PWM. + display_backlight_pwm_init(); + display_backlight_brightness(100, 0); + + // Show AMS errors + secmon_exo_check_panic(); + check_log(); + + + gfx_printf("\n\nPress POWER to power off\nPress VOLUME to boot RCM\n"); + msleep(250); + + + do{ + u8 btn = btn_read(); + if(btn & BTN_POWER){ + power_set_state(POWER_OFF); + } + if(btn & (BTN_VOL_DOWN | BTN_VOL_UP)){ + power_set_state(REBOOT_RCM); + } + }while(true); + + // Halt BPMP if we managed to get out of execution. + while (true) + bpmp_halt(); +} diff --git a/Source/fatal_handler_payload/fatal_handler/start.S b/Source/fatal_handler_payload/fatal_handler/start.S new file mode 100644 index 00000000..d1def0a7 --- /dev/null +++ b/Source/fatal_handler_payload/fatal_handler/start.S @@ -0,0 +1,78 @@ +/* +* Copyright (c) 2018 naehrwert +* +* 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 . +*/ + +.section .text._start +.arm + +.extern _reloc_ipl +.type _reloc_ipl, %function + +.extern memset +.type memset, %function + +.extern _irq_setup +.type _irq_setup, %function + +.globl _start +.type _start, %function +_start: + ADR R0, _start + LDR R1, =__ipl_start + CMP R0, R1 + BEQ _real_start + + /* If we are not in the right location already, copy a relocator to upper IRAM. */ + ADR R2, _reloc_ipl + LDR R3, =0x4003FF00 + MOV R4, #(_real_start - _reloc_ipl) +_copy_loop: + LDMIA R2!, {R5} + STMIA R3!, {R5} + SUBS R4, #4 + BNE _copy_loop + + /* Use the relocator to copy ourselves into the right place. */ + LDR R2, =__ipl_end + SUB R2, R2, R1 + LDR R3, =_real_start + LDR R4, =0x4003FF00 + BX R4 + +_reloc_ipl: + LDMIA R0!, {R4-R7} + STMIA R1!, {R4-R7} + SUBS R2, #0x10 + BNE _reloc_ipl + /* Jump to the relocated entry. */ + BX R3 + +_real_start: + /* Initially, we place our stack under relocator but will move it to under the payload. */ + /* This depends on application scope. */ + LDR SP, =0x4003FF00 + LDR R0, =__bss_start + EOR R1, R1, R1 + LDR R2, =__bss_end + SUB R2, R2, R0 + BL memset + BL _irq_setup + B . + +.globl pivot_stack +.type pivot_stack, %function +pivot_stack: + MOV SP, R0 + BX LR