mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-23 04:41:12 +00:00
thermosphere: "write" placeholder code
This commit is contained in:
parent
2e2976efba
commit
5bc923ea00
16 changed files with 2375 additions and 0 deletions
163
thermosphere/Makefile
Normal file
163
thermosphere/Makefile
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||||
|
endif
|
||||||
|
|
||||||
|
TOPDIR ?= $(CURDIR)
|
||||||
|
include $(DEVKITPRO)/devkitA64/base_rules
|
||||||
|
|
||||||
|
AMSBRANCH := $(shell git symbolic-ref --short HEAD)
|
||||||
|
AMSHASH = $(shell git rev-parse --short=16 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
|
||||||
|
DATA := data
|
||||||
|
INCLUDES := include ../common/include
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -march=armv8-a -mtune=cortex-a57 -mgeneral-regs-only #<- important
|
||||||
|
DEFINES := -D__CCPLEX__ -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" -DATMOSPHERE_RELEASE_VERSION_HASH="0x$(AMSHASH)"
|
||||||
|
CFLAGS := \
|
||||||
|
-g \
|
||||||
|
-Os \
|
||||||
|
-ffunction-sections \
|
||||||
|
-fdata-sections \
|
||||||
|
-fomit-frame-pointer \
|
||||||
|
-fno-asynchronous-unwind-tables \
|
||||||
|
-fno-unwind-tables \
|
||||||
|
-std=gnu11 \
|
||||||
|
-Werror \
|
||||||
|
-Wall \
|
||||||
|
$(ARCH) $(DEFINES)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE)
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=$(TOPDIR)/linker.specs -nostartfiles -nostdlib -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:
|
||||||
|
@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
|
||||||
|
#---------------------------------------------------------------------------------------
|
190
thermosphere/linker.ld
Normal file
190
thermosphere/linker.ld
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
OUTPUT_ARCH(aarch64)
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
NULL : ORIGIN = 0, LENGTH = 0x1000
|
||||||
|
main : ORIGIN = 0x80000000, LENGTH = 0xD000 - 0x1000 /* 0x1000 for stacks. */
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
PROVIDE(__start__ = 0x80000000);
|
||||||
|
. = __start__;
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
. = ALIGN(8);
|
||||||
|
__main_start__ = ABSOLUTE(.);
|
||||||
|
*(.text.start*)
|
||||||
|
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||||
|
*(.text.exit .text.exit.*)
|
||||||
|
*(.text.startup .text.startup.*)
|
||||||
|
*(.text.hot .text.hot.*)
|
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
. = ALIGN(0x800);
|
||||||
|
__vectors_start__ = ABSOLUTE(.);
|
||||||
|
*(.vectors*);
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP( *(.init) )
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.plt :
|
||||||
|
{
|
||||||
|
*(.plt)
|
||||||
|
*(.iplt)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP( *(.fini) )
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.got : { __got_start__ = ABSOLUTE(.); *(.got) *(.igot) } >main
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) __got_end__ = ABSOLUTE(.);} >main
|
||||||
|
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
. = ALIGN(8);
|
||||||
|
PROVIDE (__preinit_array_start = ABSOLUTE(.));
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE (__preinit_array_end = ABSOLUTE(.));
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.init_array :
|
||||||
|
{
|
||||||
|
PROVIDE (__init_array_start = ABSOLUTE(.));
|
||||||
|
KEEP (*(SORT(.init_array.*)))
|
||||||
|
KEEP (*(.init_array))
|
||||||
|
PROVIDE (__init_array_end = ABSOLUTE(.));
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.fini_array :
|
||||||
|
{
|
||||||
|
. = ALIGN(8);
|
||||||
|
PROVIDE (__fini_array_start = ABSOLUTE(.));
|
||||||
|
KEEP (*(.fini_array))
|
||||||
|
KEEP (*(SORT(.fini_array.*)))
|
||||||
|
PROVIDE (__fini_array_end = ABSOLUTE(.));
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
. = ALIGN(8);
|
||||||
|
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.dtors ALIGN(8) :
|
||||||
|
{
|
||||||
|
. = ALIGN(8);
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
.data ALIGN(8) :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
CONSTRUCTORS
|
||||||
|
. = ALIGN(8);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
|
||||||
|
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } >main
|
||||||
|
.eh_frame : { KEEP (*(.eh_frame)) *(.eh_frame.*) } >main
|
||||||
|
.gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) } >main
|
||||||
|
.gnu_extab : { *(.gnu_extab*) } >main
|
||||||
|
.exception_ranges : { *(.exception_ranges .exception_ranges*) } >main
|
||||||
|
|
||||||
|
.dynamic : { *(.dynamic) } >main
|
||||||
|
.interp : { *(.interp) } >main
|
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) } >main
|
||||||
|
.hash : { *(.hash) } >main
|
||||||
|
.gnu.hash : { *(.gnu.hash) } >main
|
||||||
|
.gnu.version : { *(.gnu.version) } >main
|
||||||
|
.gnu.version_d : { *(.gnu.version_d) } >main
|
||||||
|
.gnu.version_r : { *(.gnu.version_r) } >main
|
||||||
|
.dynsym : { *(.dynsym) } >main
|
||||||
|
.dynstr : { *(.dynstr) } >main
|
||||||
|
.rela.dyn : { *(.rela.*); __main_end__ = ABSOLUTE(.);} >main
|
||||||
|
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
. = ALIGN(8);
|
||||||
|
__bss_start__ = ABSOLUTE(.);
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(8);
|
||||||
|
__end__ = ABSOLUTE(.);
|
||||||
|
} >main
|
||||||
|
|
||||||
|
__end__ = ABSOLUTE(.) ;
|
||||||
|
|
||||||
|
__stacks_top__ = ABSOLUTE(. + 0x1000);
|
||||||
|
|
||||||
|
. = ALIGN(8);
|
||||||
|
|
||||||
|
/* ==================
|
||||||
|
==== 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) }
|
||||||
|
}
|
4
thermosphere/linker.specs
Normal file
4
thermosphere/linker.specs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
%rename link old_link
|
||||||
|
|
||||||
|
*link:
|
||||||
|
%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections
|
82
thermosphere/src/car.c
Normal file
82
thermosphere/src/car.c
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#include "car.h"
|
||||||
|
#include "timers.h"
|
||||||
|
|
||||||
|
static inline u32 get_special_clk_reg(CarDevice dev) {
|
||||||
|
switch (dev) {
|
||||||
|
case CARDEVICE_UARTA: return 0x178;
|
||||||
|
case CARDEVICE_UARTB: return 0x17C;
|
||||||
|
case CARDEVICE_I2C1: return 0x124;
|
||||||
|
case CARDEVICE_I2C5: return 0x128;
|
||||||
|
case CARDEVICE_ACTMON: return 0x3E8;
|
||||||
|
case CARDEVICE_BPMP: return 0;
|
||||||
|
default: return -1;// generic_panic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 get_special_clk_val(CarDevice dev) {
|
||||||
|
switch (dev) {
|
||||||
|
case CARDEVICE_UARTA: return 0;
|
||||||
|
case CARDEVICE_UARTB: return 0;
|
||||||
|
case CARDEVICE_I2C1: return (6 << 29);
|
||||||
|
case CARDEVICE_I2C5: return (6 << 29);
|
||||||
|
case CARDEVICE_ACTMON: return (6 << 29);
|
||||||
|
case CARDEVICE_BPMP: return 0;
|
||||||
|
default: return -1; //generic_panic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 g_clk_reg_offsets[NUM_CAR_BANKS] = {0x010, 0x014, 0x018, 0x360, 0x364, 0x280, 0x298};
|
||||||
|
static u32 g_rst_reg_offsets[NUM_CAR_BANKS] = {0x004, 0x008, 0x00C, 0x358, 0x35C, 0x28C, 0x2A4};
|
||||||
|
|
||||||
|
void clk_enable(CarDevice dev) {
|
||||||
|
u32 special_reg;
|
||||||
|
if ((special_reg = get_special_clk_reg(dev))) {
|
||||||
|
MAKE_CAR_REG(special_reg) = get_special_clk_val(dev);
|
||||||
|
}
|
||||||
|
MAKE_CAR_REG(g_clk_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clk_disable(CarDevice dev) {
|
||||||
|
MAKE_CAR_REG(g_clk_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F));
|
||||||
|
}
|
||||||
|
|
||||||
|
void rst_enable(CarDevice dev) {
|
||||||
|
MAKE_CAR_REG(g_rst_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rst_disable(CarDevice dev) {
|
||||||
|
MAKE_CAR_REG(g_rst_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void clkrst_enable(CarDevice dev) {
|
||||||
|
clk_enable(dev);
|
||||||
|
rst_disable(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clkrst_disable(CarDevice dev) {
|
||||||
|
rst_enable(dev);
|
||||||
|
clk_disable(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clkrst_reboot(CarDevice dev) {
|
||||||
|
clkrst_disable(dev);
|
||||||
|
clkrst_enable(dev);
|
||||||
|
}
|
49
thermosphere/src/car.h
Normal file
49
thermosphere/src/car.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#define CAR_BASE 0x60006000ull
|
||||||
|
|
||||||
|
#define MAKE_CAR_REG(n) MAKE_REG32(CAR_BASE + n)
|
||||||
|
|
||||||
|
#define CLK_RST_CONTROLLER_MISC_CLK_ENB_0 MAKE_CAR_REG(0x048)
|
||||||
|
#define CLK_RST_CONTROLLER_RST_DEVICES_H_0 MAKE_CAR_REG(0x008)
|
||||||
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD_0 MAKE_CAR_REG(0x3A4)
|
||||||
|
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET_0 MAKE_CAR_REG(0x450)
|
||||||
|
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR_0 MAKE_CAR_REG(0x454)
|
||||||
|
|
||||||
|
#define NUM_CAR_BANKS 7
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CARDEVICE_UARTA = 6,
|
||||||
|
CARDEVICE_UARTB = 7,
|
||||||
|
CARDEVICE_I2C1 = 12,
|
||||||
|
CARDEVICE_I2C5 = 47,
|
||||||
|
CARDEVICE_ACTMON = 119,
|
||||||
|
CARDEVICE_BPMP = 1
|
||||||
|
} CarDevice;
|
||||||
|
|
||||||
|
void clk_enable(CarDevice dev);
|
||||||
|
void clk_disable(CarDevice dev);
|
||||||
|
void rst_enable(CarDevice dev);
|
||||||
|
void rst_disable(CarDevice dev);
|
||||||
|
|
||||||
|
void clkrst_enable(CarDevice dev);
|
||||||
|
void clkrst_disable(CarDevice dev);
|
||||||
|
|
||||||
|
void clkrst_reboot(CarDevice dev);
|
187
thermosphere/src/exceptions.s
Normal file
187
thermosphere/src/exceptions.s
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
/* Some macros taken from https://github.com/ARM-software/arm-trusted-firmware/blob/master/include/common/aarch64/asm_macros.S */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Declare the exception vector table, enforcing it is aligned on a
|
||||||
|
* 2KB boundary, as required by the ARMv8 architecture.
|
||||||
|
* Use zero bytes as the fill value to be stored in the padding bytes
|
||||||
|
* so that it inserts illegal AArch64 instructions. This increases
|
||||||
|
* security, robustness and potentially facilitates debugging.
|
||||||
|
*/
|
||||||
|
.macro vector_base label, section_name=.vectors
|
||||||
|
.section \section_name, "ax"
|
||||||
|
.align 11, 0
|
||||||
|
\label:
|
||||||
|
.endm
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create an entry in the exception vector table, enforcing it is
|
||||||
|
* aligned on a 128-byte boundary, as required by the ARMv8 architecture.
|
||||||
|
* Use zero bytes as the fill value to be stored in the padding bytes
|
||||||
|
* so that it inserts illegal AArch64 instructions. This increases
|
||||||
|
* security, robustness and potentially facilitates debugging.
|
||||||
|
*/
|
||||||
|
.macro vector_entry label, section_name=.vectors
|
||||||
|
.cfi_sections .debug_frame
|
||||||
|
.section \section_name, "ax"
|
||||||
|
.align 7, 0
|
||||||
|
.type \label, %function
|
||||||
|
.func \label
|
||||||
|
.cfi_startproc
|
||||||
|
\label:
|
||||||
|
.endm
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This macro verifies that the given vector doesnt exceed the
|
||||||
|
* architectural limit of 32 instructions. This is meant to be placed
|
||||||
|
* immediately after the last instruction in the vector. It takes the
|
||||||
|
* vector entry as the parameter
|
||||||
|
*/
|
||||||
|
.macro check_vector_size since
|
||||||
|
.endfunc
|
||||||
|
.cfi_endproc
|
||||||
|
.if (. - \since) > (32 * 4)
|
||||||
|
.error "Vector exceeds 32 instructions"
|
||||||
|
.endif
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro save_all_regs
|
||||||
|
sub sp, sp, #0x110
|
||||||
|
stp x0, x1, [sp, #0x00]
|
||||||
|
stp x2, x3, [sp, #0x10]
|
||||||
|
stp x4, x5, [sp, #0x20]
|
||||||
|
stp x6, x7, [sp, #0x30]
|
||||||
|
stp x8, x9, [sp, #0x40]
|
||||||
|
stp x10, x11, [sp, #0x50]
|
||||||
|
stp x12, x13, [sp, #0x60]
|
||||||
|
stp x14, x15, [sp, #0x70]
|
||||||
|
stp x16, x17, [sp, #0x80]
|
||||||
|
stp x18, x19, [sp, #0x90]
|
||||||
|
stp x20, x21, [sp, #0xA0]
|
||||||
|
stp x22, x23, [sp, #0xB0]
|
||||||
|
stp x24, x25, [sp, #0xC0]
|
||||||
|
stp x26, x27, [sp, #0xD0]
|
||||||
|
stp x28, x29, [sp, #0xE0]
|
||||||
|
|
||||||
|
mrs x20, sp_el1
|
||||||
|
mrs x21, elr_el2
|
||||||
|
mrs x22, spsr_el2
|
||||||
|
|
||||||
|
stp x30, x20, [sp, #0xF0]
|
||||||
|
stp x21, x22, [sp, #0x100]
|
||||||
|
.endm
|
||||||
|
|
||||||
|
/* Actual Vectors for Exosphere. */
|
||||||
|
.global exosphere_vectors
|
||||||
|
vector_base exosphere_vectors
|
||||||
|
|
||||||
|
/* Current EL, SP0 */
|
||||||
|
.global unknown_exception
|
||||||
|
unknown_exception:
|
||||||
|
vector_entry synch_sp0
|
||||||
|
b .
|
||||||
|
check_vector_size synch_sp0
|
||||||
|
|
||||||
|
vector_entry irq_sp0
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size irq_sp0
|
||||||
|
|
||||||
|
vector_entry fiq_sp0
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size fiq_sp0
|
||||||
|
|
||||||
|
vector_entry serror_sp0
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size serror_sp0
|
||||||
|
|
||||||
|
/* Current EL, SPx */
|
||||||
|
vector_entry synch_spx
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size synch_spx
|
||||||
|
|
||||||
|
vector_entry irq_spx
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size irq_spx
|
||||||
|
|
||||||
|
vector_entry fiq_spx
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size fiq_spx
|
||||||
|
|
||||||
|
vector_entry serror_spx
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size serror_spx
|
||||||
|
|
||||||
|
/* Lower EL, A64 */
|
||||||
|
vector_entry synch_a64
|
||||||
|
save_all_regs
|
||||||
|
|
||||||
|
mov x0, sp
|
||||||
|
mrs x1, esr_el2
|
||||||
|
|
||||||
|
bl . // FIXME!
|
||||||
|
|
||||||
|
b _restore_all_regs
|
||||||
|
check_vector_size synch_a64
|
||||||
|
|
||||||
|
vector_entry irq_a64
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size irq_a64
|
||||||
|
|
||||||
|
vector_entry fiq_a64
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size fiq_a64
|
||||||
|
|
||||||
|
vector_entry serror_a64
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size serror_a64
|
||||||
|
|
||||||
|
|
||||||
|
/* Lower EL, A32 */
|
||||||
|
vector_entry synch_a32
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size synch_a32
|
||||||
|
|
||||||
|
vector_entry irq_a32
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size irq_a32
|
||||||
|
|
||||||
|
vector_entry fiq_a32
|
||||||
|
b fiq_a64
|
||||||
|
.endfunc
|
||||||
|
.cfi_endproc
|
||||||
|
/* To save space, insert in an unused vector segment. */
|
||||||
|
_restore_all_regs:
|
||||||
|
ldp x30, x20, [sp, #0xF0]
|
||||||
|
ldp x21, x22, [sp, #0x100]
|
||||||
|
|
||||||
|
msr sp_el1, x20
|
||||||
|
msr elr_el2, x21
|
||||||
|
msr spsr_el2, x22
|
||||||
|
|
||||||
|
ldp x0, x1, [sp, #0x00]
|
||||||
|
ldp x2, x3, [sp, #0x10]
|
||||||
|
ldp x4, x5, [sp, #0x20]
|
||||||
|
ldp x6, x7, [sp, #0x30]
|
||||||
|
ldp x8, x9, [sp, #0x40]
|
||||||
|
ldp x10, x11, [sp, #0x50]
|
||||||
|
ldp x12, x13, [sp, #0x60]
|
||||||
|
ldp x14, x15, [sp, #0x70]
|
||||||
|
ldp x16, x17, [sp, #0x80]
|
||||||
|
ldp x18, x19, [sp, #0x90]
|
||||||
|
ldp x20, x21, [sp, #0xA0]
|
||||||
|
ldp x22, x23, [sp, #0xB0]
|
||||||
|
ldp x24, x25, [sp, #0xC0]
|
||||||
|
ldp x26, x27, [sp, #0xD0]
|
||||||
|
ldp x28, x29, [sp, #0xE0]
|
||||||
|
|
||||||
|
add sp, sp, #0x110
|
||||||
|
eret
|
||||||
|
|
||||||
|
vector_entry serror_a32
|
||||||
|
b unknown_exception
|
||||||
|
check_vector_size serror_a32
|
36
thermosphere/src/misc.h
Normal file
36
thermosphere/src/misc.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#define MISC_BASE 0x70000000ull
|
||||||
|
|
||||||
|
#define MAKE_MISC_REG(n) MAKE_REG32(MISC_BASE + n)
|
||||||
|
|
||||||
|
|
||||||
|
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 MAKE_MISC_REG(0x0C00)
|
||||||
|
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 MAKE_MISC_REG(0x0C04)
|
||||||
|
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 MAKE_MISC_REG(0x0C08)
|
||||||
|
|
||||||
|
#define PINMUX_AUX_GEN1_I2C_SCL_0 MAKE_MISC_REG(0x30BC)
|
||||||
|
#define PINMUX_AUX_GEN1_I2C_SDA_0 MAKE_MISC_REG(0x30C0)
|
||||||
|
|
||||||
|
#define PINMUX_AUX_UARTn_TX_0(n) MAKE_MISC_REG(0x30E4 + 0x10 * (n))
|
||||||
|
#define PINMUX_AUX_UARTn_RX_0(n) MAKE_MISC_REG(0x30E8 + 0x10 * (n))
|
||||||
|
#define PINMUX_AUX_UARTn_RTS_0(n) MAKE_MISC_REG(0x30EC + 0x10 * (n))
|
||||||
|
#define PINMUX_AUX_UARTn_CTS_0(n) MAKE_MISC_REG(0x30F0 + 0x10 * (n))
|
1141
thermosphere/src/my_libc.c
Normal file
1141
thermosphere/src/my_libc.c
Normal file
File diff suppressed because it is too large
Load diff
48
thermosphere/src/start.s
Normal file
48
thermosphere/src/start.s
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */
|
||||||
|
#define cpuactlr_el1 s3_1_c15_c2_0
|
||||||
|
#define cpuectlr_el1 s3_1_c15_c2_1
|
||||||
|
|
||||||
|
.section .text.start, "ax", %progbits
|
||||||
|
.align 3
|
||||||
|
.global _start
|
||||||
|
.type _start, %function
|
||||||
|
|
||||||
|
_start:
|
||||||
|
// Disable interrupts
|
||||||
|
msr daifset, 0b1111
|
||||||
|
|
||||||
|
// Set VBAR
|
||||||
|
ldr x8, =__vectors_start__
|
||||||
|
msr vbar_el2, x8
|
||||||
|
|
||||||
|
// Set tmp stack
|
||||||
|
ldr x8, =__stacks_top__
|
||||||
|
mov sp, x8
|
||||||
|
|
||||||
|
// Don't call init array to save space?
|
||||||
|
// Clear BSS
|
||||||
|
ldr x0, =__bss_start__
|
||||||
|
mov w1, #0
|
||||||
|
ldr x2, =__end__
|
||||||
|
sub x2, x2, x0
|
||||||
|
bl memset
|
||||||
|
|
||||||
|
b . // FIXME!
|
||||||
|
|
||||||
|
.pool
|
25
thermosphere/src/timers.c
Normal file
25
thermosphere/src/timers.c
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#include "timers.h"
|
||||||
|
|
||||||
|
void wait(u32 microseconds) {
|
||||||
|
u32 old_time = TIMERUS_CNTR_1US_0;
|
||||||
|
while (TIMERUS_CNTR_1US_0 - old_time <= microseconds) {
|
||||||
|
/* Spin-lock. */
|
||||||
|
}
|
||||||
|
}
|
43
thermosphere/src/timers.h
Normal file
43
thermosphere/src/timers.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#define TIMERS_BASE 0x60005000ull
|
||||||
|
#define MAKE_TIMERS_REG(n) MAKE_REG32(TIMERS_BASE + n)
|
||||||
|
|
||||||
|
#define TIMERUS_CNTR_1US_0 MAKE_TIMERS_REG(0x10)
|
||||||
|
#define SHARED_INTR_STATUS_0 MAKE_TIMERS_REG(0x1A0)
|
||||||
|
#define SHARED_TIMER_SECURE_CFG_0 MAKE_TIMERS_REG(0x1A4)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u32 CONFIG;
|
||||||
|
u32 STATUS;
|
||||||
|
u32 COMMAND;
|
||||||
|
u32 PATTERN;
|
||||||
|
} watchdog_timers_t;
|
||||||
|
|
||||||
|
#define GET_WDT(n) ((volatile watchdog_timers_t *)(TIMERS_BASE + 0x100 + 0x20 * n))
|
||||||
|
#define WDT_REBOOT_PATTERN 0xC45A
|
||||||
|
#define GET_WDT_REBOOT_CFG_REG(n) MAKE_REG32(TIMERS_BASE + 0x60 + 0x8 * n)
|
||||||
|
|
||||||
|
void wait(u32 microseconds);
|
||||||
|
|
||||||
|
static inline u32 get_time(void) {
|
||||||
|
return TIMERUS_CNTR_1US_0;
|
||||||
|
}
|
25
thermosphere/src/types.h
Normal file
25
thermosphere/src/types.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef uint8_t u8; ///< 8-bit unsigned integer
|
||||||
|
typedef uint16_t u16; ///< 16-bit unsigned integer
|
||||||
|
typedef uint32_t u32; ///< 32-bit unsigned integer
|
||||||
|
typedef uint64_t u64; ///< 64-bit unsigned integer
|
||||||
|
|
||||||
|
typedef int8_t s8; ///< 8-bit signed integer
|
||||||
|
typedef int16_t s16; ///< 16-bit signed integer
|
||||||
|
typedef int32_t s32; ///< 32-bit signed integer
|
||||||
|
typedef int64_t s64; ///< 64-bit signed integer
|
||||||
|
|
||||||
|
typedef volatile u8 vu8; ///< 8-bit volatile unsigned integer.
|
||||||
|
typedef volatile u16 vu16; ///< 16-bit volatile unsigned integer.
|
||||||
|
typedef volatile u32 vu32; ///< 32-bit volatile unsigned integer.
|
||||||
|
typedef volatile u64 vu64; ///< 64-bit volatile unsigned integer.
|
||||||
|
|
||||||
|
typedef volatile s8 vs8; ///< 8-bit volatile signed integer.
|
||||||
|
typedef volatile s16 vs16; ///< 16-bit volatile signed integer.
|
||||||
|
typedef volatile s32 vs32; ///< 32-bit volatile signed integer.
|
||||||
|
typedef volatile s64 vs64; ///< 64-bit volatile signed integer.
|
81
thermosphere/src/uart.c
Normal file
81
thermosphere/src/uart.c
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "timers.h"
|
||||||
|
#include "uart.h"
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
|
void uart_select(UartDevice dev) {
|
||||||
|
unsigned int id = (unsigned int)dev;
|
||||||
|
PINMUX_AUX_UARTn_TX_0(id) = 0; /* UART */
|
||||||
|
PINMUX_AUX_UARTn_RX_0(id) = 0x48; /* UART, enable, pull up */
|
||||||
|
PINMUX_AUX_UARTn_RTS_0(id) = 0; /* UART */
|
||||||
|
PINMUX_AUX_UARTn_CTS_0(id) = 0x44; /* UART, enable, pull down */
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_init(UartDevice dev, u32 baud) {
|
||||||
|
volatile uart_t *uart = get_uart_device(dev);
|
||||||
|
|
||||||
|
/* Set baud rate. */
|
||||||
|
u32 rate = (8 * baud + 408000000) / (16 * baud);
|
||||||
|
uart->UART_LCR = UART_LCR_DLAB; /* Enable DLAB. */
|
||||||
|
uart->UART_THR_DLAB = (u8)rate; /* Divisor latch LSB. */
|
||||||
|
uart->UART_IER_DLAB = (u8)(rate >> 8); /* Divisor latch MSB. */
|
||||||
|
uart->UART_LCR = 0; /* Diable DLAB. */
|
||||||
|
|
||||||
|
/* Setup UART in fifo mode. */
|
||||||
|
uart->UART_IER_DLAB = 0;
|
||||||
|
uart->UART_IIR_FCR = UART_FCR_FCR_EN_FIFO | UART_FCR_RX_CLR | UART_FCR_TX_CLR; /* Enable and clear TX and RX FIFOs. */
|
||||||
|
uart->UART_LSR;
|
||||||
|
wait(3 * ((baud + 999999) / baud));
|
||||||
|
uart->UART_LCR = UART_LCR_WD_LENGTH_8; /* Set word length 8. */
|
||||||
|
uart->UART_MCR = 0;
|
||||||
|
uart->UART_MSR = 0;
|
||||||
|
uart->UART_IRDA_CSR = 0;
|
||||||
|
uart->UART_RX_FIFO_CFG = 1; /* Set RX_FIFO trigger level */
|
||||||
|
uart->UART_MIE = 0;
|
||||||
|
uart->UART_ASR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function blocks until the UART device (dev) is in the desired state (status). Make sure the desired state can be reached! */
|
||||||
|
void uart_wait_idle(UartDevice dev, UartVendorStatus status) {
|
||||||
|
while (!(get_uart_device(dev)->UART_VENDOR_STATUS & status)) {
|
||||||
|
/* Wait */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_send(UartDevice dev, const void *buf, size_t len) {
|
||||||
|
volatile uart_t *uart = get_uart_device(dev);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
while (uart->UART_LSR & UART_LSR_TX_FIFO_FULL) {
|
||||||
|
/* Wait until the TX FIFO isn't full */
|
||||||
|
}
|
||||||
|
uart->UART_THR_DLAB = *((const u8 *)buf + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_recv(UartDevice dev, void *buf, size_t len) {
|
||||||
|
volatile uart_t *uart = get_uart_device(dev);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
while (uart->UART_LSR & UART_LSR_RX_FIFO_EMPTY) {
|
||||||
|
/* Wait until the RX FIFO isn't empty */
|
||||||
|
}
|
||||||
|
*((u8 *)buf + i) = uart->UART_THR_DLAB;
|
||||||
|
}
|
||||||
|
}
|
167
thermosphere/src/uart.h
Normal file
167
thermosphere/src/uart.h
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#define UART_BASE 0x70006000ull
|
||||||
|
|
||||||
|
#define BAUD_115200 115200
|
||||||
|
|
||||||
|
/* Exosphère: add the clkreset values for UART C,D,E */
|
||||||
|
typedef enum {
|
||||||
|
UART_A = 0,
|
||||||
|
UART_B = 1,
|
||||||
|
UART_C = 2,
|
||||||
|
UART_D = 3,
|
||||||
|
UART_E = 4,
|
||||||
|
} UartDevice;
|
||||||
|
|
||||||
|
/* 36.3.12 UART_VENDOR_STATUS_0_0 */
|
||||||
|
typedef enum {
|
||||||
|
UART_VENDOR_STATE_TX_IDLE = 1 << 0,
|
||||||
|
UART_VENDOR_STATE_RX_IDLE = 1 << 1,
|
||||||
|
|
||||||
|
/* This bit is set to 1 when a read is issued to an empty FIFO and gets cleared on register read (sticky bit until read)
|
||||||
|
0 = NO_UNDERRUN
|
||||||
|
1 = UNDERRUN
|
||||||
|
*/
|
||||||
|
UART_VENDOR_STATE_RX_UNDERRUN = 1 << 2,
|
||||||
|
|
||||||
|
/* This bit is set to 1 when write data is issued to the TX FIFO when it is already full and gets cleared on register read (sticky bit until read)
|
||||||
|
0 = NO_OVERRUN
|
||||||
|
1 = OVERRUN
|
||||||
|
*/
|
||||||
|
UART_VENDOR_STATE_TX_OVERRUN = 1 << 3,
|
||||||
|
|
||||||
|
UART_VENDOR_STATE_RX_FIFO_COUNTER = 0b111111 << 16, /* reflects number of current entries in RX FIFO */
|
||||||
|
UART_VENDOR_STATE_TX_FIFO_COUNTER = 0b111111 << 24 /* reflects number of current entries in TX FIFO */
|
||||||
|
} UartVendorStatus;
|
||||||
|
|
||||||
|
/* 36.3.6 UART_LSR_0 */
|
||||||
|
typedef enum {
|
||||||
|
UART_LSR_RDR = 1 << 0, /* Receiver Data Ready */
|
||||||
|
UART_LSR_OVRF = 1 << 1, /* Receiver Overrun Error */
|
||||||
|
UART_LSR_PERR = 1 << 2, /* Parity Error */
|
||||||
|
UART_LSR_FERR = 1 << 3, /* Framing Error */
|
||||||
|
UART_LSR_BRK = 1 << 4, /* BREAK condition detected on line */
|
||||||
|
UART_LSR_THRE = 1 << 5, /* Transmit Holding Register is Empty -- OK to write data */
|
||||||
|
UART_LSR_TMTY = 1 << 6, /* Transmit Shift Register empty status */
|
||||||
|
UART_LSR_FIFOE = 1 << 7, /* Receive FIFO Error */
|
||||||
|
UART_LSR_TX_FIFO_FULL = 1 << 8, /* Transmitter FIFO full status */
|
||||||
|
UART_LSR_RX_FIFO_EMPTY = 1 << 9, /* Receiver FIFO empty status */
|
||||||
|
} UartLineStatus;
|
||||||
|
|
||||||
|
/* 36.3.4 UART_LCR_0 */
|
||||||
|
typedef enum {
|
||||||
|
UART_LCR_WD_LENGTH_5 = 0, /* word length 5 */
|
||||||
|
UART_LCR_WD_LENGTH_6 = 1, /* word length 6 */
|
||||||
|
UART_LCR_WD_LENGTH_7 = 2, /* word length 7 */
|
||||||
|
UART_LCR_WD_LENGTH_8 = 3, /* word length 8 */
|
||||||
|
|
||||||
|
/* STOP:
|
||||||
|
0 = Transmit 1 stop bit
|
||||||
|
1 = Transmit 2 stop bits (receiver always checks for 1 stop bit)
|
||||||
|
*/
|
||||||
|
UART_LCR_STOP = 1 << 2,
|
||||||
|
UART_LCR_PAR = 1 << 3, /* Parity enabled */
|
||||||
|
UART_LCR_EVEN = 1 << 4, /* Even parity format. There will always be an even number of 1s in the binary representation (PAR = 1) */
|
||||||
|
UART_LCR_SET_P = 1 << 5, /* Set (force) parity to value in LCR[4] */
|
||||||
|
UART_LCR_SET_B = 1 << 6, /* Set BREAK condition -- Transmitter sends all zeroes to indicate BREAK */
|
||||||
|
UART_LCR_DLAB = 1 << 7, /* Divisor Latch Access Bit (set to allow programming of the DLH, DLM Divisors) */
|
||||||
|
} UartLineControl;
|
||||||
|
|
||||||
|
/* 36.3.3 UART_IIR_FCR_0 */
|
||||||
|
typedef enum {
|
||||||
|
UART_FCR_FCR_EN_FIFO = 1 << 0, /* Enable the transmit and receive FIFOs. This bit should be enabled */
|
||||||
|
UART_FCR_RX_CLR = 1 << 1, /* Clears the contents of the receive FIFO and resets its counter logic to 0 (the receive shift register is not cleared or altered). This bit returns to 0 after clearing the FIFOs */
|
||||||
|
UART_FCR_TX_CLR = 1 << 2, /* Clears the contents of the transmit FIFO and resets its counter logic to 0 (the transmit shift register is not cleared or altered). This bit returns to 0 after clearing the FIFOs */
|
||||||
|
|
||||||
|
/* DMA:
|
||||||
|
0 = DMA_MODE_0
|
||||||
|
1 = DMA_MODE_1
|
||||||
|
*/
|
||||||
|
UART_FCR_DMA = 1 << 3,
|
||||||
|
|
||||||
|
/* TX_TRIG
|
||||||
|
0 = FIFO_COUNT_GREATER_16
|
||||||
|
1 = FIFO_COUNT_GREATER_8
|
||||||
|
2 = FIFO_COUNT_GREATER_4
|
||||||
|
3 = FIFO_COUNT_GREATER_1
|
||||||
|
*/
|
||||||
|
UART_FCR_TX_TRIG = 3 << 4,
|
||||||
|
UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_16 = 0 << 4,
|
||||||
|
UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_8 = 1 << 4,
|
||||||
|
UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_4 = 2 << 4,
|
||||||
|
UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_1 = 3 << 4,
|
||||||
|
|
||||||
|
/* RX_TRIG
|
||||||
|
0 = FIFO_COUNT_GREATER_1
|
||||||
|
1 = FIFO_COUNT_GREATER_4
|
||||||
|
2 = FIFO_COUNT_GREATER_8
|
||||||
|
3 = FIFO_COUNT_GREATER_16
|
||||||
|
*/
|
||||||
|
UART_FCR_RX_TRIG = 3 << 6,
|
||||||
|
UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_1 = 0 << 6,
|
||||||
|
UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_4 = 1 << 6,
|
||||||
|
UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_8 = 2 << 6,
|
||||||
|
UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_16 = 3 << 6,
|
||||||
|
} UartFifoControl;
|
||||||
|
|
||||||
|
/* 36.3.3 UART_IIR_FCR_0 */
|
||||||
|
typedef enum {
|
||||||
|
UART_IIR_IS_STA = 1 << 0, /* Interrupt Pending if ZERO */
|
||||||
|
UART_IIR_IS_PRI0 = 1 << 1, /* Encoded Interrupt ID Refer to IIR[3:0] table [36.3.3] */
|
||||||
|
UART_IIR_IS_PRI1 = 1 << 2, /* Encoded Interrupt ID Refer to IIR[3:0] table */
|
||||||
|
UART_IIR_IS_PRI2 = 1 << 3, /* Encoded Interrupt ID Refer to IIR[3:0] table */
|
||||||
|
|
||||||
|
/* FIFO Mode Status
|
||||||
|
0 = 16450 mode (no FIFO)
|
||||||
|
1 = 16550 mode (FIFO)
|
||||||
|
*/
|
||||||
|
UART_IIR_EN_FIFO = 3 << 6,
|
||||||
|
UART_IIR_MODE_16450 = 0 << 6,
|
||||||
|
UART_IIR_MODE_16550 = 1 << 6,
|
||||||
|
} UartInterruptIdentification;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* 0x00 */ u32 UART_THR_DLAB;
|
||||||
|
/* 0x04 */ u32 UART_IER_DLAB;
|
||||||
|
/* 0x08 */ u32 UART_IIR_FCR;
|
||||||
|
/* 0x0C */ u32 UART_LCR;
|
||||||
|
/* 0x10 */ u32 UART_MCR;
|
||||||
|
/* 0x14 */ u32 UART_LSR;
|
||||||
|
/* 0x18 */ u32 UART_MSR;
|
||||||
|
/* 0x1C */ u32 UART_SPR;
|
||||||
|
/* 0x20 */ u32 UART_IRDA_CSR;
|
||||||
|
/* 0x24 */ u32 UART_RX_FIFO_CFG;
|
||||||
|
/* 0x28 */ u32 UART_MIE;
|
||||||
|
/* 0x2C */ u32 UART_VENDOR_STATUS;
|
||||||
|
/* 0x30 */ uint8_t _pad_30[0x0C];
|
||||||
|
/* 0x3C */ u32 UART_ASR;
|
||||||
|
} uart_t;
|
||||||
|
|
||||||
|
void uart_select(UartDevice dev);
|
||||||
|
void uart_init(UartDevice dev, u32 baud);
|
||||||
|
void uart_wait_idle(UartDevice dev, UartVendorStatus status);
|
||||||
|
void uart_send(UartDevice dev, const void *buf, size_t len);
|
||||||
|
void uart_recv(UartDevice dev, void *buf, size_t len);
|
||||||
|
|
||||||
|
static inline volatile uart_t *get_uart_device(UartDevice dev) {
|
||||||
|
static const size_t offsets[] = {0, 0x40, 0x200, 0x300, 0x400};
|
||||||
|
return (volatile uart_t *)(UART_BASE + offsets[dev]);
|
||||||
|
}
|
27
thermosphere/src/utils.c
Normal file
27
thermosphere/src/utils.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
__attribute__((noinline)) bool overlaps(u64 as, u64 ae, u64 bs, u64 be)
|
||||||
|
{
|
||||||
|
if(as <= bs && bs < ae)
|
||||||
|
return true;
|
||||||
|
if(bs <= as && as < be)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
107
thermosphere/src/utils.h
Normal file
107
thermosphere/src/utils.h
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.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 u32 *)(a))
|
||||||
|
|
||||||
|
#define ALIGN(m) __attribute__((aligned(m)))
|
||||||
|
#define PACKED __attribute__((packed))
|
||||||
|
|
||||||
|
#define ALINLINE __attribute__((always_inline))
|
||||||
|
|
||||||
|
#define SET_SYSREG(reg, val) do { temp_reg = (val); __asm__ __volatile__ ("msr " #reg ", %0" :: "r"(temp_reg) : "memory"); } while(false)
|
||||||
|
|
||||||
|
bool overlaps(u64 as, u64 ae, u64 bs, u64 be);
|
||||||
|
|
||||||
|
|
||||||
|
static inline uintptr_t get_physical_address(const void *vaddr) {
|
||||||
|
uintptr_t PAR;
|
||||||
|
__asm__ __volatile__ ("at s1e3r, %0" :: "r"(vaddr));
|
||||||
|
__asm__ __volatile__ ("mrs %0, par_el1" : "=r"(PAR));
|
||||||
|
return (PAR & 1) ? 0ull : (PAR & MASK2L(40, 12)) | ((uintptr_t)vaddr & MASKL(12));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uintptr_t get_physical_address_el0(const uintptr_t el0_vaddr) {
|
||||||
|
uintptr_t PAR;
|
||||||
|
__asm__ __volatile__ ("at s1e0r, %0" :: "r"(el0_vaddr));
|
||||||
|
__asm__ __volatile__ ("mrs %0, par_el1" : "=r"(PAR));
|
||||||
|
return (PAR & 1) ? 0ull : (PAR & MASK2L(40, 12)) | ((uintptr_t)el0_vaddr & MASKL(12));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 read32le(const volatile void *dword, size_t offset) {
|
||||||
|
return *(u32 *)((uintptr_t)dword + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 read32be(const volatile void *dword, size_t offset) {
|
||||||
|
return __builtin_bswap32(read32le(dword, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u64 read64le(const volatile void *qword, size_t offset) {
|
||||||
|
return *(u64 *)((uintptr_t)qword + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u64 read64be(const volatile void *qword, size_t offset) {
|
||||||
|
return __builtin_bswap64(read64le(qword, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write32le(volatile void *dword, size_t offset, u32 value) {
|
||||||
|
*(u32 *)((uintptr_t)dword + offset) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write32be(volatile void *dword, size_t offset, u32 value) {
|
||||||
|
write32le(dword, offset, __builtin_bswap32(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write64le(volatile void *qword, size_t offset, u64 value) {
|
||||||
|
*(u64 *)((uintptr_t)qword + offset) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write64be(volatile void *qword, size_t offset, u64 value) {
|
||||||
|
write64le(qword, offset, __builtin_bswap64(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int get_core_id(void) {
|
||||||
|
u64 core_id;
|
||||||
|
__asm__ __volatile__ ("mrs %0, mpidr_el1" : "=r"(core_id));
|
||||||
|
return (unsigned int)core_id & 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u64 get_debug_authentication_status(void) {
|
||||||
|
u64 debug_auth;
|
||||||
|
__asm__ __volatile__ ("mrs %0, dbgauthstatus_el1" : "=r"(debug_auth));
|
||||||
|
return debug_auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 get_spsr(void) {
|
||||||
|
u32 spsr;
|
||||||
|
__asm__ __volatile__ ("mrs %0, spsr_el2" : "=r"(spsr));
|
||||||
|
return spsr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool check_32bit_additive_overflow(u32 a, u32 b) {
|
||||||
|
return __builtin_add_overflow_p(a, b, (u32)0);
|
||||||
|
}
|
Loading…
Reference in a new issue