fusee: uncompress fusee-primary, which is now getting pretty big.
This commit is contained in:
1 parent
8104beb2e0
commit
f600dff961
67 files changed
+2107
-1464
No files matched your search
@@ -8,7 +8,7 @@ endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
|
||||
AMS := $(TOPDIR)/../../
|
||||
AMS := $(TOPDIR)/../../../
|
||||
include $(DEVKITARM)/base_rules
|
||||
|
||||
AMSBRANCH := $(shell git symbolic-ref --short HEAD)
|
||||
@@ -18,6 +18,13 @@ ifneq (, $(strip $(shell git status --porcelain 2>/dev/null)))
|
||||
AMSREV := $(AMSREV)-dirty
|
||||
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
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
@@ -27,9 +34,9 @@ endif
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := src ../../fusee/common ../../fusee/common/display ../../fusee/common/fatfs ../../fusee/common/sdmmc
|
||||
SOURCES := src
|
||||
DATA := data
|
||||
INCLUDES := include ../../libraries/libvapours/include
|
||||
INCLUDES := include ../../../libraries/libvapours/include
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
@@ -77,14 +84,14 @@ export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
|
||||
$(AMS)/exosphere/program/rebootstub
|
||||
$(CURDIR)/fusee-primary-main
|
||||
|
||||
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
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary-main.lz4
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
@@ -100,10 +107,10 @@ else
|
||||
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 := $(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)) \
|
||||
$(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)
|
||||
|
||||
.PHONY: $(BUILD) clean all check_rebootstub
|
||||
.PHONY: $(BUILD) clean all check_main
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: check_rebootstub $(BUILD)
|
||||
all: $(BUILD)
|
||||
|
||||
check_rebootstub:
|
||||
@$(MAKE) -C $(AMS)/exosphere/program/rebootstub all
|
||||
fusee-primary-main/fusee-primary-main.lz4: check_main
|
||||
|
||||
$(BUILD): check_rebootstub
|
||||
check_main:
|
||||
@$(MAKE) -C fusee-primary-main all
|
||||
|
||||
$(BUILD): fusee-primary-main/fusee-primary-main.lz4
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@$(MAKE) -C $(AMS)/exosphere/program/rebootstub clean
|
||||
@$(MAKE) -C fusee-primary-main clean
|
||||
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf
|
||||
|
||||
|
||||
@@ -152,6 +161,8 @@ $(OUTPUT).elf : $(OFILES)
|
||||
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
@$(NM) -CSn $@ > $(notdir $*.lst)
|
||||
|
||||
utils.o: CFLAGS += -fno-builtin
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
@@ -162,6 +173,14 @@ $(OFILES_SRC) : $(HFILES_BIN)
|
||||
@echo $(notdir $<)
|
||||
@$(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)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
#---------------------------------------------------------------------------------------
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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
|
||||
@@ -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))
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2
-2
@@ -13,14 +13,14 @@
|
||||
* 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_CHAINLOADER_H
|
||||
#define FUSEE_CHAINLOADER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define CHAINLOADER_ARG_DATA_MAX_SIZE 0x6200
|
||||
#define CHAINLOADER_ARG_DATA_MAX_SIZE 0x640
|
||||
#define CHAINLOADER_MAX_ENTRIES 128
|
||||
|
||||
typedef struct chainloader_entry_t {
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1129
-1129
File diff suppressed because it is too large.
Load diff
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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) {
|
||||
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);
|
||||
|
||||
|
||||
switch (hardware_type) {
|
||||
case 0x00: return (fuse_spare_bit9 == 0) ? 0 : 3;
|
||||
case 0x01: return 0; /* HardwareType_Icosa */
|
||||
@@ -233,7 +233,7 @@ uint32_t fuse_get_hardware_type_with_firmware_check(uint32_t target_firmware) {
|
||||
}
|
||||
} else {
|
||||
hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C);
|
||||
|
||||
|
||||
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
|
||||
switch (hardware_type) {
|
||||
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_reserved_odm4 = fuse_get_reserved_odm(4);
|
||||
uint32_t hardware_state = (((fuse_reserved_odm4 >> 7) & 4) | (fuse_reserved_odm4 & 3));
|
||||
|
||||
|
||||
switch (hardware_state) {
|
||||
case 0x03: return 0; /* HardwareState_Development */
|
||||
case 0x04: return 1; /* HardwareState_Production */
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
crt0 PT_LOAD;
|
||||
chainloader PT_LOAD;
|
||||
main PT_LOAD;
|
||||
loader_stub PT_LOAD;
|
||||
}
|
||||
|
||||
/* 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
|
||||
main : ORIGIN = 0x40010000, LENGTH = 0x20000
|
||||
low_iram : ORIGIN = 0x40003000, LENGTH = 0x8000
|
||||
loader_stub : ORIGIN = 0x40030000, LENGTH = 0x4000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
PROVIDE(__start__ = 0x40010000);
|
||||
PROVIDE(__stack_top__ = 0x40010000);
|
||||
PROVIDE(__stack_bottom__ = 0x4000C000);
|
||||
PROVIDE(__start__ = 0x40008000);
|
||||
PROVIDE(__stack_top__ = 0x40038000);
|
||||
PROVIDE(__stack_bottom__ = 0x40034000);
|
||||
PROVIDE(__heap_start__ = 0);
|
||||
PROVIDE(__heap_end__ = 0);
|
||||
|
||||
@@ -34,44 +34,6 @@ SECTIONS
|
||||
. = 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)
|
||||
@@ -83,21 +45,6 @@ SECTIONS
|
||||
. = 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 = .);
|
||||
@@ -148,6 +95,25 @@ SECTIONS
|
||||
. = ALIGN(32);
|
||||
PROVIDE (__bss_end__ = ABSOLUTE(.));
|
||||
} >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(.) ;
|
||||
|
||||
/* ==================
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
.macro CLEAR_GPR_REG_ITER
|
||||
mov r\@, #0
|
||||
.endm
|
||||
@@ -27,46 +27,35 @@ _start:
|
||||
/* Switch to system mode, mask all interrupts, clear all flags */
|
||||
msr cpsr_cxsf, #0xDF
|
||||
|
||||
/* Relocate ourselves if necessary */
|
||||
ldr r2, =__start__
|
||||
adr r3, _start
|
||||
cmp r2, r3
|
||||
bne _relocation_loop_end
|
||||
/* Relocate loader stub. */
|
||||
ldr r0, =_start
|
||||
adr r1, _start
|
||||
ldr r2, =__loader_stub_lma__
|
||||
sub r2, r2, r0
|
||||
add r2, r2, r1
|
||||
|
||||
ldr r4, =__bss_start__
|
||||
sub r4, r4, r2 /* size >= 32, obviously, and we've declared 32-byte-alignment */
|
||||
ldr r3, =__loader_stub_start__
|
||||
ldr r4, =__loader_stub_end__
|
||||
sub r4, r4, r3
|
||||
_relocation_loop:
|
||||
ldmia r3!, {r5-r12}
|
||||
stmia r2!, {r5-r12}
|
||||
ldmia r2!, {r5-r12}
|
||||
stmia r3!, {r5-r12}
|
||||
subs r4, #0x20
|
||||
bne _relocation_loop
|
||||
|
||||
ldr r12, =_relocation_loop_end
|
||||
bx r12
|
||||
|
||||
_relocation_loop_end:
|
||||
/* 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
|
||||
/* Generate arguments. */
|
||||
ldr r3, =fusee_primary_main_lz4
|
||||
ldr r4, =fusee_primary_main_lz4_end
|
||||
sub r4, r4, r3
|
||||
sub r3, r3, r0
|
||||
add r3, r3, r1
|
||||
mov r0, r3
|
||||
mov r1, r4
|
||||
|
||||
/* 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
|
||||
/* Jump to the loader stub. */
|
||||
ldr r3, =load_fusee_primary_main
|
||||
bx r3
|
||||
+21
-113
@@ -13,128 +13,36 @@
|
||||
* 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 <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. */
|
||||
static void copy_forwards(uint8_t *dst, const uint8_t *src, size_t size) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
__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. */
|
||||
static void copy_backwards(uint8_t *dst, const uint8_t *src, size_t size) {
|
||||
for (int i = size - 1; i >= 0; --i) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0) {
|
||||
APBDEV_PMC_SCRATCH0_0 = scratch0;
|
||||
void loader_memcpy(void *dst, const void *src, size_t size) {
|
||||
copy_forwards(dst, src, size);
|
||||
}
|
||||
|
||||
/* Reset the processor. */
|
||||
APBDEV_PMC_CONTROL = BIT(4);
|
||||
void loader_memmove(void *dst, const void *src, size_t size) {
|
||||
const uintptr_t dst_u = (uintptr_t)dst;
|
||||
const uintptr_t src_u = (uintptr_t)src;
|
||||
|
||||
while (true) {
|
||||
/* Wait for reboot. */
|
||||
if (dst_u < src_u) {
|
||||
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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FUSEE_UTILS_H
|
||||
#define FUSEE_UTILS_H
|
||||
#pragma once
|
||||
|
||||
#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
|
||||
void loader_memcpy(void *dst, const void *src, size_t size);
|
||||
void loader_memmove(void *dst, const void *src, size_t size);
|
||||
Reference in new issue
Block a user