Merge branch 'main' of https://github.com/Horizon-OC/Horizon-OC
This commit is contained in:
@@ -28,6 +28,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "customize.hpp"
|
#include "customize.hpp"
|
||||||
|
#include "oc_log.hpp"
|
||||||
|
|
||||||
#define PATCH_OFFSET(offset, value) \
|
#define PATCH_OFFSET(offset, value) \
|
||||||
static_assert(sizeof(__typeof__(offset)) <= sizeof(u64)); \
|
static_assert(sizeof(__typeof__(offset)) <= sizeof(u64)); \
|
||||||
|
|||||||
128
Source/Atmosphere/stratosphere/loader/source/oc/oc_log.cpp
Normal file
128
Source/Atmosphere/stratosphere/loader/source/oc/oc_log.cpp
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||||
|
* Copyright (c) 2019 Atmosphere-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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<s32>(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
|
||||||
|
}
|
||||||
27
Source/Atmosphere/stratosphere/loader/source/oc/oc_log.hpp
Normal file
27
Source/Atmosphere/stratosphere/loader/source/oc/oc_log.hpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||||
|
* Copyright (c) 2019 Atmosphere-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* See https://github.com/lulle2007200/emuMMC/blob/internal-emummc/source/ */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ams::ldr::hoc {
|
||||||
|
|
||||||
|
void Log(const char *data, ...);
|
||||||
|
void ViewLog();
|
||||||
|
|
||||||
|
}
|
||||||
81
Source/fatal_handler_payload/Makefile
Normal file
81
Source/fatal_handler_payload/Makefile
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>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 <stddef.h>\n#include <stdint.h>\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)"
|
||||||
0
Source/fatal_handler_payload/compile_flags.txt
Normal file
0
Source/fatal_handler_payload/compile_flags.txt
Normal file
558
Source/fatal_handler_payload/fatal_handler/gfx/gfx.c
Normal file
558
Source/fatal_handler_payload/fatal_handler/gfx/gfx.c
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#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];
|
||||||
|
}
|
||||||
|
}
|
||||||
94
Source/fatal_handler_payload/fatal_handler/gfx/gfx.h
Normal file
94
Source/fatal_handler_payload/fatal_handler/gfx/gfx.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GFX_H_
|
||||||
|
#define _GFX_H_
|
||||||
|
|
||||||
|
#include <bdk.h>
|
||||||
|
|
||||||
|
#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
|
||||||
114
Source/fatal_handler_payload/fatal_handler/hos/secmon_exo.c
Normal file
114
Source/fatal_handler_payload/fatal_handler/hos/secmon_exo.c
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <bdk.h>
|
||||||
|
#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);
|
||||||
|
}
|
||||||
24
Source/fatal_handler_payload/fatal_handler/hos/secmon_exo.h
Normal file
24
Source/fatal_handler_payload/fatal_handler/hos/secmon_exo.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SECMON_EXO_H_
|
||||||
|
#define _SECMON_EXO_H_
|
||||||
|
|
||||||
|
#include <bdk.h>
|
||||||
|
|
||||||
|
void secmon_exo_check_panic();
|
||||||
|
|
||||||
|
#endif
|
||||||
25
Source/fatal_handler_payload/fatal_handler/link.ld
Normal file
25
Source/fatal_handler_payload/fatal_handler/link.ld
Normal file
@@ -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 = .;
|
||||||
|
}
|
||||||
|
}
|
||||||
92
Source/fatal_handler_payload/fatal_handler/main.c
Normal file
92
Source/fatal_handler_payload/fatal_handler/main.c
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <bdk.h>
|
||||||
|
#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();
|
||||||
|
}
|
||||||
78
Source/fatal_handler_payload/fatal_handler/start.S
Normal file
78
Source/fatal_handler_payload/fatal_handler/start.S
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.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
|
||||||
Reference in New Issue
Block a user