diff --git a/exosphere/lp0fw/Makefile b/exosphere/lp0fw/Makefile new file mode 100644 index 000000000..0eadd1314 --- /dev/null +++ b/exosphere/lp0fw/Makefile @@ -0,0 +1,154 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITARM)/base_rules + +#--------------------------------------------------------------------------------- +# 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 +DATA := data +INCLUDES := include + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork + +CFLAGS := \ + -g \ + -O2 \ + -ffunction-sections \ + -fdata-sections \ + -fomit-frame-pointer \ + -fno-inline \ + -std=gnu11 \ + -Werror \ + -Wall \ + $(ARCH) $(DEFINES) + +CFLAGS += $(INCLUDE) -D__BPMP__ + +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)) + +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)/*.*))) + +#--------------------------------------------------------------------------------- +# 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 + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(OUTPUT).bin + +$(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 +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/exosphere/lp0fw/linker.ld b/exosphere/lp0fw/linker.ld new file mode 100644 index 000000000..165608360 --- /dev/null +++ b/exosphere/lp0fw/linker.ld @@ -0,0 +1,24 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) + +ENTRY(_start) +SECTIONS +{ + . = 0x40010000; + + __start__ = ABSOLUTE(.); + + .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } + .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } + .bss : ALIGN(8) { __bss_start__ = .; *(.bss* COMMON); . = ALIGN(8); __bss_end__ = .; } + + . = ALIGN(4); + + __end__ = ABSOLUTE(.); + + __total_size__ = (__end__ - __start__); + __executable_size__ = (__end__ - _start); + + __stack_top__ = 0x40013000; + __stack_bottom__ = 0x40012000; +} \ No newline at end of file diff --git a/exosphere/lp0fw/linker.specs b/exosphere/lp0fw/linker.specs new file mode 100644 index 000000000..300990418 --- /dev/null +++ b/exosphere/lp0fw/linker.specs @@ -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 diff --git a/exosphere/lp0fw/src/lp0.c b/exosphere/lp0fw/src/lp0.c new file mode 100644 index 000000000..b363748e8 --- /dev/null +++ b/exosphere/lp0fw/src/lp0.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "utils.h" +#include "lp0.h" +#include "pmc.h" +#include "timer.h" + +void reboot(void) { + /* Write MAIN_RST */ + APBDEV_PMC_CNTRL_0 = 0x10; + while (true) { + /* Wait for reboot. */ + } +} + +void lp0_entry_main(warmboot_metadata_t *meta) { + /* Before doing anything else, ensure some sanity. */ + if (meta->magic != WARMBOOT_MAGIC || meta->tz_relative_offset > 0x2000) { + reboot(); + } + + /* TODO: stuff */ + + while (true) { /* TODO: Halt BPMP */ } +} + + diff --git a/exosphere/lp0fw/src/lp0.h b/exosphere/lp0fw/src/lp0.h new file mode 100644 index 000000000..189813d9b --- /dev/null +++ b/exosphere/lp0fw/src/lp0.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 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 . + */ + +#ifndef EXOSPHERE_WARMBOOT_BIN_LP0_H +#define EXOSPHERE_WARMBOOT_BIN_LP0_H + +#include "utils.h" + +/* WBT0 */ +#define WARMBOOT_MAGIC 0x30544257 + +typedef struct { + uint32_t magic; + uint32_t tz_relative_offset; + uint32_t padding[2]; +} warmboot_metadata_t; + +void lp0_entry_main(warmboot_metadata_t *meta); + +void reboot(void); + +#endif diff --git a/exosphere/lp0fw/src/pmc.h b/exosphere/lp0fw/src/pmc.h new file mode 100644 index 000000000..dd32e9c2e --- /dev/null +++ b/exosphere/lp0fw/src/pmc.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018 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 . + */ + +#ifndef EXOSPHERE_WARMBOOT_BIN_PMC_H +#define EXOSPHERE_WARMBOOT_BIN_PMC_H + +#include "utils.h" + +#define PMC_BASE (0x7000E400) + +#define MAKE_PMC_REG(ofs) (MAKE_REG32(PMC_BASE + ofs)) + +#define APBDEV_PMC_CNTRL_0 MAKE_PMC_REG(0x000) + +#define APBDEV_PMC_DPD_SAMPLE_0 MAKE_PMC_REG(0x020) + +#define APBDEV_PMC_DPD_ENABLE_0 MAKE_PMC_REG(0x024) + +#define APBDEV_PMC_CLAMP_STATUS_0 MAKE_PMC_REG(0x02C) + +#define APBDEV_PMC_PWRGATE_STATUS_0 MAKE_PMC_REG(0x038) + +#define APBDEV_PMC_SCRATCH12_0 MAKE_PMC_REG(0x080) +#define APBDEV_PMC_SCRATCH13_0 MAKE_PMC_REG(0x084) +#define APBDEV_PMC_SCRATCH18_0 MAKE_PMC_REG(0x098) + + +#define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8) + +#define APBDEV_PMC_IO_DPD3_REQ_0 MAKE_PMC_REG(0x45C) +#define APBDEV_PMC_IO_DPD3_STATUS_0 MAKE_PMC_REG(0x460) + +#define APBDEV_PMC_IO_DPD4_REQ_0 MAKE_PMC_REG(0x464) +#define APBDEV_PMC_IO_DPD4_STATUS_0 MAKE_PMC_REG(0x468) + +#define APBDEV_PMC_SET_SW_CLAMP_0 MAKE_PMC_REG(0x47C) + +#define APBDEV_PMC_DDR_CNTRL_0 MAKE_PMC_REG(0x4E4) + +#endif diff --git a/exosphere/lp0fw/src/start.s b/exosphere/lp0fw/src/start.s new file mode 100644 index 000000000..9abe6a391 --- /dev/null +++ b/exosphere/lp0fw/src/start.s @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018 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 . + */ + +.section .text.start + +/* Warmboot header. */ +/* Binary size */ +.word __total_size__ +.rept 3 +.word 0x00000000 +.endr +/* RSA modulus */ +.rept 0x40 +.word 0xFFFFFFFF +.endr +/* Padding */ +.rept 4 +.word 0x00000000 +.endr +/* RSA signature */ +.rept 0x40 +.word 0xFFFFFFFF +.endr +/* Padding */ +.rept 4 +.word 0x00000000 +.endr +/* Relocation meta */ +.word __total_size__ +.word _start +.word _start +.word __executable_size__ + +.global _start +_start: + b crt0 +.rept 0x7C + .word 0x00000000 /* Padding */ +.endr + +.global _metadata +_metadata: + .ascii "WBT0" /* Magic number */ + .word 0x00000000 /* TrustZone relative base. */ + .word 0x00000000 /* Reserved */ + .word 0x00000000 /* Reserved */ + +.global crt0 +.type crt0, %function +crt0: + @ setup to call lp0_entry_main + ldr sp, =__stack_top__ + ldr lr, =reboot + ldr r0, =_metadata + b lp0_entry_main diff --git a/exosphere/lp0fw/src/timer.h b/exosphere/lp0fw/src/timer.h new file mode 100644 index 000000000..74f4a6360 --- /dev/null +++ b/exosphere/lp0fw/src/timer.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 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 . + */ + +#ifndef EXOSPHERE_WARMBOOT_BIN_TIMER_H +#define EXOSPHERE_WARMBOOT_BIN_TIMER_H + +#include "utils.h" + +#define TIMERUS_CNTR_1US_0 MAKE_REG32(0x60005010) + +static inline void timer_wait(uint32_t microseconds) { + uint32_t old_time = TIMERUS_CNTR_1US_0; + while (TIMERUS_CNTR_1US_0 - old_time <= microseconds) { + /* Spin-lock. */ + } +} + +void spinlock_wait(uint32_t count); + +#endif diff --git a/exosphere/lp0fw/src/utils.h b/exosphere/lp0fw/src/utils.h new file mode 100644 index 000000000..60a48d6b6 --- /dev/null +++ b/exosphere/lp0fw/src/utils.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 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 . + */ + +#ifndef EXOSPHERE_WARMBOOT_BIN_UTILS_H +#define EXOSPHERE_WARMBOOT_BIN_UTILS_H + +#include +#include +#include + +#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)) + +#endif