mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-28 09:30:58 +01:00
fusee: uncompress fusee-primary, which is now getting pretty big.
This commit is contained in:
parent
8104beb2e0
commit
f600dff961
@ -8,7 +8,7 @@ endif
|
|||||||
|
|
||||||
TOPDIR ?= $(CURDIR)
|
TOPDIR ?= $(CURDIR)
|
||||||
|
|
||||||
AMS := $(TOPDIR)/../../
|
AMS := $(TOPDIR)/../../../
|
||||||
include $(DEVKITARM)/base_rules
|
include $(DEVKITARM)/base_rules
|
||||||
|
|
||||||
AMSBRANCH := $(shell git symbolic-ref --short HEAD)
|
AMSBRANCH := $(shell git symbolic-ref --short HEAD)
|
||||||
@ -18,6 +18,13 @@ ifneq (, $(strip $(shell git status --porcelain 2>/dev/null)))
|
|||||||
AMSREV := $(AMSREV)-dirty
|
AMSREV := $(AMSREV)-dirty
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
define _bin2o
|
||||||
|
bin2s $< | $(AS) -o $(@)
|
||||||
|
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _ | tr - _)`"_end[];" > `(echo $(<F) | tr . _ | tr - _)`.h
|
||||||
|
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _ | tr - _)`"[];" >> `(echo $(<F) | tr . _ | tr - _)`.h
|
||||||
|
echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _ | tr - _)`_size";" >> `(echo $(<F) | tr . _ | tr - _)`.h
|
||||||
|
endef
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# TARGET is the name of the output
|
# TARGET is the name of the output
|
||||||
# BUILD is the directory where object files & intermediate files will be placed
|
# BUILD is the directory where object files & intermediate files will be placed
|
||||||
@ -27,9 +34,9 @@ endif
|
|||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
TARGET := $(notdir $(CURDIR))
|
TARGET := $(notdir $(CURDIR))
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := src ../../fusee/common ../../fusee/common/display ../../fusee/common/fatfs ../../fusee/common/sdmmc
|
SOURCES := src
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := include ../../libraries/libvapours/include
|
INCLUDES := include ../../../libraries/libvapours/include
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# options for code generation
|
# options for code generation
|
||||||
@ -77,14 +84,14 @@ export TOPDIR := $(CURDIR)
|
|||||||
|
|
||||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
|
||||||
$(AMS)/exosphere/program/rebootstub
|
$(CURDIR)/fusee-primary-main
|
||||||
|
|
||||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary-main.lz4
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# use CXX for linking C++ projects, CC for standard C
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
@ -100,10 +107,10 @@ else
|
|||||||
endif
|
endif
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
export OFILES_BIN := $(addsuffix .o,$(subst -,_,$(BINFILES)))
|
||||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES))))
|
||||||
|
|
||||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
@ -111,22 +118,24 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
|||||||
|
|
||||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
.PHONY: $(BUILD) clean all check_rebootstub
|
.PHONY: $(BUILD) clean all check_main
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
all: check_rebootstub $(BUILD)
|
all: $(BUILD)
|
||||||
|
|
||||||
check_rebootstub:
|
fusee-primary-main/fusee-primary-main.lz4: check_main
|
||||||
@$(MAKE) -C $(AMS)/exosphere/program/rebootstub all
|
|
||||||
|
|
||||||
$(BUILD): check_rebootstub
|
check_main:
|
||||||
|
@$(MAKE) -C fusee-primary-main all
|
||||||
|
|
||||||
|
$(BUILD): fusee-primary-main/fusee-primary-main.lz4
|
||||||
@[ -d $@ ] || mkdir -p $@
|
@[ -d $@ ] || mkdir -p $@
|
||||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
clean:
|
clean:
|
||||||
@echo clean ...
|
@echo clean ...
|
||||||
@$(MAKE) -C $(AMS)/exosphere/program/rebootstub clean
|
@$(MAKE) -C fusee-primary-main clean
|
||||||
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf
|
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf
|
||||||
|
|
||||||
|
|
||||||
@ -152,6 +161,8 @@ $(OUTPUT).elf : $(OFILES)
|
|||||||
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||||
@$(NM) -CSn $@ > $(notdir $*.lst)
|
@$(NM) -CSn $@ > $(notdir $*.lst)
|
||||||
|
|
||||||
|
utils.o: CFLAGS += -fno-builtin
|
||||||
|
|
||||||
$(OFILES_SRC) : $(HFILES_BIN)
|
$(OFILES_SRC) : $(HFILES_BIN)
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
@ -162,6 +173,14 @@ $(OFILES_SRC) : $(HFILES_BIN)
|
|||||||
@echo $(notdir $<)
|
@echo $(notdir $<)
|
||||||
@$(bin2o)
|
@$(bin2o)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
fusee_primary_main.lz4.o fusee_primary_main_lz4.h: fusee-primary-main.lz4
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(_bin2o)
|
||||||
|
|
||||||
-include $(DEPENDS)
|
-include $(DEPENDS)
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------------
|
||||||
|
173
fusee/fusee-primary/fusee-primary-main/Makefile
Normal file
173
fusee/fusee-primary/fusee-primary-main/Makefile
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
TOPDIR ?= $(CURDIR)
|
||||||
|
|
||||||
|
AMS ?= $(TOPDIR)/../../../
|
||||||
|
include $(DEVKITARM)/base_rules
|
||||||
|
|
||||||
|
AMSBRANCH := $(shell git symbolic-ref --short HEAD)
|
||||||
|
AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD)
|
||||||
|
|
||||||
|
ifneq (, $(strip $(shell git status --porcelain 2>/dev/null)))
|
||||||
|
AMSREV := $(AMSREV)-dirty
|
||||||
|
endif
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# TARGET is the name of the output
|
||||||
|
# BUILD is the directory where object files & intermediate files will be placed
|
||||||
|
# SOURCES is a list of directories containing source code
|
||||||
|
# DATA is a list of directories containing data files
|
||||||
|
# INCLUDES is a list of directories containing header files
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
TARGET := $(notdir $(CURDIR))
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := src ../../../fusee/common ../../../fusee/common/display ../../../fusee/common/fatfs ../../../fusee/common/sdmmc
|
||||||
|
DATA := data
|
||||||
|
INCLUDES := include ../../../libraries/libvapours/include
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
||||||
|
DEFINES := -D__BPMP__ -DFUSEE_STAGE1_SRC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\"
|
||||||
|
|
||||||
|
CFLAGS := \
|
||||||
|
-g \
|
||||||
|
-O2 \
|
||||||
|
-fomit-frame-pointer \
|
||||||
|
-ffunction-sections \
|
||||||
|
-fdata-sections \
|
||||||
|
-std=gnu11 \
|
||||||
|
-Werror \
|
||||||
|
-Wall \
|
||||||
|
-fstrict-volatile-bitfields \
|
||||||
|
$(ARCH) $(DEFINES)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE)
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=$(TOPDIR)/linker.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
|
LIBS :=
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS :=
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||||
|
export TOPDIR := $(CURDIR)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
|
||||||
|
$(AMS)/exosphere/program/rebootstub
|
||||||
|
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||||
|
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||||
|
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean all check_rebootstub
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: check_rebootstub $(BUILD)
|
||||||
|
|
||||||
|
check_rebootstub:
|
||||||
|
@$(MAKE) -C $(AMS)/exosphere/program/rebootstub all
|
||||||
|
|
||||||
|
$(BUILD): check_rebootstub
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@$(MAKE) -C $(AMS)/exosphere/program/rebootstub clean
|
||||||
|
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all : $(OUTPUT).lz4
|
||||||
|
|
||||||
|
$(OUTPUT).lz4 : $(OUTPUT).bin
|
||||||
|
@python ../lz4_compress.py $(OUTPUT).bin $(OUTPUT).lz4
|
||||||
|
@echo built ... $(notdir $@)
|
||||||
|
|
||||||
|
$(OUTPUT).bin : $(OUTPUT).elf
|
||||||
|
$(OBJCOPY) -S -O binary $< $@
|
||||||
|
@echo built ... $(notdir $@)
|
||||||
|
|
||||||
|
$(OUTPUT).elf : $(OFILES)
|
||||||
|
|
||||||
|
%.elf: $(OFILES)
|
||||||
|
@echo linking $(notdir $@)
|
||||||
|
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||||
|
@$(NM) -CSn $@ > $(notdir $*.lst)
|
||||||
|
|
||||||
|
$(OFILES_SRC) : $(HFILES_BIN)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o %_bin.h: %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
192
fusee/fusee-primary/fusee-primary-main/linker.ld
Normal file
192
fusee/fusee-primary/fusee-primary-main/linker.ld
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||||
|
OUTPUT_ARCH(arm)
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
PHDRS
|
||||||
|
{
|
||||||
|
crt0 PT_LOAD;
|
||||||
|
chainloader PT_LOAD;
|
||||||
|
main PT_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mostly copied from https://github.com/devkitPro/buildscripts/blob/master/dkarm-eabi/crtls/3dsx.ld */
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
NULL : ORIGIN = 0x00000000, LENGTH = 0x1000
|
||||||
|
main : ORIGIN = 0x40008000, LENGTH = 0x28000
|
||||||
|
low_iram : ORIGIN = 0x40003000, LENGTH = 0x1000
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
PROVIDE(__start__ = 0x40008000);
|
||||||
|
PROVIDE(__stack_top__ = 0x40008000);
|
||||||
|
PROVIDE(__stack_bottom__ = 0x40004000);
|
||||||
|
PROVIDE(__heap_start__ = 0);
|
||||||
|
PROVIDE(__heap_end__ = 0);
|
||||||
|
|
||||||
|
. = __start__;
|
||||||
|
|
||||||
|
.crt0 :
|
||||||
|
{
|
||||||
|
KEEP( *(.text.start) )
|
||||||
|
KEEP( *(.init) )
|
||||||
|
. = ALIGN(32);
|
||||||
|
} >main :crt0
|
||||||
|
|
||||||
|
.chainloader_loadable :
|
||||||
|
{
|
||||||
|
. = ALIGN(32);
|
||||||
|
PROVIDE (__chainloader_start__ = ABSOLUTE(.));
|
||||||
|
PROVIDE (__chainloader_lma__ = LOADADDR(.chainloader_loadable));
|
||||||
|
KEEP(*(.chainloader.text.start))
|
||||||
|
chainloader.o(.text*)
|
||||||
|
chainloader.o(.rodata*)
|
||||||
|
chainloader.o(.data*)
|
||||||
|
. = ALIGN(32);
|
||||||
|
} >low_iram AT>main :chainloader
|
||||||
|
|
||||||
|
.chainloader_bss (NOLOAD) :
|
||||||
|
{
|
||||||
|
. = ALIGN(32);
|
||||||
|
PROVIDE (__chainloader_bss_start__ = ABSOLUTE(.));
|
||||||
|
chainloader.o(.bss* COMMON)
|
||||||
|
. = ALIGN(32);
|
||||||
|
PROVIDE (__chainloader_end__ = ABSOLUTE(.));
|
||||||
|
} >low_iram :NONE
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
. = ALIGN(32);
|
||||||
|
/* .text */
|
||||||
|
*(.text)
|
||||||
|
*(.text.*)
|
||||||
|
*(.glue_7)
|
||||||
|
*(.glue_7t)
|
||||||
|
*(.stub)
|
||||||
|
*(.gnu.warning)
|
||||||
|
*(.gnu.linkonce.t*)
|
||||||
|
|
||||||
|
/* .fini */
|
||||||
|
KEEP( *(.fini) )
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main :main
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
*(.rodata)
|
||||||
|
*(.roda)
|
||||||
|
*(.rodata.*)
|
||||||
|
*all.rodata*(*)
|
||||||
|
*(.gnu.linkonce.r*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
PROVIDE (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE (__preinit_array_end = .);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.init_array ALIGN(4) :
|
||||||
|
{
|
||||||
|
PROVIDE (__init_array_start = .);
|
||||||
|
KEEP (*(SORT(.init_array.*)))
|
||||||
|
KEEP (*(.init_array))
|
||||||
|
PROVIDE (__init_array_end = .);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.fini_array ALIGN(4) :
|
||||||
|
{
|
||||||
|
PROVIDE (__fini_array_start = .);
|
||||||
|
KEEP (*(.fini_array))
|
||||||
|
KEEP (*(SORT(.fini_array.*)))
|
||||||
|
PROVIDE (__fini_array_end = .);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.ctors ALIGN(4) :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.dtors ALIGN(4) :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) __exidx_start = ABSOLUTE(.);} >main
|
||||||
|
ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) __exidx_end = ABSOLUTE(.);} >main
|
||||||
|
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
*(.data.*)
|
||||||
|
*(.gnu.linkonce.d*)
|
||||||
|
CONSTRUCTORS
|
||||||
|
. = ALIGN(32);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.bss (NOLOAD) :
|
||||||
|
{
|
||||||
|
. = ALIGN(32);
|
||||||
|
PROVIDE (__bss_start__ = ABSOLUTE(.));
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss)
|
||||||
|
*(.bss.*)
|
||||||
|
*(.gnu.linkonce.b*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(32);
|
||||||
|
PROVIDE (__bss_end__ = ABSOLUTE(.));
|
||||||
|
} >main :NONE
|
||||||
|
__end__ = ABSOLUTE(.) ;
|
||||||
|
|
||||||
|
/* ==================
|
||||||
|
==== Metadata ====
|
||||||
|
================== */
|
||||||
|
|
||||||
|
/* Discard sections that difficult post-processing */
|
||||||
|
/DISCARD/ : { *(.group .comment .note) }
|
||||||
|
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
}
|
7
fusee/fusee-primary/fusee-primary-main/linker.specs
Normal file
7
fusee/fusee-primary/fusee-primary-main/linker.specs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
%rename link old_link
|
||||||
|
|
||||||
|
*link:
|
||||||
|
%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections
|
||||||
|
|
||||||
|
*startfile:
|
||||||
|
crti%O%s crtbegin%O%s
|
23
fusee/fusee-primary/fusee-primary-main/lz4_compress.py
Normal file
23
fusee/fusee-primary/fusee-primary-main/lz4_compress.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import sys, lz4
|
||||||
|
from struct import unpack as up
|
||||||
|
|
||||||
|
def lz4_compress(data):
|
||||||
|
try:
|
||||||
|
import lz4.block as block
|
||||||
|
except ImportError:
|
||||||
|
block = lz4.LZ4_compress
|
||||||
|
return block.compress(data, 'high_compression', store_size=False)
|
||||||
|
|
||||||
|
def main(argc, argv):
|
||||||
|
if argc != 3:
|
||||||
|
print('Usage: %s in out' % argv[0])
|
||||||
|
return 1
|
||||||
|
with open(argv[1], 'rb') as f:
|
||||||
|
data = f.read()
|
||||||
|
with open(argv[2], 'wb') as f:
|
||||||
|
f.write(lz4_compress(data))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(len(sys.argv), sys.argv))
|
@ -13,14 +13,14 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FUSEE_CHAINLOADER_H
|
#ifndef FUSEE_CHAINLOADER_H
|
||||||
#define FUSEE_CHAINLOADER_H
|
#define FUSEE_CHAINLOADER_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define CHAINLOADER_ARG_DATA_MAX_SIZE 0x6200
|
#define CHAINLOADER_ARG_DATA_MAX_SIZE 0x640
|
||||||
#define CHAINLOADER_MAX_ENTRIES 128
|
#define CHAINLOADER_MAX_ENTRIES 128
|
||||||
|
|
||||||
typedef struct chainloader_entry_t {
|
typedef struct chainloader_entry_t {
|
File diff suppressed because it is too large
Load Diff
@ -224,7 +224,7 @@ uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware) {
|
|||||||
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
|
||||||
volatile tegra_fuse_chip_common_t *fuse_chip = fuse_chip_common_get_regs();
|
volatile tegra_fuse_chip_common_t *fuse_chip = fuse_chip_common_get_regs();
|
||||||
uint32_t fuse_spare_bit9 = (fuse_chip->FUSE_SPARE_BIT[9] & 1);
|
uint32_t fuse_spare_bit9 = (fuse_chip->FUSE_SPARE_BIT[9] & 1);
|
||||||
|
|
||||||
switch (hardware_type) {
|
switch (hardware_type) {
|
||||||
case 0x00: return (fuse_spare_bit9 == 0) ? 0 : 3;
|
case 0x00: return (fuse_spare_bit9 == 0) ? 0 : 3;
|
||||||
case 0x01: return 0; /* HardwareType_Icosa */
|
case 0x01: return 0; /* HardwareType_Icosa */
|
||||||
@ -233,7 +233,7 @@ uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C);
|
hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C);
|
||||||
|
|
||||||
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
|
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
|
||||||
switch (hardware_type) {
|
switch (hardware_type) {
|
||||||
case 0x01: return 0; /* HardwareType_Icosa */
|
case 0x01: return 0; /* HardwareType_Icosa */
|
||||||
@ -273,7 +273,7 @@ uint32_t fuse_get_hardware_type(void) {
|
|||||||
uint32_t fuse_get_hardware_state(void) {
|
uint32_t fuse_get_hardware_state(void) {
|
||||||
uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4);
|
uint32_t fuse_reserved_odm4 = fuse_get_reserved_odm(4);
|
||||||
uint32_t hardware_state = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3));
|
uint32_t hardware_state = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3));
|
||||||
|
|
||||||
switch (hardware_state) {
|
switch (hardware_state) {
|
||||||
case 0x03: return 0; /* HardwareState_Development */
|
case 0x03: return 0; /* HardwareState_Development */
|
||||||
case 0x04: return 1; /* HardwareState_Production */
|
case 0x04: return 1; /* HardwareState_Production */
|
54
fusee/fusee-primary/fusee-primary-main/src/start.s
Normal file
54
fusee/fusee-primary/fusee-primary-main/src/start.s
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.macro CLEAR_GPR_REG_ITER
|
||||||
|
mov r\@, #0
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.section .text.start, "ax", %progbits
|
||||||
|
.arm
|
||||||
|
.align 5
|
||||||
|
.global _start
|
||||||
|
.type _start, %function
|
||||||
|
_start:
|
||||||
|
/* Switch to system mode, mask all interrupts, clear all flags */
|
||||||
|
msr cpsr_cxsf, #0xDF
|
||||||
|
|
||||||
|
/* Set the stack pointer */
|
||||||
|
ldr sp, =__stack_top__
|
||||||
|
mov fp, #0
|
||||||
|
bl __program_init
|
||||||
|
|
||||||
|
/* Set r0 to r12 to 0 (for debugging) & call main */
|
||||||
|
.rept 13
|
||||||
|
CLEAR_GPR_REG_ITER
|
||||||
|
.endr
|
||||||
|
ldr r0, =__program_argc
|
||||||
|
ldr r1, =__program_argv
|
||||||
|
ldr lr, =__program_exit
|
||||||
|
ldr r0, [r0]
|
||||||
|
ldr r1, [r1]
|
||||||
|
b main
|
||||||
|
|
||||||
|
/* No need to include this in normal programs: */
|
||||||
|
.section .chainloader.text.start, "ax", %progbits
|
||||||
|
.arm
|
||||||
|
.align 5
|
||||||
|
.global relocate_and_chainload
|
||||||
|
.type relocate_and_chainload, %function
|
||||||
|
relocate_and_chainload:
|
||||||
|
ldr sp, =__stack_top__
|
||||||
|
b relocate_and_chainload_main
|
140
fusee/fusee-primary/fusee-primary-main/src/utils.c
Normal file
140
fusee/fusee-primary/fusee-primary-main/src/utils.c
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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 <stdbool.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include "utils.h"
|
||||||
|
#include "di.h"
|
||||||
|
#include "se.h"
|
||||||
|
#include "fuse.h"
|
||||||
|
#include "pmc.h"
|
||||||
|
#include "timers.h"
|
||||||
|
#include "panic.h"
|
||||||
|
#include "car.h"
|
||||||
|
#include "btn.h"
|
||||||
|
#include "../../../fusee/common/log.h"
|
||||||
|
#include "../../../fusee/common/vsprintf.h"
|
||||||
|
#include "../../../fusee/common/display/video_fb.h"
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define u8 uint8_t
|
||||||
|
#define u32 uint32_t
|
||||||
|
#include "rebootstub_bin.h"
|
||||||
|
#undef u8
|
||||||
|
#undef u32
|
||||||
|
|
||||||
|
void wait(uint32_t microseconds) {
|
||||||
|
uint32_t old_time = TIMERUS_CNTR_1US_0;
|
||||||
|
while (TIMERUS_CNTR_1US_0 - old_time <= microseconds) {
|
||||||
|
/* Spin-lock. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void watchdog_reboot(void) {
|
||||||
|
volatile watchdog_timers_t *wdt = GET_WDT(4);
|
||||||
|
wdt->PATTERN = WDT_REBOOT_PATTERN;
|
||||||
|
wdt->COMMAND = 2; /* Disable Counter. */
|
||||||
|
GET_WDT_REBOOT_CFG_REG(4) = 0xC0000000;
|
||||||
|
wdt->CONFIG = 0x8019; /* Full System Reset after Fourth Counter expires, using TIMER(9). */
|
||||||
|
wdt->COMMAND = 1; /* Enable Counter. */
|
||||||
|
while (true) {
|
||||||
|
/* Wait for reboot. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0) {
|
||||||
|
APBDEV_PMC_SCRATCH0_0 = scratch0;
|
||||||
|
|
||||||
|
/* Reset the processor. */
|
||||||
|
APBDEV_PMC_CONTROL = BIT(4);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
/* Wait for reboot. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void reboot_to_self(void) {
|
||||||
|
/* Patch SDRAM init to perform an SVC immediately after second write */
|
||||||
|
APBDEV_PMC_SCRATCH45_0 = 0x2E38DFFF;
|
||||||
|
APBDEV_PMC_SCRATCH46_0 = 0x6001DC28;
|
||||||
|
/* Set SVC handler to jump to reboot stub in IRAM. */
|
||||||
|
APBDEV_PMC_SCRATCH33_0 = 0x4003F000;
|
||||||
|
APBDEV_PMC_SCRATCH40_0 = 0x6000F208;
|
||||||
|
|
||||||
|
/* Copy reboot stub into IRAM high. */
|
||||||
|
for (size_t i = 0; i < rebootstub_bin_size; i += sizeof(uint32_t)) {
|
||||||
|
write32le((void *)0x4003F000, i, read32le(rebootstub_bin, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trigger warm reboot. */
|
||||||
|
pmc_reboot(1 << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void wait_for_button_and_reboot(void) {
|
||||||
|
uint32_t button;
|
||||||
|
while (true) {
|
||||||
|
button = btn_read();
|
||||||
|
if (button & BTN_POWER) {
|
||||||
|
reboot_to_self();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((noreturn)) void generic_panic(void) {
|
||||||
|
panic(0xFF000006);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
|
||||||
|
/* Forcefully initialize the screen if logging is disabled. */
|
||||||
|
if (log_get_log_level() == SCREEN_LOG_LEVEL_NONE) {
|
||||||
|
/* Zero-fill the framebuffer and register it as printk provider. */
|
||||||
|
video_init((void *)0xC0000000);
|
||||||
|
|
||||||
|
/* Initialize the display. */
|
||||||
|
display_init();
|
||||||
|
|
||||||
|
/* Set the framebuffer. */
|
||||||
|
display_init_framebuffer((void *)0xC0000000);
|
||||||
|
|
||||||
|
/* Turn on the backlight after initializing the lfb */
|
||||||
|
/* to avoid flickering. */
|
||||||
|
display_backlight(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Override the global logging level. */
|
||||||
|
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
|
||||||
|
|
||||||
|
/* Display fatal error. */
|
||||||
|
va_list args;
|
||||||
|
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
|
||||||
|
va_start(args, fmt);
|
||||||
|
vprint(SCREEN_LOG_LEVEL_ERROR, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"\nPress POWER to reboot\n");
|
||||||
|
|
||||||
|
/* Wait for button and reboot. */
|
||||||
|
wait_for_button_and_reboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be)
|
||||||
|
{
|
||||||
|
if(as <= bs && bs <= ae)
|
||||||
|
return true;
|
||||||
|
if(bs <= as && as <= be)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
128
fusee/fusee-primary/fusee-primary-main/src/utils.h
Normal file
128
fusee/fusee-primary/fusee-primary-main/src/utils.h
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FUSEE_UTILS_H
|
||||||
|
#define FUSEE_UTILS_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define BIT(n) (1u << (n))
|
||||||
|
#define BITL(n) (1ull << (n))
|
||||||
|
#define MASK(n) (BIT(n) - 1)
|
||||||
|
#define MASKL(n) (BITL(n) - 1)
|
||||||
|
#define MASK2(a,b) (MASK(a) & ~MASK(b))
|
||||||
|
#define MASK2L(a,b) (MASKL(a) & ~MASKL(b))
|
||||||
|
|
||||||
|
#define MAKE_REG32(a) (*(volatile uint32_t *)(a))
|
||||||
|
|
||||||
|
#define ALIGN(m) __attribute__((aligned(m)))
|
||||||
|
#define PACKED __attribute__((packed))
|
||||||
|
|
||||||
|
#define ALINLINE __attribute__((always_inline))
|
||||||
|
#define NOINLINE __attribute__((noinline))
|
||||||
|
|
||||||
|
#define SET_SYSREG(reg, val) do { temp_reg = (val); __asm__ __volatile__ ("msr " #reg ", %0" :: "r"(temp_reg) : "memory"); } while(false)
|
||||||
|
|
||||||
|
static inline uintptr_t get_physical_address(const void *addr) {
|
||||||
|
return (uintptr_t)addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t read32le(const volatile void *dword, size_t offset) {
|
||||||
|
uintptr_t addr = (uintptr_t)dword + offset;
|
||||||
|
volatile uint32_t *target = (uint32_t *)addr;
|
||||||
|
return *target;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t read32be(const volatile void *dword, size_t offset) {
|
||||||
|
return __builtin_bswap32(read32le(dword, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t read64le(const volatile void *qword, size_t offset) {
|
||||||
|
uintptr_t addr = (uintptr_t)qword + offset;
|
||||||
|
volatile uint64_t *target = (uint64_t *)addr;
|
||||||
|
return *target;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t read64be(const volatile void *qword, size_t offset) {
|
||||||
|
return __builtin_bswap64(read64le(qword, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write32le(volatile void *dword, size_t offset, uint32_t value) {
|
||||||
|
uintptr_t addr = (uintptr_t)dword + offset;
|
||||||
|
volatile uint32_t *target = (uint32_t *)addr;
|
||||||
|
*target = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write32be(volatile void *dword, size_t offset, uint32_t value) {
|
||||||
|
write32le(dword, offset, __builtin_bswap32(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write64le(volatile void *qword, size_t offset, uint64_t value) {
|
||||||
|
uintptr_t addr = (uintptr_t)qword + offset;
|
||||||
|
volatile uint64_t *target = (uint64_t *)addr;
|
||||||
|
*target = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write64be(volatile void *qword, size_t offset, uint64_t value) {
|
||||||
|
write64le(qword, offset, __builtin_bswap64(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool check_32bit_additive_overflow(uint32_t a, uint32_t b) {
|
||||||
|
return __builtin_add_overflow_p(a, b, (uint32_t)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool check_32bit_address_loadable(uintptr_t addr) {
|
||||||
|
/* FWIW the bootROM forbids loading anything between 0x40000000 and 0x40010000, using it for itself... */
|
||||||
|
return (addr >= 0x40010000u && addr < 0x40040000u) || addr >= 0x80000000u;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool check_32bit_address_range_loadable(uintptr_t addr, size_t size) {
|
||||||
|
return
|
||||||
|
!__builtin_add_overflow_p(addr, size, (uintptr_t)0) && /* the range doesn't overflow */
|
||||||
|
check_32bit_address_loadable(addr) && check_32bit_address_loadable(addr + size) && /* bounds are valid */
|
||||||
|
!(addr >= 0x40010000u && addr < 0x40040000u && addr + size >= 0x40040000u) /* the range doesn't cross MMIO */
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be);
|
||||||
|
static inline bool overlaps_a(const void *as, const void *ae, const void *bs, const void *be) {
|
||||||
|
return overlaps((uint64_t)(uintptr_t)as, (uint64_t)(uintptr_t)ae, (uint64_t)(uintptr_t)bs, (uint64_t)(uintptr_t)be);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t size) {
|
||||||
|
extern uint8_t __chainloader_start__[], __chainloader_end__[];
|
||||||
|
extern uint8_t __stack_bottom__[], __stack_top__[];
|
||||||
|
extern uint8_t __start__[], __end__[];
|
||||||
|
uint8_t *start = (uint8_t *)addr, *end = start + size;
|
||||||
|
|
||||||
|
return overlaps_a(start, end, __chainloader_start__, __chainloader_end__) ||
|
||||||
|
overlaps_a(start, end, __stack_bottom__, __stack_top__) ||
|
||||||
|
overlaps_a(start, end, (void *)0xC0000000, (void *)0xC03C0000) || /* framebuffer */
|
||||||
|
overlaps_a(start, end, __start__, __end__);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void watchdog_reboot(void);
|
||||||
|
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
|
||||||
|
__attribute__((noreturn)) void reboot_to_self(void);
|
||||||
|
__attribute__((noreturn)) void wait_for_button_and_reboot(void);
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void generic_panic(void);
|
||||||
|
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
|
||||||
|
|
||||||
|
#endif
|
@ -5,8 +5,8 @@ ENTRY(_start)
|
|||||||
PHDRS
|
PHDRS
|
||||||
{
|
{
|
||||||
crt0 PT_LOAD;
|
crt0 PT_LOAD;
|
||||||
chainloader PT_LOAD;
|
|
||||||
main PT_LOAD;
|
main PT_LOAD;
|
||||||
|
loader_stub PT_LOAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mostly copied from https://github.com/devkitPro/buildscripts/blob/master/dkarm-eabi/crtls/3dsx.ld */
|
/* Mostly copied from https://github.com/devkitPro/buildscripts/blob/master/dkarm-eabi/crtls/3dsx.ld */
|
||||||
@ -14,14 +14,14 @@ MEMORY
|
|||||||
{
|
{
|
||||||
NULL : ORIGIN = 0x00000000, LENGTH = 0x1000
|
NULL : ORIGIN = 0x00000000, LENGTH = 0x1000
|
||||||
main : ORIGIN = 0x40010000, LENGTH = 0x20000
|
main : ORIGIN = 0x40010000, LENGTH = 0x20000
|
||||||
low_iram : ORIGIN = 0x40003000, LENGTH = 0x8000
|
loader_stub : ORIGIN = 0x40030000, LENGTH = 0x4000
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
PROVIDE(__start__ = 0x40010000);
|
PROVIDE(__start__ = 0x40008000);
|
||||||
PROVIDE(__stack_top__ = 0x40010000);
|
PROVIDE(__stack_top__ = 0x40038000);
|
||||||
PROVIDE(__stack_bottom__ = 0x4000C000);
|
PROVIDE(__stack_bottom__ = 0x40034000);
|
||||||
PROVIDE(__heap_start__ = 0);
|
PROVIDE(__heap_start__ = 0);
|
||||||
PROVIDE(__heap_end__ = 0);
|
PROVIDE(__heap_end__ = 0);
|
||||||
|
|
||||||
@ -34,44 +34,6 @@ SECTIONS
|
|||||||
. = ALIGN(32);
|
. = ALIGN(32);
|
||||||
} >main :crt0
|
} >main :crt0
|
||||||
|
|
||||||
.chainloader_loadable :
|
|
||||||
{
|
|
||||||
. = ALIGN(32);
|
|
||||||
PROVIDE (__chainloader_start__ = ABSOLUTE(.));
|
|
||||||
PROVIDE (__chainloader_lma__ = LOADADDR(.chainloader_loadable));
|
|
||||||
KEEP(*(.chainloader.text.start))
|
|
||||||
chainloader.o(.text*)
|
|
||||||
chainloader.o(.rodata*)
|
|
||||||
chainloader.o(.data*)
|
|
||||||
. = ALIGN(32);
|
|
||||||
} >low_iram AT>main :chainloader
|
|
||||||
|
|
||||||
.chainloader_bss (NOLOAD) :
|
|
||||||
{
|
|
||||||
. = ALIGN(32);
|
|
||||||
PROVIDE (__chainloader_bss_start__ = ABSOLUTE(.));
|
|
||||||
chainloader.o(.bss* COMMON)
|
|
||||||
. = ALIGN(32);
|
|
||||||
PROVIDE (__chainloader_end__ = ABSOLUTE(.));
|
|
||||||
} >low_iram :NONE
|
|
||||||
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
. = ALIGN(32);
|
|
||||||
/* .text */
|
|
||||||
*(.text)
|
|
||||||
*(.text.*)
|
|
||||||
*(.glue_7)
|
|
||||||
*(.glue_7t)
|
|
||||||
*(.stub)
|
|
||||||
*(.gnu.warning)
|
|
||||||
*(.gnu.linkonce.t*)
|
|
||||||
|
|
||||||
/* .fini */
|
|
||||||
KEEP( *(.fini) )
|
|
||||||
. = ALIGN(8);
|
|
||||||
} >main :main
|
|
||||||
|
|
||||||
.rodata :
|
.rodata :
|
||||||
{
|
{
|
||||||
*(.rodata)
|
*(.rodata)
|
||||||
@ -83,21 +45,6 @@ SECTIONS
|
|||||||
. = ALIGN(8);
|
. = ALIGN(8);
|
||||||
} >main
|
} >main
|
||||||
|
|
||||||
.preinit_array :
|
|
||||||
{
|
|
||||||
PROVIDE (__preinit_array_start = .);
|
|
||||||
KEEP (*(.preinit_array))
|
|
||||||
PROVIDE (__preinit_array_end = .);
|
|
||||||
} >main
|
|
||||||
|
|
||||||
.init_array ALIGN(4) :
|
|
||||||
{
|
|
||||||
PROVIDE (__init_array_start = .);
|
|
||||||
KEEP (*(SORT(.init_array.*)))
|
|
||||||
KEEP (*(.init_array))
|
|
||||||
PROVIDE (__init_array_end = .);
|
|
||||||
} >main
|
|
||||||
|
|
||||||
.fini_array ALIGN(4) :
|
.fini_array ALIGN(4) :
|
||||||
{
|
{
|
||||||
PROVIDE (__fini_array_start = .);
|
PROVIDE (__fini_array_start = .);
|
||||||
@ -148,6 +95,25 @@ SECTIONS
|
|||||||
. = ALIGN(32);
|
. = ALIGN(32);
|
||||||
PROVIDE (__bss_end__ = ABSOLUTE(.));
|
PROVIDE (__bss_end__ = ABSOLUTE(.));
|
||||||
} >main :NONE
|
} >main :NONE
|
||||||
|
|
||||||
|
.loader_stub :
|
||||||
|
{
|
||||||
|
. = ALIGN(32);
|
||||||
|
PROVIDE (__loader_stub_start__ = ABSOLUTE(.));
|
||||||
|
PROVIDE (__loader_stub_lma__ = LOADADDR(.loader_stub));
|
||||||
|
loader_stub.o(.text*)
|
||||||
|
lz4.o(.text*)
|
||||||
|
utils.o(.text*)
|
||||||
|
loader_stub.o(.rodata*)
|
||||||
|
lz4.o(.rodata*)
|
||||||
|
utils.o(.rodata*)
|
||||||
|
loader_stub.o(.data*)
|
||||||
|
lz4.o(.data*)
|
||||||
|
utils.o(data)
|
||||||
|
. = ALIGN(32);
|
||||||
|
PROVIDE (__loader_stub_end__ = ABSOLUTE(.));
|
||||||
|
} >loader_stub AT>main : loader_stub
|
||||||
|
|
||||||
__end__ = ABSOLUTE(.) ;
|
__end__ = ABSOLUTE(.) ;
|
||||||
|
|
||||||
/* ==================
|
/* ==================
|
||||||
|
39
fusee/fusee-primary/src/loader_stub.c
Normal file
39
fusee/fusee-primary/src/loader_stub.c
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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 <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "lz4.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#define PRIMARY_START (0x40008000)
|
||||||
|
#define PRIMARY_SIZE_MAX (0x28000)
|
||||||
|
#define PRIMARY_END (PRIMARY_START + PRIMARY_SIZE_MAX)
|
||||||
|
|
||||||
|
void load_fusee_primary_main(void *compressed_main, size_t main_size) {
|
||||||
|
/* Relocate the compressed binary to a place where we can safely decompress it. */
|
||||||
|
void *relocated_main = (void *)(PRIMARY_END - main_size);
|
||||||
|
loader_memmove(relocated_main, compressed_main, main_size);
|
||||||
|
|
||||||
|
/* Uncompress the compressed binary. */
|
||||||
|
lz4_uncompress((void *)PRIMARY_START, PRIMARY_SIZE_MAX, relocated_main, main_size);
|
||||||
|
|
||||||
|
/* Jump to the newly uncompressed binary. */
|
||||||
|
((void (*)(void))(PRIMARY_START))();
|
||||||
|
|
||||||
|
/* We will never reach this point. */
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
96
fusee/fusee-primary/src/lz4.c
Normal file
96
fusee/fusee-primary/src/lz4.c
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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 <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "lz4.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const uint8_t *src;
|
||||||
|
size_t src_size;
|
||||||
|
size_t src_offset;
|
||||||
|
uint8_t *dst;
|
||||||
|
size_t dst_size;
|
||||||
|
size_t dst_offset;
|
||||||
|
} lz4_ctx;
|
||||||
|
|
||||||
|
static uint8_t lz4_ctx_read_byte(lz4_ctx *ctx) {
|
||||||
|
return ctx->src[ctx->src_offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool lz4_ctx_can_read(const lz4_ctx *ctx) {
|
||||||
|
return ctx->src_offset < ctx->src_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t lz4_ctx_get_copy_size(lz4_ctx *ctx, uint8_t ctrl) {
|
||||||
|
size_t size = ctrl;
|
||||||
|
|
||||||
|
if (ctrl >= 0xF) {
|
||||||
|
do {
|
||||||
|
while (!lz4_ctx_can_read(ctx));
|
||||||
|
ctrl = lz4_ctx_read_byte(ctx);
|
||||||
|
size += ctrl;
|
||||||
|
} while (ctrl == 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lz4_ctx_copy(lz4_ctx *ctx, size_t size) {
|
||||||
|
/* Perform the copy. */
|
||||||
|
loader_memcpy(ctx->dst + ctx->dst_offset, ctx->src + ctx->src_offset, size);
|
||||||
|
|
||||||
|
ctx->dst_offset += size;
|
||||||
|
ctx->src_offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lz4_ctx_uncompress(lz4_ctx *ctx) {
|
||||||
|
while (true) {
|
||||||
|
/* Read a control byte. */
|
||||||
|
const uint8_t control = lz4_ctx_read_byte(ctx);
|
||||||
|
|
||||||
|
/* Copy what it specifies we should copy. */
|
||||||
|
lz4_ctx_copy(ctx, lz4_ctx_get_copy_size(ctx, control >> 4));
|
||||||
|
|
||||||
|
/* If we've exceeded size, we're done. */
|
||||||
|
if (ctx->src_offset >= ctx->src_size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the wide copy offset. */
|
||||||
|
uint16_t wide_offset = lz4_ctx_read_byte(ctx);
|
||||||
|
while (!lz4_ctx_can_read(ctx));
|
||||||
|
wide_offset |= (lz4_ctx_read_byte(ctx) << 8);
|
||||||
|
|
||||||
|
/* Determine the copy size. */
|
||||||
|
const size_t wide_copy_size = lz4_ctx_get_copy_size(ctx, control & 0xF);
|
||||||
|
|
||||||
|
/* Copy bytes. */
|
||||||
|
const size_t end_offset = ctx->dst_offset + wide_copy_size + 4;
|
||||||
|
for (size_t cur_offset = ctx->dst_offset; cur_offset < end_offset; ctx->dst_offset = (++cur_offset)) {
|
||||||
|
while (!(wide_offset <= cur_offset));
|
||||||
|
|
||||||
|
ctx->dst[cur_offset] = ctx->dst[cur_offset - wide_offset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lz4_uncompress(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||||
|
/* Create and execute a decompressor. */
|
||||||
|
lz4_ctx ctx = { src, src_size, 0, dst, dst_size, 0 };
|
||||||
|
lz4_ctx_uncompress(&ctx);
|
||||||
|
}
|
18
fusee/fusee-primary/src/lz4.h
Normal file
18
fusee/fusee-primary/src/lz4.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void lz4_uncompress(void *dst, size_t dst_size, const void *src, size_t src_size);
|
@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.macro CLEAR_GPR_REG_ITER
|
.macro CLEAR_GPR_REG_ITER
|
||||||
mov r\@, #0
|
mov r\@, #0
|
||||||
.endm
|
.endm
|
||||||
@ -27,46 +27,35 @@ _start:
|
|||||||
/* Switch to system mode, mask all interrupts, clear all flags */
|
/* Switch to system mode, mask all interrupts, clear all flags */
|
||||||
msr cpsr_cxsf, #0xDF
|
msr cpsr_cxsf, #0xDF
|
||||||
|
|
||||||
/* Relocate ourselves if necessary */
|
/* Relocate loader stub. */
|
||||||
ldr r2, =__start__
|
ldr r0, =_start
|
||||||
adr r3, _start
|
adr r1, _start
|
||||||
cmp r2, r3
|
ldr r2, =__loader_stub_lma__
|
||||||
bne _relocation_loop_end
|
sub r2, r2, r0
|
||||||
|
add r2, r2, r1
|
||||||
|
|
||||||
ldr r4, =__bss_start__
|
ldr r3, =__loader_stub_start__
|
||||||
sub r4, r4, r2 /* size >= 32, obviously, and we've declared 32-byte-alignment */
|
ldr r4, =__loader_stub_end__
|
||||||
|
sub r4, r4, r3
|
||||||
_relocation_loop:
|
_relocation_loop:
|
||||||
ldmia r3!, {r5-r12}
|
ldmia r2!, {r5-r12}
|
||||||
stmia r2!, {r5-r12}
|
stmia r3!, {r5-r12}
|
||||||
subs r4, #0x20
|
subs r4, #0x20
|
||||||
bne _relocation_loop
|
bne _relocation_loop
|
||||||
|
|
||||||
ldr r12, =_relocation_loop_end
|
|
||||||
bx r12
|
|
||||||
|
|
||||||
_relocation_loop_end:
|
|
||||||
/* Set the stack pointer */
|
/* Set the stack pointer */
|
||||||
ldr sp, =__stack_top__
|
ldr sp, =__stack_top__
|
||||||
mov fp, #0
|
mov fp, #0
|
||||||
bl __program_init
|
|
||||||
|
|
||||||
/* Set r0 to r12 to 0 (for debugging) & call main */
|
/* Generate arguments. */
|
||||||
.rept 13
|
ldr r3, =fusee_primary_main_lz4
|
||||||
CLEAR_GPR_REG_ITER
|
ldr r4, =fusee_primary_main_lz4_end
|
||||||
.endr
|
sub r4, r4, r3
|
||||||
ldr r0, =__program_argc
|
sub r3, r3, r0
|
||||||
ldr r1, =__program_argv
|
add r3, r3, r1
|
||||||
ldr lr, =__program_exit
|
mov r0, r3
|
||||||
ldr r0, [r0]
|
mov r1, r4
|
||||||
ldr r1, [r1]
|
|
||||||
b main
|
|
||||||
|
|
||||||
/* No need to include this in normal programs: */
|
/* Jump to the loader stub. */
|
||||||
.section .chainloader.text.start, "ax", %progbits
|
ldr r3, =load_fusee_primary_main
|
||||||
.arm
|
bx r3
|
||||||
.align 5
|
|
||||||
.global relocate_and_chainload
|
|
||||||
.type relocate_and_chainload, %function
|
|
||||||
relocate_and_chainload:
|
|
||||||
ldr sp, =__stack_top__
|
|
||||||
b relocate_and_chainload_main
|
|
||||||
|
@ -13,128 +13,36 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "di.h"
|
|
||||||
#include "se.h"
|
|
||||||
#include "fuse.h"
|
|
||||||
#include "pmc.h"
|
|
||||||
#include "timers.h"
|
|
||||||
#include "panic.h"
|
|
||||||
#include "car.h"
|
|
||||||
#include "btn.h"
|
|
||||||
#include "../../../fusee/common/log.h"
|
|
||||||
#include "../../../fusee/common/vsprintf.h"
|
|
||||||
#include "../../../fusee/common/display/video_fb.h"
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
static void copy_forwards(uint8_t *dst, const uint8_t *src, size_t size) {
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
#define u8 uint8_t
|
dst[i] = src[i];
|
||||||
#define u32 uint32_t
|
|
||||||
#include "rebootstub_bin.h"
|
|
||||||
#undef u8
|
|
||||||
#undef u32
|
|
||||||
|
|
||||||
void wait(uint32_t microseconds) {
|
|
||||||
uint32_t old_time = TIMERUS_CNTR_1US_0;
|
|
||||||
while (TIMERUS_CNTR_1US_0 - old_time <= microseconds) {
|
|
||||||
/* Spin-lock. */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noreturn)) void watchdog_reboot(void) {
|
static void copy_backwards(uint8_t *dst, const uint8_t *src, size_t size) {
|
||||||
volatile watchdog_timers_t *wdt = GET_WDT(4);
|
for (int i = size - 1; i >= 0; --i) {
|
||||||
wdt->PATTERN = WDT_REBOOT_PATTERN;
|
dst[i] = src[i];
|
||||||
wdt->COMMAND = 2; /* Disable Counter. */
|
|
||||||
GET_WDT_REBOOT_CFG_REG(4) = 0xC0000000;
|
|
||||||
wdt->CONFIG = 0x8019; /* Full System Reset after Fourth Counter expires, using TIMER(9). */
|
|
||||||
wdt->COMMAND = 1; /* Enable Counter. */
|
|
||||||
while (true) {
|
|
||||||
/* Wait for reboot. */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0) {
|
void loader_memcpy(void *dst, const void *src, size_t size) {
|
||||||
APBDEV_PMC_SCRATCH0_0 = scratch0;
|
copy_forwards(dst, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
/* Reset the processor. */
|
void loader_memmove(void *dst, const void *src, size_t size) {
|
||||||
APBDEV_PMC_CONTROL = BIT(4);
|
const uintptr_t dst_u = (uintptr_t)dst;
|
||||||
|
const uintptr_t src_u = (uintptr_t)src;
|
||||||
|
|
||||||
while (true) {
|
if (dst_u < src_u) {
|
||||||
/* Wait for reboot. */
|
copy_forwards(dst, src, size);
|
||||||
|
} else if (dst_u > src_u) {
|
||||||
|
copy_backwards(dst, src, size);
|
||||||
|
} else {
|
||||||
|
/* Nothing to do */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noreturn)) void reboot_to_self(void) {
|
|
||||||
/* Patch SDRAM init to perform an SVC immediately after second write */
|
|
||||||
APBDEV_PMC_SCRATCH45_0 = 0x2E38DFFF;
|
|
||||||
APBDEV_PMC_SCRATCH46_0 = 0x6001DC28;
|
|
||||||
/* Set SVC handler to jump to reboot stub in IRAM. */
|
|
||||||
APBDEV_PMC_SCRATCH33_0 = 0x4003F000;
|
|
||||||
APBDEV_PMC_SCRATCH40_0 = 0x6000F208;
|
|
||||||
|
|
||||||
/* Copy reboot stub into IRAM high. */
|
|
||||||
for (size_t i = 0; i < rebootstub_bin_size; i += sizeof(uint32_t)) {
|
|
||||||
write32le((void *)0x4003F000, i, read32le(rebootstub_bin, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Trigger warm reboot. */
|
|
||||||
pmc_reboot(1 << 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((noreturn)) void wait_for_button_and_reboot(void) {
|
|
||||||
uint32_t button;
|
|
||||||
while (true) {
|
|
||||||
button = btn_read();
|
|
||||||
if (button & BTN_POWER) {
|
|
||||||
reboot_to_self();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((noreturn)) void generic_panic(void) {
|
|
||||||
panic(0xFF000006);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
|
|
||||||
/* Forcefully initialize the screen if logging is disabled. */
|
|
||||||
if (log_get_log_level() == SCREEN_LOG_LEVEL_NONE) {
|
|
||||||
/* Zero-fill the framebuffer and register it as printk provider. */
|
|
||||||
video_init((void *)0xC0000000);
|
|
||||||
|
|
||||||
/* Initialize the display. */
|
|
||||||
display_init();
|
|
||||||
|
|
||||||
/* Set the framebuffer. */
|
|
||||||
display_init_framebuffer((void *)0xC0000000);
|
|
||||||
|
|
||||||
/* Turn on the backlight after initializing the lfb */
|
|
||||||
/* to avoid flickering. */
|
|
||||||
display_backlight(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Override the global logging level. */
|
|
||||||
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
|
|
||||||
|
|
||||||
/* Display fatal error. */
|
|
||||||
va_list args;
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
|
|
||||||
va_start(args, fmt);
|
|
||||||
vprint(SCREEN_LOG_LEVEL_ERROR, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"\nPress POWER to reboot\n");
|
|
||||||
|
|
||||||
/* Wait for button and reboot. */
|
|
||||||
wait_for_button_and_reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be)
|
|
||||||
{
|
|
||||||
if(as <= bs && bs <= ae)
|
|
||||||
return true;
|
|
||||||
if(bs <= as && as <= be)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
@ -13,116 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#ifndef FUSEE_UTILS_H
|
|
||||||
#define FUSEE_UTILS_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
void loader_memcpy(void *dst, const void *src, size_t size);
|
||||||
#include <stddef.h>
|
void loader_memmove(void *dst, const void *src, size_t size);
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define BIT(n) (1u << (n))
|
|
||||||
#define BITL(n) (1ull << (n))
|
|
||||||
#define MASK(n) (BIT(n) - 1)
|
|
||||||
#define MASKL(n) (BITL(n) - 1)
|
|
||||||
#define MASK2(a,b) (MASK(a) & ~MASK(b))
|
|
||||||
#define MASK2L(a,b) (MASKL(a) & ~MASKL(b))
|
|
||||||
|
|
||||||
#define MAKE_REG32(a) (*(volatile uint32_t *)(a))
|
|
||||||
|
|
||||||
#define ALIGN(m) __attribute__((aligned(m)))
|
|
||||||
#define PACKED __attribute__((packed))
|
|
||||||
|
|
||||||
#define ALINLINE __attribute__((always_inline))
|
|
||||||
#define NOINLINE __attribute__((noinline))
|
|
||||||
|
|
||||||
#define SET_SYSREG(reg, val) do { temp_reg = (val); __asm__ __volatile__ ("msr " #reg ", %0" :: "r"(temp_reg) : "memory"); } while(false)
|
|
||||||
|
|
||||||
static inline uintptr_t get_physical_address(const void *addr) {
|
|
||||||
return (uintptr_t)addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t read32le(const volatile void *dword, size_t offset) {
|
|
||||||
uintptr_t addr = (uintptr_t)dword + offset;
|
|
||||||
volatile uint32_t *target = (uint32_t *)addr;
|
|
||||||
return *target;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t read32be(const volatile void *dword, size_t offset) {
|
|
||||||
return __builtin_bswap32(read32le(dword, offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint64_t read64le(const volatile void *qword, size_t offset) {
|
|
||||||
uintptr_t addr = (uintptr_t)qword + offset;
|
|
||||||
volatile uint64_t *target = (uint64_t *)addr;
|
|
||||||
return *target;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint64_t read64be(const volatile void *qword, size_t offset) {
|
|
||||||
return __builtin_bswap64(read64le(qword, offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void write32le(volatile void *dword, size_t offset, uint32_t value) {
|
|
||||||
uintptr_t addr = (uintptr_t)dword + offset;
|
|
||||||
volatile uint32_t *target = (uint32_t *)addr;
|
|
||||||
*target = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void write32be(volatile void *dword, size_t offset, uint32_t value) {
|
|
||||||
write32le(dword, offset, __builtin_bswap32(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void write64le(volatile void *qword, size_t offset, uint64_t value) {
|
|
||||||
uintptr_t addr = (uintptr_t)qword + offset;
|
|
||||||
volatile uint64_t *target = (uint64_t *)addr;
|
|
||||||
*target = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void write64be(volatile void *qword, size_t offset, uint64_t value) {
|
|
||||||
write64le(qword, offset, __builtin_bswap64(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool check_32bit_additive_overflow(uint32_t a, uint32_t b) {
|
|
||||||
return __builtin_add_overflow_p(a, b, (uint32_t)0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool check_32bit_address_loadable(uintptr_t addr) {
|
|
||||||
/* FWIW the bootROM forbids loading anything between 0x40000000 and 0x40010000, using it for itself... */
|
|
||||||
return (addr >= 0x40010000u && addr < 0x40040000u) || addr >= 0x80000000u;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool check_32bit_address_range_loadable(uintptr_t addr, size_t size) {
|
|
||||||
return
|
|
||||||
!__builtin_add_overflow_p(addr, size, (uintptr_t)0) && /* the range doesn't overflow */
|
|
||||||
check_32bit_address_loadable(addr) && check_32bit_address_loadable(addr + size) && /* bounds are valid */
|
|
||||||
!(addr >= 0x40010000u && addr < 0x40040000u && addr + size >= 0x40040000u) /* the range doesn't cross MMIO */
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be);
|
|
||||||
static inline bool overlaps_a(const void *as, const void *ae, const void *bs, const void *be) {
|
|
||||||
return overlaps((uint64_t)(uintptr_t)as, (uint64_t)(uintptr_t)ae, (uint64_t)(uintptr_t)bs, (uint64_t)(uintptr_t)be);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t size) {
|
|
||||||
extern uint8_t __chainloader_start__[], __chainloader_end__[];
|
|
||||||
extern uint8_t __stack_bottom__[], __stack_top__[];
|
|
||||||
extern uint8_t __start__[], __end__[];
|
|
||||||
uint8_t *start = (uint8_t *)addr, *end = start + size;
|
|
||||||
|
|
||||||
return overlaps_a(start, end, __chainloader_start__, __chainloader_end__) ||
|
|
||||||
overlaps_a(start, end, __stack_bottom__, __stack_top__) ||
|
|
||||||
overlaps_a(start, end, (void *)0xC0000000, (void *)0xC03C0000) || /* framebuffer */
|
|
||||||
overlaps_a(start, end, __start__, __end__);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((noreturn)) void watchdog_reboot(void);
|
|
||||||
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
|
|
||||||
__attribute__((noreturn)) void reboot_to_self(void);
|
|
||||||
__attribute__((noreturn)) void wait_for_button_and_reboot(void);
|
|
||||||
|
|
||||||
__attribute__((noreturn)) void generic_panic(void);
|
|
||||||
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
Loading…
Reference in New Issue
Block a user